diff options
author | takeshi_hoshina <takeshi_hoshina@mail.toyota.co.jp> | 2020-11-02 11:07:33 +0900 |
---|---|---|
committer | takeshi_hoshina <takeshi_hoshina@mail.toyota.co.jp> | 2020-11-02 11:07:33 +0900 |
commit | 1c7d6584a7811b7785ae5c1e378f14b5ba0971cf (patch) | |
tree | cd70a267a5ef105ba32f200aa088e281fbd85747 /bsp/meta-rcar | |
parent | 4204309872da5cb401cbb2729d9e2d4869a87f42 (diff) |
basesystem-jjsandbox/ToshikazuOhiwa/master-jj
recipes
Diffstat (limited to 'bsp/meta-rcar')
174 files changed, 54978 insertions, 433 deletions
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/conf/layer.conf b/bsp/meta-rcar/meta-rcar-gen3-adas/conf/layer.conf index 9c1cabad..befdb200 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/conf/layer.conf +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/conf/layer.conf @@ -11,7 +11,7 @@ BBFILE_COLLECTIONS += "rcar-gen3-adas" BBFILE_PATTERN_rcar-gen3-adas := "^${LAYERDIR}/" BBFILE_PRIORITY_rcar-gen3-adas = "7" -LAYERSERIES_COMPAT_rcar-gen3-adas = "thud" +LAYERSERIES_COMPAT_rcar-gen3-adas = "dunfell" # Distro features needed for all boards DISTRO_FEATURES_remove = "x11" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/arm-trusted-firmware/files/0003-plat-renesas-rcar-Add-R-Car-V3M-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/arm-trusted-firmware/files/0003-plat-renesas-rcar-Add-R-Car-V3M-support.patch index 08b0cd4a..d6a6f6d5 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/arm-trusted-firmware/files/0003-plat-renesas-rcar-Add-R-Car-V3M-support.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/arm-trusted-firmware/files/0003-plat-renesas-rcar-Add-R-Car-V3M-support.patch @@ -123,7 +123,7 @@ index 2377cd2..32a6746 100644 case RCAR_PRODUCT_M3N: bl2_realtime_cpg_init_m3n(); break; -+ case RCAR_PRODUCT_v3m: ++ case RCAR_PRODUCT_V3M: + bl2_realtime_cpg_init_v3m(); + break; default: diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/arm-trusted-firmware/files/0004-plat-renesas-rcar-Add-R-Car-V3H-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/arm-trusted-firmware/files/0004-plat-renesas-rcar-Add-R-Car-V3H-support.patch index 9d2c7b95..841db094 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/arm-trusted-firmware/files/0004-plat-renesas-rcar-Add-R-Car-V3H-support.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/arm-trusted-firmware/files/0004-plat-renesas-rcar-Add-R-Car-V3H-support.patch @@ -110,10 +110,10 @@ index 32a6746..1481029 100644 { uint32_t modemr; @@ -454,6 +512,9 @@ void bl2_cpg_init(void) - case RCAR_PRODUCT_v3m: + case RCAR_PRODUCT_V3M: bl2_realtime_cpg_init_v3m(); break; -+ case RCAR_PRODUCT_v3h: ++ case RCAR_PRODUCT_V3H: + bl2_realtime_cpg_init_v3h(); + break; default: diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/linux-firmware/linux-firmware_git.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/linux-firmware/linux-firmware_20200122.bbappend index fdee4b08..fdee4b08 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/linux-firmware/linux-firmware_git.bbappend +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/linux-firmware/linux-firmware_20200122.bbappend diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/most-tools/files/most-tools.tar.gz b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/most-tools/files/most-tools.tar.gz Binary files differindex f1eaacb7..e13d1343 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/most-tools/files/most-tools.tar.gz +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/most-tools/files/most-tools.tar.gz diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0022-arm-dts-r8a77970-Disable-RPC-on-all-R-Car-V3M-boards.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0022-arm-dts-r8a77970-Disable-RPC-on-all-R-Car-V3M-boards.patch new file mode 100644 index 00000000..c756eafe --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0022-arm-dts-r8a77970-Disable-RPC-on-all-R-Car-V3M-boards.patch @@ -0,0 +1,58 @@ +From a807c19c45eb347a2d5b4391ff396b94a875d9dc Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Tue, 26 Nov 2019 21:52:37 +0300 +Subject: [PATCH 1/2] arm: dts: r8a77970: Disable RPC on all R-Car V3M boards + +This disables RPC device on all R-Car V3M boards. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm/dts/r8a77970-eagle-u-boot.dts | 4 ++-- + arch/arm/dts/r8a77970-v3msk-u-boot.dts | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/dts/r8a77970-eagle-u-boot.dts b/arch/arm/dts/r8a77970-eagle-u-boot.dts +index 5b17f1d..6c910c2 100644 +--- a/arch/arm/dts/r8a77970-eagle-u-boot.dts ++++ b/arch/arm/dts/r8a77970-eagle-u-boot.dts +@@ -36,7 +36,7 @@ + + &rpc { + num-cs = <1>; +- status = "okay"; ++ status = "disabled"; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <0>; +@@ -49,6 +49,6 @@ + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + reg = <0>; +- status = "okay"; ++ status = "disabled"; + }; + }; +diff --git a/arch/arm/dts/r8a77970-v3msk-u-boot.dts b/arch/arm/dts/r8a77970-v3msk-u-boot.dts +index 6ee06d7..5ae02ae 100644 +--- a/arch/arm/dts/r8a77970-v3msk-u-boot.dts ++++ b/arch/arm/dts/r8a77970-v3msk-u-boot.dts +@@ -47,7 +47,7 @@ + + &rpc { + num-cs = <1>; +- status = "okay"; ++ status = "disabled"; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <0>; +@@ -60,6 +60,6 @@ + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + reg = <0>; +- status = "okay"; ++ status = "disabled"; + }; + }; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0023-arm-dts-r8a77980-Disable-RPC-on-all-R-Car-V3H-boards.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0023-arm-dts-r8a77980-Disable-RPC-on-all-R-Car-V3H-boards.patch new file mode 100644 index 00000000..1819c8d9 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0023-arm-dts-r8a77980-Disable-RPC-on-all-R-Car-V3H-boards.patch @@ -0,0 +1,59 @@ +From 076a4721fde3f02eca24e4e3a218b35c62127cb9 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Tue, 26 Nov 2019 21:53:28 +0300 +Subject: [PATCH 2/2] arm: dts: r8a77980: Disable RPC on all R-Car V3H boards + +This disables RPC device on all R-Car V3H boards. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm/dts/r8a77980-condor-u-boot.dts | 4 ++-- + arch/arm/dts/r8a77980-v3hsk-u-boot.dts | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/dts/r8a77980-condor-u-boot.dts b/arch/arm/dts/r8a77980-condor-u-boot.dts +index 68897ed..8a101bf 100644 +--- a/arch/arm/dts/r8a77980-condor-u-boot.dts ++++ b/arch/arm/dts/r8a77980-condor-u-boot.dts +@@ -16,7 +16,7 @@ + + &rpc { + num-cs = <1>; +- status = "okay"; ++ status = "disabled"; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <0>; +@@ -29,6 +29,6 @@ + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + reg = <0>; +- status = "okay"; ++ status = "disabled"; + }; + }; +diff --git a/arch/arm/dts/r8a77980-v3hsk-u-boot.dts b/arch/arm/dts/r8a77980-v3hsk-u-boot.dts +index d083df6..4842314 100644 +--- a/arch/arm/dts/r8a77980-v3hsk-u-boot.dts ++++ b/arch/arm/dts/r8a77980-v3hsk-u-boot.dts +@@ -16,7 +16,7 @@ + + &rpc { + num-cs = <1>; +- status = "okay"; ++ status = "disabled"; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <0>; +@@ -29,7 +29,7 @@ + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + reg = <0>; +- status = "okay"; ++ status = "disabled"; + }; + }; + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0024-mmc-mmc-Set-clock-when-reverting-to-safe-bus-mode.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0024-mmc-mmc-Set-clock-when-reverting-to-safe-bus-mode.patch new file mode 100644 index 00000000..3f695c74 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0024-mmc-mmc-Set-clock-when-reverting-to-safe-bus-mode.patch @@ -0,0 +1,29 @@ +From d299ca847ab26f76fcd49eb14aecff9ea37b1bc8 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Fri, 25 Oct 2019 01:06:46 +0300 +Subject: [PATCH] mmc: mmc: Set clock when reverting to safe bus mode + +Set MMC clock when reverting to safe bus mode and speed +in case current MMC mode fails. Otherwise, trying out +the other modes may fail as well. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/mmc/mmc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c +index 0cecb10..b3f29ee 100644 +--- a/drivers/mmc/mmc.c ++++ b/drivers/mmc/mmc.c +@@ -2033,6 +2033,7 @@ error: + mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); + mmc_select_mode(mmc, MMC_LEGACY); ++ mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); + mmc_set_bus_width(mmc, 1); + } + } +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0025-net-Add-an-accessor-to-know-if-waiting-for-ARP.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0025-net-Add-an-accessor-to-know-if-waiting-for-ARP.patch new file mode 100644 index 00000000..96cac426 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0025-net-Add-an-accessor-to-know-if-waiting-for-ARP.patch @@ -0,0 +1,66 @@ +From 3ce40bb31bf1785bfa541805ada5f5f872a683a6 Mon Sep 17 00:00:00 2001 +From: Joe Hershberger <joe.hershberger@ni.com> +Date: Wed, 26 Sep 2018 16:48:58 -0500 +Subject: [PATCH 1/2] net: Add an accessor to know if waiting for ARP + +This single-sources the state of the ARP. + +Signed-off-by: Joe Hershberger <joe.hershberger@ni.com> +Reviewed-by: Simon Glass <sjg@chromium.org> +Reviewed-by: Bin Meng <bmeng.cn@gmail.com> + +(cherry picked from commit 3f02c98bd1000fc26ee2700fd5a75112cdeaca6c) +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + include/net.h | 1 + + net/arp.c | 11 ++++++++--- + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/include/net.h b/include/net.h +index 2b2deb5..259c4a7 100644 +--- a/include/net.h ++++ b/include/net.h +@@ -635,6 +635,7 @@ rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */ + void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */ + rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */ + void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */ ++bool arp_is_waiting(void); /* Waiting for ARP reply? */ + void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ + void net_set_timeout_handler(ulong, thand_f *);/* Set timeout handler */ + +diff --git a/net/arp.c b/net/arp.c +index b8a7168..ea685d9 100644 +--- a/net/arp.c ++++ b/net/arp.c +@@ -100,7 +100,7 @@ int arp_timeout_check(void) + { + ulong t; + +- if (!net_arp_wait_packet_ip.s_addr) ++ if (!arp_is_waiting()) + return 0; + + t = get_timer(0); +@@ -187,8 +187,8 @@ void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) + return; + + case ARPOP_REPLY: /* arp reply */ +- /* are we waiting for a reply */ +- if (!net_arp_wait_packet_ip.s_addr) ++ /* are we waiting for a reply? */ ++ if (!arp_is_waiting()) + break; + + #ifdef CONFIG_KEEP_SERVERADDR +@@ -233,3 +233,8 @@ void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) + return; + } + } ++ ++bool arp_is_waiting(void) ++{ ++ return !!net_arp_wait_packet_ip.s_addr; ++} +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0026-net-Don-t-overwrite-waiting-packets-with-asynchronou.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0026-net-Don-t-overwrite-waiting-packets-with-asynchronou.patch new file mode 100644 index 00000000..3456ac1f --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0026-net-Don-t-overwrite-waiting-packets-with-asynchronou.patch @@ -0,0 +1,158 @@ +From c8ecac854c314fa4bf8955991ca59c178ced8a64 Mon Sep 17 00:00:00 2001 +From: Joe Hershberger <joe.hershberger@ni.com> +Date: Wed, 26 Sep 2018 16:49:02 -0500 +Subject: [PATCH 2/2] net: Don't overwrite waiting packets with asynchronous + replies + +Peter originally sent a fix, but it breaks a number of other things. +This addresses the original reported issue in a different way. + +That report was: + +> U-Boot has 1 common buffer to send Ethernet frames, pointed to by +> net_tx_packet. When sending to an IP address without knowing the MAC +> address, U-Boot makes an ARP request (using the arp_tx_packet buffer) +> to find out the MAC address of the IP addressr. When a matching ARP +> reply is received, U-Boot continues sending the frame stored in the +> net_tx_packet buffer. +> +> However, in the mean time, if U-Boot needs to send out any network +> packets (e.g. replying ping packets or ARP requests for its own IP +> address etc.), it will use the net_tx_packet buffer to prepare the +> new packet. Thus this buffer is no longer the original packet meant +> to be transmitted after the ARP reply. The original packet will be +> lost. + +This instead uses the ARP tx buffer to send async replies in the case +where we are actively waiting for an ARP reply. + +Signed-off-by: Joe Hershberger <joe.hershberger@ni.com> + +Reported-by: Tran Tien Dat <peter.trantiendat@gmail.com> +Reviewed-by: Simon Glass <sjg@chromium.org> +Reviewed-by: Bin Meng <bmeng.cn@gmail.com> +Tested-by: Bin Meng <bmeng.cn@gmail.com> + +(cherry picked from commit ac3f26cc15ad7e3e9efc2b0b0e18c6e84d93af77) +[valentine.barshak: removed test/dm/eth.c part as not applicable] +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + include/net.h | 8 ++++++++ + net/arp.c | 9 +++++---- + net/arp.h | 1 + + net/net.c | 8 ++++++++ + net/ping.c | 7 +++++-- + 5 files changed, 27 insertions(+), 6 deletions(-) + +diff --git a/include/net.h b/include/net.h +index 259c4a7..a789a38 100644 +--- a/include/net.h ++++ b/include/net.h +@@ -654,6 +654,14 @@ static inline void net_set_state(enum net_loop_state state) + net_state = state; + } + ++/* ++ * net_get_async_tx_pkt_buf - Get a packet buffer that is not in use for ++ * sending an asynchronous reply ++ * ++ * returns - ptr to packet buffer ++ */ ++uchar * net_get_async_tx_pkt_buf(void); ++ + /* Transmit a packet */ + static inline void net_send_packet(uchar *pkt, int len) + { +diff --git a/net/arp.c b/net/arp.c +index ea685d9..b49c3d3 100644 +--- a/net/arp.c ++++ b/net/arp.c +@@ -34,8 +34,7 @@ uchar *arp_wait_packet_ethaddr; + int arp_wait_tx_packet_size; + ulong arp_wait_timer_start; + int arp_wait_try; +- +-static uchar *arp_tx_packet; /* THE ARP transmit packet */ ++uchar *arp_tx_packet; /* THE ARP transmit packet */ + static uchar arp_tx_packet_buf[PKTSIZE_ALIGN + PKTALIGN]; + + void arp_init(void) +@@ -126,6 +125,7 @@ void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) + struct arp_hdr *arp; + struct in_addr reply_ip_addr; + int eth_hdr_size; ++ uchar *tx_packet; + + /* + * We have to deal with two types of ARP packets: +@@ -182,8 +182,9 @@ void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) + (net_read_ip(&arp->ar_spa).s_addr & net_netmask.s_addr)) + udelay(5000); + #endif +- memcpy(net_tx_packet, et, eth_hdr_size + ARP_HDR_SIZE); +- net_send_packet(net_tx_packet, eth_hdr_size + ARP_HDR_SIZE); ++ tx_packet = net_get_async_tx_pkt_buf(); ++ memcpy(tx_packet, et, eth_hdr_size + ARP_HDR_SIZE); ++ net_send_packet(tx_packet, eth_hdr_size + ARP_HDR_SIZE); + return; + + case ARPOP_REPLY: /* arp reply */ +diff --git a/net/arp.h b/net/arp.h +index afb8695..25b3c00 100644 +--- a/net/arp.h ++++ b/net/arp.h +@@ -20,6 +20,7 @@ extern uchar *arp_wait_packet_ethaddr; + extern int arp_wait_tx_packet_size; + extern ulong arp_wait_timer_start; + extern int arp_wait_try; ++extern uchar *arp_tx_packet; + + void arp_init(void); + void arp_request(void); +diff --git a/net/net.c b/net/net.c +index 31cf306..77a7141 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -799,6 +799,14 @@ void net_set_timeout_handler(ulong iv, thand_f *f) + } + } + ++uchar *net_get_async_tx_pkt_buf(void) ++{ ++ if (arp_is_waiting()) ++ return arp_tx_packet; /* If we are waiting, we already sent */ ++ else ++ return net_tx_packet; ++} ++ + int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport, + int payload_len) + { +diff --git a/net/ping.c b/net/ping.c +index 3e5461a..821d35d 100644 +--- a/net/ping.c ++++ b/net/ping.c +@@ -84,6 +84,7 @@ void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) + struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src; + struct in_addr src_ip; + int eth_hdr_size; ++ uchar *tx_packet; + + switch (icmph->type) { + case ICMP_ECHO_REPLY: +@@ -107,8 +108,10 @@ void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) + icmph->type = ICMP_ECHO_REPLY; + icmph->checksum = 0; + icmph->checksum = compute_ip_checksum(icmph, len - IP_HDR_SIZE); +- memcpy(net_tx_packet, et, eth_hdr_size + len); +- net_send_packet(net_tx_packet, eth_hdr_size + len); ++ ++ tx_packet = net_get_async_tx_pkt_buf(); ++ memcpy(tx_packet, et, eth_hdr_size + len); ++ net_send_packet(tx_packet, eth_hdr_size + len); + return; + /* default: + return;*/ +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0027-net-sh_eth-Keep-phy-running.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0027-net-sh_eth-Keep-phy-running.patch new file mode 100644 index 00000000..38f7f0e0 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0027-net-sh_eth-Keep-phy-running.patch @@ -0,0 +1,126 @@ +From 04b535af397c8302f306952e09d531fc96fe523e Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Wed, 27 Nov 2019 03:46:52 +0300 +Subject: [PATCH 1/4] net: sh_eth: Keep phy running + +This doesn't stop the PHY, and disable the clock once the Ethernet +transfer is complete. We need PHY initialized for the "mii" console +commands to work. This also reduces Ethernet start time since we +don't have to reinitialize the PHY and restart auto-negotiation +every time an Ethernet command is issued. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/net/sh_eth.c | 52 +++++++++++++++++++++++++++------------------------- + 1 file changed, 27 insertions(+), 25 deletions(-) + +diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c +index be8c3d2..b120977 100644 +--- a/drivers/net/sh_eth.c ++++ b/drivers/net/sh_eth.c +@@ -778,35 +778,17 @@ static int sh_eth_phy_config(struct udevice *dev) + static int sh_ether_start(struct udevice *dev) + { + struct sh_ether_priv *priv = dev_get_priv(dev); +- struct eth_pdata *pdata = dev_get_platdata(dev); + struct sh_eth_dev *eth = &priv->shdev; ++ struct sh_eth_info *port_info = ð->port_info[eth->port]; + int ret; + +- ret = clk_enable(&priv->clk); +- if (ret) +- return ret; +- +- ret = sh_eth_init_common(eth, pdata->enetaddr); +- if (ret) +- goto err_clk; +- +- ret = sh_eth_phy_config(dev); ++ ret = phy_startup(port_info->phydev); + if (ret) { +- printf(SHETHER_NAME ": phy config timeout\n"); +- goto err_start; ++ printf(SHETHER_NAME ": phy startup failure\n"); ++ return ret; + } + + ret = sh_eth_start_common(eth); +- if (ret) +- goto err_start; +- +- return 0; +- +-err_start: +- sh_eth_tx_desc_free(eth); +- sh_eth_rx_desc_free(eth); +-err_clk: +- clk_disable(&priv->clk); + return ret; + } + +@@ -815,7 +797,6 @@ static void sh_ether_stop(struct udevice *dev) + struct sh_ether_priv *priv = dev_get_priv(dev); + + sh_eth_stop(&priv->shdev); +- clk_disable(&priv->clk); + } + + static int sh_ether_probe(struct udevice *udev) +@@ -857,7 +838,7 @@ static int sh_ether_probe(struct udevice *udev) + + ret = mdio_register(mdiodev); + if (ret < 0) +- goto err_mdio_register; ++ goto err_mdio; + + priv->bus = miiphy_get_dev_by_name(udev->name); + +@@ -866,9 +847,25 @@ static int sh_ether_probe(struct udevice *udev) + eth->port_info[eth->port].iobase = + (void __iomem *)(BASE_IO_ADDR + 0x800 * eth->port); + ++ ret = clk_enable(&priv->clk); ++ if (ret) ++ goto err_mdio; ++ ++ ret = sh_eth_init_common(eth, pdata->enetaddr); ++ if (ret) ++ goto err_clk; ++ ++ ret = sh_eth_phy_config(udev); ++ if (ret) { ++ printf(SHETHER_NAME ": phy config timeout\n"); ++ goto err_clk; ++ } ++ + return 0; + +-err_mdio_register: ++err_clk: ++ clk_disable(&priv->clk); ++err_mdio: + mdio_free(mdiodev); + return ret; + } +@@ -879,13 +876,18 @@ static int sh_ether_remove(struct udevice *udev) + struct sh_eth_dev *eth = &priv->shdev; + struct sh_eth_info *port_info = ð->port_info[eth->port]; + ++ sh_eth_tx_desc_free(eth); ++ sh_eth_rx_desc_free(eth); ++ + free(port_info->phydev); ++ + mdio_unregister(priv->bus); + mdio_free(priv->bus); + + if (dm_gpio_is_valid(&priv->reset_gpio)) + dm_gpio_free(udev, &priv->reset_gpio); + ++ clk_disable(&priv->clk); + return 0; + } + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0028-net-sh_eth-Fix-compilation-warnings.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0028-net-sh_eth-Fix-compilation-warnings.patch new file mode 100644 index 00000000..2e878538 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0028-net-sh_eth-Fix-compilation-warnings.patch @@ -0,0 +1,135 @@ +From 4d00819431c519c143242b230f6afaf59dc57051 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 2 Dec 2019 01:08:01 +0300 +Subject: [PATCH 2/4] net: sh_eth: Fix compilation warnings + +This fixes multiple type cast warnings: + "warning: cast to pointer from integer of different size" + +In most cases we use uintptr_t type instead of int or u32. +Also, use iobase address obtained from the device tree +instead of hard-coded macro for the phy address. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/net/sh_eth.c | 24 ++++++++++++------------ + drivers/net/sh_eth.h | 8 ++++---- + 2 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c +index b120977..fbae6ce 100644 +--- a/drivers/net/sh_eth.c ++++ b/drivers/net/sh_eth.c +@@ -36,8 +36,8 @@ + + #if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && !defined(CONFIG_SYS_DCACHE_OFF) + #define flush_cache_wback(addr, len) \ +- flush_dcache_range((u32)addr, \ +- (u32)(addr + ALIGN(len, CONFIG_SH_ETHER_ALIGNE_SIZE))) ++ flush_dcache_range((uintptr_t)(addr), \ ++ (uintptr_t)(addr) + ALIGN((len), CONFIG_SH_ETHER_ALIGNE_SIZE)) + #else + #define flush_cache_wback(...) + #endif +@@ -45,11 +45,11 @@ + #if defined(CONFIG_SH_ETHER_CACHE_INVALIDATE) && defined(CONFIG_ARM) + #define invalidate_cache(addr, len) \ + { \ +- u32 line_size = CONFIG_SH_ETHER_ALIGNE_SIZE; \ +- u32 start, end; \ ++ uintptr_t line_size = CONFIG_SH_ETHER_ALIGNE_SIZE; \ ++ uintptr_t start, end; \ + \ +- start = (u32)addr; \ +- end = start + len; \ ++ start = (uintptr_t)(addr); \ ++ end = start + (len); \ + start &= ~(line_size - 1); \ + end = ((end + line_size - 1) & ~(line_size - 1)); \ + \ +@@ -73,7 +73,7 @@ static int sh_eth_send_common(struct sh_eth_dev *eth, void *packet, int len) + } + + /* packet must be a 4 byte boundary */ +- if ((int)packet & 3) { ++ if ((uintptr_t)packet & 3) { + printf(SHETHER_NAME ": %s: packet not 4 byte aligned\n" + , __func__); + ret = -EFAULT; +@@ -210,7 +210,7 @@ static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) + + /* Make sure we use a P2 address (non-cacheable) */ + port_info->tx_desc_base = +- (struct tx_desc_s *)ADDR_TO_P2((u32)port_info->tx_desc_alloc); ++ (struct tx_desc_s *)ADDR_TO_P2((uintptr_t)port_info->tx_desc_alloc); + port_info->tx_desc_cur = port_info->tx_desc_base; + + /* Initialize all descriptors */ +@@ -264,7 +264,7 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) + + /* Make sure we use a P2 address (non-cacheable) */ + port_info->rx_desc_base = +- (struct rx_desc_s *)ADDR_TO_P2((u32)port_info->rx_desc_alloc); ++ (struct rx_desc_s *)ADDR_TO_P2((uintptr_t)port_info->rx_desc_alloc); + + port_info->rx_desc_cur = port_info->rx_desc_base; + +@@ -280,7 +280,7 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) + goto err_buf_alloc; + } + +- port_info->rx_buf_base = (u8 *)ADDR_TO_P2((u32)port_info->rx_buf_alloc); ++ port_info->rx_buf_base = (u8 *)ADDR_TO_P2((uintptr_t)port_info->rx_buf_alloc); + + /* Initialize all descriptors */ + for (cur_rx_desc = port_info->rx_desc_base, +@@ -699,7 +699,7 @@ static int sh_ether_recv(struct udevice *dev, int flags, uchar **packetp) + struct sh_ether_priv *priv = dev_get_priv(dev); + struct sh_eth_dev *eth = &priv->shdev; + struct sh_eth_info *port_info = ð->port_info[eth->port]; +- uchar *packet = (uchar *)ADDR_TO_P2(port_info->rx_desc_cur->rd2); ++ uchar *packet = (uchar *)ADDR_TO_P2((uintptr_t)port_info->rx_desc_cur->rd2); + int len; + + len = sh_eth_recv_start(eth); +@@ -845,7 +845,7 @@ static int sh_ether_probe(struct udevice *udev) + eth->port = CONFIG_SH_ETHER_USE_PORT; + eth->port_info[eth->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR; + eth->port_info[eth->port].iobase = +- (void __iomem *)(BASE_IO_ADDR + 0x800 * eth->port); ++ (void __iomem *)(priv->iobase + 0x800 * eth->port); + + ret = clk_enable(&priv->clk); + if (ret) +diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h +index 1fa38e7..61fe0c9 100644 +--- a/drivers/net/sh_eth.h ++++ b/drivers/net/sh_eth.h +@@ -15,20 +15,20 @@ + #if defined(CONFIG_SH) + /* Malloc returns addresses in the P1 area (cacheable). However we need to + use area P2 (non-cacheable) */ +-#define ADDR_TO_P2(addr) ((((int)(addr) & ~0xe0000000) | 0xa0000000)) ++#define ADDR_TO_P2(addr) ((((uintptr_t)(addr) & ~0xe0000000) | 0xa0000000)) + + /* The ethernet controller needs to use physical addresses */ + #if defined(CONFIG_SH_32BIT) +-#define ADDR_TO_PHY(addr) ((((int)(addr) & ~0xe0000000) | 0x40000000)) ++#define ADDR_TO_PHY(addr) ((((uintptr_t)(addr) & ~0xe0000000) | 0x40000000)) + #else +-#define ADDR_TO_PHY(addr) ((int)(addr) & ~0xe0000000) ++#define ADDR_TO_PHY(addr) ((uintptr_t)(addr) & ~0xe0000000) + #endif + #elif defined(CONFIG_ARM) + #ifndef inl + #define inl readl + #define outl writel + #endif +-#define ADDR_TO_PHY(addr) ((int)(addr)) ++#define ADDR_TO_PHY(addr) ((uintptr_t)(addr)) + #define ADDR_TO_P2(addr) (addr) + #endif /* defined(CONFIG_SH) */ + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0029-net-sh_eth-Workaround-cache-issues.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0029-net-sh_eth-Workaround-cache-issues.patch new file mode 100644 index 00000000..79eba33b --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0029-net-sh_eth-Workaround-cache-issues.patch @@ -0,0 +1,74 @@ +From 869da2f4ee518558382f4a929ca302d1b2f91274 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 2 Dec 2019 01:13:19 +0300 +Subject: [PATCH 3/4] net: sh_eth: Workaround cache issues + +U-Boot writes to RX packets when constructing replies. +This can cause stale cached data to be written to RX +buffer while we're receiving a packet. This causes RX +packet corruption because we invalidate the cache right +before processing the packet. Invalidate packet buffer +cache when preparing RX descriptor as well. This seems +to fix RX packet drops with high RX traffic. + +While at it flush the descriptors right before enabling +RX/TX in sh_eth_tx_desc_init/sh_eth_rx_desc_init callbacks +when they are ready instead of flushing after allocation. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/net/sh_eth.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c +index fbae6ce..5df078d 100644 +--- a/drivers/net/sh_eth.c ++++ b/drivers/net/sh_eth.c +@@ -138,6 +138,8 @@ static void sh_eth_recv_finish(struct sh_eth_dev *eth) + { + struct sh_eth_info *port_info = ð->port_info[eth->port]; + ++ invalidate_cache(ADDR_TO_P2(port_info->rx_desc_cur->rd2), MAX_BUF_SIZE); ++ + /* Make current descriptor available again */ + if (port_info->rx_desc_cur->rd0 & RD_RDLE) + port_info->rx_desc_cur->rd0 = RD_RACT | RD_RDLE; +@@ -206,8 +208,6 @@ static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) + goto err; + } + +- flush_cache_wback(port_info->tx_desc_alloc, alloc_desc_size); +- + /* Make sure we use a P2 address (non-cacheable) */ + port_info->tx_desc_base = + (struct tx_desc_s *)ADDR_TO_P2((uintptr_t)port_info->tx_desc_alloc); +@@ -225,6 +225,7 @@ static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) + cur_tx_desc--; + cur_tx_desc->td0 |= TD_TDLE; + ++ flush_cache_wback(port_info->tx_desc_alloc, alloc_desc_size); + /* + * Point the controller to the tx descriptor list. Must use physical + * addresses +@@ -260,8 +261,6 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) + goto err; + } + +- flush_cache_wback(port_info->rx_desc_alloc, alloc_desc_size); +- + /* Make sure we use a P2 address (non-cacheable) */ + port_info->rx_desc_base = + (struct rx_desc_s *)ADDR_TO_P2((uintptr_t)port_info->rx_desc_alloc); +@@ -295,6 +294,9 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) + cur_rx_desc--; + cur_rx_desc->rd0 |= RD_RDLE; + ++ invalidate_cache(port_info->rx_buf_alloc, NUM_RX_DESC * MAX_BUF_SIZE); ++ flush_cache_wback(port_info->rx_desc_alloc, alloc_desc_size); ++ + /* Point the controller to the rx descriptor list */ + sh_eth_write(port_info, ADDR_TO_PHY(port_info->rx_desc_base), RDLAR); + #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0030-net-sh_eth-Fix-RX-error-handling.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0030-net-sh_eth-Fix-RX-error-handling.patch new file mode 100644 index 00000000..a93ce617 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0030-net-sh_eth-Fix-RX-error-handling.patch @@ -0,0 +1,73 @@ +From d71076d2f04dace4483f184899e365a27a74d07d Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 2 Dec 2019 01:20:34 +0300 +Subject: [PATCH 4/4] net: sh_eth: Fix RX error handling + +In case RX error occurs, and the RD_RFE bit is set, the descriptor +is never returned back to the queue. Make sh_eth_recv_start return +zero length in this case so that the descriptor can be released +and pushed back to the list. Also return the more appropriate +-EAGAIN instead of -EINVAL if the descriptor is not ready yet. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/net/sh_eth.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c +index 5df078d..eeb1d32 100644 +--- a/drivers/net/sh_eth.c ++++ b/drivers/net/sh_eth.c +@@ -125,11 +125,11 @@ static int sh_eth_recv_start(struct sh_eth_dev *eth) + /* Check if the rx descriptor is ready */ + invalidate_cache(port_info->rx_desc_cur, sizeof(struct rx_desc_s)); + if (port_info->rx_desc_cur->rd0 & RD_RACT) +- return -EINVAL; ++ return -EAGAIN; + + /* Check for errors */ + if (port_info->rx_desc_cur->rd0 & RD_RFE) +- return -EINVAL; ++ return 0; + + return port_info->rx_desc_cur->rd1 & 0xffff; + } +@@ -553,9 +553,11 @@ static int sh_eth_recv_common(struct sh_eth_dev *eth) + uchar *packet = (uchar *)ADDR_TO_P2(port_info->rx_desc_cur->rd2); + + len = sh_eth_recv_start(eth); +- if (len > 0) { +- invalidate_cache(packet, len); +- net_process_received_packet(packet, len); ++ if (len >= 0) { ++ if (len > 0) { ++ invalidate_cache(packet, len); ++ net_process_received_packet(packet, len); ++ } + sh_eth_recv_finish(eth); + } else + len = 0; +@@ -710,15 +712,13 @@ static int sh_ether_recv(struct udevice *dev, int flags, uchar **packetp) + *packetp = packet; + + return len; +- } else { +- len = 0; ++ } + +- /* Restart the receiver if disabled */ +- if (!(sh_eth_read(port_info, EDRRR) & EDRRR_R)) +- sh_eth_write(port_info, EDRRR_R, EDRRR); ++ /* Restart the receiver if disabled */ ++ if (!(sh_eth_read(port_info, EDRRR) & EDRRR_R)) ++ sh_eth_write(port_info, EDRRR_R, EDRRR); + +- return -EAGAIN; +- } ++ return len; + } + + static int sh_ether_free_pkt(struct udevice *dev, uchar *packet, int length) +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot_2018.09.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot_2018.09.bbappend index 6e28e5e9..ebc38928 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot_2018.09.bbappend +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot_2018.09.bbappend @@ -1,5 +1,15 @@ FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +RPC_ENABLED = " \ + file://0022-arm-renesas-Enable-RPC-HF-MTD-support-for-all-Salvat.patch \ + file://0023-arm-renesas-Enable-RPC-HF-MTD-support-for-all-ULCB-b.patch \ +" + +RPC_DISABLED = " \ + file://0022-arm-dts-r8a77970-Disable-RPC-on-all-R-Car-V3M-boards.patch \ + file://0023-arm-dts-r8a77980-Disable-RPC-on-all-R-Car-V3H-boards.patch \ +" + SRC_URI_append = " \ file://0001-uboot-ravb-remove-APSR-quirk.patch \ file://0002-net-ravb-fix-unsafe-phy-access.patch \ @@ -22,6 +32,12 @@ SRC_URI_append = " \ file://0019-ARM-rmobile-Add-R8A7795-H3ULCB-HAD-board-support.patch \ file://0020-arm-renesas-v3msk-Add-CPLD-support.patch \ file://0021-arm-renesas-v3hsk-Add-CPLD-support.patch \ - file://0022-arm-renesas-Enable-RPC-HF-MTD-support-for-all-Salvat.patch \ - file://0023-arm-renesas-Enable-RPC-HF-MTD-support-for-all-ULCB-b.patch \ + ${@oe.utils.conditional("DISABLE_RPC_ACCESS", "1", "${RPC_DISABLED}", "${RPC_ENABLED}", d)} \ + file://0024-mmc-mmc-Set-clock-when-reverting-to-safe-bus-mode.patch \ + file://0025-net-Add-an-accessor-to-know-if-waiting-for-ARP.patch \ + file://0026-net-Don-t-overwrite-waiting-packets-with-asynchronou.patch \ + file://0027-net-sh_eth-Keep-phy-running.patch \ + file://0028-net-sh_eth-Fix-compilation-warnings.patch \ + file://0029-net-sh_eth-Workaround-cache-issues.patch \ + file://0030-net-sh_eth-Fix-RX-error-handling.patch \ " diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/utest-apps/utest-cam-imr-drm.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/utest-apps/utest-cam-imr-drm.bb index 7b834ce9..945a2b08 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/utest-apps/utest-cam-imr-drm.bb +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-bsp/utest-apps/utest-cam-imr-drm.bb @@ -7,7 +7,7 @@ S = "${WORKDIR}/git" BRANCH = "rcar_gen3" SRC_URI = "git://github.com/CogentEmbedded/utest-cam-imr-drm.git;branch=${BRANCH}" -SRCREV = "27e5984c05357194759a1f81d0ffa20d523d0103" +SRCREV = "fd160edb99b34223f2c49fecbef3cca3daddbe59" PV = "v1.0+renesas+git" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd/dummy0.network b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd/70-dummy0.network index 054e17bb..054e17bb 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd/dummy0.network +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd/70-dummy0.network diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd/eth0.network b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd/70-eth0.network index 74951b47..74951b47 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd/eth0.network +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd/70-eth0.network diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd_%.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd_%.bbappend index 5aded79b..ed91218c 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd_%.bbappend +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-core/systemd/systemd_%.bbappend @@ -1,10 +1,9 @@ FILESEXTRAPATHS_append := '${THISDIR}/${PN}:' -SRC_URI_append = "file://eth0.network" - -SRC_URI_append= '${@ " \ - file://dummy0.network \ -" if 'surroundview' in '${DISTRO_FEATURES}' else ""}' +SRC_URI_append = " \ + file://70-eth0.network \ + ${@bb.utils.contains("DISTRO_FEATURES", "surroundview", "file://70-dummy0.network", "", d)} \ +" FILES_${PN} += "${sysconfdir}/systemd/network/*" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/gcc/gcc-sanitizers_%.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/gcc/gcc-sanitizers_%.bbappend new file mode 100644 index 00000000..f422a78d --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/gcc/gcc-sanitizers_%.bbappend @@ -0,0 +1 @@ +COMPATIBLE_HOST_aarch64 = 'aarch64.*-linux' diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/yaml-cpp/yaml-cpp_0.5.3.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/yaml-cpp/yaml-cpp_0.5.3.bb index 91c35c3f..c84d11cb 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/yaml-cpp/yaml-cpp_0.5.3.bb +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/yaml-cpp/yaml-cpp_0.5.3.bb @@ -8,15 +8,16 @@ DEPENDS = "boost" PR = "r0" -S = "${WORKDIR}/yaml-cpp-release-${PV}" +S = "${WORKDIR}/git" -SRC_URI = "https://github.com/jbeder/yaml-cpp/archive/release-${PV}.tar.gz" -SRC_URI[md5sum] = "64200ca0bf5e0af065804d8d3e8f6d42" -SRC_URI[sha256sum] = "ac50a27a201d16dc69a881b80ad39a7be66c4d755eda1f76c3a68781b922af8f" +SRC_URI = "git://github.com/jbeder/${BPN}.git" + +# tag: yaml-cpp-0.5.3 +SRCREV = "b57efe94e7d445713c29f863adb8c23438eaa217" inherit cmake -EXTRA_OECMAKE += "-DBUILD_SHARED_LIBS=ON -DYAML_CPP_BUILD_TESTS=OFF -DLIB_SUFFIX=64" +EXTRA_OECMAKE += "-DBUILD_SHARED_LIBS=ON -DYAML_CPP_BUILD_TESTS=OFF" FILES_${PN}-dev += "${libdir}/cmake" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/yaml-cpp/yaml-cpp_0.6.2.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/yaml-cpp/yaml-cpp_0.6.2.bb index 8c8d5aa6..a2a9d90e 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/yaml-cpp/yaml-cpp_0.6.2.bb +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-devtools/yaml-cpp/yaml-cpp_0.6.2.bb @@ -8,11 +8,12 @@ DEPENDS = "boost" PR = "r0" -S = "${WORKDIR}/yaml-cpp-${PN}-${PV}" +S = "${WORKDIR}/git" -SRC_URI = "https://github.com/jbeder/yaml-cpp/archive/${PN}-${PV}.tar.gz" -SRC_URI[md5sum] = "5b943e9af0060d0811148b037449ef82" -SRC_URI[sha256sum] = "e4d8560e163c3d875fd5d9e5542b5fd5bec810febdcba61481fe5fc4e6b1fd05" +SRC_URI = "git://github.com/jbeder/${BPN}.git" + +# tag: yaml-cpp-0.6.2 +SRCREV = "562aefc114938e388457e6a531ed7b54d9dc1b62" inherit cmake diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/cairo/cairo_1.14.12.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/cairo/cairo_1.16.0.bbappend index fa555a8d..17c4e718 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/cairo/cairo_1.14.12.bbappend +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/cairo/cairo_1.16.0.bbappend @@ -1,4 +1,2 @@ -require include/gles-control.inc - PACKAGECONFIG_pn-cairo_append = "${@' egl glesv2' if '${USE_GLES_WAYLAND}' == '1' else ''}" PACKAGECONFIG_pn-cairo_append += "${@bb.utils.contains('DISTRO_FEATURES', 'directfb', 'directfb', '', d)}" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv/0001-Merge-pull-request-10011-from-jviney-master.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv/0001-Merge-pull-request-10011-from-jviney-master.patch deleted file mode 100644 index b20183b3..00000000 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv/0001-Merge-pull-request-10011-from-jviney-master.patch +++ /dev/null @@ -1,112 +0,0 @@ -From b1d208891b9f6ae3968730b120a5d0dcbba679d0 Mon Sep 17 00:00:00 2001 -From: Jonathan Viney <jonathan.viney@gmail.com> -Date: Sun, 19 Nov 2017 07:08:41 +1300 -Subject: [PATCH] Merge pull request #10011 from jviney:master - -Fix build with FFmpeg master. Some deprecated APIs have been removed. (#10011) - -* Fix build with FFmpeg master. - -* ffmpeg: update AVFMT_RAWPICTURE support removal ---- - modules/videoio/src/cap_ffmpeg_impl.hpp | 37 +++++++++++++++++++++++++-------- - 1 file changed, 28 insertions(+), 9 deletions(-) - -diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp -index 5f51e65..4646148 100644 ---- a/modules/videoio/src/cap_ffmpeg_impl.hpp -+++ b/modules/videoio/src/cap_ffmpeg_impl.hpp -@@ -149,6 +149,10 @@ extern "C" { - #define AV_PIX_FMT_GRAY16BE PIX_FMT_GRAY16BE - #endif - -+#ifndef PKT_FLAG_KEY -+#define PKT_FLAG_KEY AV_PKT_FLAG_KEY -+#endif -+ - #if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \ - ? CALC_FFMPEG_VERSION(52, 38, 100) : CALC_FFMPEG_VERSION(52, 13, 0)) - #define USE_AV_FRAME_GET_BUFFER 1 -@@ -1570,7 +1574,11 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc, - // some formats want stream headers to be seperate - if(oc->oformat->flags & AVFMT_GLOBALHEADER) - { -+#if LIBAVCODEC_BUILD > CALC_FFMPEG_VERSION(56, 35, 0) -+ c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; -+#else - c->flags |= CODEC_FLAG_GLOBAL_HEADER; -+#endif - } - #endif - -@@ -1598,23 +1606,24 @@ static int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, - #endif - int ret = OPENCV_NO_FRAMES_WRITTEN_CODE; - -- if (oc->oformat->flags & AVFMT_RAWPICTURE) { -+#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(57, 0, 0) -+ if (oc->oformat->flags & AVFMT_RAWPICTURE) -+ { - /* raw video case. The API will change slightly in the near - futur for that */ - AVPacket pkt; - av_init_packet(&pkt); - --#ifndef PKT_FLAG_KEY --#define PKT_FLAG_KEY AV_PKT_FLAG_KEY --#endif -- - pkt.flags |= PKT_FLAG_KEY; - pkt.stream_index= video_st->index; - pkt.data= (uint8_t *)picture; - pkt.size= sizeof(AVPicture); - - ret = av_write_frame(oc, &pkt); -- } else { -+ } -+ else -+#endif -+ { - /* encode the image */ - AVPacket pkt; - av_init_packet(&pkt); -@@ -1772,7 +1781,9 @@ void CvVideoWriter_FFMPEG::close() - /* write the trailer, if any */ - if(ok && oc) - { -- if( (oc->oformat->flags & AVFMT_RAWPICTURE) == 0 ) -+#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(57, 0, 0) -+ if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) -+#endif - { - for(;;) - { -@@ -2071,7 +2082,11 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, - - outbuf = NULL; - -- if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) { -+ -+#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(57, 0, 0) -+ if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) -+#endif -+ { - /* allocate output buffer */ - /* assume we will never get codec output with more than 4 bytes per pixel... */ - outbuf_size = width*height*4; -@@ -2376,7 +2391,11 @@ AVStream* OutputMediaStream_FFMPEG::addVideoStream(AVFormatContext *oc, CV_CODEC - // some formats want stream headers to be seperate - if (oc->oformat->flags & AVFMT_GLOBALHEADER) - { -- c->flags |= CODEC_FLAG_GLOBAL_HEADER; -+ #if LIBAVCODEC_BUILD > CALC_FFMPEG_VERSION(56, 35, 0) -+ c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; -+ #else -+ c->flags |= CODEC_FLAG_GLOBAL_HEADER; -+ #endif - } - #endif - --- -2.7.4 - diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv_2.4.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv_2.4.bb index 602b1b45..4c63f961 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv_2.4.bb +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv_2.4.bb @@ -44,7 +44,9 @@ PACKAGECONFIG[gstreamer] = "-DWITH_GSTREAMER=ON,-DWITH_GSTREAMER=OFF,gstreamer1. PACKAGECONFIG[opengl] = "-DWITH_OPENGL=ON,-DWITH_OPENGL=OFF,," PACKAGECONFIG[qt5] = "-DWITH_QT=ON,-DWITH_QT=OFF,qtbase," -inherit distutils-base pkgconfig cmake ${@bb.utils.contains( 'DISTRO_FEATURES', 'qt5', 'cmake_qt5','', d)} +inherit pkgconfig cmake ${@bb.utils.contains( 'DISTRO_FEATURES', 'qt5', 'cmake_qt5','', d)} +inherit ${@bb.utils.contains('PACKAGECONFIG', 'python3', 'distutils3-base', '', d)} +inherit ${@bb.utils.contains('PACKAGECONFIG', 'python2', 'distutils-base', '', d)} export BUILD_SYS export HOST_SYS diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv_3.2.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv_3.2.bb index 01ed0210..682aebd4 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv_3.2.bb +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/opencv/opencv_3.2.bb @@ -30,7 +30,6 @@ SRC_URI = "git://github.com/opencv/opencv.git;name=opencv \ file://uselocalxfeatures.patch;patchdir=../contrib/ \ file://useoeprotobuf.patch;patchdir=../contrib/ \ file://0001-Revert-cuda-fix-fp16-compilation.patch \ - file://0001-Merge-pull-request-10011-from-jviney-master.patch \ " # file://0002-Revert-check-FP16-build-condition-correctly.patch \ # diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0001-Allow-to-boot-without-input-device.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0001-Allow-to-boot-without-input-device.patch index d453103e..5636c23d 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0001-Allow-to-boot-without-input-device.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0001-Allow-to-boot-without-input-device.patch @@ -1,17 +1,17 @@ -From 980b48bc279d46559465665e94e546f661d1d427 Mon Sep 17 00:00:00 2001 +From d04c556bc8eac439cc87c7cdf9b4446d4a9cecaa Mon Sep 17 00:00:00 2001 From: Grigory Kletsko <grigory.kletsko@cogentembedded.com> Date: Fri, 17 Feb 2017 03:06:27 +0300 -Subject: [PATCH 1/7] Allow to boot without input device +Subject: [PATCH] Allow to boot without input device --- libweston/libinput-seat.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libweston/libinput-seat.c b/libweston/libinput-seat.c -index ac1e8e9..b7f601a 100644 +index 9801551..190acfd 100644 --- a/libweston/libinput-seat.c +++ b/libweston/libinput-seat.c -@@ -302,7 +302,6 @@ udev_input_enable(struct udev_input *input) +@@ -305,7 +305,6 @@ udev_input_enable(struct udev_input *input) "\t- seats misconfigured " "(Weston backend option 'seat', " "udev device property ID_SEAT)\n"); diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0002-Share-toytoolkit-lib.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0002-Share-toytoolkit-lib.patch index a641cb30..e799649a 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0002-Share-toytoolkit-lib.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0002-Share-toytoolkit-lib.patch @@ -1,96 +1,50 @@ -From 6e0aeaec800a9155a09c8b94c33705acc420ab1b Mon Sep 17 00:00:00 2001 +From 32bb2f9f31945fda4d3a530c7e48632f3249d3a6 Mon Sep 17 00:00:00 2001 From: Grigory Kletsko <grigory.kletsko@cogentembedded.com> Date: Tue, 13 Jun 2017 23:51:22 +0300 -Subject: [PATCH 2/7] Share toytoolkit lib +Subject: [PATCH 1/4] Share toytoolkit lib --- - Makefile.am | 35 +++ - clients/toytoolkit.h | 741 +++++++++++++++++++++++++++++++++++++++++++++++++++ - clients/window.h | 714 +------------------------------------------------ - configure.ac | 2 +- - 4 files changed, 778 insertions(+), 714 deletions(-) + clients/meson.build | 11 + + clients/toytoolkit.h | 738 +++++++++++++++++++++++++++++++++++++++++++++++++++ + clients/window.h | 711 +------------------------------------------------ + 3 files changed, 750 insertions(+), 710 deletions(-) create mode 100644 clients/toytoolkit.h -diff --git a/Makefile.am b/Makefile.am -index 83bb253..9433362 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -8,6 +8,7 @@ module_LTLIBRARIES = - libweston_moduledir = $(libdir)/libweston-$(LIBWESTON_MAJOR) - libweston_module_LTLIBRARIES = - noinst_LTLIBRARIES = -+lib_LTLIBRARIES = - BUILT_SOURCES = - - AM_DISTCHECK_CONFIGURE_FLAGS = --disable-setuid-install -@@ -101,6 +102,7 @@ libweston_@LIBWESTON_MAJOR@_la_SOURCES = \ - shared/matrix.h \ - shared/timespec-util.h \ - shared/zalloc.h \ -+ clients/toytoolkit.h \ - shared/platform.h \ - shared/weston-egl-ext.h - -@@ -279,6 +281,7 @@ dist_wayland_session_DATA = compositor/weston.desktop - - libwestonincludedir = $(includedir)/libweston-${LIBWESTON_MAJOR} - libwestoninclude_HEADERS = \ -+ clients/toytoolkit.h \ - libweston/version.h \ - libweston/compositor.h \ - libweston/compositor-drm.h \ -@@ -655,6 +658,7 @@ noinst_LTLIBRARIES += libtoytoolkit.la - libtoytoolkit_la_SOURCES = \ - clients/window.c \ - clients/window.h \ -+ clients/toytoolkit.h \ - shared/helpers.h - - nodist_libtoytoolkit_la_SOURCES = \ -@@ -680,6 +684,37 @@ libtoytoolkit_la_LIBADD = \ - libshared-cairo.la $(CLOCK_GETTIME_LIBS) -lm - libtoytoolkit_la_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) $(CAIRO_EGL_CFLAGS) - -+lib_LTLIBRARIES += libweston-toytoolkit.la -+ -+libweston_toytoolkit_la_SOURCES = \ -+ clients/window.c \ -+ clients/window.h \ -+ clients/toytoolkit.h \ -+ protocol/text-cursor-position-protocol.c \ -+ protocol/text-cursor-position-client-protocol.h \ -+ protocol/viewporter-client-protocol.h \ -+ protocol/viewporter-protocol.c \ -+ protocol/xdg-shell-unstable-v6-protocol.c \ -+ protocol/xdg-shell-unstable-v6-client-protocol.h \ -+ \ -+ \ -+ protocol/ivi-application-protocol.c \ -+ protocol/ivi-application-client-protocol.h -+ -+BUILT_SOURCES += $(libweston_toytoolkit_la_SOURCES) -+ -+libweston_toytoolkit_la_CFLAGS = \ -+ $(AM_CFLAGS) $(CLIENT_CFLAGS) $(CAIRO_EGL_CFLAGS) \ -+ $(GCC_CFLAGS) -pthread -fvisibility=default -+libweston_toytoolkit_la_LIBADD = \ -+ $(CLIENT_LIBS) \ -+ $(CAIRO_EGL_LIBS) \ -+ libshared-cairo.la -lrt -lm -+libweston_toytoolkit_la_LDFLAGS = -version-info 1:0:1 -+ -+ -+ -+ - weston_flower_SOURCES = clients/flower.c - weston_flower_LDADD = libtoytoolkit.la - weston_flower_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) +diff --git a/clients/meson.build b/clients/meson.build +index bdc5d44..c48e522 100644 +--- a/clients/meson.build ++++ b/clients/meson.build +@@ -24,6 +24,7 @@ deps_toytoolkit = [ + dependency('wayland-cursor'), + cc.find_library('util'), + ] ++ + lib_toytoolkit = static_library( + 'toytoolkit', + srcs_toytoolkit, +@@ -31,6 +32,16 @@ lib_toytoolkit = static_library( + dependencies: deps_toytoolkit, + install: false, + ) ++ ++lib_toytoolkit_shared = shared_library( ++ 'weston-toytoolkit-@0@'.format(libweston_major), ++ srcs_toytoolkit, ++ include_directories: include_directories('..', '../shared'), ++ dependencies: deps_toytoolkit, ++ version: '0.0.@0@'.format(libweston_revision), ++ install: true, ++) ++ + dep_toytoolkit = declare_dependency( + link_with: lib_toytoolkit, + dependencies: deps_toytoolkit, diff --git a/clients/toytoolkit.h b/clients/toytoolkit.h new file mode 100644 -index 0000000..1c0b77d +index 0000000..cd5455e --- /dev/null +++ b/clients/toytoolkit.h -@@ -0,0 +1,741 @@ +@@ -0,0 +1,738 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * @@ -222,8 +176,6 @@ index 0000000..1c0b77d + +#define SURFACE_HINT_RESIZE 0x10 + -+#define SURFACE_HINT_RGB565 0x100 -+ +cairo_surface_t * +display_create_surface(struct display *display, + struct wl_surface *surface, @@ -595,15 +547,6 @@ index 0000000..1c0b77d +void +window_set_text_cursor_position(struct window *window, int32_t x, int32_t y); + -+enum preferred_format { -+ WINDOW_PREFERRED_FORMAT_NONE, -+ WINDOW_PREFERRED_FORMAT_RGB565 -+}; -+ -+void -+window_set_preferred_format(struct window *window, -+ enum preferred_format format); -+ +int +widget_set_tooltip(struct widget *parent, char *entry, float x, float y); + @@ -700,6 +643,14 @@ index 0000000..1c0b77d +void +widget_set_use_cairo(struct widget *widget, int use_cairo); + ++/* ++ * Sets the viewport destination for the widget's surface ++ * return 0 on success and -1 on failure. Set width and height to ++ * -1 to reset the viewport. ++ */ ++int ++widget_set_viewport_destination(struct widget *widget, int width, int height); ++ +struct widget * +window_frame_create(struct window *window, void *data); + @@ -833,10 +784,10 @@ index 0000000..1c0b77d + +#endif diff --git a/clients/window.h b/clients/window.h -index fde5c2f..fea173f 100644 +index c66dd06..f07d711 100644 --- a/clients/window.h +++ b/clients/window.h -@@ -27,721 +27,9 @@ +@@ -27,718 +27,9 @@ #include "config.h" #include <stdint.h> @@ -845,8 +796,8 @@ index fde5c2f..fea173f 100644 -#include <wayland-client.h> -#include <cairo.h> +#include "toytoolkit.h" - #include "shared/config-parser.h" - #include "shared/zalloc.h" + #include <libweston/config-parser.h> + #include <libweston/zalloc.h> #include "shared/platform.h" -struct window; @@ -949,8 +900,6 @@ index fde5c2f..fea173f 100644 - -#define SURFACE_HINT_RESIZE 0x10 - --#define SURFACE_HINT_RGB565 0x100 -- -cairo_surface_t * -display_create_surface(struct display *display, - struct wl_surface *surface, @@ -1322,15 +1271,6 @@ index fde5c2f..fea173f 100644 -void -window_set_text_cursor_position(struct window *window, int32_t x, int32_t y); - --enum preferred_format { -- WINDOW_PREFERRED_FORMAT_NONE, -- WINDOW_PREFERRED_FORMAT_RGB565 --}; -- --void --window_set_preferred_format(struct window *window, -- enum preferred_format format); -- -int -widget_set_tooltip(struct widget *parent, char *entry, float x, float y); - @@ -1427,6 +1367,14 @@ index fde5c2f..fea173f 100644 -void -widget_set_use_cairo(struct widget *widget, int use_cairo); - +-/* +- * Sets the viewport destination for the widget's surface +- * return 0 on success and -1 on failure. Set width and height to +- * -1 to reset the viewport. +- */ +-int +-widget_set_viewport_destination(struct widget *widget, int width, int height); +- -struct widget * -window_frame_create(struct window *window, void *data); - @@ -1559,19 +1507,6 @@ index fde5c2f..fea173f 100644 -toytimer_disarm(struct toytimer *tt); - #endif -diff --git a/configure.ac b/configure.ac -index 96acf75..d3fa5af 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -82,7 +82,7 @@ AC_PROG_SED - - # Initialize libtool - LT_PREREQ([2.2]) --LT_INIT([disable-static]) -+LT_INIT([shared static]) - - AC_ARG_VAR([WESTON_NATIVE_BACKEND], - [Set the native backend to use, if Weston is not running under Wayland nor X11. @<:@default=drm-backend.so@:>@]) -- 2.7.4 diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0003-add-window-set-fullscreen-at-output.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0003-add-window_set_fullscreen_at_output.patch index bf3ef82c..478f7929 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0003-add-window-set-fullscreen-at-output.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0003-add-window_set_fullscreen_at_output.patch @@ -1,7 +1,7 @@ -From 91ccb8d7fa92a55fd3d14da8f7fa883e951ae49a Mon Sep 17 00:00:00 2001 -From: Valentine Barshak <valentine.barshak@cogentembedded.com> -Date: Wed, 6 Mar 2019 00:17:31 +0300 -Subject: [PATCH 3/7] add window_set_fullscreen_at_output +From 96bcbcc000541653e8937ff51b9ba945290d354d Mon Sep 17 00:00:00 2001 +From: Grigory Kletsko <grigory.kletsko@cogentembedded.com> +Date: Tue, 13 Jun 2017 23:51:22 +0300 +Subject: [PATCH 2/4] add window_set_fullscreen_at_output --- clients/toytoolkit.h | 9 +++++++++ @@ -9,7 +9,7 @@ Subject: [PATCH 3/7] add window_set_fullscreen_at_output 2 files changed, 47 insertions(+) diff --git a/clients/toytoolkit.h b/clients/toytoolkit.h -index 1c0b77d..2bcecc1 100644 +index cd5455e..b99b6f1 100644 --- a/clients/toytoolkit.h +++ b/clients/toytoolkit.h @@ -74,6 +74,12 @@ display_get_compositor(struct display *display); @@ -25,7 +25,7 @@ index 1c0b77d..2bcecc1 100644 uint32_t display_get_serial(struct display *display); -@@ -432,6 +438,9 @@ window_is_fullscreen(struct window *window); +@@ -430,6 +436,9 @@ window_is_fullscreen(struct window *window); void window_set_fullscreen(struct window *window, int fullscreen); @@ -36,11 +36,11 @@ index 1c0b77d..2bcecc1 100644 window_is_maximized(struct window *window); diff --git a/clients/window.c b/clients/window.c -index b64e96c..43f20e2 100644 +index 2bd303e..34645b2 100644 --- a/clients/window.c +++ b/clients/window.c -@@ -4597,6 +4597,21 @@ window_set_fullscreen(struct window *window, int fullscreen) - zxdg_toplevel_v6_unset_fullscreen(window->xdg_toplevel); +@@ -4672,6 +4672,21 @@ window_set_fullscreen(struct window *window, int fullscreen) + xdg_toplevel_unset_fullscreen(window->xdg_toplevel); } +void @@ -53,15 +53,15 @@ index b64e96c..43f20e2 100644 + return; + + if (fullscreen) -+ zxdg_toplevel_v6_set_fullscreen(window->xdg_toplevel, output ? output_get_wl_output(output) : NULL); ++ xdg_toplevel_set_fullscreen(window->xdg_toplevel, output ? output_get_wl_output(output) : NULL); + else -+ zxdg_toplevel_v6_unset_fullscreen(window->xdg_toplevel); ++ xdg_toplevel_unset_fullscreen(window->xdg_toplevel); +} + int window_is_maximized(struct window *window) { -@@ -6328,6 +6343,29 @@ display_get_output(struct display *display) +@@ -6397,6 +6412,29 @@ display_get_output(struct display *display) return container_of(display->output_list.next, struct output, link); } diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0004-Add-display_poll-function.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0004-Add-display_poll-function.patch index b171271a..e0ffa92a 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0004-Add-display_poll-function.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0004-Add-display_poll-function.patch @@ -1,7 +1,7 @@ -From 5dfdbc46524919521c9b3cc485100a54c0908016 Mon Sep 17 00:00:00 2001 -From: Valentine Barshak <valentine.barshak@cogentembedded.com> -Date: Wed, 6 Mar 2019 00:19:06 +0300 -Subject: [PATCH 4/7] Add display_poll function +From 1d64f24383749038ccc8c5f273a279698b2a9662 Mon Sep 17 00:00:00 2001 +From: Grigory Kletsko <grigory.kletsko@cogentembedded.com> +Date: Tue, 13 Jun 2017 23:51:22 +0300 +Subject: [PATCH 3/4] Add display_poll function --- clients/toytoolkit.h | 3 +++ @@ -9,10 +9,10 @@ Subject: [PATCH 4/7] Add display_poll function 2 files changed, 55 insertions(+) diff --git a/clients/toytoolkit.h b/clients/toytoolkit.h -index 2bcecc1..a77eda3 100644 +index b99b6f1..67c2720 100644 --- a/clients/toytoolkit.h +++ b/clients/toytoolkit.h -@@ -163,6 +163,9 @@ display_unwatch_fd(struct display *display, int fd); +@@ -161,6 +161,9 @@ display_unwatch_fd(struct display *display, int fd); void display_run(struct display *d); @@ -23,10 +23,10 @@ index 2bcecc1..a77eda3 100644 display_exit(struct display *d); diff --git a/clients/window.c b/clients/window.c -index 43f20e2..9cd0e8e 100644 +index 34645b2..3b7def3 100644 --- a/clients/window.c +++ b/clients/window.c -@@ -6490,6 +6490,58 @@ display_run(struct display *display) +@@ -6559,6 +6559,58 @@ display_run(struct display *display) } } diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0005-Add-wl-ivi-shell-surface-creating-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0005-Add-wl-ivi-shell-surface-creating-support.patch index 563f2a2a..7163cb36 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0005-Add-wl-ivi-shell-surface-creating-support.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0005-Add-wl-ivi-shell-surface-creating-support.patch @@ -1,7 +1,7 @@ -From 5009db4e22545def833be7e2946419d209026bd6 Mon Sep 17 00:00:00 2001 +From 626341e48f4159d91ff39af2d0dc7bc720521121 Mon Sep 17 00:00:00 2001 From: Grigory Kletsko <grigory.kletsko@cogentembedded.com> Date: Tue, 13 Jun 2017 23:58:37 +0300 -Subject: [PATCH 5/7] Add wl ivi shell surface creating support +Subject: [PATCH 4/4] Add wl ivi shell sirface creating support --- ivi-shell/ivi-layout-export.h | 19 +++++++++++++++++++ @@ -9,10 +9,10 @@ Subject: [PATCH 5/7] Add wl ivi shell surface creating support 2 files changed, 21 insertions(+) diff --git a/ivi-shell/ivi-layout-export.h b/ivi-shell/ivi-layout-export.h -index 016d8b5..29d84dc 100644 +index 740e1ac..bd97d4a 100644 --- a/ivi-shell/ivi-layout-export.h +++ b/ivi-shell/ivi-layout-export.h -@@ -154,6 +154,25 @@ struct ivi_layout_interface { +@@ -156,6 +156,25 @@ struct ivi_layout_interface { */ int32_t (*commit_changes)(void); @@ -39,10 +39,10 @@ index 016d8b5..29d84dc 100644 * surface controller interface */ diff --git a/ivi-shell/ivi-layout.c b/ivi-shell/ivi-layout.c -index d9a0c2d..968819f 100644 +index 7cec79d..615c026 100644 --- a/ivi-shell/ivi-layout.c +++ b/ivi-shell/ivi-layout.c -@@ -1950,6 +1950,8 @@ static struct ivi_layout_interface ivi_layout_interface = { +@@ -2054,6 +2054,8 @@ static struct ivi_layout_interface ivi_layout_interface = { * commit all changes */ .commit_changes = ivi_layout_commit_changes, diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0006-Add-widget_set_surface_allocation-func.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0006-Add-widget_set_surface_allocation-func.patch index 21f68ce5..2992a37f 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0006-Add-widget_set_surface_allocation-func.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0006-Add-widget_set_surface_allocation-func.patch @@ -1,7 +1,7 @@ -From a74be0a8f1b71ae24e43e337d44f215d33fe012c Mon Sep 17 00:00:00 2001 +From e513edbcb6d870c9ce956f0a092d01540073b750 Mon Sep 17 00:00:00 2001 From: Grigory Kletsko <grigory.kletsko@cogentembedded.com> Date: Tue, 13 Dec 2016 00:43:11 +0300 -Subject: [PATCH 6/7] Add widget_set_surface_allocation func +Subject: [PATCH] Add widget_set_surface_allocation func --- clients/toytoolkit.h | 3 +++ @@ -9,10 +9,10 @@ Subject: [PATCH 6/7] Add widget_set_surface_allocation func 2 files changed, 15 insertions(+) diff --git a/clients/toytoolkit.h b/clients/toytoolkit.h -index a77eda3..0f6145d 100644 +index 67c2720..45d322a 100644 --- a/clients/toytoolkit.h +++ b/clients/toytoolkit.h -@@ -543,6 +543,9 @@ void +@@ -532,6 +532,9 @@ void widget_set_allocation(struct widget *widget, int32_t x, int32_t y, int32_t width, int32_t height); void @@ -23,10 +23,10 @@ index a77eda3..0f6145d 100644 void widget_set_transparent(struct widget *widget, int transparent); diff --git a/clients/window.c b/clients/window.c -index 9cd0e8e..d0e2ece 100644 +index 3b7def3..c0b25e8 100644 --- a/clients/window.c +++ b/clients/window.c -@@ -1744,6 +1744,18 @@ widget_set_allocation(struct widget *widget, +@@ -1761,6 +1761,18 @@ widget_set_allocation(struct widget *widget, } void diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0007-Add-call-for-setting-fullscreen-with-IVI.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0007-Add-call-for-setting-fullscreen-with-IVI.patch index 86daf5c4..90893cde 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-5.0.0/0007-Add-call-for-setting-fullscreen-with-IVI.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston-8.0.0/0007-Add-call-for-setting-fullscreen-with-IVI.patch @@ -1,7 +1,7 @@ -From 48c11b3d668383cb964fa41a73e6b666f30fea57 Mon Sep 17 00:00:00 2001 +From 9f1228fad3e549fd0ead4fd37573e02b874d1661 Mon Sep 17 00:00:00 2001 From: Grigory Kletsko <grigory.kletsko@cogentembedded.com> Date: Tue, 13 Dec 2016 18:20:11 +0300 -Subject: [PATCH 7/7] Add call for setting fullscreen with IVI +Subject: [PATCH] Add call for setting fullscreen with IVI --- clients/toytoolkit.h | 3 +++ @@ -9,10 +9,10 @@ Subject: [PATCH 7/7] Add call for setting fullscreen with IVI 2 files changed, 9 insertions(+) diff --git a/clients/toytoolkit.h b/clients/toytoolkit.h -index 0f6145d..7058c41 100644 +index 45d322a..481bfe1 100644 --- a/clients/toytoolkit.h +++ b/clients/toytoolkit.h -@@ -444,6 +444,9 @@ window_set_fullscreen(struct window *window, int fullscreen); +@@ -442,6 +442,9 @@ window_set_fullscreen(struct window *window, int fullscreen); void window_set_fullscreen_at_output(struct window *window, int fullscreen, struct output *output); @@ -23,11 +23,11 @@ index 0f6145d..7058c41 100644 window_is_maximized(struct window *window); diff --git a/clients/window.c b/clients/window.c -index d0e2ece..81fb674 100644 +index c0b25e8..0ba9307 100644 --- a/clients/window.c +++ b/clients/window.c -@@ -4624,6 +4624,12 @@ window_set_fullscreen_at_output(struct window *window, int fullscreen, struct ou - zxdg_toplevel_v6_unset_fullscreen(window->xdg_toplevel); +@@ -4699,6 +4699,12 @@ window_set_fullscreen_at_output(struct window *window, int fullscreen, struct ou + xdg_toplevel_unset_fullscreen(window->xdg_toplevel); } +void diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston_5.0.0.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston_8.0.0.bbappend index 96e48aba..9521606c 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston_5.0.0.bbappend +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-graphics/wayland/weston_8.0.0.bbappend @@ -3,7 +3,7 @@ FILESEXTRAPATHS_prepend := '${THISDIR}/${PN}-${PV}:' SRC_URI_append = " \ file://0001-Allow-to-boot-without-input-device.patch \ file://0002-Share-toytoolkit-lib.patch \ - file://0003-add-window-set-fullscreen-at-output.patch \ + file://0003-add-window_set_fullscreen_at_output.patch \ file://0004-Add-display_poll-function.patch \ file://0005-Add-wl-ivi-shell-surface-creating-support.patch \ file://0006-Add-widget_set_surface_allocation-func.patch \ diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch index 2f6fa35f..4b800adc 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch @@ -262,7 +262,7 @@ index ff25470..2cce294 100644 - if ((fmtinfo->alpha) && + dev_dbg(vsp1->dev, "rpf#%d: alpha=%x, fourcc=%x\n", rpf->entity.index, fmtinfo->alpha, fmtinfo->fourcc); + -+ if (0 && (fmtinfo->alpha) && ++ if (fmtinfo->alpha && (fmtinfo->fourcc != V4L2_PIX_FMT_ARGB555)) { /* When the input contains an alpha channel enable the * alpha multiplier. If the input is premultiplied we diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0285-iommu-ipmmu-vmsa-Add-r8a779-7-8-0-whitelist.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0285-iommu-ipmmu-vmsa-Add-r8a779-7-8-0-whitelist.patch index 8ec4be85..08fa2038 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0285-iommu-ipmmu-vmsa-Add-r8a779-7-8-0-whitelist.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0285-iommu-ipmmu-vmsa-Add-r8a779-7-8-0-whitelist.patch @@ -19,12 +19,12 @@ index cdbfc53..52e292a 100644 NULL, /* Terminator */ }; -+/* R-Car E3 (R8A77970) */ ++/* R-Car V3M (R8A77970) */ +static struct ipmmu_whitelist *r8a77970_whitelist[] = { + NULL, /* Terminator */ +}; + -+/* R-Car E3 (R8A77980) */ ++/* R-Car V3H (R8A77980) */ +static struct ipmmu_whitelist *r8a77980_whitelist[] = { + NULL, /* Terminator */ +}; diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch index 538ca4a6..5e455335 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch @@ -14,9 +14,9 @@ Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> drivers/gpu/drm/rcar-du/rcar_du_kms.c | 38 ++++++ drivers/gpu/drm/rcar-du/rcar_du_plane.c | 2 + drivers/gpu/drm/rcar-du/rcar_du_plane.h | 5 + - drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 228 +++++++++++++++++++++++++++----- + drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 229 ++++++++++++++++++++++++++------ drivers/gpu/drm/rcar-du/rcar_du_vsp.h | 7 +- - 7 files changed, 249 insertions(+), 37 deletions(-) + 7 files changed, 249 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 9c0152d..5f1a175 100644 @@ -110,7 +110,7 @@ index d66ae53..f74bc6a 100644 } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c -index 1b70db3..e934b4c 100644 +index 5818c59..74e0bb1 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -11,6 +11,7 @@ @@ -146,7 +146,7 @@ index e0ddecf..3e9dfdb 100644 static inline struct rcar_du_plane_state * diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c -index c44d336..2b076cf 100644 +index 0c352a0..e53c20e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -11,6 +11,7 @@ @@ -492,34 +492,33 @@ index c44d336..2b076cf 100644 else return -EINVAL; -@@ -633,8 +777,10 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, +@@ -633,7 +777,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, drm_plane_helper_add(&plane->plane, &rcar_du_vsp_plane_helper_funcs); -+#if 0 // ...use same set of properties for all planes - if (type == DRM_PLANE_TYPE_PRIMARY) - continue; -+#endif - - drm_object_attach_property(&plane->plane.base, - rcdu->props.alpha, 255); -@@ -647,6 +793,16 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, +- if (type == DRM_PLANE_TYPE_PRIMARY) { ++ // ...use same set of properties for all planes ++ if (0 && type == DRM_PLANE_TYPE_PRIMARY) { + drm_plane_create_zpos_immutable_property(&plane->plane, + 0); + } else { +@@ -648,6 +793,16 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, 0); - drm_plane_create_zpos_property(&plane->plane, 1, 1, + drm_plane_create_zpos_property(&plane->plane, 1, 1, vsp->num_planes - 1); -+ drm_object_attach_property(&plane->plane.base, -+ rcdu->props.alphaplane, 0); -+ drm_object_attach_property(&plane->plane.base, -+ rcdu->props.blend, 0); -+ drm_object_attach_property(&plane->plane.base, -+ rcdu->props.ckey, 0); -+ drm_object_attach_property(&plane->plane.base, -+ rcdu->props.ckey_set0, 0); -+ drm_object_attach_property(&plane->plane.base, -+ rcdu->props.ckey_set1, 0); ++ drm_object_attach_property(&plane->plane.base, ++ rcdu->props.alphaplane, 0); ++ drm_object_attach_property(&plane->plane.base, ++ rcdu->props.blend, 0); ++ drm_object_attach_property(&plane->plane.base, ++ rcdu->props.ckey, 0); ++ drm_object_attach_property(&plane->plane.base, ++ rcdu->props.ckey_set0, 0); ++ drm_object_attach_property(&plane->plane.base, ++ rcdu->props.ckey_set1, 0); + } } - return 0; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h index 93dbb9e..083d065 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0420-media-i2c-ov2311-fix-otp-id-read.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0420-media-i2c-ov2311-fix-otp-id-read.patch new file mode 100644 index 00000000..9557ae91 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0420-media-i2c-ov2311-fix-otp-id-read.patch @@ -0,0 +1,51 @@ +From 3ef8db409fb567da880f15a08df5cea08f3f2a45 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 18 Sep 2019 14:18:49 +0300 +Subject: [PATCH] media: i2c: ov2311: fix otp id read + +The OTP ID may fail if power rail comes early and imager +get into lpm mode. +Hence read otp id after full setup and stream enable + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov2311.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ov2311.c b/drivers/media/i2c/soc_camera/ov2311.c +index f04f271..c61059d 100644 +--- a/drivers/media/i2c/soc_camera/ov2311.c ++++ b/drivers/media/i2c/soc_camera/ov2311.c +@@ -376,7 +376,6 @@ static void ov2311_otp_id_read(struct i2c_client *client) + struct ov2311_priv *priv = to_ov2311(client); + int i; + +- reg16_write(client, 0x100, 1); + reg16_write(client, 0x3d81, 1); + usleep_range(25000, 25500); /* wait 25 ms */ + +@@ -384,8 +383,6 @@ static void ov2311_otp_id_read(struct i2c_client *client) + /* first 6 bytes are equal on all ov2311 */ + reg16_read(client, 0x7000 + i + 6, &priv->id[i]); + } +- +- reg16_write(client, 0x100, 0); + } + + static ssize_t ov2311_otp_id_show(struct device *dev, +@@ -432,10 +429,10 @@ static int ov2311_initialize(struct i2c_client *client) + + /* check revision */ + reg16_read(client, OV2311_REV, &rev); +- /* Read OTP IDs */ +- ov2311_otp_id_read(client); + /* Program wizard registers */ + ov2311_set_regs(client, ov2311_regs_wizard_r1c, ARRAY_SIZE(ov2311_regs_wizard_r1c)); ++ /* Read OTP IDs */ ++ ov2311_otp_id_read(client); + + dev_info(&client->dev, "ov2311 PID %x (rev %x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", + pid, rev, OV2311_MAX_WIDTH, OV2311_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0421-media-i2c-imx390-add-user-defined-size-for-register-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0421-media-i2c-imx390-add-user-defined-size-for-register-.patch new file mode 100644 index 00000000..bbae277a --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0421-media-i2c-imx390-add-user-defined-size-for-register-.patch @@ -0,0 +1,197 @@ +From 5dc710a5cfcaf038155e2a6c6c1a5becfb684a41 Mon Sep 17 00:00:00 2001 +From: Petr Nechaev <petr.nechaev@cogentembedded.com> +Date: Thu, 3 Oct 2019 14:04:23 +0300 +Subject: [PATCH] media: i2c: imx390: add user defined size for register access + +This adds user defined size during VIDIOC_DBG_G/S_REGISTER + +Signed-off-by: Petr Nechaev <petr.nechaev@cogentembedded.com> +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imx390.c | 20 +++++++---- + drivers/media/i2c/soc_camera/max9286.h | 61 ++++++++++++++++++++++++++++++++++ + drivers/media/i2c/soc_camera/ti9x4.h | 48 ++++++++++++++++++++++++++ + 3 files changed, 123 insertions(+), 6 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imx390.c b/drivers/media/i2c/soc_camera/imx390.c +index 87279d0..b1df1ba 100644 +--- a/drivers/media/i2c/soc_camera/imx390.c ++++ b/drivers/media/i2c/soc_camera/imx390.c +@@ -213,16 +213,18 @@ static int imx390_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 s = reg->size; + int ret; +- u8 val = 0; + +- ret = reg16_read(client, (u16)reg->reg, &val); ++ if (!s) ++ s = 4; ++ if (s > sizeof(reg->val)) ++ s = sizeof(reg->val); ++ ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)®->val, s); + if (ret < 0) + return ret; + +- reg->val = val; +- reg->size = sizeof(u8); +- + return 0; + } + +@@ -230,8 +232,14 @@ static int imx390_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 s = reg->size; ++ ++ if (!s) ++ s = 4; ++ if (s > sizeof(reg->val)) ++ s = sizeof(reg->val); + +- return reg16_write(client, (u16)reg->reg, (u8)reg->val); ++ return reg16_write_n(client, (u16)reg->reg, (u8*)®->val, s); + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/max9286.h b/drivers/media/i2c/soc_camera/max9286.h +index 2875b3c..b53ac27 100644 +--- a/drivers/media/i2c/soc_camera/max9286.h ++++ b/drivers/media/i2c/soc_camera/max9286.h +@@ -131,6 +131,67 @@ static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val) + return ret < 0 ? ret : 0; + } + ++static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n) ++{ ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; ++ ++ for (retries = REG16_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, val, n); ++ if (ret == n) ++ break; ++ } ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x registers 0x%x-0x%x: %d\n", ++ client->addr, reg, reg + n, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n) ++{ ++ int ret, retries; ++ u8 buf[2 + n]; ++ ++ buf[0] = reg >> 8; ++ buf[1] = reg & 0xff; ++ memcpy(&buf[2], val, n); ++ ++ for (retries = REG16_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2 + n); ++ if (ret == 2 + n) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x-0x%x: %d\n", ++ client->addr, reg, reg + n, ret); ++ } else { ++#ifdef WRITE_VERIFY ++ u8 val2[n]; ++ ret = reg16_read_n(client, reg, val2, n); ++ if (ret < 0) ++ return ret; ++ ++ if (memcmp(val, val2, n)) { ++ dev_err(&client->dev, ++ "write verify mismatch: chip 0x%x reg=0x%x-0x%x " ++ "'%*phN'->'%*phN'\n", client->addr, reg, reg + n, ++ n, val, n, val2); ++ ret = -EBADE; ++ } ++#endif ++ } ++ ++ return ret < 0 ? ret : 0; ++} + + static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val) + { +diff --git a/drivers/media/i2c/soc_camera/ti9x4.h b/drivers/media/i2c/soc_camera/ti9x4.h +index b53b4c6..6825f8a 100644 +--- a/drivers/media/i2c/soc_camera/ti9x4.h ++++ b/drivers/media/i2c/soc_camera/ti9x4.h +@@ -109,6 +109,53 @@ static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val) + return ret < 0 ? ret : 0; + } + ++static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n) ++{ ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, val, n); ++ if (ret == n) ++ break; ++ } ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x registers 0x%x-0x%x: %d\n", ++ client->addr, reg, reg + n, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n) ++{ ++ int ret, retries; ++ u8 buf[2 + n]; ++ ++ buf[0] = reg >> 8; ++ buf[1] = reg & 0xff; ++ memcpy(&buf[2], val, n); ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2 + n); ++ if (ret == 2 + n) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x-0x%x: %d\n", ++ client->addr, reg, reg + n, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ + static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val) + { + int ret, retries; +@@ -154,3 +201,4 @@ static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val) + return ret < 0 ? ret : 0; + } + #endif /* _TI9X4_H */ ++ +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0422-mmc-core-mmc-Try-other-timings-if-the-higher-one-fai.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0422-mmc-core-mmc-Try-other-timings-if-the-higher-one-fai.patch new file mode 100644 index 00000000..2225db0d --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0422-mmc-core-mmc-Try-other-timings-if-the-higher-one-fai.patch @@ -0,0 +1,45 @@ +From b0b23fee0c630e00e5a117a1fc48cf11de356822 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Fri, 25 Oct 2019 00:59:49 +0300 +Subject: [PATCH] mmc: core: mmc: Try other timings if the higher one fails + +Do not bail out in case the higher supported timing +setup fails. Try other supported timings as well. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/mmc/core/mmc.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c +index bad5c1b..c7c1c54 100644 +--- a/drivers/mmc/core/mmc.c ++++ b/drivers/mmc/core/mmc.c +@@ -1473,12 +1473,21 @@ static int mmc_select_timing(struct mmc_card *card) + if (!mmc_can_ext_csd(card)) + goto bus_speed; + +- if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) ++ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) { + err = mmc_select_hs400es(card); +- else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) ++ if (!err) ++ goto bus_speed; ++ } ++ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) { + err = mmc_select_hs200(card); +- else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) ++ if (!err) ++ goto bus_speed; ++ } ++ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) { + err = mmc_select_hs(card); ++ if (!err) ++ goto bus_speed; ++ } + + if (err && err != -EBADMSG) + return err; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0423-media-i2c-ap0101_ar014x-add-AP0102-chip.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0423-media-i2c-ap0101_ar014x-add-AP0102-chip.patch new file mode 100644 index 00000000..9928e879 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0423-media-i2c-ap0101_ar014x-add-AP0102-chip.patch @@ -0,0 +1,77 @@ +From 45e394a4669fa60e5e0837f68148907af7b757eb Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Fri, 1 Nov 2019 21:46:47 +0300 +Subject: [PATCH] media: i2c: ap0101_ar014x: add AP0102 chip + +This add AP0102 ISP support + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ap0101_ar014x.c | 31 ++++++++++++++++------------ + 1 file changed, 18 insertions(+), 13 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/ap0101_ar014x.c +index c35e5a0..4df5793 100644 +--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.c ++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.c +@@ -1,7 +1,7 @@ + /* +- * ON Semiconductor AP0101-AR014X sensor camera driver ++ * ON Semiconductor AP010X-AR014X sensor camera driver + * +- * Copyright (C) 2018 Cogent Embedded, Inc. ++ * Copyright (C) 2018-2019 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the +@@ -26,6 +26,7 @@ static const int ap0101_i2c_addr[] = {0x5d, 0x48}; + + #define AP0101_PID 0x0000 + #define AP0101_VERSION_REG 0x0160 ++#define AP0102_VERSION_REG 0x0064 + + #define AP0101_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8 + +@@ -432,24 +433,28 @@ static int ap0101_initialize(struct i2c_client *client) + /* check model ID */ + reg16_read16(client, AP0101_PID, &pid); + +- if (pid == AP0101_VERSION_REG) ++ if (pid == AP0101_VERSION_REG || pid == AP0102_VERSION_REG) + break; + } + +- /* check and show model ID */ +- reg16_read16(client, AP0101_PID, &pid); +- +- if (pid != AP0101_VERSION_REG) { +- dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ if (pid != AP0101_VERSION_REG && pid != AP0102_VERSION_REG) { ++ dev_err(&client->dev, "Product ID error %x\n", pid); + ret = -ENODEV; + goto err; + } + #if 1 +- /* read resolution used by current firmware */ +- reg16_read16(client, 0xca90, &val); +- priv->max_width = val; +- reg16_read16(client, 0xca92, &val); +- priv->max_height = val; ++ if (pid == AP0101_VERSION_REG) { ++ /* read resolution used by current firmware */ ++ reg16_read16(client, 0xca90, &val); ++ priv->max_width = val; ++ reg16_read16(client, 0xca92, &val); ++ priv->max_height = val; ++ } else if (pid == AP0102_VERSION_REG) { ++ reg16_read16(client, 0xcae4, &val); ++ priv->max_width = val; ++ reg16_read16(client, 0xcae6, &val); ++ priv->max_height = val; ++ } + #else + priv->max_width = AP0101_MAX_WIDTH; + priv->max_height = AP0101_MAX_HEIGHT; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0424-arm64-dts-renesas-ulcb-vb-Fix-lvds0-port-routing.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0424-arm64-dts-renesas-ulcb-vb-Fix-lvds0-port-routing.patch new file mode 100644 index 00000000..7de384e3 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0424-arm64-dts-renesas-ulcb-vb-Fix-lvds0-port-routing.patch @@ -0,0 +1,304 @@ +From 291865bff36306d70c6975e73eb299d977abbc2c Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Tue, 5 Nov 2019 19:40:06 +0300 +Subject: [PATCH] arm64: dts: renesas: ulcb-vb: Fix lvds0 port routing + +This fixes LVDS port routing on all H3ULCB VideoBox +boards which is needed for the FDPLink output. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts | 11 +++++++++-- + arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts | 11 +++++++++-- + arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts | 8 +++++--- + arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts | 11 +++++++++-- + arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts | 11 +++++++++-- + arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts | 11 +++++++++-- + arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts | 8 +++++--- + arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts | 11 +++++++++-- + arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts | 11 +++++++++-- + arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts | 11 +++++++++-- + arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts | 8 +++++--- + arch/arm64/boot/dts/renesas/ulcb-vb.dtsi | 2 +- + arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi | 2 +- + arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi | 2 +- + 14 files changed, 90 insertions(+), 28 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts +index db9f80f..310d2df 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts +@@ -34,8 +34,15 @@ + remote-endpoint = <&rcar_dw_hdmi1_in>; + }; + }; +- port@3 { +- endpoint { ++ }; ++}; ++ ++&lvds0 { ++ status = "okay"; ++ ++ ports { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts +index 6d51ffd..65b9aa5 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts +@@ -40,8 +40,15 @@ + remote-endpoint = <&rcar_dw_hdmi1_in>; + }; + }; +- port@3 { +- endpoint { ++ }; ++}; ++ ++&lvds0 { ++ status = "okay"; ++ ++ ports { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts +index 64815d4..a3b51da 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts +@@ -15,10 +15,12 @@ + model = "Renesas H3ULCB Videobox Mini board based on r8a7795"; + }; + +-&du { ++&lvds0 { ++ status = "okay"; ++ + ports { +- port@3 { +- endpoint { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts +index ce16cab..1f8c229 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts +@@ -33,8 +33,15 @@ + remote-endpoint = <&rcar_dw_hdmi1_in>; + }; + }; +- port@3 { +- endpoint { ++ }; ++}; ++ ++&lvds0 { ++ status = "okay"; ++ ++ ports { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts +index 1a9d0be..aa99875 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts +@@ -33,8 +33,15 @@ + remote-endpoint = <&rcar_dw_hdmi1_in>; + }; + }; +- port@3 { +- endpoint { ++ }; ++}; ++ ++&lvds0 { ++ status = "okay"; ++ ++ ports { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts +index 1351c6f..fb45133 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts +@@ -33,8 +33,15 @@ + remote-endpoint = <&rcar_dw_hdmi1_in>; + }; + }; +- port@3 { +- endpoint { ++ }; ++}; ++ ++&lvds0 { ++ status = "okay"; ++ ++ ports { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts +index 352cc0d..b415e88 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts +@@ -15,10 +15,12 @@ + model = "Renesas H3ULCB with 8GiB (4 x 2 GiB) Videobox Mini board based on r8a7795"; + }; + +-&du { ++&lvds0 { ++ status = "okay"; ++ + ports { +- port@3 { +- endpoint { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts +index 26c15f4..9517ff0 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts +@@ -33,8 +33,15 @@ + remote-endpoint = <&rcar_dw_hdmi1_in>; + }; + }; +- port@3 { +- endpoint { ++ }; ++}; ++ ++&lvds0 { ++ status = "okay"; ++ ++ ports { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts +index 43c20b0..5f97b60 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts +@@ -33,8 +33,15 @@ + remote-endpoint = <&rcar_dw_hdmi1_in>; + }; + }; +- port@3 { +- endpoint { ++ }; ++}; ++ ++&lvds0 { ++ status = "okay"; ++ ++ ports { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts +index 816c7da..56d43d07 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts +@@ -33,8 +33,15 @@ + remote-endpoint = <&rcar_dw_hdmi1_in>; + }; + }; +- port@3 { +- endpoint { ++ }; ++}; ++ ++&lvds0 { ++ status = "okay"; ++ ++ ports { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts +index 053a60e..7fcf527 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts +@@ -15,10 +15,12 @@ + model = "Renesas H3ULCB Videobox Mini board based on r8a7795"; + }; + +-&du { ++&lvds0 { ++ status = "okay"; ++ + ports { +- port@3 { +- endpoint { ++ port@1 { ++ lvds0_out: endpoint { + remote-endpoint = <&lvds_in>; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi +index 67903db..6fb2b38 100644 +--- a/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi ++++ b/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi +@@ -145,7 +145,7 @@ + + port { + lvds_in: endpoint { +- remote-endpoint = <&du_out_lvds0>; ++ remote-endpoint = <&lvds0_out>; + }; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi +index 50cdfd8..1a73059 100644 +--- a/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi ++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi +@@ -137,7 +137,7 @@ + + port { + lvds_in: endpoint { +- remote-endpoint = <&du_out_lvds0>; ++ remote-endpoint = <&lvds0_out>; + }; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi +index 067607a..b7e3817 100644 +--- a/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi ++++ b/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi +@@ -36,7 +36,7 @@ + + port { + lvds_in: endpoint { +- remote-endpoint = <&du_out_lvds0>; ++ remote-endpoint = <&lvds0_out>; + }; + }; + }; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0425-arm64-dts-r8a7798-v3hsk-vb-4-8ch-change-i2c-rate-to-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0425-arm64-dts-r8a7798-v3hsk-vb-4-8ch-change-i2c-rate-to-.patch new file mode 100644 index 00000000..a2809257 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0425-arm64-dts-r8a7798-v3hsk-vb-4-8ch-change-i2c-rate-to-.patch @@ -0,0 +1,44 @@ +From 7cd42e725a0221bb9c0443b15311fe3f5d37ed97 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 9 Oct 2019 18:34:48 +0300 +Subject: [PATCH] arm64: dts: r8a7798-v3hsk-vb-4/8ch: change i2c rate to 400khz + +Change i2c rate to 400kHz for bus with cameras. +This speeds up the cameras backchannel transactions. +The restriction of 100khz for cs2300 looks not needed for rev C1 chip. + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts | 2 +- + arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts +index 12ef357..4ca62c6 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts +@@ -142,7 +142,7 @@ + pinctrl-names = "default"; + status = "okay"; + +- clock-frequency = <100000>; ++ clock-frequency = <400000>; + + i2cswitch1: i2c-switch@74 { + compatible = "nxp,pca9548"; +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts +index 861b90f..b635132 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts +@@ -142,7 +142,7 @@ + pinctrl-names = "default"; + status = "okay"; + +- clock-frequency = <100000>; ++ clock-frequency = <400000>; + + i2cswitch1: i2c-switch@74 { + compatible = "nxp,pca9548"; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0426-media-i2c-ov106xx-change-order.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0426-media-i2c-ov106xx-change-order.patch new file mode 100644 index 00000000..6a89c310 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0426-media-i2c-ov106xx-change-order.patch @@ -0,0 +1,90 @@ +From a9fc14847d14cb2dabad47064b1821928e8a743a Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 6 Nov 2019 15:17:50 +0300 +Subject: [PATCH] media: i2c: ov106xx: change order + +Put OV2775, OX03A tail becase they force change serilzier gpios. +Becase of this chagne the further autodetection becomes broken. + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov106xx.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c +index c7f1bbe..624f0be 100644 +--- a/drivers/media/i2c/soc_camera/ov106xx.c ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -79,6 +79,12 @@ static int ov106xx_probe(struct i2c_client *client, + goto out; + } + ++ ret = ap0101_probe(client, did); ++ if (!ret) { ++ chip_id = ID_AP0101_AR014X; ++ goto out; ++ } ++ + ret = ov495_probe(client, did); + if (!ret) { + chip_id = ID_OV495_OV2775; +@@ -139,12 +145,6 @@ static int ov106xx_probe(struct i2c_client *client, + goto out; + } + +- ret = ap0101_probe(client, did); +- if (!ret) { +- chip_id = ID_AP0101_AR014X; +- goto out; +- } +- + ret = gw4200_probe(client, did); + if (!ret) { + chip_id = ID_GW4200_AR014X; +@@ -157,33 +157,33 @@ static int ov106xx_probe(struct i2c_client *client, + goto out; + } + +- ret = ov2775_probe(client, did); ++ ret = imx390_probe(client, did); + if (!ret) { +- chip_id = ID_OV2775; ++ chip_id = ID_IMX390; + goto out; + } + +- ret = imx390_probe(client, did); ++ ret = isx016_probe(client, did); + if (!ret) { +- chip_id = ID_IMX390; ++ chip_id = ID_ISX016; + goto out; + } + +- ret = ox03a_probe(client, did); ++ ret = isx019_probe(client, did); + if (!ret) { +- chip_id = ID_OX03A; ++ chip_id = ID_ISX019; + goto out; + } + +- ret = isx016_probe(client, did); ++ ret = ov2775_probe(client, did); + if (!ret) { +- chip_id = ID_ISX016; ++ chip_id = ID_OV2775; + goto out; + } + +- ret = isx019_probe(client, did); ++ ret = ox03a_probe(client, did); + if (!ret) { +- chip_id = ID_ISX019; ++ chip_id = ID_OX03A; + goto out; + } + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0427-media-i2c-gw5200-fix-imager-hang.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0427-media-i2c-gw5200-fix-imager-hang.patch new file mode 100644 index 00000000..c4c74b51 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0427-media-i2c-gw5200-fix-imager-hang.patch @@ -0,0 +1,60 @@ +From 424d69732e6085cc527c66fef8e2bea5584ebc4f Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 7 Nov 2019 20:31:27 +0300 +Subject: [PATCH] media: i2c: gw5200: fix imager hang + +The LI-GW5200-IMX390 firmare may hang on any of 16bit i2c transaction. +Since the GW5200 is forceed detection then no problem to put it head + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/gw5200_imx390.c | 2 +- + drivers/media/i2c/soc_camera/ov106xx.c | 12 ++++++------ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/gw5200_imx390.c b/drivers/media/i2c/soc_camera/gw5200_imx390.c +index e750a85..2fcfced 100644 +--- a/drivers/media/i2c/soc_camera/gw5200_imx390.c ++++ b/drivers/media/i2c/soc_camera/gw5200_imx390.c +@@ -22,7 +22,7 @@ + + #include "gw5200_imx390.h" + +-static const int gw5200_i2c_addr[] = {0x6d}; ++static const int gw5200_i2c_addr[] = {0x6c}; + + #define GW5200_PID 0x00 + #define GW5200_VERSION_REG 0x00 +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c +index 624f0be..208267c 100644 +--- a/drivers/media/i2c/soc_camera/ov106xx.c ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -61,6 +61,12 @@ static int ov106xx_probe(struct i2c_client *client, + int ret = -1; + chip_id = -EINVAL; + ++ ret = gw5200_probe(client, did); ++ if (!ret) { ++ chip_id = ID_GW5200_IMX390; ++ goto out; ++ } ++ + ret = ar0231_probe(client, did); + if (!ret) { + chip_id = ID_AR0231; +@@ -151,12 +157,6 @@ static int ov106xx_probe(struct i2c_client *client, + goto out; + } + +- ret = gw5200_probe(client, did); +- if (!ret) { +- chip_id = ID_GW5200_IMX390; +- goto out; +- } +- + ret = imx390_probe(client, did); + if (!ret) { + chip_id = ID_IMX390; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0428-arch64-dts-renesas-r8a77970-Fix-IPMMU-probe-order.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0428-arch64-dts-renesas-r8a77970-Fix-IPMMU-probe-order.patch new file mode 100644 index 00000000..ec40f20d --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0428-arch64-dts-renesas-r8a77970-Fix-IPMMU-probe-order.patch @@ -0,0 +1,53 @@ +From 63a0c5c8fef06c0894a81d6e31b2b3eeec452f74 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Sat, 9 Nov 2019 20:22:31 +0300 +Subject: [PATCH 1/2] arch64: dts: renesas: r8a77970: Fix IPMMU probe order + +This moves the main IPMMU node in front of all the other IPMMU +nodes to prevent PROBE_DEFER errors and late initialization +of the slave IPMMU devices. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a77970.dtsi | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77970.dtsi b/arch/arm64/boot/dts/renesas/r8a77970.dtsi +index 7ecbc01..456eeb6 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77970.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a77970.dtsi +@@ -1121,6 +1121,15 @@ + <&ipmmu_ds1 22>, <&ipmmu_ds1 23>; + }; + ++ ipmmu_mm: mmu@e67b0000 { ++ compatible = "renesas,ipmmu-r8a77970"; ++ reg = <0 0xe67b0000 0 0x1000>; ++ interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>; ++ power-domains = <&sysc R8A77970_PD_ALWAYS_ON>; ++ #iommu-cells = <1>; ++ }; ++ + ipmmu_ds1: mmu@e7740000 { + compatible = "renesas,ipmmu-r8a77970"; + reg = <0 0xe7740000 0 0x1000>; +@@ -1137,15 +1146,6 @@ + #iommu-cells = <1>; + }; + +- ipmmu_mm: mmu@e67b0000 { +- compatible = "renesas,ipmmu-r8a77970"; +- reg = <0 0xe67b0000 0 0x1000>; +- interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>, +- <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>; +- power-domains = <&sysc R8A77970_PD_ALWAYS_ON>; +- #iommu-cells = <1>; +- }; +- + ipmmu_rt: mmu@ffc80000 { + compatible = "renesas,ipmmu-r8a77970"; + reg = <0 0xffc80000 0 0x1000>; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0429-arch64-dts-renesas-r8a77980-Fix-IPMMU-probe-order.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0429-arch64-dts-renesas-r8a77980-Fix-IPMMU-probe-order.patch new file mode 100644 index 00000000..634576cc --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0429-arch64-dts-renesas-r8a77980-Fix-IPMMU-probe-order.patch @@ -0,0 +1,53 @@ +From 86a07c0c042acb9f06c11c9319294d83d6ecbb59 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Sat, 9 Nov 2019 20:33:36 +0300 +Subject: [PATCH 2/2] arch64: dts: renesas: r8a77980: Fix IPMMU probe order + +This moves the main IPMMU node in front of all the other IPMMU +nodes to prevent PROBE_DEFER errors and late initialization +of the slave IPMMU devices. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a77980.dtsi | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi +index 045b517..0d25b35 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi +@@ -1636,6 +1636,15 @@ + status = "disabled"; + }; + ++ ipmmu_mm: mmu@e67b0000 { ++ compatible = "renesas,ipmmu-r8a77980"; ++ reg = <0 0xe67b0000 0 0x1000>; ++ interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>; ++ power-domains = <&sysc R8A77980_PD_ALWAYS_ON>; ++ #iommu-cells = <1>; ++ }; ++ + ipmmu_ds1: mmu@e7740000 { + compatible = "renesas,ipmmu-r8a77980"; + reg = <0 0xe7740000 0 0x1000>; +@@ -1652,15 +1661,6 @@ + #iommu-cells = <1>; + }; + +- ipmmu_mm: mmu@e67b0000 { +- compatible = "renesas,ipmmu-r8a77980"; +- reg = <0 0xe67b0000 0 0x1000>; +- interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>, +- <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>; +- power-domains = <&sysc R8A77980_PD_ALWAYS_ON>; +- #iommu-cells = <1>; +- }; +- + ipmmu_rt: mmu@ffc80000 { + compatible = "renesas,ipmmu-r8a77980"; + reg = <0 0xffc80000 0 0x1000>; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0430-media-i2c-ar0140-update-driver-to-use-rGPIO-and-dyna.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0430-media-i2c-ar0140-update-driver-to-use-rGPIO-and-dyna.patch new file mode 100644 index 00000000..cdec2996 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0430-media-i2c-ar0140-update-driver-to-use-rGPIO-and-dyna.patch @@ -0,0 +1,162 @@ +From 8eb36a5043bfb90974d3149f29197cb7f72df171 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Tue, 12 Nov 2019 22:57:34 +0300 +Subject: [PATCH] media: i2c: ar0140: update driver to use rGPIO and dynamic + i2c + +This fix driver to use remote gpio from deserizlier and dynamic +i2c probing + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ar0140.c | 36 +++++++++++++++++++++------------- + drivers/media/i2c/soc_camera/ar0140.h | 4 +--- + drivers/media/i2c/soc_camera/ov106xx.c | 22 ++++++++++----------- + 3 files changed, 34 insertions(+), 28 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ar0140.c b/drivers/media/i2c/soc_camera/ar0140.c +index b156fc5..ec2b2e5 100644 +--- a/drivers/media/i2c/soc_camera/ar0140.c ++++ b/drivers/media/i2c/soc_camera/ar0140.c +@@ -22,7 +22,7 @@ + + #include "ar0140.h" + +-#define AR0140_I2C_ADDR 0x10 ++static const int ar0140_i2c_addr[] = {0x10, 0x20}; + + #define AR0140_PID 0x3000 + #define AR0140_VERSION_REG 0x0051 +@@ -407,15 +407,30 @@ static DEVICE_ATTR(otp_id_ar0140, S_IRUGO, ar0140_otp_id_show, NULL); + static int ar0140_initialize(struct i2c_client *client) + { + struct ar0140_priv *priv = to_ar0140(client); +- u16 val = 0; +- u16 pid = 0; ++ u16 val = 0, pid = 0; + int ret = 0; +- int tmp_addr; ++ int tmp_addr, i; + +- ar0140_s_port(client, 1); ++ for (i = 0; i < ARRAY_SIZE(ar0140_i2c_addr); i++) { ++ tmp_addr = client->addr; ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; ++ reg8_write(client, 0x5d, ar0140_i2c_addr[i] << 1); /* Sensor native I2C address */ ++ usleep_range(2000, 2500); ++ } ++ if (priv->max9286_addr) { ++ client->addr = priv->max9271_addr; ++ reg8_write(client, 0x0a, ar0140_i2c_addr[i] << 1); /* Sensor native I2C address */ ++ usleep_range(2000, 2500); ++ }; ++ client->addr = tmp_addr; + +- /* check and show model ID */ +- reg16_read16(client, AR0140_PID, &pid); ++ /* check model ID */ ++ reg16_read16(client, AR0140_PID, &pid); ++ ++ if (pid == AR0140_VERSION_REG) ++ break; ++ } + + if (pid != AR0140_VERSION_REG) { + dev_dbg(&client->dev, "Product ID error %x\n", pid); +@@ -452,7 +467,6 @@ static int ar0140_initialize(struct i2c_client *client) + pid, AR0140_MAX_WIDTH, AR0140_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + err: + ar0140_s_port(client, 0); +- + return ret; + } + +@@ -499,7 +513,6 @@ static int ar0140_parse_dt(struct device_node *np, struct ar0140_priv *priv) + client->addr = priv->max9271_addr; /* Serializer I2C address */ + + reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */ +- reg8_write(client, 0x0A, AR0140_I2C_ADDR << 1); /* Sensor native I2C address */ + usleep_range(2000, 2500); /* wait 2ms */ + }; + if (priv->ti9x4_addr) { +@@ -508,14 +521,9 @@ static int ar0140_parse_dt(struct device_node *np, struct ar0140_priv *priv) + reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ + usleep_range(2000, 2500); /* wait 2ms */ + reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ +- reg8_write(client, 0x5d, AR0140_I2C_ADDR << 1); /* Sensor native I2C address */ +- +- reg8_write(client, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - reset */ + } + client->addr = tmp_addr; + +- mdelay(10); +- + return 0; + } + +diff --git a/drivers/media/i2c/soc_camera/ar0140.h b/drivers/media/i2c/soc_camera/ar0140.h +index f90762c..2993478 100644 +--- a/drivers/media/i2c/soc_camera/ar0140.h ++++ b/drivers/media/i2c/soc_camera/ar0140.h +@@ -467,9 +467,7 @@ static const struct ar0140_reg ar0140_regs_wizard[] = { + // patch start + {0x3012, 0x0206}, // COARSE_INTEGRATION_TIME_: T1 exposure - max=0x400 + // patch end +-// enable trigger +-{0x340A, 0x0070}, // GPIO_CONTROL1: GPIO3 is trigger +-{0x340C, 0x0080}, // GPIO_CONTROL2: GPIO3 is trigger ++// enable trigger (trigger pin is dedicated) + {0x30CE, 0x0120}, // TRIGGER_MODE + //{0x30DC, 0x0120}, // TRIGGER_DELAY + }; +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c +index 208267c..08d3816 100644 +--- a/drivers/media/i2c/soc_camera/ov106xx.c ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -67,6 +67,12 @@ static int ov106xx_probe(struct i2c_client *client, + goto out; + } + ++ ret = ar0140_probe(client, did); ++ if (!ret) { ++ chip_id = ID_AR0140; ++ goto out; ++ } ++ + ret = ar0231_probe(client, did); + if (!ret) { + chip_id = ID_AR0231; +@@ -85,11 +91,11 @@ static int ov106xx_probe(struct i2c_client *client, + goto out; + } + +- ret = ap0101_probe(client, did); +- if (!ret) { +- chip_id = ID_AP0101_AR014X; +- goto out; +- } ++ ret = ap0101_probe(client, did); ++ if (!ret) { ++ chip_id = ID_AP0101_AR014X; ++ goto out; ++ } + + ret = ov495_probe(client, did); + if (!ret) { +@@ -127,12 +133,6 @@ static int ov106xx_probe(struct i2c_client *client, + goto out; + } + +- ret = ar0140_probe(client, did); +- if (!ret) { +- chip_id = ID_AR0140; +- goto out; +- } +- + ret = ar0143_probe(client, did); + if (!ret) { + chip_id = ID_AR0143; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0431-media-i2c-ti9x4-update-remote-gpio-function.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0431-media-i2c-ti9x4-update-remote-gpio-function.patch new file mode 100644 index 00000000..79006e58 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0431-media-i2c-ti9x4-update-remote-gpio-function.patch @@ -0,0 +1,53 @@ +From 9098f3a6deac6fb81695cf7fbf97e32ac3e0c399 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Fri, 15 Nov 2019 14:31:52 +0300 +Subject: [PATCH] media: i2c: ti9x4: update remote gpio function + +Enable only FSIN for remote gpio, all permanent states (0 or 1) setup on serializer side: +this avoids intermittent remote gpio noise (f.e. reset or spuriouse fsin) caused by +unstable/bad link, hence unstable backchannel + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ti9x4.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c +index 0cfcfaa..aa85d92 100644 +--- a/drivers/media/i2c/soc_camera/ti9x4.c ++++ b/drivers/media/i2c/soc_camera/ti9x4.c +@@ -327,14 +327,29 @@ static int ti9x4_initialize(struct i2c_client *client) + reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */ + usleep_range(1000, 1500); /* wait 1ms */ + ++ /* ++ * Enable only FSIN for remote gpio, all permanent states (0 or 1) setup on serializer side: ++ * this avoids intermittent remote gpio noise (f.e. reset or spuriouse fsin) caused by ++ * unstable/bad link, hence unstable backchannel ++ */ + client->addr = priv->ti9x3_addr_map[idx]; /* TI9X3 I2C addr */ + switch (priv->ser_id) { + case TI913_ID: + reg8_write(client, 0x0d, 0x55); /* Enable remote GPIO0/1 */ + break; + case TI953_ID: +- reg8_write(client, 0x0d, 0xf0); /* Enable all remote GPIOs */ +- reg8_write(client, 0x0e, 0xf0); /* Enable serializer GPIOs */ ++ reg8_write(client, 0x0d, (priv->gpio[0] & 0x1) << 0 | ++ (priv->gpio[1] & 0x1) << 1 | ++ (priv->gpio[2] & 0x1) << 2 | ++ (priv->gpio[3] & 0x1) << 3 | ++ (priv->gpio[0] & 0x2) << 3 | ++ (priv->gpio[1] & 0x2) << 4 | ++ (priv->gpio[2] & 0x2) << 5 | ++ (priv->gpio[3] & 0x2) << 6); /* Enable FSIN remote GPIOs and set local constant gpios */ ++ reg8_write(client, 0x0e, (!!priv->gpio[0] << 4) | ++ (!!priv->gpio[1] << 5) | ++ (!!priv->gpio[2] << 6) | ++ (!!priv->gpio[3] << 7)); /* Enable serializer GPIOs only for output */ + break; + } + client->addr = priv->des_addr; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0432-media-i2c-soc_camera-add-AR0220.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0432-media-i2c-soc_camera-add-AR0220.patch new file mode 100644 index 00000000..eb37d0a9 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0432-media-i2c-soc_camera-add-AR0220.patch @@ -0,0 +1,1689 @@ +From b79fd9163f868b78aea5ba634b52541d518f10a5 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 18 Nov 2019 19:07:21 +0300 +Subject: [PATCH] media: i2c: soc_camera: add AR0220 + +This adds AR0220 imager glue driver +The chip is appended to AR0233 glue for further rework of all AR0XXX chips + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ar0220.c | 539 ----------------------------- + drivers/media/i2c/soc_camera/ar0220.h | 39 +-- + drivers/media/i2c/soc_camera/ar0220_rev4.h | 370 ++++++++++++++++++++ + drivers/media/i2c/soc_camera/ar0233.c | 164 ++++++--- + drivers/media/i2c/soc_camera/ar0233.h | 7 - + drivers/media/i2c/soc_camera/ar0233_rev1.h | 26 +- + drivers/media/i2c/soc_camera/ar0233_rev2.h | 38 +- + drivers/media/i2c/soc_camera/ov106xx.c | 54 ++- + 8 files changed, 549 insertions(+), 688 deletions(-) + delete mode 100644 drivers/media/i2c/soc_camera/ar0220.c + create mode 100644 drivers/media/i2c/soc_camera/ar0220_rev4.h + +diff --git a/drivers/media/i2c/soc_camera/ar0220.c b/drivers/media/i2c/soc_camera/ar0220.c +deleted file mode 100644 +index b1ca101..0000000 +--- a/drivers/media/i2c/soc_camera/ar0220.c ++++ /dev/null +@@ -1,539 +0,0 @@ +-/* +- * ON Semiconductor AR0220 sensor camera driver +- * +- * Copyright (C) 2017-2018 Cogent Embedded, Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- */ +- +-#include <linux/delay.h> +-#include <linux/init.h> +-#include <linux/i2c.h> +-#include <linux/module.h> +-#include <linux/of_graph.h> +-#include <linux/videodev2.h> +- +-#include <media/soc_camera.h> +-#include <media/v4l2-common.h> +-#include <media/v4l2-ctrls.h> +- +-#include "ar0220.h" +- +-#define AR0220_I2C_ADDR 0x10 +-//#define AR0220_I2C_ADDR 0x54 // eeprom +- +-#define AR0220_PID 0x3000 +-#define AR0220_VERSION_REG 0x0C54 +- +-#define AR0220_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG14_1X14 +- +-struct ar0220_priv { +- struct v4l2_subdev sd; +- struct v4l2_ctrl_handler hdl; +- struct media_pad pad; +- struct v4l2_rect rect; +- int init_complete; +- u8 id[6]; +- int exposure; +- int gain; +- int autogain; +- /* serializers */ +- int ti9x4_addr; +- int ti9x3_addr; +- int port; +- int gpio_resetb; +- int gpio_fsin; +-}; +- +-static inline struct ar0220_priv *to_ar0220(const struct i2c_client *client) +-{ +- return container_of(i2c_get_clientdata(client), struct ar0220_priv, sd); +-} +- +-static int ar0220_set_regs(struct i2c_client *client, +- const struct ar0220_reg *regs, int nr_regs) +-{ +- int i; +- +- for (i = 0; i < nr_regs; i++) { +- if (regs[i].reg == AR0220_DELAY) { +- mdelay(regs[i].val); +- continue; +- } +- +- reg16_write16(client, regs[i].reg, regs[i].val); +- } +- +- return 0; +-} +- +-static int ar0220_s_stream(struct v4l2_subdev *sd, int enable) +-{ +- return 0; +-} +- +-static int ar0220_get_fmt(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_format *format) +-{ +- struct v4l2_mbus_framefmt *mf = &format->format; +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct ar0220_priv *priv = to_ar0220(client); +- +- if (format->pad) +- return -EINVAL; +- +- mf->width = priv->rect.width; +- mf->height = priv->rect.height; +- mf->code = AR0220_MEDIA_BUS_FMT; +- mf->colorspace = V4L2_COLORSPACE_SMPTE170M; +- mf->field = V4L2_FIELD_NONE; +- +- return 0; +-} +- +-static int ar0220_set_fmt(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_format *format) +-{ +- struct v4l2_mbus_framefmt *mf = &format->format; +- +- mf->code = AR0220_MEDIA_BUS_FMT; +- mf->colorspace = V4L2_COLORSPACE_SMPTE170M; +- mf->field = V4L2_FIELD_NONE; +- +- if (format->which == V4L2_SUBDEV_FORMAT_TRY) +- cfg->try_fmt = *mf; +- +- return 0; +-} +- +-static int ar0220_enum_mbus_code(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_mbus_code_enum *code) +-{ +- if (code->pad || code->index > 0) +- return -EINVAL; +- +- code->code = AR0220_MEDIA_BUS_FMT; +- +- return 0; +-} +- +-static int ar0220_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +-{ +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct ar0220_priv *priv = to_ar0220(client); +- +- memcpy(edid->edid, priv->id, 6); +- +- edid->edid[6] = 0xff; +- edid->edid[7] = client->addr; +- edid->edid[8] = AR0220_VERSION_REG >> 8; +- edid->edid[9] = AR0220_VERSION_REG & 0xff; +- +- return 0; +-} +- +-static int ar0220_set_selection(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_selection *sel) +-{ +- struct v4l2_rect *rect = &sel->r; +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct ar0220_priv *priv = to_ar0220(client); +- +- if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || +- sel->target != V4L2_SEL_TGT_CROP) +- return -EINVAL; +- +- rect->left = ALIGN(rect->left, 2); +- rect->top = ALIGN(rect->top, 2); +- rect->width = ALIGN(rect->width, 2); +- rect->height = ALIGN(rect->height, 2); +- +- if ((rect->left + rect->width > AR0220_MAX_WIDTH) || +- (rect->top + rect->height > AR0220_MAX_HEIGHT)) +- *rect = priv->rect; +- +- priv->rect.left = rect->left; +- priv->rect.top = rect->top; +- priv->rect.width = rect->width; +- priv->rect.height = rect->height; +- +- return 0; +-} +- +-static int ar0220_get_selection(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_selection *sel) +-{ +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct ar0220_priv *priv = to_ar0220(client); +- +- if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) +- return -EINVAL; +- +- switch (sel->target) { +- case V4L2_SEL_TGT_CROP_BOUNDS: +- sel->r.left = 0; +- sel->r.top = 0; +- sel->r.width = AR0220_MAX_WIDTH; +- sel->r.height = AR0220_MAX_HEIGHT; +- return 0; +- case V4L2_SEL_TGT_CROP_DEFAULT: +- sel->r.left = 0; +- sel->r.top = 0; +- sel->r.width = AR0220_MAX_WIDTH; +- sel->r.height = AR0220_MAX_HEIGHT; +- return 0; +- case V4L2_SEL_TGT_CROP: +- sel->r = priv->rect; +- return 0; +- default: +- return -EINVAL; +- } +-} +- +-static int ar0220_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) +-{ +- cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | +- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; +- cfg->type = V4L2_MBUS_CSI2; +- +- return 0; +-} +- +-#ifdef CONFIG_VIDEO_ADV_DEBUG +-static int ar0220_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) +-{ +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- int ret; +- u16 val = 0; +- +- ret = reg16_read16(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; +- +- reg->val = val; +- reg->size = sizeof(u16); +- +- return 0; +-} +- +-static int ar0220_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) +-{ +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- +- return reg16_write16(client, (u16)reg->reg, (u16)reg->val); +-} +-#endif +- +-static struct v4l2_subdev_core_ops ar0220_core_ops = { +-#ifdef CONFIG_VIDEO_ADV_DEBUG +- .g_register = ar0220_g_register, +- .s_register = ar0220_s_register, +-#endif +-}; +- +-static int ar0220_s_ctrl(struct v4l2_ctrl *ctrl) +-{ +- struct v4l2_subdev *sd = to_sd(ctrl); +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct ar0220_priv *priv = to_ar0220(client); +- int ret = -EINVAL; +- +- if (!priv->init_complete) +- return 0; +- +- switch (ctrl->id) { +- case V4L2_CID_BRIGHTNESS: +- case V4L2_CID_CONTRAST: +- case V4L2_CID_SATURATION: +- case V4L2_CID_HUE: +- case V4L2_CID_GAMMA: +- case V4L2_CID_SHARPNESS: +- case V4L2_CID_AUTOGAIN: +- case V4L2_CID_GAIN: +- case V4L2_CID_EXPOSURE: +- case V4L2_CID_HFLIP: +- case V4L2_CID_VFLIP: +- break; +- } +- +- return ret; +-} +- +-static const struct v4l2_ctrl_ops ar0220_ctrl_ops = { +- .s_ctrl = ar0220_s_ctrl, +-}; +- +-static struct v4l2_subdev_video_ops ar0220_video_ops = { +- .s_stream = ar0220_s_stream, +- .g_mbus_config = ar0220_g_mbus_config, +-}; +- +-static const struct v4l2_subdev_pad_ops ar0220_subdev_pad_ops = { +- .get_edid = ar0220_get_edid, +- .enum_mbus_code = ar0220_enum_mbus_code, +- .get_selection = ar0220_get_selection, +- .set_selection = ar0220_set_selection, +- .get_fmt = ar0220_get_fmt, +- .set_fmt = ar0220_set_fmt, +-}; +- +-static struct v4l2_subdev_ops ar0220_subdev_ops = { +- .core = &ar0220_core_ops, +- .video = &ar0220_video_ops, +- .pad = &ar0220_subdev_pad_ops, +-}; +- +-static void ar0220_otp_id_read(struct i2c_client *client) +-{ +-} +- +-static ssize_t ar0220_otp_id_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct ar0220_priv *priv = to_ar0220(client); +- +- return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", +- priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +-} +- +-static DEVICE_ATTR(otp_id_ar0220, S_IRUGO, ar0220_otp_id_show, NULL); +- +-static int ar0220_initialize(struct i2c_client *client) +-{ +- struct ar0220_priv *priv = to_ar0220(client); +- u16 val = 0; +- u16 pid = 0; +- int ret = 0; +- int tmp_addr; +- +- /* check and show model ID */ +- reg16_read16(client, AR0220_PID, &pid); +- +- if (pid != AR0220_VERSION_REG) { +- dev_dbg(&client->dev, "Product ID error %x\n", pid); +- ret = -ENODEV; +- goto err; +- } +- +- /* setup XCLK */ +- tmp_addr = client->addr; +- if (priv->ti9x4_addr) { +- /* CLK_OUT=22.5792*160*M/N/CLKDIV -> CLK_OUT=27MHz: CLKDIV=2, M=15, N=251: 22.5792*160/8*15/251=26.987MHz=CLK_OUT */ +- client->addr = priv->ti9x3_addr; /* Serializer I2C address */ +- reg8_write(client, 0x06, 0x6f); /* Set CLKDIV and M */ +- reg8_write(client, 0x07, 0xfb); /* Set N */ +- } +- client->addr = tmp_addr; +- +- /* Program wizard registers */ +- ar0220_set_regs(client, ar0220_regs_wizard, ARRAY_SIZE(ar0220_regs_wizard)); +- +- /* Enable stream */ +- reg16_read16(client, 0x301a, &val); // read inital reset_register value +- val |= (1 << 2); // Set streamOn bit +- reg16_write16(client, 0x301a, val); // Start Streaming +- +- /* Read OTP IDs */ +- ar0220_otp_id_read(client); +- +- dev_info(&client->dev, "ar0220 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", +- pid, AR0220_MAX_WIDTH, AR0220_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +-err: +- return ret; +-} +- +-static int ar0220_parse_dt(struct device_node *np, struct ar0220_priv *priv) +-{ +- struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); +- int i; +- struct device_node *endpoint = NULL, *rendpoint = NULL; +- int tmp_addr = 0; +- +- for (i = 0; ; i++) { +- endpoint = of_graph_get_next_endpoint(np, endpoint); +- if (!endpoint) +- break; +- +- +- rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); +- if (!rendpoint) +- continue; +- +- if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && +- !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") && +- !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) && +- !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) +- break; +- } +- +- of_node_put(endpoint); +- +- if (!priv->ti9x4_addr) { +- dev_err(&client->dev, "deserializer does not present\n"); +- return -EINVAL; +- } +- +- /* setup I2C translator address */ +- tmp_addr = client->addr; +- if (priv->ti9x4_addr) { +- client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ +- +- reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ +- usleep_range(2000, 2500); /* wait 2ms */ +- reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ +- reg8_write(client, 0x5d, AR0220_I2C_ADDR << 1); /* Sensor native I2C address */ +- +-// reg8_write(client, 0x6e, 0xa9); /* GPIO0 - reset, GPIO1 - fsin */ +- } +- client->addr = tmp_addr; +- +- mdelay(10); +- +- return 0; +-} +- +-static int ar0220_probe(struct i2c_client *client, +- const struct i2c_device_id *did) +-{ +- struct ar0220_priv *priv; +- int ret; +- +- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- v4l2_i2c_subdev_init(&priv->sd, client, &ar0220_subdev_ops); +- priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; +- +- priv->exposure = 0x100; +- priv->gain = 0x100; +- priv->autogain = 1; +- v4l2_ctrl_handler_init(&priv->hdl, 4); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_CONTRAST, 0, 16, 1, 7); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_SATURATION, 0, 7, 1, 2); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_HUE, 0, 23, 1, 12); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_GAMMA, -128, 128, 1, 0); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_SHARPNESS, 0, 10, 1, 3); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_HFLIP, 0, 1, 1, 1); +- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, +- V4L2_CID_VFLIP, 0, 1, 1, 0); +- priv->sd.ctrl_handler = &priv->hdl; +- +- ret = priv->hdl.error; +- if (ret) +- goto cleanup; +- +- v4l2_ctrl_handler_setup(&priv->hdl); +- +- priv->pad.flags = MEDIA_PAD_FL_SOURCE; +- priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; +- ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); +- if (ret < 0) +- goto cleanup; +- +- ret = ar0220_parse_dt(client->dev.of_node, priv); +- if (ret) +- goto cleanup; +- +- ret = ar0220_initialize(client); +- if (ret < 0) +- goto cleanup; +- +- priv->rect.left = 0; +- priv->rect.top = 0; +- priv->rect.width = AR0220_MAX_WIDTH; +- priv->rect.height = AR0220_MAX_HEIGHT; +- +- ret = v4l2_async_register_subdev(&priv->sd); +- if (ret) +- goto cleanup; +- +- if (device_create_file(&client->dev, &dev_attr_otp_id_ar0220) != 0) { +- dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); +- goto cleanup; +- } +- +- priv->init_complete = 1; +- +- return 0; +- +-cleanup: +- media_entity_cleanup(&priv->sd.entity); +- v4l2_ctrl_handler_free(&priv->hdl); +- v4l2_device_unregister_subdev(&priv->sd); +-#ifdef CONFIG_SOC_CAMERA_AR0220 +- v4l_err(client, "failed to probe @ 0x%02x (%s)\n", +- client->addr, client->adapter->name); +-#endif +- return ret; +-} +- +-static int ar0220_remove(struct i2c_client *client) +-{ +- struct ar0220_priv *priv = i2c_get_clientdata(client); +- +- device_remove_file(&client->dev, &dev_attr_otp_id_ar0220); +- v4l2_async_unregister_subdev(&priv->sd); +- media_entity_cleanup(&priv->sd.entity); +- v4l2_ctrl_handler_free(&priv->hdl); +- v4l2_device_unregister_subdev(&priv->sd); +- +- return 0; +-} +- +-#ifdef CONFIG_SOC_CAMERA_AR0220 +-static const struct i2c_device_id ar0220_id[] = { +- { "ar0220", 0 }, +- { } +-}; +-MODULE_DEVICE_TABLE(i2c, ar0220_id); +- +-static const struct of_device_id ar0220_of_ids[] = { +- { .compatible = "aptina,ar0220", }, +- { } +-}; +-MODULE_DEVICE_TABLE(of, ar0220_of_ids); +- +-static struct i2c_driver ar0220_i2c_driver = { +- .driver = { +- .name = "ar0220", +- .of_match_table = ar0220_of_ids, +- }, +- .probe = ar0220_probe, +- .remove = ar0220_remove, +- .id_table = ar0220_id, +-}; +- +-module_i2c_driver(ar0220_i2c_driver); +- +-MODULE_DESCRIPTION("SoC Camera driver for AR0220"); +-MODULE_AUTHOR("Vladimir Barinov"); +-MODULE_LICENSE("GPL"); +-#endif +diff --git a/drivers/media/i2c/soc_camera/ar0220.h b/drivers/media/i2c/soc_camera/ar0220.h +index 205c351..e372a9c 100644 +--- a/drivers/media/i2c/soc_camera/ar0220.h ++++ b/drivers/media/i2c/soc_camera/ar0220.h +@@ -1,7 +1,7 @@ + /* +- * ON Semiconductor AR0220 sensor camera wizard 1820x940@44/RCCB/MIPI ++ * ON Semiconductor AR0220 sensor camera wizard 1848x948@30/BGGR/MIPI + * +- * Copyright (C) 2017 Cogent Embedded, Inc. ++ * Copyright (C) 2019 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the +@@ -12,32 +12,15 @@ + //#define AR0220_DISPLAY_PATTERN_FIXED + //#define AR0220_DISPLAY_PATTERN_COLOR_BAR + +-#define AR0220_MAX_WIDTH 1820 +-#define AR0220_MAX_HEIGHT 944 ++#define AR0220_MAX_WIDTH 1828 ++#define AR0220_MAX_HEIGHT 948 + +-#define AR0220_DELAY 0xffff ++#define AR0220_SENSOR_WIDTH 1828 ++#define AR0220_SENSOR_HEIGHT 948 + +-struct ar0220_reg { +- u16 reg; +- u16 val; +-}; ++#define AR0220_X_START ((AR0220_SENSOR_WIDTH - AR0220_MAX_WIDTH) / 2) ++#define AR0220_Y_START ((AR0220_SENSOR_HEIGHT - AR0220_MAX_HEIGHT) / 2) ++#define AR0220_X_END (AR0220_X_START + AR0220_MAX_WIDTH - 1) ++#define AR0220_Y_END (AR0220_Y_START + AR0220_MAX_HEIGHT - 1) + +-static const struct ar0220_reg ar0220_regs_wizard[] = { +-{0x301A, 0x0018}, // RESET_REGISTER +-{AR0220_DELAY, 500}, // Wait 500ms +-{0x3070, 0x0000}, // 1: Solid color test pattern, +- // 2: Full color bar test pattern, +- // 3: Fade to grey color bar test pattern, +- //256: Walking 1 test pattern (12 bit) +-{0x3072, 0x0123}, // R +-{0x3074, 0x0456}, // G(GR row) +-{0x3076, 0x0abc}, // B +-{0x3078, 0x0def}, // G(GB row) +-#ifdef AR0220_DISPLAY_PATTERN_FIXED +-{0x3070, 0x0001}, +-#endif +-#ifdef AR0220_DISPLAY_PATTERN_COLOR_BAR +-{0x3070, 0x0002}, +-#endif +-{AR0220_DELAY, 100}, // Wait 100ms +-}; ++#include "ar0220_rev4.h" +diff --git a/drivers/media/i2c/soc_camera/ar0220_rev4.h b/drivers/media/i2c/soc_camera/ar0220_rev4.h +new file mode 100644 +index 0000000..55923a3 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ar0220_rev4.h +@@ -0,0 +1,370 @@ ++/* ++ * ON Semiconductor AR0220 sensor camera wizard 1848x944@30/BGGR/MIPI ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++static const struct ar0xxx_reg ar0220_rev4_Reset[] = { ++{0x301A, 0x0018}, // Stream off and setup MIPI ++{AR_DELAY, 200}, ++{0x3070, 0x0000}, // 1: Solid color test pattern, ++ // 2: Full color bar test pattern, ++ // 3: Fade to grey color bar test pattern, ++ //256: Walking 1 test pattern (12 bit) ++{0x3072, 0x0123}, // R ++{0x3074, 0x0456}, // G(GR row) ++{0x3076, 0x0abc}, // B ++{0x3078, 0x0def}, // G(GB row) ++#ifdef AR0220_DISPLAY_PATTERN_FIXED ++{0x3070, 0x0001}, ++#endif ++#ifdef AR0220_DISPLAY_PATTERN_COLOR_BAR ++{0x3070, 0x0002}, ++#endif ++{AR_DELAY, 100}, ++{ } ++}; /* Reset */ ++ ++static const struct ar0xxx_reg ar0220_rev4_Recommended_Settings[] = { ++// Set the SREG_WRITE_ALL bit to remove potential higher current during intial standby ++{0x3500, 0x0100}, //This is a self clearing bit ++{AR_DELAY, 1}, //Delay => 4100 * Extclk ++ ++{0x3092, 0x0824}, // row noise dither enabled, dither scale=0 udpated 6/30/2017 ++{0x3096, 0x227C}, // row noise adjust top update 4/27/2017 with Jan-4 timing...YL ++{0x3098, 0x227C}, // row noise adjust bot update 4/27/2017 with Jan-4 timing...YL ++{0x3750, 0x227C}, // row noise adjust top gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL ++{0x3752, 0x227C}, // row noise adjust btm gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL ++{0x351C, 0x00B3}, // vaapix load cap=11, agnd load cap=3 updated 4/27 with Jan-4 timing...YL ++ ++{0x3364, 172}, // set dual conversion gain ratio (HCG/LCG) to 5.3x (~172/32) updated 3/29 ++{0x337A, 0x0BB8}, // dblc scale factor 0.733x, updated 4/25 ++ ++// DLO settings ++{0x3110, 0x0011}, // Pre-HDR gain enable; Pixel_width_enable ++// These settings match AR0138 REV3 settings ++{0x3100, 0x4000}, // dlo control. turn on dlo noise filter. set barrier dither select to 0 to match AR0138 ++{0x3102, 0x6060}, // "better" filter settings. This is S2=96 and range=6 ++{0x3104, 0x6060}, // T3 ++{0x3106, 0x6060}, // T4 ++ ++{0x32EC, 0x72A2}, // shut_ctrl2_t3_sh_adcance=2 ++{0x350E, 0x0F14}, // adc_pedestal_dither_en=15 (from 231) to minimize RTN periodical bumps... updated 8/9/17 ++ ++// boost settings ++// Load booster settings. Early CREV4 headboards and parts will require booster settings to be manually programmed, ++// while CREV4 ES samples have part-specific booster settings programmed in OTPM. Booster settings are instored in ++// following 4 registers: 0x3520, 0x3522, 0x3524, and 0x352C. (9/22/2017 Lin) ++// Remove soft trim booster settings for CRev3-1 sensors as they are boosters trimmed. (01/14/2018 Lin) ++//PYTHON= loadBoosterSettings() ++//{0x3520, 0x1288 // RSTHI=3.9v, use fine_code=18 and coarse_code=0, Casey's rec'd, updated 12/16, ++//{0x3522, 0x860C // ROWHI=3.6v, Vrst_lo for hcg_lg change from 8 to 6 for eclipse margin 9/27, HTOL updated 12/16, use fine_code=12 and coarse_code=0, Casey's rec'd ++//{0x3524, 0x0C12 // DCGHI=3.6v, TXHI=3.9v updated HTOL voltage 12/16 Casey's rec'd ++//{0x352c, 0x0012 // RSTWELLHI=3.9v using fine_code=18 and coarse_code=0 HTOL voltage updated 12/16 C. Hoekstra rec'd, ++//{0x3532, 0x826C // updated (12/14) ++{0x3528, 0x3633}, //update vtxlo for lcg_lg to 0.3V for blue blooming issue 6/1/2018 ++{0x3532, 0xAE6C}, // ECL settings updated (1/9 Lin) ++{0x353a, 0x9000}, // use AGND based boosters, enable continuous boost for RSTHI_WELL, TXHI_WELL (12/14) ++ ++{0x3540, 0xC63C}, // eclipse clamp updated 5/16 ++{0x3542, 0x4637}, // eclipse clamp updated 5/16 ++{0x3544, 0x3750}, // eclipse clamp updated 5/16 ++{0x3546, 0x5656}, // eclipse clamp updated 5/16 ++{0x3548, 0x5600}, // eclipse clamp updated 5/16 ++ ++//{0x3566, 0xBF38}, // col_mem settings, sa_park_en ++{0x3566, 0x3F28}, // col_mem settings, sa_park_en 5/2/2019 disable READOUT_PARK_ENABLE and SA_PARK_EN ++ ++{0x30BA, 0x0112}, // Add dither after delay buffer decompander ++{0x30BA, 0x0112}, //stop read back of dtest register from analog core to remove dark row on top 5/9 ++{ } ++}; /* Rev3 Recommended Settings */ ++ ++static const struct ar0xxx_reg ar0220_rev4_REV3_Optimized_Sequencer[] = { ++{0x2512, 0x8000}, ++{0x2510, 0x0905}, ++{0x2510, 0x3350}, ++{0x2510, 0x2004}, ++{0x2510, 0x1460}, ++{0x2510, 0x1578}, ++{0x2510, 0x1360}, ++{0x2510, 0x7B24}, ++{0x2510, 0xFF24}, ++{0x2510, 0xFF24}, ++{0x2510, 0xEA24}, ++{0x2510, 0x1022}, ++{0x2510, 0x2410}, ++{0x2510, 0x155A}, ++{0x2510, 0x1342}, ++{0x2510, 0x1440}, ++{0x2510, 0x24FF}, ++{0x2510, 0x24FF}, ++{0x2510, 0x24EA}, ++{0x2510, 0x2324}, ++{0x2510, 0x647A}, ++{0x2510, 0x2404}, ++{0x2510, 0x052C}, ++{0x2510, 0x400A}, ++{0x2510, 0xFF0A}, ++{0x2510, 0x850A}, ++{0x2510, 0x0608}, ++{0x2510, 0x3851}, ++{0x2510, 0x0905}, ++{0x2510, 0x15DC}, ++{0x2510, 0x134C}, ++{0x2510, 0x0004}, ++{0x2510, 0x0801}, ++{0x2510, 0x0408}, ++{0x2510, 0x1180}, ++{0x2510, 0x1002}, ++{0x2510, 0x1016}, ++{0x2510, 0x1181}, ++{0x2510, 0x1189}, ++{0x2510, 0x1056}, ++{0x2510, 0x1210}, ++{0x2510, 0x0D09}, ++{0x2510, 0x0714}, ++{0x2510, 0x4114}, ++{0x2510, 0x4009}, ++{0x2510, 0x0815}, ++{0x2510, 0xCC13}, ++{0x2510, 0xCC15}, ++{0x2510, 0x8813}, ++{0x2510, 0x8809}, ++{0x2510, 0x1111}, ++{0x2510, 0x9909}, ++{0x2510, 0x0B11}, ++{0x2510, 0xD909}, ++{0x2510, 0x0B12}, ++{0x2510, 0x1409}, ++{0x2510, 0x0112}, ++{0x2510, 0x1010}, ++{0x2510, 0xD612}, ++{0x2510, 0x1212}, ++{0x2510, 0x1011}, ++{0x2510, 0xDD11}, ++{0x2510, 0xD910}, ++{0x2510, 0x5609}, ++{0x2510, 0x1111}, ++{0x2510, 0xDB09}, ++{0x2510, 0x1D11}, ++{0x2510, 0xFB09}, ++{0x2510, 0x0911}, ++{0x2510, 0xBB12}, ++{0x2510, 0x1A12}, ++{0x2510, 0x1010}, ++{0x2510, 0xD612}, ++{0x2510, 0x5010}, ++{0x2510, 0xF610}, ++{0x2510, 0xE609}, ++{0x2510, 0x0315}, ++{0x2510, 0xAB13}, ++{0x2510, 0xAB12}, ++{0x2510, 0x4012}, ++{0x2510, 0x6009}, ++{0x2510, 0x2315}, ++{0x2510, 0x8809}, ++{0x2510, 0x0113}, ++{0x2510, 0x880B}, ++{0x2510, 0x0906}, ++{0x2510, 0x158D}, ++{0x2510, 0x138D}, ++{0x2510, 0x090B}, ++{0x2510, 0x1066}, ++{0x2510, 0x1588}, ++{0x2510, 0x1388}, ++{0x2510, 0x0C09}, ++{0x2510, 0x0410}, ++{0x2510, 0xE612}, ++{0x2510, 0x6212}, ++{0x2510, 0x6011}, ++{0x2510, 0xBF11}, ++{0x2510, 0xFB10}, ++{0x2510, 0x6609}, ++{0x2510, 0x3B11}, ++{0x2510, 0xBB12}, ++{0x2510, 0x6312}, ++{0x2510, 0x6009}, ++{0x2510, 0x0115}, ++{0x2510, 0x5A11}, ++{0x2510, 0xB812}, ++{0x2510, 0xA012}, ++{0x2510, 0x0010}, ++{0x2510, 0x2610}, ++{0x2510, 0x0013}, ++{0x2510, 0x0211}, ++{0x2510, 0x8014}, ++{0x2510, 0x007A}, ++{0x2510, 0x0611}, ++{0x2510, 0x0005}, ++{0x2510, 0x0708}, ++{0x2510, 0x4137}, ++{0x2510, 0x502C}, ++{0x2510, 0x2CFE}, ++{0x2510, 0x112C}, ++{AR_DELAY, 300}, ++ ++{0x1008, 0x02B6}, //fine_integration_time_min ++{0x100c, 0x0452}, //fine_integration_time2_min ++{0x100e, 0x05EE}, //fine_integration_time3_min ++{0x1010, 0x011A}, //fine_integration_time4_min ++ ++{0x3230, 0x0254}, //fine_correction ++{0x3232, 0x03F0}, //fine_correction2 ++{0x3234, 0x058C}, //fine_correction3 ++{0x3236, 0x00B8}, //fine_correction4 ++//{0x32e6, 0x009A}, //min_subrow ++{0x32e6, 0x00BC}, //min_subrow 188 2/6/2018 Lin ++{ } ++}; /* AR0220AT REV3 Optimized Sequencer */ ++ ++static const struct ar0xxx_reg ar0220_rev4_pll_23_4lane_12b[] = { ++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ ++/* PCLK=23Mhz/2 *44/1/12 *2= 84Mhz - TI serializers */ ++{0x3030, 44}, //PLL_MULTIPLIER ++{0x302E, 2}, //PRE_PLL_CLK_DIV ++{0x302C, 1}, //P1 divider (vt_sys_clk_div) ++{0x302A, 6}, //P2 divider (vt_pix_clk_div) ++{0x3038, 1}, //P3 divider (op_sys_clk_div) ++{0x3036, 12}, //P4 divider (op_word_clk_div) ++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 ++{ } ++}; /* PLL Setup Serial 4 lane 12-bit Output 23Mhz MCLK */ ++ ++static const struct ar0xxx_reg ar0220_rev4_pll_25_4lane_12b[] = { ++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ ++/* PCLK=25Mhz/5 *102/1/12 *2= 85Mhz - IN-CAMERA REFCLK */ ++/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */ ++{0x3030, 102}, //PLL_MULTIPLIER ++{0x302E, 5}, //PRE_PLL_CLK_DIV ++{0x302C, 1}, //P1 divider (vt_sys_clk_div) ++{0x302A, 6}, //P2 divider (vt_pix_clk_div) ++{0x3038, 1}, //P3 divider (op_sys_clk_div) ++{0x3036, 12}, //P4 divider (op_word_clk_div) ++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 ++{ } ++}; /* PLL Setup Serial 4 lane 12-bit Output 25Mhz MCLK */ ++ ++static const struct ar0xxx_reg ar0220_rev4_pll_27_4lane_12b[] = { ++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ ++/* PCLK=27Mhz/3 *56/1/12 *2= 84Mhz - IN-CAMERA REFCLK */ ++/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */ ++{0x3030, 56}, //PLL_MULTIPLIER ++{0x302E, 3}, //PRE_PLL_CLK_DIV ++{0x302C, 1}, //P1 divider (vt_sys_clk_div) ++{0x302A, 6}, //P2 divider (vt_pix_clk_div) ++{0x3038, 1}, //P3 divider (op_sys_clk_div) ++{0x3036, 12}, //P4 divider (op_word_clk_div) ++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 ++{ } ++}; /* PLL Setup Serial 4 lane 12-bit Output 27Mhz MCLK */ ++ ++static const struct ar0xxx_reg ar0220_rev4_Readout_Mode_Configuration[] = { ++{0x30A2, 1}, // x_odd_inc_ ++{0x30A6, 1}, // y_odd_inc_ ++{0x3040, 0}, // read_mode ++{ } ++}; /* Readout Mode Configuration */ ++ ++static const struct ar0xxx_reg ar0220_rev4_Full_Res_FOV[] = { ++{0x3004, AR0220_X_START}, // X_ADDR_START_ ++{0x3008, AR0220_X_END}, // X_ADDR_END_ ++{0x3002, AR0220_Y_START}, // Y_ADDR_START_ ++{0x3006, AR0220_Y_END}, // Y_ADDR_END_ ++{ } ++}; /* Full Res FOV */ ++ ++static const struct ar0xxx_reg ar0220_rev4_hdr_Timing_and_Exposure[] = { ++{0x3082, 0x8}, // operation_mode_ctrl ++{0x30BA, 0x1112}, // digital_ctrl: num_exp_max=2 ++#ifdef AR0231_EMBEDDED_LINE ++{0x3064, 0x1982}, // SMIA_TEST ++#else ++{0x3064, 0x1802}, // SMIA_TEST ++#endif ++//{0x33E0, 0xC80}, ++//{0x3180, 0x80}, ++//{0x33E4, 0x80}, ++ ++{0x306e, 9010}, // datapath_select,ime_mode,0 ++ ++{0x300A, AR0220_SENSOR_HEIGHT + 794}, // frame_length_lines_ (1742) ++{0x300C, AR0220_SENSOR_WIDTH/2 + 424}, // line_length_pck_ (1338) ++{0x3042, 0}, // extra_delay ++ ++{0x3238, 0x444}, // exposure_ratio ++{0x3012, 1000}, // coarse_integration_time_ ++{0x3014, 1526}, // fine_integration_time_ ++{0x321E, 1526}, // fine_integration_time2 ++{0x3222, 282}, // fine_integration_time3 ++{0x32EA, 0x3C0E}, ++//{0x32EC, 0x7151}, ++ ++{0x30B0, 0x800}, // enable_subrow_pair_reset ++{0x32E8, 637}, // max subrow margin for 3exp HDR ++{ } ++}; /* 3exp 36FPS Timing and Exposure */ ++ ++static const struct ar0xxx_reg ar0220_rev4_hdr_12bit_output[] = { ++{0x31D0, 1}, // companding ++{0x31AC, 0x140C}, // data_format_bits: RAW20, OUT12 ++{ } ++}; /* HDR Serial 4 lane 12 bit Output */ ++ ++static const struct ar0xxx_reg ar0220_rev4_mipi_12bit_4lane[] = { ++{0x31AE, 0x204}, // serial_format: MIPI 4 lanes ++//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C ++//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C ++//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C ++//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C ++//{0x3344, 0x0011}, // default, VC=0 ++//{0x3348, 0x0111}, // default, VC=1 ++//{0x334C, 0x0211}, // default, VC=2 ++//{0x3350, 0x0311}, // default, VC=3 ++{0x31B0, 0x46}, // frame_preamble ++{0x31B2, 0x31}, // line_preamble ++{0x31B4, 0x2144}, //MIPI_TIMING_0 update @504Mbps 12 bit, 04/17 ++{0x31B6, 0x3145}, //MIPI_TIMING_1 update @504Mbps 12 bit, 04/17 ++{0x31B8, 0x3147}, //MIPI_TIMING_2 update @504Mbps 12 bit, 04/17 ++{0x31BA, 0x0186}, //MIPI_TIMING_3 ++{0x31BC, 0x0785}, //MIPI_TIMING_4 ++{ } ++}; /* HDR MIPI 12 bit Settings */ ++ ++static const struct ar0xxx_reg ar0220_rev4_Recommended_HDR_Settings[] = { ++{ } ++}; /* Recommended HDR Settings */ ++ ++/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */ ++static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev4[] = { ++ ar0220_rev4_Reset, ++ ar0220_rev4_Recommended_Settings, ++ ar0220_rev4_pll_23_4lane_12b, ++ ar0220_rev4_Readout_Mode_Configuration, ++ ar0220_rev4_Full_Res_FOV, ++ ar0220_rev4_hdr_Timing_and_Exposure, ++ ar0220_rev4_hdr_12bit_output, ++ ar0220_rev4_mipi_12bit_4lane, ++ ar0220_rev4_Recommended_HDR_Settings, ++ NULL, ++}; ++ ++/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */ ++static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev3[] = { ++ ar0220_rev4_Reset, ++ ar0220_rev4_Recommended_Settings, ++ ar0220_rev4_REV3_Optimized_Sequencer, ++ ar0220_rev4_pll_23_4lane_12b, ++ ar0220_rev4_Readout_Mode_Configuration, ++ ar0220_rev4_Full_Res_FOV, ++ ar0220_rev4_hdr_Timing_and_Exposure, ++ ar0220_rev4_hdr_12bit_output, ++ ar0220_rev4_mipi_12bit_4lane, ++ ar0220_rev4_Recommended_HDR_Settings, ++ NULL, ++}; +diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c +index 9294267..500fa75 100644 +--- a/drivers/media/i2c/soc_camera/ar0233.c ++++ b/drivers/media/i2c/soc_camera/ar0233.c +@@ -1,7 +1,7 @@ + /* +- * ON Semiconductor AR0233 sensor camera driver ++ * ON Semiconductor AR0220/233 sensor camera driver + * +- * Copyright (C) 2018 Cogent Embedded, Inc. ++ * Copyright (C) 2018-2019 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the +@@ -20,15 +20,33 @@ + #include <media/v4l2-common.h> + #include <media/v4l2-ctrls.h> + ++#define AR_DELAY 0xffff ++static int AR_MAX_WIDTH; ++static int AR_MAX_HEIGHT; ++static int AR_X_START; ++static int AR_Y_START; ++static int AR_X_END; ++static int AR_Y_END; ++ ++struct ar0xxx_reg { ++ u16 reg; ++ u16 val; ++}; ++ ++#include "ar0220.h" + #include "ar0233.h" + + static const int ar0233_i2c_addr[] = {0x10, 0x20}; + +-#define AR0233_PID 0x3000 +-#define AR0233_REV 0x31FE +-#define AR0233_VERSION_REG 0x0956 ++#define AR_PID_REG 0x3000 ++#define AR_REV_REG 0x31FE + +-#define AR0233_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG12_1X12 ++enum { ++ AR0220_PID = 0x0C54, ++ AR0233_PID = 0x0956, ++} chipid; ++ ++#define AR_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG12_1X12 + + struct ar0233_priv { + struct v4l2_subdev sd; +@@ -57,9 +75,9 @@ static inline struct ar0233_priv *to_ar0233(const struct i2c_client *client) + return container_of(i2c_get_clientdata(client), struct ar0233_priv, sd); + } + +-static int ar0233_set_regs(struct i2c_client *client, const struct ar0233_reg **pregs) ++static int ar0233_set_regs(struct i2c_client *client, const struct ar0xxx_reg **pregs) + { +- const struct ar0233_reg *regs; ++ const struct ar0xxx_reg *regs; + int i, j; + + for (j = 0; ; j++) { +@@ -72,7 +90,7 @@ static int ar0233_set_regs(struct i2c_client *client, const struct ar0233_reg ** + if (!regs[i].reg && !regs[i].val) + break; + +- if (regs[i].reg == AR0233_DELAY) { ++ if (regs[i].reg == AR_DELAY) { + mdelay(regs[i].val); + continue; + } +@@ -97,13 +115,13 @@ static int ar0233_set_window(struct v4l2_subdev *sd) + dev_dbg(&client->dev, "L=%d T=%d %dx%d\n", priv->rect.left, priv->rect.top, priv->rect.width, priv->rect.height); + + /* horiz crop start */ +- reg16_write16(client, 0x3004, priv->rect.left + AR0233_X_START); ++ reg16_write16(client, 0x3004, priv->rect.left + AR_X_START); + /* horiz crop end */ +- reg16_write16(client, 0x3008, priv->rect.left + priv->rect.width - 1 + AR0233_X_START); ++ reg16_write16(client, 0x3008, priv->rect.left + priv->rect.width - 1 + AR_X_START); + /* vert crop start */ +- reg16_write16(client, 0x3002, priv->rect.top + AR0233_Y_START); ++ reg16_write16(client, 0x3002, priv->rect.top + AR_Y_START); + /* vert crop end */ +- reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR0233_Y_START); ++ reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START); + + return 0; + }; +@@ -121,7 +139,7 @@ static int ar0233_get_fmt(struct v4l2_subdev *sd, + + mf->width = priv->rect.width; + mf->height = priv->rect.height; +- mf->code = AR0233_MEDIA_BUS_FMT; ++ mf->code = AR_MEDIA_BUS_FMT; + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + mf->field = V4L2_FIELD_NONE; + +@@ -134,7 +152,7 @@ static int ar0233_set_fmt(struct v4l2_subdev *sd, + { + struct v4l2_mbus_framefmt *mf = &format->format; + +- mf->code = AR0233_MEDIA_BUS_FMT; ++ mf->code = AR_MEDIA_BUS_FMT; + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + mf->field = V4L2_FIELD_NONE; + +@@ -151,7 +169,7 @@ static int ar0233_enum_mbus_code(struct v4l2_subdev *sd, + if (code->pad || code->index > 0) + return -EINVAL; + +- code->code = AR0233_MEDIA_BUS_FMT; ++ code->code = AR_MEDIA_BUS_FMT; + + return 0; + } +@@ -165,8 +183,8 @@ static int ar0233_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) + + edid->edid[6] = 0xff; + edid->edid[7] = client->addr; +- edid->edid[8] = AR0233_VERSION_REG >> 8; +- edid->edid[9] = AR0233_VERSION_REG & 0xff; ++ edid->edid[8] = chipid >> 8; ++ edid->edid[9] = chipid & 0xff; + + return 0; + } +@@ -188,8 +206,8 @@ static int ar0233_set_selection(struct v4l2_subdev *sd, + rect->width = ALIGN(rect->width, 2); + rect->height = ALIGN(rect->height, 2); + +- if ((rect->left + rect->width > AR0233_MAX_WIDTH) || +- (rect->top + rect->height > AR0233_MAX_HEIGHT)) ++ if ((rect->left + rect->width > AR_MAX_WIDTH) || ++ (rect->top + rect->height > AR_MAX_HEIGHT)) + *rect = priv->rect; + + priv->rect.left = rect->left; +@@ -216,14 +234,14 @@ static int ar0233_get_selection(struct v4l2_subdev *sd, + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; +- sel->r.width = AR0233_MAX_WIDTH; +- sel->r.height = AR0233_MAX_HEIGHT; ++ sel->r.width = AR_MAX_WIDTH; ++ sel->r.height = AR_MAX_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; +- sel->r.width = AR0233_MAX_WIDTH; +- sel->r.height = AR0233_MAX_HEIGHT; ++ sel->r.width = AR_MAX_WIDTH; ++ sel->r.height = AR_MAX_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r = priv->rect; +@@ -400,6 +418,7 @@ static DEVICE_ATTR(otp_id_ar0233, S_IRUGO, ar0233_otp_id_show, NULL); + static int ar0233_initialize(struct i2c_client *client) + { + struct ar0233_priv *priv = to_ar0233(client); ++ char chip_name[10] = "unknown"; + u16 val = 0; + u16 pid = 0, rev = 0; + int ret = 0; +@@ -416,42 +435,85 @@ static int ar0233_initialize(struct i2c_client *client) + client->addr = tmp_addr; + + /* check model ID */ +- reg16_read16(client, AR0233_PID, &pid); ++ reg16_read16(client, AR_PID_REG, &pid); + +- if (pid == AR0233_VERSION_REG) ++ if (pid == AR0220_PID || pid == AR0233_PID) + break; + } + +- if (pid != AR0233_VERSION_REG) { ++ if (pid != AR0220_PID && pid != AR0233_PID) { + dev_dbg(&client->dev, "Product ID error %x\n", pid); + ret = -ENODEV; + goto err; + } + + /* check revision */ +- reg16_read16(client, AR0233_REV, &rev); ++ reg16_read16(client, AR_REV_REG, &rev); + /* Read OTP IDs */ + ar0233_otp_id_read(client); +- /* Program wizard registers */ +- switch (rev & 0xf) { +- case 0x1: +- ar0233_set_regs(client, ar0233_regs_hdr_mipi_12bit_30fps_rev1); +- break; +- case 0x2: +- if (extclk == 27) { +- ar0233_regs_hdr_mipi_12bit_30fps_rev2[4] = ar0233_rev2_pll_27_102_4lane_12b; +- ar0233_regs_seplus_mipi_12bit_30fps_rev2[2] = ar0233_rev2_pll_27_102_4lane_12b; +- } + +- if (strcmp(mode, "hdr") == 0) +- ar0233_set_regs(client, ar0233_regs_hdr_mipi_12bit_30fps_rev2); +- else if (strcmp(mode, "seplus") == 0) +- ar0233_set_regs(client, ar0233_regs_seplus_mipi_12bit_30fps_rev2); +- else +- dev_err(&client->dev, "Unsupported mode %s\n", mode); +- break; +- default: +- dev_err(&client->dev, "Unsupported chip revision\n"); ++ switch (pid) { ++ case AR0220_PID: ++ chipid = ID_AR0220; ++ strncpy(chip_name, "AR0220", 10); ++ AR_MAX_WIDTH = AR0220_MAX_WIDTH; ++ AR_MAX_HEIGHT = AR0220_MAX_HEIGHT; ++ AR_X_START = AR0220_X_START; ++ AR_Y_START = AR0220_Y_START; ++ AR_X_END = AR0220_X_END; ++ AR_Y_END = AR0220_Y_END; ++ ++ switch (rev & 0xf) { ++ case 0x1: ++ case 0x2: ++ case 0x3: ++ if (extclk == 25) { ++ ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev4_pll_25_4lane_12b; ++ } ++ if (extclk == 27) { ++ ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev4_pll_27_4lane_12b; ++ } ++ ar0233_set_regs(client, ar0220_regs_hdr_mipi_12bit_36fps_rev3); ++ break; ++ case 0x4: ++ ar0233_set_regs(client, ar0220_regs_hdr_mipi_12bit_36fps_rev4); ++ break; ++ default: ++ dev_err(&client->dev, "Unsupported chip revision\n"); ++ } ++ break; ++ case AR0233_PID: ++ chipid = ID_AR0233; ++ strncpy(chip_name, "AR0233", 10); ++ AR_MAX_WIDTH = AR0233_MAX_WIDTH; ++ AR_MAX_HEIGHT = AR0233_MAX_HEIGHT; ++ AR_X_START = AR0233_X_START; ++ AR_Y_START = AR0233_Y_START; ++ AR_X_END = AR0233_X_END; ++ AR_Y_END = AR0233_Y_END; ++ ++ /* Program wizard registers */ ++ switch (rev & 0xf) { ++ case 0x1: ++ ar0233_set_regs(client, ar0233_regs_hdr_mipi_12bit_30fps_rev1); ++ break; ++ case 0x2: ++ if (extclk == 27) { ++ ar0233_regs_hdr_mipi_12bit_30fps_rev2[4] = ar0233_rev2_pll_27_102_4lane_12b; ++ ar0233_regs_seplus_mipi_12bit_30fps_rev2[2] = ar0233_rev2_pll_27_102_4lane_12b; ++ } ++ ++ if (strcmp(mode, "hdr") == 0) ++ ar0233_set_regs(client, ar0233_regs_hdr_mipi_12bit_30fps_rev2); ++ else if (strcmp(mode, "seplus") == 0) ++ ar0233_set_regs(client, ar0233_regs_seplus_mipi_12bit_30fps_rev2); ++ else ++ dev_err(&client->dev, "Unsupported mode %s\n", mode); ++ break; ++ default: ++ dev_err(&client->dev, "Unsupported chip revision\n"); ++ } ++ break; + } + + /* Enable trigger */ +@@ -468,8 +530,8 @@ static int ar0233_initialize(struct i2c_client *client) + val |= (1 << 2); // Set streamOn bit + reg16_write16(client, 0x301a, val); // Start Streaming + +- dev_info(&client->dev, "ar0233 PID %x (rev%x), res %dx%d, mode=%s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", +- pid, rev & 0xf, AR0233_MAX_WIDTH, AR0233_MAX_HEIGHT, mode, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ dev_info(&client->dev, "%s PID %x (rev%x), res %dx%d, mode=%s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", chip_name, ++ pid, rev & 0xf, AR_MAX_WIDTH, AR_MAX_HEIGHT, mode, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + err: + return ret; + } +@@ -586,8 +648,8 @@ static int ar0233_probe(struct i2c_client *client, + + priv->rect.left = 0; + priv->rect.top = 0; +- priv->rect.width = AR0233_MAX_WIDTH; +- priv->rect.height = AR0233_MAX_HEIGHT; ++ priv->rect.width = AR_MAX_WIDTH; ++ priv->rect.height = AR_MAX_HEIGHT; + + ret = v4l2_async_register_subdev(&priv->sd); + if (ret) +diff --git a/drivers/media/i2c/soc_camera/ar0233.h b/drivers/media/i2c/soc_camera/ar0233.h +index 5f2bada..33b661a 100644 +--- a/drivers/media/i2c/soc_camera/ar0233.h ++++ b/drivers/media/i2c/soc_camera/ar0233.h +@@ -15,8 +15,6 @@ + #define AR0233_MAX_WIDTH 2048 + #define AR0233_MAX_HEIGHT 1280 + +-#define AR0233_DELAY 0xffff +- + #define AR0233_SENSOR_WIDTH 2072 + #define AR0233_SENSOR_HEIGHT 1296 + +@@ -25,10 +23,5 @@ + #define AR0233_X_END (AR0233_X_START + AR0233_MAX_WIDTH - 1) + #define AR0233_Y_END (AR0233_Y_START + AR0233_MAX_HEIGHT - 1) + +-struct ar0233_reg { +- u16 reg; +- u16 val; +-}; +- + #include "ar0233_rev1.h" + #include "ar0233_rev2.h" +diff --git a/drivers/media/i2c/soc_camera/ar0233_rev1.h b/drivers/media/i2c/soc_camera/ar0233_rev1.h +index ddc1612..0389e51 100644 +--- a/drivers/media/i2c/soc_camera/ar0233_rev1.h ++++ b/drivers/media/i2c/soc_camera/ar0233_rev1.h +@@ -9,9 +9,9 @@ + * option) any later version. + */ + +-static const struct ar0233_reg ar0233_rev1_Reset[] = { ++static const struct ar0xxx_reg ar0233_rev1_Reset[] = { + {0x301A, 0x0018}, // Stream off and setup MIPI +-{AR0233_DELAY, 200}, ++{AR_DELAY, 200}, + {0x3070, 0x0000}, // 1: Solid color test pattern, + // 2: Full color bar test pattern, + // 3: Fade to grey color bar test pattern, +@@ -26,11 +26,11 @@ static const struct ar0233_reg ar0233_rev1_Reset[] = { + #ifdef AR0233_DISPLAY_PATTERN_COLOR_BAR + {0x3070, 0x0002}, + #endif +-{AR0233_DELAY, 100}, ++{AR_DELAY, 100}, + { } + }; /* Reset */ + +-static const struct ar0233_reg ar0233_rev1_Sequencer_Settings[] = { ++static const struct ar0xxx_reg ar0233_rev1_Sequencer_Settings[] = { + /* Design_recommended_settings_v5 */ + {0x356C, 0xEA55}, //mte.Sensor.Register("DAC_LD_108_109").Value = 0xEA55& -- ADC write Memory delay 7 + {0x3566, 0x2407}, //mte.Sensor.Register("DAC_LD_102_103").Value = 0x2407& -- Enable column amp bypass for 1x +@@ -1095,12 +1095,12 @@ static const struct ar0233_reg ar0233_rev1_Sequencer_Settings[] = { + {0x2510, 0xffff}, + {0x2510, 0xffff}, + {0x2510, 0xffff}, +-{AR0233_DELAY, 100}, ++{AR_DELAY, 100}, + /* Sequencer_LFM_HDR_v6 */ + { } + }; /* Sequencer_Settings */ + +-static const struct ar0233_reg ar0233_rev1_HDR_3exp_12bit[] = { ++static const struct ar0xxx_reg ar0233_rev1_HDR_3exp_12bit[] = { + {0x3082, 0x8}, //num_exp = 3 + {0x3110, 0x11}, //Set bypass pix comb for HDR,Pre_hdr_gain_enable_07Jul + {0x30BA, 0x1122}, //num_exp_max =3 +@@ -1116,7 +1116,7 @@ static const struct ar0233_reg ar0233_rev1_HDR_3exp_12bit[] = { + { } + }; /* HDR_3exp_12bit */ + +-static const struct ar0233_reg ar0233_rev1_Serial_12bit_Timing_Setup_103p5[] = { ++static const struct ar0xxx_reg ar0233_rev1_Serial_12bit_Timing_Setup_103p5[] = { + /* PCLK=DES_REFCLK /PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 */ + /* PCLK=23MHz/2 *54/1/6= 103.5Mhz - TI serializers */ + {0x3030, 54}, //PLL_MULTIPLIER ; 0x3030 [11:0] +@@ -1129,7 +1129,7 @@ static const struct ar0233_reg ar0233_rev1_Serial_12bit_Timing_Setup_103p5[] = { + { } + }; /* Serial_12bit_Timing_Setup_103p5 */ + +-static const struct ar0233_reg ar0233_rev1_MIPI_4Lane_12BITS[] = { ++static const struct ar0xxx_reg ar0233_rev1_MIPI_4Lane_12BITS[] = { + {0x31AE, 0x204}, //MIPI enable, 4 lanes + {0x31B0, 0x4B}, //frame_preamble + {0x31B2, 0x33}, //line_preamble +@@ -1145,7 +1145,7 @@ static const struct ar0233_reg ar0233_rev1_MIPI_4Lane_12BITS[] = { + { } + }; /* MIPI_4Lane_12BITS */ + +-static const struct ar0233_reg ar0233_rev1_Full_resolution[] = { ++static const struct ar0xxx_reg ar0233_rev1_Full_resolution[] = { + {0x3004, AR0233_X_START}, // X_ADDR_START_ + {0x3008, AR0233_X_END}, // X_ADDR_END_ + {0x3002, AR0233_Y_START}, // Y_ADDR_START_ +@@ -1155,7 +1155,7 @@ static const struct ar0233_reg ar0233_rev1_Full_resolution[] = { + { } + }; /* Full_resolution */ + +-static const struct ar0233_reg ar0233_rev1_disable_embed_data_stat[] = { ++static const struct ar0xxx_reg ar0233_rev1_disable_embed_data_stat[] = { + {0x3040, 0xC000}, //Embedded stat2 and data2 rows, hflip/vflip=1 + #ifdef AR0233_EMBEDDED_LINE + {0x3064, 0x0180}, //Enable embedded data and stat +@@ -1165,7 +1165,7 @@ static const struct ar0233_reg ar0233_rev1_disable_embed_data_stat[] = { + { } + }; /* disable_embed_data_stat */ + +-static const struct ar0233_reg ar0233_rev1_Gain_3p28x[] = { ++static const struct ar0xxx_reg ar0233_rev1_Gain_3p28x[] = { + {0x3022, 0x01}, // GROUPED_PARAMETER_HOLD_ + {0x3362, 0x000F}, // DC_GAIN + {0x3366, 0x1111}, +@@ -1174,7 +1174,7 @@ static const struct ar0233_reg ar0233_rev1_Gain_3p28x[] = { + { } + }; /* Gain_3.28x */ + +-static const struct ar0233_reg ar0233_rev1_MEC_DLO_default[] = { ++static const struct ar0xxx_reg ar0233_rev1_MEC_DLO_default[] = { + {0x3D00, 0x6F73}, // control + {0x3D02, 0x0033}, + {0x3364, 0x068C}, // dcg_trim = 13.1 +@@ -1260,7 +1260,7 @@ static const struct ar0233_reg ar0233_rev1_MEC_DLO_default[] = { + }; /* MEC_DLO_default */ + + /* 3Exp HDR, 1280P, MIPI 4-lane 12-bit, 30fps, EXTCLK=23MHz (comes from deser) */ +-static const struct ar0233_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev1[] = { ++static const struct ar0xxx_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev1[] = { + ar0233_rev1_Reset, + ar0233_rev1_Sequencer_Settings, + ar0233_rev1_disable_embed_data_stat, +diff --git a/drivers/media/i2c/soc_camera/ar0233_rev2.h b/drivers/media/i2c/soc_camera/ar0233_rev2.h +index 7085fbc..7f71056 100644 +--- a/drivers/media/i2c/soc_camera/ar0233_rev2.h ++++ b/drivers/media/i2c/soc_camera/ar0233_rev2.h +@@ -9,9 +9,9 @@ + * option) any later version. + */ + +-static const struct ar0233_reg ar0233_rev2_Reset[] = { ++static const struct ar0xxx_reg ar0233_rev2_Reset[] = { + {0x301A, 0x0018}, // Stream off and setup MIPI +-{AR0233_DELAY, 200}, ++{AR_DELAY, 200}, + {0x3070, 0x0000}, // 1: Solid color test pattern, + // 2: Full color bar test pattern, + // 3: Fade to grey color bar test pattern, +@@ -26,11 +26,11 @@ static const struct ar0233_reg ar0233_rev2_Reset[] = { + #ifdef AR0233_DISPLAY_PATTERN_COLOR_BAR + {0x3070, 0x0002}, + #endif +-{AR0233_DELAY, 100}, ++{AR_DELAY, 100}, + { } + }; /* Reset */ + +-static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_LFM_HDR[] = { ++static const struct ar0xxx_reg ar0233_rev2_O1_Recommended_Defaults_LFM_HDR[] = { + /* Design_recommended_settings_REV2_V9 */ + {0x3C72, 0x0076}, + {0x3C74, 0x0031}, +@@ -1106,7 +1106,7 @@ static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_LFM_HDR[] = { + {0x2510, 0xffff}, + {0x2510, 0x3426}, + {0x2510, 0x3614}, +-{AR0233_DELAY, 100}, ++{AR_DELAY, 100}, + /* Sequence_hidy_ar0233_REV2_V13 */ + + /* Pre_hdr_gain_enable */ +@@ -1124,7 +1124,7 @@ static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_LFM_HDR[] = { + { } + }; /* O1_Recommended_Defaults_LFM_HDR */ + +-static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[] = { ++static const struct ar0xxx_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[] = { + /* Design_recommended_settings_REV2_seplus */ + {0x3086, 0x0000}, + {0x3092, 0x400C}, +@@ -2243,7 +2243,7 @@ static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[ + {0x2510, 0xFFFF}, + {0x2510, 0xFFFF}, + {0x2510, 0xFFFF}, +-{AR0233_DELAY, 100}, ++{AR_DELAY, 100}, + /* Sequence_hidy_ar0233_REV2_seplus */ + + {0x3E14, 0x003F}, +@@ -2264,7 +2264,7 @@ static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[ + { } + }; /* O1_Recommended_Defaults_SE_T1_LIN_T2 */ + +-static const struct ar0233_reg ar0233_rev2_disable_embed_data_stat[] = { ++static const struct ar0xxx_reg ar0233_rev2_disable_embed_data_stat[] = { + {0x3040, 0xC000}, //Embedded stat2 and data2 rows, hflip/vflip=1 + {0x350e, 0x2089}, // bit0 must be set for vflip=1 + #ifdef AR0233_EMBEDDED_LINE +@@ -2275,7 +2275,7 @@ static const struct ar0233_reg ar0233_rev2_disable_embed_data_stat[] = { + { } + }; /* disable_embed_data_stat */ + +-static const struct ar0233_reg ar0233_rev2_HDR_3exp_12bit[] = { ++static const struct ar0xxx_reg ar0233_rev2_HDR_3exp_12bit[] = { + {0x3082, 0x8}, //num_exp = 3 + {0x30BA, 0x1122}, //num_exp_max =3 + {0x31AC, 0x140C}, //12 bit output +@@ -2289,7 +2289,7 @@ static const struct ar0233_reg ar0233_rev2_HDR_3exp_12bit[] = { + { } + }; /* HDR_3exp_12bit */ + +-static const struct ar0233_reg ar0233_rev2_SEPLUS_12bit[] = { ++static const struct ar0xxx_reg ar0233_rev2_SEPLUS_12bit[] = { + {0x3082, 0x4}, //num_exp = 2 + {0x30BA, 0x1121}, //num_exp_max =2 + {0x31AC, 0x140C}, //12 bit output +@@ -2305,7 +2305,7 @@ static const struct ar0233_reg ar0233_rev2_SEPLUS_12bit[] = { + { } + }; /* HDR_3exp_12bit */ + +-static const struct ar0233_reg ar0233_rev2_pll_23_102_4lane_12b[] = { ++static const struct ar0xxx_reg ar0233_rev2_pll_23_102_4lane_12b[] = { + // serial_data_rate was *2 in REV1. but not in REV2 + /* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 */ + /* PCLK=23Mhz/0x3 *0x50/1/6= 102Mhz - TI serializers */ +@@ -2319,7 +2319,7 @@ static const struct ar0233_reg ar0233_rev2_pll_23_102_4lane_12b[] = { + { } + }; /* pll_23_102_4lane_12b */ + +-static const struct ar0233_reg ar0233_rev2_pll_27_102_4lane_12b[] = { ++static const struct ar0xxx_reg ar0233_rev2_pll_27_102_4lane_12b[] = { + // serial_data_rate was *2 in REV1. but not in REV2 + /* PCLK=27Mhz/0x3 *0x44/1/6= 102Mhz - TI serializers */ + {0x3030, 0x44}, //PLL_MULTIPLIER +@@ -2332,7 +2332,7 @@ static const struct ar0233_reg ar0233_rev2_pll_27_102_4lane_12b[] = { + { } + }; /* pll_27_102_4lane_12b */ + +-static const struct ar0233_reg ar0233_rev2_mipi_12bit_4lane[] = { ++static const struct ar0xxx_reg ar0233_rev2_mipi_12bit_4lane[] = { + {0x31AE, 0x204}, //serial type and lane + {0x31B0, 0x67}, //frame_preamble + {0x31B2, 0x30}, //line_preamble +@@ -2348,7 +2348,7 @@ static const struct ar0233_reg ar0233_rev2_mipi_12bit_4lane[] = { + { } + }; /* mipi_12bit_4lane */ + +-static const struct ar0233_reg ar0233_rev2_LUT_24_to_12[] = { ++static const struct ar0xxx_reg ar0233_rev2_LUT_24_to_12[] = { + {0x31AC, 0x180C}, + {0x31D0, 0x01}, //companding + {0x33DA, 0}, +@@ -2371,7 +2371,7 @@ static const struct ar0233_reg ar0233_rev2_LUT_24_to_12[] = { + { } + }; /* LUT_24_to_12 */ + +-static const struct ar0233_reg ar0233_rev2_Full_resolution[] = { ++static const struct ar0xxx_reg ar0233_rev2_Full_resolution[] = { + {0x3004, AR0233_X_START}, // X_ADDR_START_ + {0x3008, AR0233_X_END}, // X_ADDR_END_ + {0x3002, AR0233_Y_START}, // Y_ADDR_START_ +@@ -2381,14 +2381,14 @@ static const struct ar0233_reg ar0233_rev2_Full_resolution[] = { + { } + }; /* Full_resolution */ + +-static const struct ar0233_reg ar0233_rev2_HDR_ratio_gain_default[] = { ++static const struct ar0xxx_reg ar0233_rev2_HDR_ratio_gain_default[] = { + {0x3362, 0x000F}, //HCG + {0x3366, 0x1111}, //1x + {0x3238, 0x0444}, // Ratio 16x, Use retio setting + { } + }; /* HDR_ratio_gain_default */ + +-static const struct ar0233_reg ar0233_rev2_SEPLUS_ratio_gain_default[] = { ++static const struct ar0xxx_reg ar0233_rev2_SEPLUS_ratio_gain_default[] = { + {0x3362, 0x0001}, // DC_GAIN + {0x3238, 0x8446}, // EXPOSURE_RATIO + {0x562E, 0x0111}, // OCL_T1_GAIN_ +@@ -2401,7 +2401,7 @@ static const struct ar0233_reg ar0233_rev2_SEPLUS_ratio_gain_default[] = { + }; /* SEPLUS_ratio_gain_default */ + + /* 3Exp HDR, 1280P, MIPI 4-lane 12-bit, 30fps, EXTCLK=23MHz (comes from deser) */ +-static const struct ar0233_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev2[] = { ++static const struct ar0xxx_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev2[] = { + ar0233_rev2_Reset, + ar0233_rev2_O1_Recommended_Defaults_LFM_HDR, + ar0233_rev2_disable_embed_data_stat, +@@ -2415,7 +2415,7 @@ static const struct ar0233_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev2[] = { + }; + + /* SE_T1 + Lin_T2, 1280P, MIPI 750MBPS 4-lane 12-bit, 30fps, EXTCLK=23MHz (comes from deser) */ +-static const struct ar0233_reg *ar0233_regs_seplus_mipi_12bit_30fps_rev2[] = { ++static const struct ar0xxx_reg *ar0233_regs_seplus_mipi_12bit_30fps_rev2[] = { + ar0233_rev2_Reset, + ar0233_rev2_Full_resolution, + ar0233_rev2_pll_23_102_4lane_12b, +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c +index 08d3816..876b3c1 100644 +--- a/drivers/media/i2c/soc_camera/ov106xx.c ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -9,28 +9,6 @@ + * option) any later version. + */ + +-#include "ov10635.c" +-#include "ov10640.c" +-#include "ov490_ov10640.c" +-#include "ov495_ov2775.c" +-#include "ar0132.c" +-#include "ar0140.c" +-#include "ar0143.c" +-#include "ar0220.c" +-#include "ar0231.c" +-#include "ar0233.c" +-#include "ar0323.c" +-#include "ap0101_ar014x.c" +-#include "gw4200_ar014x.c" +-#include "gw5200_imx390.c" +-#include "ov2775.c" +-#include "imx390.c" +-#include "ox03a.c" +-#include "isx016.c" +-#include "isx019.c" +-#include "ov2311.c" +-#include "ar0147.c" +- + static enum { + ID_OV10635, + ID_OV10640, +@@ -55,6 +33,27 @@ static enum { + ID_OV2311, + } chip_id; + ++#include "ov10635.c" ++#include "ov10640.c" ++#include "ov490_ov10640.c" ++#include "ov495_ov2775.c" ++#include "ar0132.c" ++#include "ar0140.c" ++#include "ar0143.c" ++#include "ar0231.c" ++#include "ar0233.c" ++#include "ar0323.c" ++#include "ap0101_ar014x.c" ++#include "gw4200_ar014x.c" ++#include "gw5200_imx390.c" ++#include "ov2775.c" ++#include "imx390.c" ++#include "ox03a.c" ++#include "isx016.c" ++#include "isx019.c" ++#include "ov2311.c" ++#include "ar0147.c" ++ + static int ov106xx_probe(struct i2c_client *client, + const struct i2c_device_id *did) + { +@@ -145,12 +144,6 @@ static int ov106xx_probe(struct i2c_client *client, + goto out; + } + +- ret = ar0220_probe(client, did); +- if (!ret) { +- chip_id = ID_AR0220; +- goto out; +- } +- + ret = gw4200_probe(client, did); + if (!ret) { + chip_id = ID_GW4200_AR014X; +@@ -220,9 +213,6 @@ static int ov106xx_remove(struct i2c_client *client) + case ID_AR0147: + ar0147_remove(client); + break; +- case ID_AR0220: +- ar0220_remove(client); +- break; + case ID_AR0231: + ar0231_remove(client); + break; +@@ -259,6 +249,8 @@ static int ov106xx_remove(struct i2c_client *client) + case ID_OV2311: + ov2311_remove(client); + break; ++ default: ++ break; + }; + + return 0; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0433-media-i2c-ar0220-add-rev2-rev3.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0433-media-i2c-ar0220-add-rev2-rev3.patch new file mode 100644 index 00000000..96a30a14 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0433-media-i2c-ar0220-add-rev2-rev3.patch @@ -0,0 +1,1021 @@ +From 8bfe841bb241b2c0582a1f2a82aa3207efc9a282 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 18 Nov 2019 20:20:03 +0300 +Subject: [PATCH] media: i2c: ar0220: add rev2, rev3 + +This adds REV2, REV3 imager versions + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ar0220.h | 2 + + drivers/media/i2c/soc_camera/ar0220_rev2.h | 349 +++++++++++++++++++++++++++ + drivers/media/i2c/soc_camera/ar0220_rev3.h | 218 +++++++++++++++++ + drivers/media/i2c/soc_camera/ar0220_rev4.h | 364 +---------------------------- + drivers/media/i2c/soc_camera/ar0233.c | 19 +- + 5 files changed, 591 insertions(+), 361 deletions(-) + create mode 100644 drivers/media/i2c/soc_camera/ar0220_rev2.h + create mode 100644 drivers/media/i2c/soc_camera/ar0220_rev3.h + +diff --git a/drivers/media/i2c/soc_camera/ar0220.h b/drivers/media/i2c/soc_camera/ar0220.h +index e372a9c..59a949e 100644 +--- a/drivers/media/i2c/soc_camera/ar0220.h ++++ b/drivers/media/i2c/soc_camera/ar0220.h +@@ -23,4 +23,6 @@ + #define AR0220_X_END (AR0220_X_START + AR0220_MAX_WIDTH - 1) + #define AR0220_Y_END (AR0220_Y_START + AR0220_MAX_HEIGHT - 1) + ++#include "ar0220_rev2.h" ++#include "ar0220_rev3.h" + #include "ar0220_rev4.h" +diff --git a/drivers/media/i2c/soc_camera/ar0220_rev2.h b/drivers/media/i2c/soc_camera/ar0220_rev2.h +new file mode 100644 +index 0000000..c66872d +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ar0220_rev2.h +@@ -0,0 +1,349 @@ ++/* ++ * ON Semiconductor AR0220 sensor camera wizard 1848x944@30/BGGR/MIPI ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++static const struct ar0xxx_reg ar0220_rev2_Reset[] = { ++{0x301A, 0x0018}, // Stream off and setup MIPI ++{AR_DELAY, 200}, ++{0x3070, 0x0000}, // 1: Solid color test pattern, ++ // 2: Full color bar test pattern, ++ // 3: Fade to grey color bar test pattern, ++ //256: Walking 1 test pattern (12 bit) ++{0x3072, 0x0123}, // R ++{0x3074, 0x0456}, // G(GR row) ++{0x3076, 0x0abc}, // B ++{0x3078, 0x0def}, // G(GB row) ++#ifdef AR0220_DISPLAY_PATTERN_FIXED ++{0x3070, 0x0001}, ++#endif ++#ifdef AR0220_DISPLAY_PATTERN_COLOR_BAR ++{0x3070, 0x0002}, ++#endif ++{AR_DELAY, 100}, ++{ } ++}; /* Reset */ ++ ++static const struct ar0xxx_reg ar0220_rev2_Recommended_Settings[] = { ++{0x3092, 0x0824}, // row noise dither enabled, dither scale=0 udpated 6/30/2017 ++{0x3096, 0x227C}, // row noise adjust top update 4/27/2017 with Jan-4 timing...YL ++{0x3098, 0x227C}, // row noise adjust bot update 4/27/2017 with Jan-4 timing...YL ++{0x3750, 0x227C}, // row noise adjust top gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL ++{0x3752, 0x227C}, // row noise adjust btm gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL ++{0x351C, 0x00B3}, // vaapix load cap=11, agnd load cap=3 updated 4/27 with Jan-4 timing...YL ++ ++{0x3364, 172}, // set dual conversion gain ratio (HCG/LCG) to 5.3x (~172/32) updated 3/29 ++{0x337A, 0x0BB8}, // dblc scale factor 0.733x, updated 4/25 ++ ++// DLO settings ++{0x3110, 0x0011}, // Pre-HDR gain enable; Pixel_width_enable ++// These settings match AR0138 REV3 settings ++{0x3100, 0x4000}, // dlo control. turn on dlo noise filter. set barrier dither select to 0 to match AR0138 ++{0x3102, 0x6060}, // "better" filter settings. This is S2=96 and range=6 ++{0x3104, 0x6060}, // T3 ++{0x3106, 0x6060}, // T4 ++ ++{0x32EC, 0x72A2}, // shut_ctrl2_t3_sh_adcance=2 ++{0x350E, 0x0F14}, // adc_pedestal_dither_en=15 (from 231) to minimize RTN periodical bumps... updated 8/9/17 ++ ++// boost settings ++// Load booster settings. Early CREV4 headboards and parts will require booster settings to be manually programmed, ++// while CREV4 ES samples have part-specific booster settings programmed in OTPM. Booster settings are instored in ++// following 4 registers: 0x3520, 0x3522, 0x3524, and 0x352C. (9/22/2017 Lin) ++// Remove soft trim booster settings for CRev3-1 sensors as they are boosters trimmed. (01/14/2018 Lin) ++//PYTHON= loadBoosterSettings() ++//{0x3520, 0x1288 // RSTHI=3.9v, use fine_code=18 and coarse_code=0, Casey's rec'd, updated 12/16, ++//{0x3522, 0x860C // ROWHI=3.6v, Vrst_lo for hcg_lg change from 8 to 6 for eclipse margin 9/27, HTOL updated 12/16, use fine_code=12 and coarse_code=0, Casey's rec'd ++//{0x3524, 0x0C12 // DCGHI=3.6v, TXHI=3.9v updated HTOL voltage 12/16 Casey's rec'd ++//{0x352c, 0x0012 // RSTWELLHI=3.9v using fine_code=18 and coarse_code=0 HTOL voltage updated 12/16 C. Hoekstra rec'd, ++{0x3532, 0x826C}, // updated (12/14) ++{0x3532, 0xAE6C}, // ECL settings updated (1/9 Lin) ++{0x353a, 0x9000}, // use AGND based boosters, enable continuous boost for RSTHI_WELL, TXHI_WELL (12/14) ++ ++{0x3540, 0xC63C}, // eclipse clamp updated 5/16 ++{0x3542, 0x4637}, // eclipse clamp updated 5/16 ++{0x3544, 0x3750}, // eclipse clamp updated 5/16 ++{0x3546, 0x5656}, // eclipse clamp updated 5/16 ++{0x3548, 0x5600}, // eclipse clamp updated 5/16 ++ ++{0x3566, 0xBF38}, // col_mem settings, sa_park_en ++ ++{0x30BA, 0x0112}, // Add dither after delay buffer decompander ++{0x30BA, 0x0112}, //stop read back of dtest register from analog core to remove dark row on top 5/9 ++{ } ++}; /* Rev2 Recommended Settings */ ++ ++static const struct ar0xxx_reg ar0220_rev2_REV2_Optimized_Sequencer[] = { ++{0x2512, 0x8000}, ++{0x2510, 0x0905}, ++{0x2510, 0x3350}, ++{0x2510, 0x2004}, ++{0x2510, 0x1460}, ++{0x2510, 0x1578}, ++{0x2510, 0x1360}, ++{0x2510, 0x7B24}, ++{0x2510, 0xFF24}, ++{0x2510, 0xFF24}, ++{0x2510, 0xEA24}, ++{0x2510, 0x1022}, ++{0x2510, 0x2410}, ++{0x2510, 0x155A}, ++{0x2510, 0x1342}, ++{0x2510, 0x1440}, ++{0x2510, 0x24FF}, ++{0x2510, 0x24FF}, ++{0x2510, 0x24EA}, ++{0x2510, 0x2324}, ++{0x2510, 0x647A}, ++{0x2510, 0x2404}, ++{0x2510, 0x052C}, ++{0x2510, 0x400A}, ++{0x2510, 0xFF0A}, ++{0x2510, 0x850A}, ++{0x2510, 0x0608}, ++{0x2510, 0x3851}, ++{0x2510, 0x0905}, ++{0x2510, 0x15DC}, ++{0x2510, 0x134C}, ++{0x2510, 0x0004}, ++{0x2510, 0x0801}, ++{0x2510, 0x0408}, ++{0x2510, 0x1180}, ++{0x2510, 0x1002}, ++{0x2510, 0x1016}, ++{0x2510, 0x1181}, ++{0x2510, 0x1189}, ++{0x2510, 0x1056}, ++{0x2510, 0x1210}, ++{0x2510, 0x0D09}, ++{0x2510, 0x0714}, ++{0x2510, 0x4114}, ++{0x2510, 0x4009}, ++{0x2510, 0x0815}, ++{0x2510, 0xCC13}, ++{0x2510, 0xCC15}, ++{0x2510, 0x8813}, ++{0x2510, 0x8809}, ++{0x2510, 0x1111}, ++{0x2510, 0x9909}, ++{0x2510, 0x0B11}, ++{0x2510, 0xD909}, ++{0x2510, 0x0B12}, ++{0x2510, 0x1409}, ++{0x2510, 0x0112}, ++{0x2510, 0x1010}, ++{0x2510, 0xD612}, ++{0x2510, 0x1212}, ++{0x2510, 0x1011}, ++{0x2510, 0xDD11}, ++{0x2510, 0xD910}, ++{0x2510, 0x5609}, ++{0x2510, 0x1111}, ++{0x2510, 0xDB09}, ++{0x2510, 0x1D11}, ++{0x2510, 0xFB09}, ++{0x2510, 0x0911}, ++{0x2510, 0xBB12}, ++{0x2510, 0x1A12}, ++{0x2510, 0x1010}, ++{0x2510, 0xD612}, ++{0x2510, 0x5010}, ++{0x2510, 0xF610}, ++{0x2510, 0xE609}, ++{0x2510, 0x0315}, ++{0x2510, 0xAB13}, ++{0x2510, 0xAB12}, ++{0x2510, 0x4012}, ++{0x2510, 0x6009}, ++{0x2510, 0x2315}, ++{0x2510, 0x8809}, ++{0x2510, 0x0113}, ++{0x2510, 0x880B}, ++{0x2510, 0x0906}, ++{0x2510, 0x158D}, ++{0x2510, 0x138D}, ++{0x2510, 0x090B}, ++{0x2510, 0x1066}, ++{0x2510, 0x1588}, ++{0x2510, 0x1388}, ++{0x2510, 0x0C09}, ++{0x2510, 0x0410}, ++{0x2510, 0xE612}, ++{0x2510, 0x6212}, ++{0x2510, 0x6011}, ++{0x2510, 0xBF11}, ++{0x2510, 0xFB10}, ++{0x2510, 0x6609}, ++{0x2510, 0x3B11}, ++{0x2510, 0xBB12}, ++{0x2510, 0x6312}, ++{0x2510, 0x6009}, ++{0x2510, 0x0115}, ++{0x2510, 0x5A11}, ++{0x2510, 0xB812}, ++{0x2510, 0xA012}, ++{0x2510, 0x0010}, ++{0x2510, 0x2610}, ++{0x2510, 0x0013}, ++{0x2510, 0x0211}, ++{0x2510, 0x8014}, ++{0x2510, 0x007A}, ++{0x2510, 0x0611}, ++{0x2510, 0x0005}, ++{0x2510, 0x0708}, ++{0x2510, 0x4137}, ++{0x2510, 0x502C}, ++{0x2510, 0x2CFE}, ++{0x2510, 0x112C}, ++{AR_DELAY, 300}, ++ ++{0x1008, 0x02B6}, //fine_integration_time_min ++{0x100c, 0x0452}, //fine_integration_time2_min ++{0x100e, 0x05EE}, //fine_integration_time3_min ++{0x1010, 0x011A}, //fine_integration_time4_min ++ ++{0x3230, 0x0254}, //fine_correction ++{0x3232, 0x03F0}, //fine_correction2 ++{0x3234, 0x058C}, //fine_correction3 ++{0x3236, 0x00B8}, //fine_correction4 ++{0x32e6, 0x009A}, //min_subrow ++{ } ++}; /* AR0220AT REV2 Optimized Sequencer */ ++ ++static const struct ar0xxx_reg ar0220_rev2_pll_23_4lane_12b[] = { ++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ ++/* PCLK=23Mhz/2 *44/1/12 *2= 84Mhz - TI serializers */ ++{0x3030, 44}, //PLL_MULTIPLIER ++{0x302E, 2}, //PRE_PLL_CLK_DIV ++{0x302C, 1}, //P1 divider (vt_sys_clk_div) ++{0x302A, 6}, //P2 divider (vt_pix_clk_div) ++{0x3038, 1}, //P3 divider (op_sys_clk_div) ++{0x3036, 12}, //P4 divider (op_word_clk_div) ++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 ++{ } ++}; /* PLL Setup Serial 4 lane 12-bit Output 23Mhz MCLK */ ++ ++static const struct ar0xxx_reg ar0220_rev2_pll_25_4lane_12b[] = { ++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ ++/* PCLK=25Mhz/5 *102/1/12 *2= 85Mhz - IN-CAMERA REFCLK */ ++/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */ ++{0x3030, 102}, //PLL_MULTIPLIER ++{0x302E, 5}, //PRE_PLL_CLK_DIV ++{0x302C, 1}, //P1 divider (vt_sys_clk_div) ++{0x302A, 6}, //P2 divider (vt_pix_clk_div) ++{0x3038, 1}, //P3 divider (op_sys_clk_div) ++{0x3036, 12}, //P4 divider (op_word_clk_div) ++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 ++{ } ++}; /* PLL Setup Serial 4 lane 12-bit Output 25Mhz MCLK */ ++ ++static const struct ar0xxx_reg ar0220_rev2_pll_27_4lane_12b[] = { ++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ ++/* PCLK=27Mhz/3 *56/1/12 *2= 84Mhz - IN-CAMERA REFCLK */ ++/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */ ++{0x3030, 56}, //PLL_MULTIPLIER ++{0x302E, 3}, //PRE_PLL_CLK_DIV ++{0x302C, 1}, //P1 divider (vt_sys_clk_div) ++{0x302A, 6}, //P2 divider (vt_pix_clk_div) ++{0x3038, 1}, //P3 divider (op_sys_clk_div) ++{0x3036, 12}, //P4 divider (op_word_clk_div) ++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 ++{ } ++}; /* PLL Setup Serial 4 lane 12-bit Output 27Mhz MCLK */ ++ ++static const struct ar0xxx_reg ar0220_rev2_Readout_Mode_Configuration[] = { ++{0x30A2, 1}, // x_odd_inc_ ++{0x30A6, 1}, // y_odd_inc_ ++{0x3040, 0}, // read_mode ++{ } ++}; /* Readout Mode Configuration */ ++ ++static const struct ar0xxx_reg ar0220_rev2_Full_Res_FOV[] = { ++{0x3004, AR0220_X_START}, // X_ADDR_START_ ++{0x3008, AR0220_X_END}, // X_ADDR_END_ ++{0x3002, AR0220_Y_START}, // Y_ADDR_START_ ++{0x3006, AR0220_Y_END}, // Y_ADDR_END_ ++{ } ++}; /* Full Res FOV */ ++ ++static const struct ar0xxx_reg ar0220_rev2_hdr_Timing_and_Exposure[] = { ++{0x3082, 0x8}, // operation_mode_ctrl ++{0x30BA, 0x1112}, // digital_ctrl: num_exp_max=2 ++#ifdef AR0231_EMBEDDED_LINE ++{0x3064, 0x1982}, // SMIA_TEST ++#else ++{0x3064, 0x1802}, // SMIA_TEST ++#endif ++//{0x33E0, 0xC80}, ++//{0x3180, 0x80}, ++//{0x33E4, 0x80}, ++ ++{0x306e, 9010}, // datapath_select,ime_mode,0 ++ ++{0x300A, AR0220_SENSOR_HEIGHT + 794}, // frame_length_lines_ (1742) ++{0x300C, AR0220_SENSOR_WIDTH/2 + 424}, // line_length_pck_ (1338) ++{0x3042, 0}, // extra_delay ++ ++{0x3238, 0x444}, // exposure_ratio ++{0x3012, 1000}, // coarse_integration_time_ ++{0x3014, 1526}, // fine_integration_time_ ++{0x321E, 1526}, // fine_integration_time2 ++{0x3222, 282}, // fine_integration_time3 ++{0x32EA, 0x3C0E}, ++//{0x32EC, 0x7151}, ++ ++{0x30B0, 0x800}, // enable_subrow_pair_reset ++{0x32E8, 637}, // max subrow margin for 3exp HDR ++{ } ++}; /* 3exp 36FPS Timing and Exposure */ ++ ++static const struct ar0xxx_reg ar0220_rev2_hdr_12bit_output[] = { ++{0x31D0, 1}, // companding ++{0x31AC, 0x140C}, // data_format_bits: RAW20, OUT12 ++{ } ++}; /* HDR Serial 4 lane 12 bit Output */ ++ ++static const struct ar0xxx_reg ar0220_rev2_mipi_12bit_4lane[] = { ++{0x31AE, 0x204}, // serial_format: MIPI 4 lanes ++//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C ++//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C ++//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C ++//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C ++//{0x3344, 0x0011}, // default, VC=0 ++//{0x3348, 0x0111}, // default, VC=1 ++//{0x334C, 0x0211}, // default, VC=2 ++//{0x3350, 0x0311}, // default, VC=3 ++{0x31B0, 0x46}, // frame_preamble ++{0x31B2, 0x31}, // line_preamble ++{0x31B4, 0x2144}, //MIPI_TIMING_0 update @504Mbps 12 bit, 04/17 ++{0x31B6, 0x3145}, //MIPI_TIMING_1 update @504Mbps 12 bit, 04/17 ++{0x31B8, 0x3147}, //MIPI_TIMING_2 update @504Mbps 12 bit, 04/17 ++{0x31BA, 0x0186}, //MIPI_TIMING_3 ++{0x31BC, 0x0785}, //MIPI_TIMING_4 ++{ } ++}; /* HDR MIPI 12 bit Settings */ ++ ++static const struct ar0xxx_reg ar0220_rev2_Recommended_HDR_Settings[] = { ++{ } ++}; /* Recommended HDR Settings */ ++ ++/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */ ++static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev2[] = { ++ ar0220_rev2_Reset, ++ ar0220_rev2_Recommended_Settings, ++ ar0220_rev2_REV2_Optimized_Sequencer, ++ ar0220_rev2_pll_23_4lane_12b, ++ ar0220_rev2_Readout_Mode_Configuration, ++ ar0220_rev2_Full_Res_FOV, ++ ar0220_rev2_hdr_Timing_and_Exposure, ++ ar0220_rev2_hdr_12bit_output, ++ ar0220_rev2_mipi_12bit_4lane, ++ ar0220_rev2_Recommended_HDR_Settings, ++ NULL, ++}; +diff --git a/drivers/media/i2c/soc_camera/ar0220_rev3.h b/drivers/media/i2c/soc_camera/ar0220_rev3.h +new file mode 100644 +index 0000000..6dad762 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ar0220_rev3.h +@@ -0,0 +1,218 @@ ++/* ++ * ON Semiconductor AR0220 sensor camera wizard 1848x944@30/BGGR/MIPI ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++static const struct ar0xxx_reg ar0220_rev3_Recommended_Settings[] = { ++// Set the SREG_WRITE_ALL bit to remove potential higher current during intial standby ++{0x3500, 0x0100}, //This is a self clearing bit ++{AR_DELAY, 1}, //Delay => 4100 * Extclk ++ ++{0x3092, 0x0824}, // row noise dither enabled, dither scale=0 udpated 6/30/2017 ++{0x3096, 0x227C}, // row noise adjust top update 4/27/2017 with Jan-4 timing...YL ++{0x3098, 0x227C}, // row noise adjust bot update 4/27/2017 with Jan-4 timing...YL ++{0x3750, 0x227C}, // row noise adjust top gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL ++{0x3752, 0x227C}, // row noise adjust btm gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL ++{0x351C, 0x00B3}, // vaapix load cap=11, agnd load cap=3 updated 4/27 with Jan-4 timing...YL ++ ++{0x3364, 172}, // set dual conversion gain ratio (HCG/LCG) to 5.3x (~172/32) updated 3/29 ++{0x337A, 0x0BB8}, // dblc scale factor 0.733x, updated 4/25 ++ ++// DLO settings ++{0x3110, 0x0011}, // Pre-HDR gain enable; Pixel_width_enable ++// These settings match AR0138 REV3 settings ++{0x3100, 0x4000}, // dlo control. turn on dlo noise filter. set barrier dither select to 0 to match AR0138 ++{0x3102, 0x6060}, // "better" filter settings. This is S2=96 and range=6 ++{0x3104, 0x6060}, // T3 ++{0x3106, 0x6060}, // T4 ++ ++{0x32EC, 0x72A2}, // shut_ctrl2_t3_sh_adcance=2 ++{0x350E, 0x0F14}, // adc_pedestal_dither_en=15 (from 231) to minimize RTN periodical bumps... updated 8/9/17 ++ ++// boost settings ++// Load booster settings. Early CREV4 headboards and parts will require booster settings to be manually programmed, ++// while CREV4 ES samples have part-specific booster settings programmed in OTPM. Booster settings are instored in ++// following 4 registers: 0x3520, 0x3522, 0x3524, and 0x352C. (9/22/2017 Lin) ++// Remove soft trim booster settings for CRev3-1 sensors as they are boosters trimmed. (01/14/2018 Lin) ++//PYTHON= loadBoosterSettings() ++//{0x3520, 0x1288 // RSTHI=3.9v, use fine_code=18 and coarse_code=0, Casey's rec'd, updated 12/16, ++//{0x3522, 0x860C // ROWHI=3.6v, Vrst_lo for hcg_lg change from 8 to 6 for eclipse margin 9/27, HTOL updated 12/16, use fine_code=12 and coarse_code=0, Casey's rec'd ++//{0x3524, 0x0C12 // DCGHI=3.6v, TXHI=3.9v updated HTOL voltage 12/16 Casey's rec'd ++//{0x352c, 0x0012 // RSTWELLHI=3.9v using fine_code=18 and coarse_code=0 HTOL voltage updated 12/16 C. Hoekstra rec'd, ++//{0x3532, 0x826C // updated (12/14) ++{0x3528, 0x3633}, //update vtxlo for lcg_lg to 0.3V for blue blooming issue 6/1/2018 ++{0x3532, 0xAE6C}, // ECL settings updated (1/9 Lin) ++{0x353a, 0x9000}, // use AGND based boosters, enable continuous boost for RSTHI_WELL, TXHI_WELL (12/14) ++ ++{0x3540, 0xC63C}, // eclipse clamp updated 5/16 ++{0x3542, 0x4637}, // eclipse clamp updated 5/16 ++{0x3544, 0x3750}, // eclipse clamp updated 5/16 ++{0x3546, 0x5656}, // eclipse clamp updated 5/16 ++{0x3548, 0x5600}, // eclipse clamp updated 5/16 ++ ++//{0x3566, 0xBF38}, // col_mem settings, sa_park_en ++{0x3566, 0x3F28}, // col_mem settings, sa_park_en 5/2/2019 disable READOUT_PARK_ENABLE and SA_PARK_EN ++ ++{0x30BA, 0x0112}, // Add dither after delay buffer decompander ++{0x30BA, 0x0112}, //stop read back of dtest register from analog core to remove dark row on top 5/9 ++{ } ++}; /* Rev3 Recommended Settings */ ++ ++static const struct ar0xxx_reg ar0220_rev3_REV3_Optimized_Sequencer[] = { ++{0x2512, 0x8000}, ++{0x2510, 0x0905}, ++{0x2510, 0x3350}, ++{0x2510, 0x2004}, ++{0x2510, 0x1460}, ++{0x2510, 0x1578}, ++{0x2510, 0x1360}, ++{0x2510, 0x7B24}, ++{0x2510, 0xFF24}, ++{0x2510, 0xFF24}, ++{0x2510, 0xEA24}, ++{0x2510, 0x1022}, ++{0x2510, 0x2410}, ++{0x2510, 0x155A}, ++{0x2510, 0x1342}, ++{0x2510, 0x1440}, ++{0x2510, 0x24FF}, ++{0x2510, 0x24FF}, ++{0x2510, 0x24EA}, ++{0x2510, 0x2324}, ++{0x2510, 0x647A}, ++{0x2510, 0x2404}, ++{0x2510, 0x052C}, ++{0x2510, 0x400A}, ++{0x2510, 0xFF0A}, ++{0x2510, 0x850A}, ++{0x2510, 0x0608}, ++{0x2510, 0x3851}, ++{0x2510, 0x0905}, ++{0x2510, 0x15DC}, ++{0x2510, 0x134C}, ++{0x2510, 0x0004}, ++{0x2510, 0x0801}, ++{0x2510, 0x0408}, ++{0x2510, 0x1180}, ++{0x2510, 0x1002}, ++{0x2510, 0x1016}, ++{0x2510, 0x1181}, ++{0x2510, 0x1189}, ++{0x2510, 0x1056}, ++{0x2510, 0x1210}, ++{0x2510, 0x0D09}, ++{0x2510, 0x0714}, ++{0x2510, 0x4114}, ++{0x2510, 0x4009}, ++{0x2510, 0x0815}, ++{0x2510, 0xCC13}, ++{0x2510, 0xCC15}, ++{0x2510, 0x8813}, ++{0x2510, 0x8809}, ++{0x2510, 0x1111}, ++{0x2510, 0x9909}, ++{0x2510, 0x0B11}, ++{0x2510, 0xD909}, ++{0x2510, 0x0B12}, ++{0x2510, 0x1409}, ++{0x2510, 0x0112}, ++{0x2510, 0x1010}, ++{0x2510, 0xD612}, ++{0x2510, 0x1212}, ++{0x2510, 0x1011}, ++{0x2510, 0xDD11}, ++{0x2510, 0xD910}, ++{0x2510, 0x5609}, ++{0x2510, 0x1111}, ++{0x2510, 0xDB09}, ++{0x2510, 0x1D11}, ++{0x2510, 0xFB09}, ++{0x2510, 0x0911}, ++{0x2510, 0xBB12}, ++{0x2510, 0x1A12}, ++{0x2510, 0x1010}, ++{0x2510, 0xD612}, ++{0x2510, 0x5010}, ++{0x2510, 0xF610}, ++{0x2510, 0xE609}, ++{0x2510, 0x0315}, ++{0x2510, 0xAB13}, ++{0x2510, 0xAB12}, ++{0x2510, 0x4012}, ++{0x2510, 0x6009}, ++{0x2510, 0x2315}, ++{0x2510, 0x8809}, ++{0x2510, 0x0113}, ++{0x2510, 0x880B}, ++{0x2510, 0x0906}, ++{0x2510, 0x158D}, ++{0x2510, 0x138D}, ++{0x2510, 0x090B}, ++{0x2510, 0x1066}, ++{0x2510, 0x1588}, ++{0x2510, 0x1388}, ++{0x2510, 0x0C09}, ++{0x2510, 0x0410}, ++{0x2510, 0xE612}, ++{0x2510, 0x6212}, ++{0x2510, 0x6011}, ++{0x2510, 0xBF11}, ++{0x2510, 0xFB10}, ++{0x2510, 0x6609}, ++{0x2510, 0x3B11}, ++{0x2510, 0xBB12}, ++{0x2510, 0x6312}, ++{0x2510, 0x6009}, ++{0x2510, 0x0115}, ++{0x2510, 0x5A11}, ++{0x2510, 0xB812}, ++{0x2510, 0xA012}, ++{0x2510, 0x0010}, ++{0x2510, 0x2610}, ++{0x2510, 0x0013}, ++{0x2510, 0x0211}, ++{0x2510, 0x8014}, ++{0x2510, 0x007A}, ++{0x2510, 0x0611}, ++{0x2510, 0x0005}, ++{0x2510, 0x0708}, ++{0x2510, 0x4137}, ++{0x2510, 0x502C}, ++{0x2510, 0x2CFE}, ++{0x2510, 0x112C}, ++{AR_DELAY, 300}, ++ ++{0x1008, 0x02B6}, //fine_integration_time_min ++{0x100c, 0x0452}, //fine_integration_time2_min ++{0x100e, 0x05EE}, //fine_integration_time3_min ++{0x1010, 0x011A}, //fine_integration_time4_min ++ ++{0x3230, 0x0254}, //fine_correction ++{0x3232, 0x03F0}, //fine_correction2 ++{0x3234, 0x058C}, //fine_correction3 ++{0x3236, 0x00B8}, //fine_correction4 ++//{0x32e6, 0x009A}, //min_subrow ++{0x32e6, 0x00BC}, //min_subrow 188 2/6/2018 Lin ++{ } ++}; /* AR0220AT REV3 Optimized Sequencer */ ++ ++/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */ ++static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev3[] = { ++ ar0220_rev2_Reset, ++ ar0220_rev3_Recommended_Settings, ++ ar0220_rev3_REV3_Optimized_Sequencer, ++ ar0220_rev2_pll_23_4lane_12b, ++ ar0220_rev2_Readout_Mode_Configuration, ++ ar0220_rev2_Full_Res_FOV, ++ ar0220_rev2_hdr_Timing_and_Exposure, ++ ar0220_rev2_hdr_12bit_output, ++ ar0220_rev2_mipi_12bit_4lane, ++ ar0220_rev2_Recommended_HDR_Settings, ++ NULL, ++}; +diff --git a/drivers/media/i2c/soc_camera/ar0220_rev4.h b/drivers/media/i2c/soc_camera/ar0220_rev4.h +index 55923a3..14dfe13 100644 +--- a/drivers/media/i2c/soc_camera/ar0220_rev4.h ++++ b/drivers/media/i2c/soc_camera/ar0220_rev4.h +@@ -9,362 +9,16 @@ + * option) any later version. + */ + +-static const struct ar0xxx_reg ar0220_rev4_Reset[] = { +-{0x301A, 0x0018}, // Stream off and setup MIPI +-{AR_DELAY, 200}, +-{0x3070, 0x0000}, // 1: Solid color test pattern, +- // 2: Full color bar test pattern, +- // 3: Fade to grey color bar test pattern, +- //256: Walking 1 test pattern (12 bit) +-{0x3072, 0x0123}, // R +-{0x3074, 0x0456}, // G(GR row) +-{0x3076, 0x0abc}, // B +-{0x3078, 0x0def}, // G(GB row) +-#ifdef AR0220_DISPLAY_PATTERN_FIXED +-{0x3070, 0x0001}, +-#endif +-#ifdef AR0220_DISPLAY_PATTERN_COLOR_BAR +-{0x3070, 0x0002}, +-#endif +-{AR_DELAY, 100}, +-{ } +-}; /* Reset */ +- +-static const struct ar0xxx_reg ar0220_rev4_Recommended_Settings[] = { +-// Set the SREG_WRITE_ALL bit to remove potential higher current during intial standby +-{0x3500, 0x0100}, //This is a self clearing bit +-{AR_DELAY, 1}, //Delay => 4100 * Extclk +- +-{0x3092, 0x0824}, // row noise dither enabled, dither scale=0 udpated 6/30/2017 +-{0x3096, 0x227C}, // row noise adjust top update 4/27/2017 with Jan-4 timing...YL +-{0x3098, 0x227C}, // row noise adjust bot update 4/27/2017 with Jan-4 timing...YL +-{0x3750, 0x227C}, // row noise adjust top gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL +-{0x3752, 0x227C}, // row noise adjust btm gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL +-{0x351C, 0x00B3}, // vaapix load cap=11, agnd load cap=3 updated 4/27 with Jan-4 timing...YL +- +-{0x3364, 172}, // set dual conversion gain ratio (HCG/LCG) to 5.3x (~172/32) updated 3/29 +-{0x337A, 0x0BB8}, // dblc scale factor 0.733x, updated 4/25 +- +-// DLO settings +-{0x3110, 0x0011}, // Pre-HDR gain enable; Pixel_width_enable +-// These settings match AR0138 REV3 settings +-{0x3100, 0x4000}, // dlo control. turn on dlo noise filter. set barrier dither select to 0 to match AR0138 +-{0x3102, 0x6060}, // "better" filter settings. This is S2=96 and range=6 +-{0x3104, 0x6060}, // T3 +-{0x3106, 0x6060}, // T4 +- +-{0x32EC, 0x72A2}, // shut_ctrl2_t3_sh_adcance=2 +-{0x350E, 0x0F14}, // adc_pedestal_dither_en=15 (from 231) to minimize RTN periodical bumps... updated 8/9/17 +- +-// boost settings +-// Load booster settings. Early CREV4 headboards and parts will require booster settings to be manually programmed, +-// while CREV4 ES samples have part-specific booster settings programmed in OTPM. Booster settings are instored in +-// following 4 registers: 0x3520, 0x3522, 0x3524, and 0x352C. (9/22/2017 Lin) +-// Remove soft trim booster settings for CRev3-1 sensors as they are boosters trimmed. (01/14/2018 Lin) +-//PYTHON= loadBoosterSettings() +-//{0x3520, 0x1288 // RSTHI=3.9v, use fine_code=18 and coarse_code=0, Casey's rec'd, updated 12/16, +-//{0x3522, 0x860C // ROWHI=3.6v, Vrst_lo for hcg_lg change from 8 to 6 for eclipse margin 9/27, HTOL updated 12/16, use fine_code=12 and coarse_code=0, Casey's rec'd +-//{0x3524, 0x0C12 // DCGHI=3.6v, TXHI=3.9v updated HTOL voltage 12/16 Casey's rec'd +-//{0x352c, 0x0012 // RSTWELLHI=3.9v using fine_code=18 and coarse_code=0 HTOL voltage updated 12/16 C. Hoekstra rec'd, +-//{0x3532, 0x826C // updated (12/14) +-{0x3528, 0x3633}, //update vtxlo for lcg_lg to 0.3V for blue blooming issue 6/1/2018 +-{0x3532, 0xAE6C}, // ECL settings updated (1/9 Lin) +-{0x353a, 0x9000}, // use AGND based boosters, enable continuous boost for RSTHI_WELL, TXHI_WELL (12/14) +- +-{0x3540, 0xC63C}, // eclipse clamp updated 5/16 +-{0x3542, 0x4637}, // eclipse clamp updated 5/16 +-{0x3544, 0x3750}, // eclipse clamp updated 5/16 +-{0x3546, 0x5656}, // eclipse clamp updated 5/16 +-{0x3548, 0x5600}, // eclipse clamp updated 5/16 +- +-//{0x3566, 0xBF38}, // col_mem settings, sa_park_en +-{0x3566, 0x3F28}, // col_mem settings, sa_park_en 5/2/2019 disable READOUT_PARK_ENABLE and SA_PARK_EN +- +-{0x30BA, 0x0112}, // Add dither after delay buffer decompander +-{0x30BA, 0x0112}, //stop read back of dtest register from analog core to remove dark row on top 5/9 +-{ } +-}; /* Rev3 Recommended Settings */ +- +-static const struct ar0xxx_reg ar0220_rev4_REV3_Optimized_Sequencer[] = { +-{0x2512, 0x8000}, +-{0x2510, 0x0905}, +-{0x2510, 0x3350}, +-{0x2510, 0x2004}, +-{0x2510, 0x1460}, +-{0x2510, 0x1578}, +-{0x2510, 0x1360}, +-{0x2510, 0x7B24}, +-{0x2510, 0xFF24}, +-{0x2510, 0xFF24}, +-{0x2510, 0xEA24}, +-{0x2510, 0x1022}, +-{0x2510, 0x2410}, +-{0x2510, 0x155A}, +-{0x2510, 0x1342}, +-{0x2510, 0x1440}, +-{0x2510, 0x24FF}, +-{0x2510, 0x24FF}, +-{0x2510, 0x24EA}, +-{0x2510, 0x2324}, +-{0x2510, 0x647A}, +-{0x2510, 0x2404}, +-{0x2510, 0x052C}, +-{0x2510, 0x400A}, +-{0x2510, 0xFF0A}, +-{0x2510, 0x850A}, +-{0x2510, 0x0608}, +-{0x2510, 0x3851}, +-{0x2510, 0x0905}, +-{0x2510, 0x15DC}, +-{0x2510, 0x134C}, +-{0x2510, 0x0004}, +-{0x2510, 0x0801}, +-{0x2510, 0x0408}, +-{0x2510, 0x1180}, +-{0x2510, 0x1002}, +-{0x2510, 0x1016}, +-{0x2510, 0x1181}, +-{0x2510, 0x1189}, +-{0x2510, 0x1056}, +-{0x2510, 0x1210}, +-{0x2510, 0x0D09}, +-{0x2510, 0x0714}, +-{0x2510, 0x4114}, +-{0x2510, 0x4009}, +-{0x2510, 0x0815}, +-{0x2510, 0xCC13}, +-{0x2510, 0xCC15}, +-{0x2510, 0x8813}, +-{0x2510, 0x8809}, +-{0x2510, 0x1111}, +-{0x2510, 0x9909}, +-{0x2510, 0x0B11}, +-{0x2510, 0xD909}, +-{0x2510, 0x0B12}, +-{0x2510, 0x1409}, +-{0x2510, 0x0112}, +-{0x2510, 0x1010}, +-{0x2510, 0xD612}, +-{0x2510, 0x1212}, +-{0x2510, 0x1011}, +-{0x2510, 0xDD11}, +-{0x2510, 0xD910}, +-{0x2510, 0x5609}, +-{0x2510, 0x1111}, +-{0x2510, 0xDB09}, +-{0x2510, 0x1D11}, +-{0x2510, 0xFB09}, +-{0x2510, 0x0911}, +-{0x2510, 0xBB12}, +-{0x2510, 0x1A12}, +-{0x2510, 0x1010}, +-{0x2510, 0xD612}, +-{0x2510, 0x5010}, +-{0x2510, 0xF610}, +-{0x2510, 0xE609}, +-{0x2510, 0x0315}, +-{0x2510, 0xAB13}, +-{0x2510, 0xAB12}, +-{0x2510, 0x4012}, +-{0x2510, 0x6009}, +-{0x2510, 0x2315}, +-{0x2510, 0x8809}, +-{0x2510, 0x0113}, +-{0x2510, 0x880B}, +-{0x2510, 0x0906}, +-{0x2510, 0x158D}, +-{0x2510, 0x138D}, +-{0x2510, 0x090B}, +-{0x2510, 0x1066}, +-{0x2510, 0x1588}, +-{0x2510, 0x1388}, +-{0x2510, 0x0C09}, +-{0x2510, 0x0410}, +-{0x2510, 0xE612}, +-{0x2510, 0x6212}, +-{0x2510, 0x6011}, +-{0x2510, 0xBF11}, +-{0x2510, 0xFB10}, +-{0x2510, 0x6609}, +-{0x2510, 0x3B11}, +-{0x2510, 0xBB12}, +-{0x2510, 0x6312}, +-{0x2510, 0x6009}, +-{0x2510, 0x0115}, +-{0x2510, 0x5A11}, +-{0x2510, 0xB812}, +-{0x2510, 0xA012}, +-{0x2510, 0x0010}, +-{0x2510, 0x2610}, +-{0x2510, 0x0013}, +-{0x2510, 0x0211}, +-{0x2510, 0x8014}, +-{0x2510, 0x007A}, +-{0x2510, 0x0611}, +-{0x2510, 0x0005}, +-{0x2510, 0x0708}, +-{0x2510, 0x4137}, +-{0x2510, 0x502C}, +-{0x2510, 0x2CFE}, +-{0x2510, 0x112C}, +-{AR_DELAY, 300}, +- +-{0x1008, 0x02B6}, //fine_integration_time_min +-{0x100c, 0x0452}, //fine_integration_time2_min +-{0x100e, 0x05EE}, //fine_integration_time3_min +-{0x1010, 0x011A}, //fine_integration_time4_min +- +-{0x3230, 0x0254}, //fine_correction +-{0x3232, 0x03F0}, //fine_correction2 +-{0x3234, 0x058C}, //fine_correction3 +-{0x3236, 0x00B8}, //fine_correction4 +-//{0x32e6, 0x009A}, //min_subrow +-{0x32e6, 0x00BC}, //min_subrow 188 2/6/2018 Lin +-{ } +-}; /* AR0220AT REV3 Optimized Sequencer */ +- +-static const struct ar0xxx_reg ar0220_rev4_pll_23_4lane_12b[] = { +-/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ +-/* PCLK=23Mhz/2 *44/1/12 *2= 84Mhz - TI serializers */ +-{0x3030, 44}, //PLL_MULTIPLIER +-{0x302E, 2}, //PRE_PLL_CLK_DIV +-{0x302C, 1}, //P1 divider (vt_sys_clk_div) +-{0x302A, 6}, //P2 divider (vt_pix_clk_div) +-{0x3038, 1}, //P3 divider (op_sys_clk_div) +-{0x3036, 12}, //P4 divider (op_word_clk_div) +-{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 +-{ } +-}; /* PLL Setup Serial 4 lane 12-bit Output 23Mhz MCLK */ +- +-static const struct ar0xxx_reg ar0220_rev4_pll_25_4lane_12b[] = { +-/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ +-/* PCLK=25Mhz/5 *102/1/12 *2= 85Mhz - IN-CAMERA REFCLK */ +-/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */ +-{0x3030, 102}, //PLL_MULTIPLIER +-{0x302E, 5}, //PRE_PLL_CLK_DIV +-{0x302C, 1}, //P1 divider (vt_sys_clk_div) +-{0x302A, 6}, //P2 divider (vt_pix_clk_div) +-{0x3038, 1}, //P3 divider (op_sys_clk_div) +-{0x3036, 12}, //P4 divider (op_word_clk_div) +-{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 +-{ } +-}; /* PLL Setup Serial 4 lane 12-bit Output 25Mhz MCLK */ +- +-static const struct ar0xxx_reg ar0220_rev4_pll_27_4lane_12b[] = { +-/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ +-/* PCLK=27Mhz/3 *56/1/12 *2= 84Mhz - IN-CAMERA REFCLK */ +-/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */ +-{0x3030, 56}, //PLL_MULTIPLIER +-{0x302E, 3}, //PRE_PLL_CLK_DIV +-{0x302C, 1}, //P1 divider (vt_sys_clk_div) +-{0x302A, 6}, //P2 divider (vt_pix_clk_div) +-{0x3038, 1}, //P3 divider (op_sys_clk_div) +-{0x3036, 12}, //P4 divider (op_word_clk_div) +-{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 +-{ } +-}; /* PLL Setup Serial 4 lane 12-bit Output 27Mhz MCLK */ +- +-static const struct ar0xxx_reg ar0220_rev4_Readout_Mode_Configuration[] = { +-{0x30A2, 1}, // x_odd_inc_ +-{0x30A6, 1}, // y_odd_inc_ +-{0x3040, 0}, // read_mode +-{ } +-}; /* Readout Mode Configuration */ +- +-static const struct ar0xxx_reg ar0220_rev4_Full_Res_FOV[] = { +-{0x3004, AR0220_X_START}, // X_ADDR_START_ +-{0x3008, AR0220_X_END}, // X_ADDR_END_ +-{0x3002, AR0220_Y_START}, // Y_ADDR_START_ +-{0x3006, AR0220_Y_END}, // Y_ADDR_END_ +-{ } +-}; /* Full Res FOV */ +- +-static const struct ar0xxx_reg ar0220_rev4_hdr_Timing_and_Exposure[] = { +-{0x3082, 0x8}, // operation_mode_ctrl +-{0x30BA, 0x1112}, // digital_ctrl: num_exp_max=2 +-#ifdef AR0231_EMBEDDED_LINE +-{0x3064, 0x1982}, // SMIA_TEST +-#else +-{0x3064, 0x1802}, // SMIA_TEST +-#endif +-//{0x33E0, 0xC80}, +-//{0x3180, 0x80}, +-//{0x33E4, 0x80}, +- +-{0x306e, 9010}, // datapath_select,ime_mode,0 +- +-{0x300A, AR0220_SENSOR_HEIGHT + 794}, // frame_length_lines_ (1742) +-{0x300C, AR0220_SENSOR_WIDTH/2 + 424}, // line_length_pck_ (1338) +-{0x3042, 0}, // extra_delay +- +-{0x3238, 0x444}, // exposure_ratio +-{0x3012, 1000}, // coarse_integration_time_ +-{0x3014, 1526}, // fine_integration_time_ +-{0x321E, 1526}, // fine_integration_time2 +-{0x3222, 282}, // fine_integration_time3 +-{0x32EA, 0x3C0E}, +-//{0x32EC, 0x7151}, +- +-{0x30B0, 0x800}, // enable_subrow_pair_reset +-{0x32E8, 637}, // max subrow margin for 3exp HDR +-{ } +-}; /* 3exp 36FPS Timing and Exposure */ +- +-static const struct ar0xxx_reg ar0220_rev4_hdr_12bit_output[] = { +-{0x31D0, 1}, // companding +-{0x31AC, 0x140C}, // data_format_bits: RAW20, OUT12 +-{ } +-}; /* HDR Serial 4 lane 12 bit Output */ +- +-static const struct ar0xxx_reg ar0220_rev4_mipi_12bit_4lane[] = { +-{0x31AE, 0x204}, // serial_format: MIPI 4 lanes +-//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x3344, 0x0011}, // default, VC=0 +-//{0x3348, 0x0111}, // default, VC=1 +-//{0x334C, 0x0211}, // default, VC=2 +-//{0x3350, 0x0311}, // default, VC=3 +-{0x31B0, 0x46}, // frame_preamble +-{0x31B2, 0x31}, // line_preamble +-{0x31B4, 0x2144}, //MIPI_TIMING_0 update @504Mbps 12 bit, 04/17 +-{0x31B6, 0x3145}, //MIPI_TIMING_1 update @504Mbps 12 bit, 04/17 +-{0x31B8, 0x3147}, //MIPI_TIMING_2 update @504Mbps 12 bit, 04/17 +-{0x31BA, 0x0186}, //MIPI_TIMING_3 +-{0x31BC, 0x0785}, //MIPI_TIMING_4 +-{ } +-}; /* HDR MIPI 12 bit Settings */ +- +-static const struct ar0xxx_reg ar0220_rev4_Recommended_HDR_Settings[] = { +-{ } +-}; /* Recommended HDR Settings */ +- + /* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */ + static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev4[] = { +- ar0220_rev4_Reset, +- ar0220_rev4_Recommended_Settings, +- ar0220_rev4_pll_23_4lane_12b, +- ar0220_rev4_Readout_Mode_Configuration, +- ar0220_rev4_Full_Res_FOV, +- ar0220_rev4_hdr_Timing_and_Exposure, +- ar0220_rev4_hdr_12bit_output, +- ar0220_rev4_mipi_12bit_4lane, +- ar0220_rev4_Recommended_HDR_Settings, +- NULL, +-}; +- +-/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */ +-static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev3[] = { +- ar0220_rev4_Reset, +- ar0220_rev4_Recommended_Settings, +- ar0220_rev4_REV3_Optimized_Sequencer, +- ar0220_rev4_pll_23_4lane_12b, +- ar0220_rev4_Readout_Mode_Configuration, +- ar0220_rev4_Full_Res_FOV, +- ar0220_rev4_hdr_Timing_and_Exposure, +- ar0220_rev4_hdr_12bit_output, +- ar0220_rev4_mipi_12bit_4lane, +- ar0220_rev4_Recommended_HDR_Settings, ++ ar0220_rev2_Reset, ++ ar0220_rev3_Recommended_Settings, ++ ar0220_rev2_pll_23_4lane_12b, ++ ar0220_rev2_Readout_Mode_Configuration, ++ ar0220_rev2_Full_Res_FOV, ++ ar0220_rev2_hdr_Timing_and_Exposure, ++ ar0220_rev2_hdr_12bit_output, ++ ar0220_rev2_mipi_12bit_4lane, ++ ar0220_rev2_Recommended_HDR_Settings, + NULL, + }; +diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c +index 500fa75..312b9fe 100644 +--- a/drivers/media/i2c/soc_camera/ar0233.c ++++ b/drivers/media/i2c/soc_camera/ar0233.c +@@ -463,16 +463,23 @@ static int ar0233_initialize(struct i2c_client *client) + AR_X_END = AR0220_X_END; + AR_Y_END = AR0220_Y_END; + ++ if (extclk == 25) { ++ ar0220_regs_hdr_mipi_12bit_36fps_rev2[3] = ar0220_rev2_pll_25_4lane_12b; ++ ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev2_pll_25_4lane_12b; ++ ar0220_regs_hdr_mipi_12bit_36fps_rev4[2] = ar0220_rev2_pll_25_4lane_12b; ++ } ++ if (extclk == 27) { ++ ar0220_regs_hdr_mipi_12bit_36fps_rev2[3] = ar0220_rev2_pll_27_4lane_12b; ++ ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev2_pll_27_4lane_12b; ++ ar0220_regs_hdr_mipi_12bit_36fps_rev4[2] = ar0220_rev2_pll_27_4lane_12b; ++ } ++ + switch (rev & 0xf) { + case 0x1: + case 0x2: ++ ar0233_set_regs(client, ar0220_regs_hdr_mipi_12bit_36fps_rev2); ++ break; + case 0x3: +- if (extclk == 25) { +- ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev4_pll_25_4lane_12b; +- } +- if (extclk == 27) { +- ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev4_pll_27_4lane_12b; +- } + ar0233_set_regs(client, ar0220_regs_hdr_mipi_12bit_36fps_rev3); + break; + case 0x4: +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0434-media-i2c-max9286-parse-crossbard-from-cmdline.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0434-media-i2c-max9286-parse-crossbard-from-cmdline.patch new file mode 100644 index 00000000..2bd283b3 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0434-media-i2c-max9286-parse-crossbard-from-cmdline.patch @@ -0,0 +1,154 @@ +From 164a97c4370a29ee27145c5d1c44fe03ec2ce7b1 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 20 Nov 2019 16:41:12 +0300 +Subject: [PATCH] media: i2c: max9286: parse crossbard from cmdline + +This allows to change crossbar by command line parameter + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/max9286.c | 93 +++++++++++++++++++--------------- + 1 file changed, 51 insertions(+), 42 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c +index 3184ff1..b185566 100644 +--- a/drivers/media/i2c/soc_camera/max9286.c ++++ b/drivers/media/i2c/soc_camera/max9286.c +@@ -56,6 +56,7 @@ struct max9286_priv { + int dbl; + int dt; + int hsgen; ++ char cb[16]; + int hts; + int vts; + int hts_delay; +@@ -140,6 +141,10 @@ static int switchin = 0; + module_param(switchin, int, 0644); + MODULE_PARM_DESC(switchin, " COAX SWITCH IN+ and IN- (default: 0 - not switched)"); + ++static long crossbar = 0xba9876543210; ++module_param(crossbar, long, 0644); ++MODULE_PARM_DESC(crossbar, " Crossbar setup (default: ba9876543210 - reversed)"); ++ + enum { + RGB888_DT = 0, + RGB565_DT, +@@ -421,54 +426,53 @@ static void max9286_gmsl_link_setup(struct i2c_client *client, int idx) + switch (priv->dt) { + case YUV8_DT: + /* setup crossbar for YUV8/RAW8: reverse DVP bus */ +- reg8_write(client, 0x20, 7); +- reg8_write(client, 0x21, 6); +- reg8_write(client, 0x22, 5); +- reg8_write(client, 0x23, 4); +- reg8_write(client, 0x24, 3); +- reg8_write(client, 0x25, 2); +- reg8_write(client, 0x26, 1); +- reg8_write(client, 0x27, 0); ++ reg8_write(client, 0x20, priv->cb[7]); ++ reg8_write(client, 0x21, priv->cb[6]); ++ reg8_write(client, 0x22, priv->cb[5]); ++ reg8_write(client, 0x23, priv->cb[4]); ++ reg8_write(client, 0x24, priv->cb[3]); ++ reg8_write(client, 0x25, priv->cb[2]); ++ reg8_write(client, 0x26, priv->cb[1]); ++ reg8_write(client, 0x27, priv->cb[0]); + + /* this is second byte if DBL=1 */ +- reg8_write(client, 0x30, 23); +- reg8_write(client, 0x31, 22); +- reg8_write(client, 0x32, 21); +- reg8_write(client, 0x33, 20); +- reg8_write(client, 0x34, 19); +- reg8_write(client, 0x35, 18); +- reg8_write(client, 0x36, 17); +- reg8_write(client, 0x37, 16); +- ++ reg8_write(client, 0x30, priv->cb[7] + 16); ++ reg8_write(client, 0x31, priv->cb[6] + 16); ++ reg8_write(client, 0x32, priv->cb[5] + 16); ++ reg8_write(client, 0x33, priv->cb[4] + 16); ++ reg8_write(client, 0x34, priv->cb[3] + 16); ++ reg8_write(client, 0x35, priv->cb[2] + 16); ++ reg8_write(client, 0x36, priv->cb[1] + 16); ++ reg8_write(client, 0x37, priv->cb[0] + 16); + break; + case RAW12_DT: + /* setup crossbar for RAW12: reverse DVP bus */ +- reg8_write(client, 0x20, 11); +- reg8_write(client, 0x21, 10); +- reg8_write(client, 0x22, 9); +- reg8_write(client, 0x23, 8); +- reg8_write(client, 0x24, 7); +- reg8_write(client, 0x25, 6); +- reg8_write(client, 0x26, 5); +- reg8_write(client, 0x27, 4); +- reg8_write(client, 0x28, 3); +- reg8_write(client, 0x29, 2); +- reg8_write(client, 0x2a, 1); +- reg8_write(client, 0x2b, 0); ++ reg8_write(client, 0x20, priv->cb[11]); ++ reg8_write(client, 0x21, priv->cb[10]); ++ reg8_write(client, 0x22, priv->cb[9]); ++ reg8_write(client, 0x23, priv->cb[8]); ++ reg8_write(client, 0x24, priv->cb[7]); ++ reg8_write(client, 0x25, priv->cb[6]); ++ reg8_write(client, 0x26, priv->cb[5]); ++ reg8_write(client, 0x27, priv->cb[4]); ++ reg8_write(client, 0x28, priv->cb[3]); ++ reg8_write(client, 0x29, priv->cb[2]); ++ reg8_write(client, 0x2a, priv->cb[1]); ++ reg8_write(client, 0x2b, priv->cb[0]); + + /* this is second byte if DBL=1 */ +- reg8_write(client, 0x30, 27); +- reg8_write(client, 0x31, 26); +- reg8_write(client, 0x32, 25); +- reg8_write(client, 0x33, 24); +- reg8_write(client, 0x34, 23); +- reg8_write(client, 0x35, 22); +- reg8_write(client, 0x36, 21); +- reg8_write(client, 0x37, 20); +- reg8_write(client, 0x38, 19); +- reg8_write(client, 0x39, 18); +- reg8_write(client, 0x3a, 17); +- reg8_write(client, 0x3b, 16); ++ reg8_write(client, 0x30, priv->cb[11] + 16); ++ reg8_write(client, 0x31, priv->cb[10] + 16); ++ reg8_write(client, 0x32, priv->cb[9] + 16); ++ reg8_write(client, 0x33, priv->cb[8] + 16); ++ reg8_write(client, 0x34, priv->cb[7] + 16); ++ reg8_write(client, 0x35, priv->cb[6] + 16); ++ reg8_write(client, 0x36, priv->cb[5] + 16); ++ reg8_write(client, 0x37, priv->cb[4] + 16); ++ reg8_write(client, 0x38, priv->cb[3] + 16); ++ reg8_write(client, 0x39, priv->cb[2] + 16); ++ reg8_write(client, 0x3a, priv->cb[1] + 16); ++ reg8_write(client, 0x3b, priv->cb[0] + 16); + + if (!priv->bws && priv->dbl) + dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n"); +@@ -733,7 +737,6 @@ static int max9286_parse_dt(struct i2c_client *client) + if (of_property_read_u32(np, "maxim,switchin", &priv->switchin)) + priv->switchin = 0; + +- + /* module params override dts */ + if (him) + priv->him = him; +@@ -766,6 +769,12 @@ static int max9286_parse_dt(struct i2c_client *client) + if (switchin) + priv->switchin = switchin; + ++ /* parse crossbar setup */ ++ for (i = 0; i < 16; i++) { ++ priv->cb[i] = crossbar % 16; ++ crossbar /= 16; ++ } ++ + for (i = 0; i < priv->links; i++) { + endpoint = of_graph_get_next_endpoint(np, endpoint); + if (!endpoint) +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0435-clk-renesas-r8a7795-cpg-mssr-Add-RPC-clocks.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0435-clk-renesas-r8a7795-cpg-mssr-Add-RPC-clocks.patch new file mode 100644 index 00000000..d797cb9f --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0435-clk-renesas-r8a7795-cpg-mssr-Add-RPC-clocks.patch @@ -0,0 +1,51 @@ +From a2f64f8aadc505509045f2bc5da0be93e302b244 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 00:58:51 +0300 +Subject: [PATCH 01/12] clk: renesas: r8a7795-cpg-mssr: Add RPC clocks + +This adds RPC clock support to the R8A7795 CPG MSSR driver. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/clk/renesas/r8a7795-cpg-mssr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c +index bd5a73f..f20d47d 100644 +--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c ++++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c +@@ -47,6 +47,7 @@ enum clk_ids { + CLK_S3, + CLK_SDSRC, + CLK_SSPSRC, ++ CLK_RPCSRC, + CLK_RINT, + + /* Module Clocks */ +@@ -73,9 +74,15 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { + DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), ++ DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1), + + DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), + ++ DEF_BASE("rpc", R8A7795_CLK_RPC, CLK_TYPE_GEN3_RPC, ++ CLK_RPCSRC), ++ DEF_BASE("rpcd2", R8A7795_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, ++ R8A7795_CLK_RPC), ++ + /* Core Clock Outputs */ + DEF_GEN3_Z("z", R8A7795_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2), + DEF_GEN3_Z("z2", R8A7795_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2, 2), +@@ -245,6 +252,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { + DEF_MOD("can-fd", 914, R8A7795_CLK_S3D2), + DEF_MOD("can-if1", 915, R8A7795_CLK_S3D4), + DEF_MOD("can-if0", 916, R8A7795_CLK_S3D4), ++ DEF_MOD("rpc-if", 917, R8A7795_CLK_RPCD2), + DEF_MOD("i2c6", 918, R8A7795_CLK_S0D6), + DEF_MOD("i2c5", 919, R8A7795_CLK_S0D6), + DEF_MOD("adg", 922, R8A7795_CLK_S0D1), +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0436-clk-renesas-r8a7796-cpg-mssr-Add-RPC-clocks.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0436-clk-renesas-r8a7796-cpg-mssr-Add-RPC-clocks.patch new file mode 100644 index 00000000..d65360f8 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0436-clk-renesas-r8a7796-cpg-mssr-Add-RPC-clocks.patch @@ -0,0 +1,51 @@ +From ec658a740c059ebc224dcdd3da1461faa2ce71e9 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 01:00:14 +0300 +Subject: [PATCH 02/12] clk: renesas: r8a7796-cpg-mssr: Add RPC clocks + +This adds RPC clock support to the R8A7796 CPG MSSR driver. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/clk/renesas/r8a7796-cpg-mssr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c +index f4f1350..069a53a 100644 +--- a/drivers/clk/renesas/r8a7796-cpg-mssr.c ++++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c +@@ -48,6 +48,7 @@ enum clk_ids { + CLK_S3, + CLK_SDSRC, + CLK_SSPSRC, ++ CLK_RPCSRC, + CLK_RINT, + + /* Module Clocks */ +@@ -74,9 +75,15 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { + DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), ++ DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1), + + DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), + ++ DEF_BASE("rpc", R8A7796_CLK_RPC, CLK_TYPE_GEN3_RPC, ++ CLK_RPCSRC), ++ DEF_BASE("rpcd2", R8A7796_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, ++ R8A7796_CLK_RPC), ++ + /* Core Clock Outputs */ + DEF_GEN3_Z("z", R8A7796_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2), + DEF_GEN3_Z("z2", R8A7796_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2, 2), +@@ -218,6 +225,7 @@ static struct mssr_mod_clk r8a7796_mod_clks[] __initdata = { + DEF_MOD("can-fd", 914, R8A7796_CLK_S3D2), + DEF_MOD("can-if1", 915, R8A7796_CLK_S3D4), + DEF_MOD("can-if0", 916, R8A7796_CLK_S3D4), ++ DEF_MOD("rpc-if", 917, R8A7796_CLK_RPCD2), + DEF_MOD("i2c6", 918, R8A7796_CLK_S0D6), + DEF_MOD("i2c5", 919, R8A7796_CLK_S0D6), + DEF_MOD("adg", 922, R8A7796_CLK_S0D1), +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0437-clk-renesas-r8a77965-cpg-mssr-Add-RPC-clocks.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0437-clk-renesas-r8a77965-cpg-mssr-Add-RPC-clocks.patch new file mode 100644 index 00000000..c51385cc --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0437-clk-renesas-r8a77965-cpg-mssr-Add-RPC-clocks.patch @@ -0,0 +1,51 @@ +From c76e22071bc721ccd05a7e1acbe9a0e4ea078385 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 01:00:35 +0300 +Subject: [PATCH 03/12] clk: renesas: r8a77965-cpg-mssr: Add RPC clocks + +This adds RPC clock support to the R8A77965 CPG MSSR driver. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/clk/renesas/r8a77965-cpg-mssr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c +index 3d4fe53..dbcd320 100644 +--- a/drivers/clk/renesas/r8a77965-cpg-mssr.c ++++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c +@@ -43,6 +43,7 @@ enum clk_ids { + CLK_S3, + CLK_SDSRC, + CLK_SSPSRC, ++ CLK_RPCSRC, + CLK_RINT, + + /* Module Clocks */ +@@ -68,9 +69,15 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = { + DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), ++ DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1), + + DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), + ++ DEF_BASE("rpc", R8A77965_CLK_RPC, CLK_TYPE_GEN3_RPC, ++ CLK_RPCSRC), ++ DEF_BASE("rpcd2", R8A77965_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, ++ R8A77965_CLK_RPC), ++ + /* Core Clock Outputs */ + DEF_GEN3_Z("z", R8A77965_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2), + DEF_GEN3_Z("zg", R8A77965_CLK_ZG, CLK_TYPE_GEN3_ZG, CLK_PLL4, 4), +@@ -215,6 +222,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { + DEF_MOD("can-fd", 914, R8A77965_CLK_S3D2), + DEF_MOD("can-if1", 915, R8A77965_CLK_S3D4), + DEF_MOD("can-if0", 916, R8A77965_CLK_S3D4), ++ DEF_MOD("rpc-if", 917, R8A77965_CLK_RPCD2), + DEF_MOD("i2c6", 918, R8A77965_CLK_S0D6), + DEF_MOD("i2c5", 919, R8A77965_CLK_S0D6), + DEF_MOD("adg", 922, R8A77965_CLK_S0D1), +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0438-clk-renesas-rcar-gen3-cpg-Allow-to-set-RPCD2-clock-p.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0438-clk-renesas-rcar-gen3-cpg-Allow-to-set-RPCD2-clock-p.patch new file mode 100644 index 00000000..dcf9de27 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0438-clk-renesas-rcar-gen3-cpg-Allow-to-set-RPCD2-clock-p.patch @@ -0,0 +1,30 @@ +From 08560a298e3528a510e37f02553d4096445bfc3b Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 02:28:48 +0300 +Subject: [PATCH 04/12] clk: renesas: rcar-gen3-cpg: Allow to set RPCD2 clock + parent's rate + +This makes RPC clocks adjustable by allowing +the RPCD2 clock parent's rate changes. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/clk/renesas/rcar-gen3-cpg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c +index 5993dbd..9333d34 100644 +--- a/drivers/clk/renesas/rcar-gen3-cpg.c ++++ b/drivers/clk/renesas/rcar-gen3-cpg.c +@@ -814,7 +814,7 @@ static struct clk * __init cpg_rpcd2_clk_register(const char *name, + + clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, + &rpcd2->fixed.hw, &clk_fixed_factor_ops, +- &rpcd2->gate.hw, &clk_gate_ops, 0); ++ &rpcd2->gate.hw, &clk_gate_ops, CLK_SET_RATE_PARENT); + if (IS_ERR(clk)) + kfree(rpcd2); + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0439-mtd-Consolidate-Renesas-RPC-drivers.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0439-mtd-Consolidate-Renesas-RPC-drivers.patch new file mode 100644 index 00000000..0b27c085 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0439-mtd-Consolidate-Renesas-RPC-drivers.patch @@ -0,0 +1,4450 @@ +From 596c2def7a2037f33973c6a064ed54d465a157f0 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 01:01:19 +0300 +Subject: [PATCH 05/12] mtd: Consolidate Renesas RPC drivers + +This consolidates RPC HyperFlash and SPI NOR drivers. +Flash device detection, and DMA read operation is done +by the renesas-rpc driver. The operation mode is selected +based on the child flash device node. If it's "jedec,spi-nor" +compatible, the "renesas-rpc-qspi" platform device is created. +If it's "cfi-flash" compatible, the "renesas-rpc-hyperflash" +device is created instead. + +The RPC device compatibility string is adjusted to match U-Boot. +The following configuration options are available: + + CONFIG_MTD_RENESAS_RPC: enables generic RPC support; + CONFIG_MTD_RENESAS_RPC_QSPI: enables SPI NOR support; + CONFIG_MTD_RENESAS_RPC_HYPERFLASH: enables HyperFlash support. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/mtd/Kconfig | 6 - + drivers/mtd/Makefile | 1 - + drivers/mtd/rpc_hyperflash.c | 976 ------------------ + drivers/mtd/spi-nor/Kconfig | 22 +- + drivers/mtd/spi-nor/Makefile | 4 +- + drivers/mtd/spi-nor/renesas-rpc-hyperflash.c | 742 ++++++++++++++ + drivers/mtd/spi-nor/renesas-rpc-qspi.c | 794 +++++++++++++++ + drivers/mtd/spi-nor/renesas-rpc.c | 1356 ++++---------------------- + drivers/mtd/spi-nor/renesas-rpc.h | 267 +++++ + 9 files changed, 1991 insertions(+), 2177 deletions(-) + delete mode 100644 drivers/mtd/rpc_hyperflash.c + create mode 100644 drivers/mtd/spi-nor/renesas-rpc-hyperflash.c + create mode 100644 drivers/mtd/spi-nor/renesas-rpc-qspi.c + create mode 100644 drivers/mtd/spi-nor/renesas-rpc.h + +diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig +index 0619e1f..89925b5 100644 +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -11,12 +11,6 @@ menuconfig MTD + particular hardware and users of MTD devices. If unsure, say N. + + if MTD +-config MTD_RPC_HYPERFLASH +- tristate "MTD Renesas R-Car Gen3 RPC HyperFlash" +- depends on ARCH_R8A7795 +- ---help--- +- This option includes Renesas R-Car Gen3 RPC HyperFlash support. +- + config MTD_TESTS + tristate "MTD tests support (DANGEROUS)" + depends on m +diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile +index f3fb2b0..d6f8f62 100644 +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o + obj-y += parsers/ +-obj-$(CONFIG_MTD_RPC_HYPERFLASH) += rpc_hyperflash.o + + # 'Users' - code which presents functionality to userspace. + obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o +diff --git a/drivers/mtd/rpc_hyperflash.c b/drivers/mtd/rpc_hyperflash.c +deleted file mode 100644 +index cf4d56e..0000000 +--- a/drivers/mtd/rpc_hyperflash.c ++++ /dev/null +@@ -1,976 +0,0 @@ +-/* +- * Linux driver for R-Car Gen3 RPC HyperFlash +- * +- * Copyright (C) 2016 Renesas Electronics Corporation +- * Copyright (C) 2016 Cogent Embedded, Inc. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +-#include <linux/delay.h> +-#include <linux/io.h> +-#include <linux/module.h> +-#include <linux/mtd/mtd.h> +-#include <linux/mtd/partitions.h> +-#include <linux/of.h> +-#include <linux/rwsem.h> +-#include <linux/slab.h> +- +-/* RPC */ +-#define RPC_BASE 0xEE200000 +-#define RPC_SIZE 0x8100 +-#define RPC_FLASH_BASE 0x08000000 +-#define RPC_FLASH_SIZE 0x04000000 +- +-#define RPC_CMNCR 0x0000 /* R/W */ +-#define RPC_CMNCR_MD (0x1 << 31) +-#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) +-#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) +-#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) +-#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) +-#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \ +- RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3)) +-#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8) +-#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12) +-#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14) +-#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \ +- RPC_CMNCR_IO3FV(3)) +-#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0) +- +-#define RPC_SSLDR 0x0004 /* R/W */ +-#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16) +-#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8) +-#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0) +- +-#define RPC_DRCR 0x000C /* R/W */ +-#define RPC_DRCR_SSLN (0x1 << 24) +-#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16) +-#define RPC_DRCR_RCF (0x1 << 9) +-#define RPC_DRCR_RBE (0x1 << 8) +-#define RPC_DRCR_SSLE (0x1 << 0) +- +-#define RPC_DRCMR 0x0010 /* R/W */ +-#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16) +-#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0) +- +-#define RPC_DREAR 0x0014 /* R/W */ +-#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16) +-#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0) +- +-#define RPC_DROPR 0x0018 /* R/W */ +-#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24) +-#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16) +-#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8) +-#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0) +- +-#define RPC_DRENR 0x001C /* R/W */ +-#define RPC_DRENR_CDB(o) (((o) & 0x3) << 30) +-#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28) +-#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24) +-#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20) +-#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16) +-#define RPC_DRENR_DME (0x1 << 15) +-#define RPC_DRENR_CDE (0x1 << 14) +-#define RPC_DRENR_OCDE (0x1 << 12) +-#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8) +-#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4) +- +-#define RPC_SMCR 0x0020 /* R/W */ +-#define RPC_SMCR_SSLKP (0x1 << 8) +-#define RPC_SMCR_SPIRE (0x1 << 2) +-#define RPC_SMCR_SPIWE (0x1 << 1) +-#define RPC_SMCR_SPIE (0x1 << 0) +- +-#define RPC_SMCMR 0x0024 /* R/W */ +-#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16) +-#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0) +- +-#define RPC_SMADR 0x0028 /* R/W */ +-#define RPC_SMOPR 0x002C /* R/W */ +-#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0) +-#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8) +-#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16) +-#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24) +- +-#define RPC_SMENR 0x0030 /* R/W */ +-#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30) +-#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28) +-#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24) +-#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20) +-#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16) +-#define RPC_SMENR_DME (0x1 << 15) +-#define RPC_SMENR_CDE (0x1 << 14) +-#define RPC_SMENR_OCDE (0x1 << 12) +-#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8) +-#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4) +-#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0) +- +-#define RPC_SMRDR0 0x0038 /* R */ +-#define RPC_SMRDR1 0x003C /* R */ +-#define RPC_SMWDR0 0x0040 /* R/W */ +-#define RPC_SMWDR1 0x0044 /* R/W */ +-#define RPC_CMNSR 0x0048 /* R */ +-#define RPC_CMNSR_SSLF (0x1 << 1) +-#define RPC_CMNSR_TEND (0x1 << 0) +- +-#define RPC_DRDMCR 0x0058 /* R/W */ +-#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0) +- +-#define RPC_DRDRENR 0x005C /* R/W */ +-#define RPC_DRDRENR_HYPE (0x5 << 12) +-#define RPC_DRDRENR_ADDRE (0x1 << 0x8) +-#define RPC_DRDRENR_OPDRE (0x1 << 0x4) +-#define RPC_DRDRENR_DRDRE (0x1 << 0x0) +- +-#define RPC_SMDMCR 0x0060 /* R/W */ +-#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0) +- +-#define RPC_SMDRENR 0x0064 /* R/W */ +-#define RPC_SMDRENR_HYPE (0x5 << 12) +-#define RPC_SMDRENR_ADDRE (0x1 << 0x8) +-#define RPC_SMDRENR_OPDRE (0x1 << 0x4) +-#define RPC_SMDRENR_SPIDRE (0x1 << 0x0) +- +-#define RPC_PHYCNT 0x007C /* R/W */ +-#define RPC_PHYCNT_CAL (0x1 << 31) +-#define PRC_PHYCNT_OCTA_AA (0x1 << 22) +-#define PRC_PHYCNT_OCTA_SA (0x2 << 22) +-#define PRC_PHYCNT_EXDS (0x1 << 21) +-#define RPC_PHYCNT_OCT (0x1 << 20) +-#define RPC_PHYCNT_WBUF2 (0x1 << 4) +-#define RPC_PHYCNT_WBUF (0x1 << 2) +-#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0) +- +-#define RPC_PHYINT 0x0088 /* R/W */ +-#define RPC_PHYINT_RSTEN (0x1 << 18) +-#define RPC_PHYINT_WPEN (0x1 << 17) +-#define RPC_PHYINT_INTEN (0x1 << 16) +-#define RPC_PHYINT_RST (0x1 << 2) +-#define RPC_PHYINT_WP (0x1 << 1) +-#define RPC_PHYINT_INT (0x1 << 0) +- +-#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */ +-#define RPC_WBUF_SIZE 0x100 +- +-struct rpc_info { +- struct rw_semaphore lock; +- void __iomem *rpc_base; +- void __iomem *flash_base; +- struct resource *rpc_res; +- struct resource *flash_res; +- u32 flash_id; +- struct mtd_info mtd; +-}; +- +-static inline void __iomem *rpc_addr(struct rpc_info *info, u32 offset) +-{ +- return info->rpc_base + offset; +-} +- +-static inline u32 rpc_readl(struct rpc_info *info, u32 offset) +-{ +- u32 val; +- +- val = readl(rpc_addr(info, offset)); +- return val; +-} +- +-static inline void rpc_writel(struct rpc_info *info, u32 offset, u32 val) +-{ +- writel(val, rpc_addr(info, offset)); +-} +- +-static inline void rpc_setl(struct rpc_info *info, u32 offset, u32 mask, u32 set) +-{ +- void __iomem *addr; +- u32 val; +- +- addr = rpc_addr(info, offset); +- val = readl(addr); +- val &= mask; +- val |= set; +- writel(val, addr); +-} +- +-static void rpc_wait_tend(struct rpc_info *info) +-{ +- while (!(rpc_readl(info, RPC_CMNSR) & RPC_CMNSR_TEND)) +- cpu_relax(); +-} +- +-/* RPC HyperFlash */ +-#define RPC_HF_CMD_CA47 (0x1 << 7) /* Read */ +-#define RPC_HF_CMD_CA46 (0x1 << 6) /* Register space */ +-#define RPC_HF_CMD_CA45 (0x1 << 5) /* Liner burst */ +- +-#define RPC_HF_CMD_READ_REG (RPC_HF_CMD_CA47 | RPC_HF_CMD_CA46) +-#define RPC_HF_CMD_READ_MEM RPC_HF_CMD_CA47 +-#define RPC_HF_CMD_WRITE_REG RPC_HF_CMD_CA46 +-#define RPC_HF_CMD_WRITE_MEM 0x0 +- +-#define RPC_HF_ERASE_SIZE 0x40000 +- +-#define RPC_CFI_STATUS_DRB (0x1 << 7) +-#define RPC_CFI_STATUS_ESSB (0x1 << 6) +-#define RPC_CFI_STATUS_ESB (0x1 << 5) +-#define RPC_CFI_STATUS_PSB (0x1 << 4) +-#define RPC_CFI_STATUS_WBASB (0x1 << 3) +-#define RPC_CFI_STATUS_PSSB (0x1 << 2) +-#define RPC_CFI_STATUS_SLSB (0x1 << 1) +-#define RPC_CFI_STATUS_ESTAT (0x1 << 0) +- +-#define RPC_CFI_UNLOCK1 (0x555 << 1) +-#define RPC_CFI_UNLOCK2 (0x2AA << 1) +- +-#define RPC_CFI_CMD_UNLOCK_START 0xAA +-#define RPC_CFI_CMD_UNLOCK_ACK 0x55 +-#define RPC_CFI_CMD_RESET 0xF0 +-#define RPC_CFI_CMD_READ_STATUS 0x70 +-#define RPC_CFI_CMD_READ_ID 0x90 +-#define RPC_CFI_CMD_WRITE 0xA0 +-#define RPC_CFI_CMD_ERASE_START 0x80 +-#define RPC_CFI_CMD_ERASE_SECTOR 0x30 +- +-#define RPC_CFI_ID_MASK 0x000F +-#define RPC_CFI_ID_MAN_SPANSION 0x0001 +-#define RPC_CFI_ID_TYPE_HYPERFLASH 0x000E +- +-enum rpc_hf_size { +- RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8), +- RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC), +- RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF), +-}; +- +-struct rpc_info *rpc_info; +- +-static void rpc_hf_mode_man(struct rpc_info *info) +-{ +- rpc_wait_tend(info); +- +- /* +- * RPC_PHYCNT = 0x80000263 +- * bit31 CAL = 1 : PHY calibration +- * bit1-0 PHYMEM[1:0] = 11 : HyperFlash +- */ +- rpc_setl(info, RPC_PHYCNT, +- ~(RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | +- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)), +- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); +- +- /* +- * RPC_CMNCR = 0x81FFF301 +- * bit31 MD = 1 : Manual mode +- * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash +- */ +- rpc_setl(info, RPC_CMNCR, +- ~(RPC_CMNCR_MD | RPC_CMNCR_BSZ(3)), +- RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | +- RPC_CMNCR_MD | RPC_CMNCR_BSZ(1)); +-} +- +-static void rpc_hf_mode_ext(struct rpc_info *info) +-{ +- rpc_wait_tend(info); +- +- /* +- * RPC_PHYCNT = 0x80000263 +- * bit31 CAL = 1 : PHY calibration +- * bit1-0 PHYMEM[1:0] = 11 : HyperFlash +- */ +- rpc_setl(info, RPC_PHYCNT, +- ~(RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | +- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)), +- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); +- +- /* +- * RPC_CMNCR = 0x81FFF301 +- * bit31 MD = 1 : Manual mode +- * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash +- */ +- rpc_setl(info, RPC_CMNCR, +- ~(RPC_CMNCR_MD | RPC_CMNCR_BSZ(3)), +- RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | +- RPC_CMNCR_BSZ(1)); +- +- /* +- * RPC_DRCR = 0x001F0100 +- * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units +- * bit9 RCF = 1 : Clear cache +- * bit8 RBE = 1 : Read burst enable +- */ +- rpc_writel(info, RPC_DRCR, +- RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE); +- +- rpc_writel(info, RPC_DRCMR, RPC_DRCMR_CMD(0xA0)); +- rpc_writel(info, RPC_DRENR, +- RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) | +- RPC_DRENR_ADB(2) | RPC_DRENR_SPIDB(2) | +- RPC_DRENR_CDE | RPC_DRENR_OCDE | RPC_DRENR_ADE(4)); +- rpc_writel(info, RPC_DRDMCR, RPC_DRDMCR_DMCYC(0xE)); +- rpc_writel(info, RPC_DRDRENR, +- RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE | RPC_DRDRENR_DRDRE); +- +- /* Dummy read */ +- rpc_readl(info, RPC_DRCR); +-} +- +-static void rpc_hf_xfer(struct rpc_info *info, u32 addr, u16 *data, +- enum rpc_hf_size size, u8 cmd) +-{ +- u32 val; +- +- rpc_hf_mode_man(info); +- +- /* +- * bit23-21 CMD[7:5] : CA47-45 +- * CA47 = 0/1 : Write/Read +- * CA46 = 0/1 : Memory Space/Register Space +- * CA45 = 0/1 : Wrapped Burst/Linear Burst +- */ +- rpc_writel(info, RPC_SMCMR, RPC_SMCMR_CMD(cmd)); +- +- rpc_writel(info, RPC_SMADR, addr >> 1); +- +- rpc_writel(info, RPC_SMOPR, 0x0); +- +- /* +- * RPC_SMDRENR = 0x00005101 +- * bit14-12 HYPE = 101: Hyperflash mode +- * bit8 ADDRE = 1 : Address DDR transfer +- * bit0 SPIDRE = 1 : DATA DDR transfer +- */ +- rpc_writel(info, RPC_SMDRENR, +- RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE); +- +- val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) | +- RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) | +- RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size; +- +- if (cmd & RPC_HF_CMD_CA47) +- goto read_transfer; +- +- /* +- * RPC_SMENR = 0xA222540x +- * bit31-30 CDB[1:0] = 10 : 4bit width command +- * bit25-24 ADB[1:0] = 10 : 4bit width address +- * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data +- * bit15 DME = 0 : dummy cycle disable +- * bit14 CDE = 1 : Command enable +- * bit12 OCDE = 1 : Option Command enable +- * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output +- * bit7-4 OPDE[3:0] = 0000 : Option data disable +- * bit3-0 SPIDE[3:0] = xxxx : Transfer size +- */ +- rpc_writel(info, RPC_SMENR, val); +- +- switch (size) { +- case RPC_HF_SIZE_64BIT: +- val = cmd & RPC_HF_CMD_CA46 ? +- cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 : +- data[0] | data[1] << 16; +- rpc_writel(info, RPC_SMWDR1, val); +- val = cmd & RPC_HF_CMD_CA46 ? +- cpu_to_be16(data[2]) | cpu_to_be16(data[3]) << 16 : +- data[2] | data[3] << 16; +- break; +- case RPC_HF_SIZE_32BIT: +- val = cmd & RPC_HF_CMD_CA46 ? +- cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 : +- data[0] | data[1] << 16; +- break; +- default: +- val = cmd & RPC_HF_CMD_CA46 ? +- cpu_to_be16(data[0]) << 16 : +- data[0] << 16; +- break; +- } +- +- rpc_writel(info, RPC_SMWDR0, val); +- /* +- * RPC_SMCR = 0x00000003 +- * bit1 SPIWE = 1 : Data write enable +- * bit0 SPIE = 1 : SPI transfer start +- */ +- rpc_writel(info, RPC_SMCR, RPC_SMCR_SPIWE | RPC_SMCR_SPIE); +- return; +- +-read_transfer: +- rpc_writel(info, RPC_SMDMCR, RPC_SMDMCR_DMCYC(0xE)); +- val |= RPC_SMENR_DME; +- +- /* +- * RPC_SMENR = 0xA222D40x +- * bit31-30 CDB[1:0] = 10 : 4bit width command +- * bit25-24 ADB[1:0] = 10 : 4bit width address +- * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data +- * bit15 DME = 1 : dummy cycle disable +- * bit14 CDE = 1 : Command enable +- * bit12 OCDE = 1 : Option Command enable +- * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address) +- * bit7-4 OPDE[3:0] = 0000 : Option data disable +- * bit3-0 SPIDE[3:0] = xxxx : Transfer size +- */ +- rpc_writel(info, RPC_SMENR, val); +- +- /* +- * RPC_SMCR = 0x00000005 +- * bit2 SPIRE = 1 : Data read disable +- * bit0 SPIE = 1 : SPI transfer start +- */ +- rpc_writel(info, RPC_SMCR, RPC_SMCR_SPIRE | RPC_SMCR_SPIE); +- +- rpc_wait_tend(info); +- val = rpc_readl(info, RPC_SMRDR0); +- +- /* +- * Read data from either register or memory space. +- * Register space is always big-endian. +- */ +- switch (size) { +- case RPC_HF_SIZE_64BIT: +- if (cmd & RPC_HF_CMD_CA46) { +- data[3] = be16_to_cpu((val >> 16) & 0xFFFF); +- data[2] = be16_to_cpu(val & 0xFFFF); +- } else { +- data[3] = (val >> 16) & 0xFFFF; +- data[2] = val & 0xFFFF; +- } +- val = rpc_readl(info, RPC_SMRDR1); +- if (cmd & RPC_HF_CMD_CA46) { +- data[1] = be16_to_cpu((val >> 16) & 0xFFFF); +- data[0] = be16_to_cpu(val & 0xFFFF); +- } else { +- data[1] = (val >> 16) & 0xFFFF; +- data[0] = val & 0xFFFF; +- } +- break; +- case RPC_HF_SIZE_32BIT: +- if (cmd & RPC_HF_CMD_CA46) { +- data[1] = be16_to_cpu((val >> 16) & 0xFFFF); +- data[0] = be16_to_cpu(val & 0xFFFF); +- } else { +- data[1] = (val >> 16) & 0xFFFF; +- data[0] = val & 0xFFFF; +- } +- break; +- default: +- data[0] = cmd & RPC_HF_CMD_CA46 ? +- be16_to_cpu((val >> 16) & 0xFFFF) : +- (val >> 16) & 0xFFFF; +- break; +- } +-} +- +-static void rpc_hf_wbuf_enable(struct rpc_info *info) +-{ +- rpc_wait_tend(info); +- +- /* +- * RPC_PHYCNT = 0x80000277 +- * bit31 CAL = 1 : PHY calibration +- * bit4 WBUF2 = 1 : Write buffer enable 2 +- * bit2 WBUF = 1 : Write buffer enable +- * bit1-0 PHYMEM[1:0] = 11 : HyperFlash +- */ +- rpc_setl(info, RPC_PHYCNT, +- ~(RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF | +- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)), +- RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF | +- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); +- +- /* +- * RPC_DRCR = 0x001F0100 +- * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units +- * bit9 RCF = 1 : Clear cache +- * bit8 RBE = 1 : Read burst enable +- */ +- rpc_writel(info, RPC_DRCR, +- RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE); +- +- rpc_writel(info, RPC_SMCMR, RPC_SMCMR_CMD(RPC_HF_CMD_WRITE_MEM)); +- +- rpc_writel(info, RPC_SMOPR, 0x0); +- +- /* +- * RPC_SMDRENR = 0x00005101 +- * bit14-12 HYPE = 101:Hyperflash mode +- * bit8 ADDRE = 1 : Address DDR transfer +- * bit0 SPIDRE = 1 : DATA DDR transfer +- */ +- rpc_writel(info, RPC_SMDRENR, +- RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE); +- +- /* +- * RPC_SMENR = 0xA222540F +- * bit31-30 CDB[1:0] = 10 : 4bit width command +- * bit25-24 ADB[1:0] = 10 : 4bit width address +- * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data +- * bit15 DME = 0 : dummy cycle disable +- * bit14 CDE = 1 : Command enable +- * bit12 OCDE = 1 : Option Command enable +- * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address) +- * bit7-4 OPDE[3:0] = 0000 : Option data disable +- * bit3-0 SPIDE[3:0] = 1111 : 64-bit transfer size +- */ +- rpc_writel(info, RPC_SMENR, +- RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) | +- RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) | +- RPC_SMENR_CDE | RPC_SMENR_OCDE | +- RPC_SMENR_ADE(4) | RPC_HF_SIZE_64BIT); +- +- /* Dummy read */ +- rpc_readl(info, RPC_DRCR); +-} +- +-static inline void rpc_hf_write_cmd(struct rpc_info *info, u32 addr, u16 cmd) +-{ +- rpc_hf_xfer(info, addr, &cmd, RPC_HF_SIZE_16BIT, RPC_HF_CMD_WRITE_REG); +-} +- +-static inline void rpc_hf_read_reg(struct rpc_info *info, u32 addr, u16 *data, +- enum rpc_hf_size size) +-{ +- rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_READ_REG); +-} +- +-static inline void rpc_hf_write_reg(struct rpc_info *info, u32 addr, u16 *data, +- enum rpc_hf_size size) +-{ +- rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_WRITE_REG); +-} +- +-static inline void rpc_hf_read_mem(struct rpc_info *info, u32 addr, u16 *data, +- enum rpc_hf_size size) +-{ +- rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_READ_MEM); +-} +- +-static inline void rpc_hf_write_mem(struct rpc_info *info, u32 addr, u16 *data, +- enum rpc_hf_size size) +-{ +- rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_WRITE_MEM); +-} +- +-static void rpc_hf_wp(struct rpc_info *info, int enable) +-{ +- rpc_setl(info, RPC_PHYINT, ~RPC_PHYINT_WP, enable ? RPC_PHYINT_WP : 0); +-} +- +-static void rpc_hf_unlock(struct rpc_info *info, u32 addr) +-{ +- rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK1, +- RPC_CFI_CMD_UNLOCK_START); +- rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK2, +- RPC_CFI_CMD_UNLOCK_ACK); +-} +- +-static inline int rpc_hf_status(struct rpc_info *info, u32 addr, +- int iterations, int delay) +-{ +- int retval; +- u16 status = 0; +- +- while (iterations-- > 0) { +- rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK1, RPC_CFI_CMD_READ_STATUS); +- rpc_hf_read_reg(info, addr, &status, RPC_HF_SIZE_16BIT); +- +- if (status & RPC_CFI_STATUS_DRB) +- break; +- +- if (delay < 10000) +- usleep_range(delay, delay * 2); +- else +- msleep(delay / 1000); +- } +- +- if (!(status & RPC_CFI_STATUS_DRB)) { +- retval = -ETIMEDOUT; +- goto out; +- } +- +- if (status & (RPC_CFI_STATUS_PSB | RPC_CFI_STATUS_ESB)) { +- retval = -EIO; +- goto out; +- } +- +- return 0; +- +-out: +- /* Reset the flash */ +- rpc_hf_write_cmd(info, 0, RPC_CFI_CMD_RESET); +- return retval; +-} +- +-static int rpc_hf_sector_erase(struct rpc_info *info, u32 addr) +-{ +- rpc_hf_unlock(info, addr); +- rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK1, RPC_CFI_CMD_ERASE_START); +- rpc_hf_unlock(info, addr); +- rpc_hf_write_cmd(info, addr, RPC_CFI_CMD_ERASE_SECTOR); +- +- return rpc_hf_status(info, addr, 1000, 10000); +-} +- +-/* Flash read */ +-static int rpc_hf_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, +- size_t *retlen, u_char *buf) +-{ +- struct rpc_info *info = mtd->priv; +- +- down_read(&info->lock); +- memcpy_fromio(buf, info->flash_base + from, len); +- up_read(&info->lock); +- +- *retlen = len; +- return 0; +-} +- +-/* Flash erase */ +-static int rpc_hf_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +-{ +- struct rpc_info *info = mtd->priv; +- u32 addr, end; +- int retval = 0; +- +- if (mtd_mod_by_eb(instr->addr, mtd)) { +- pr_debug("%s: unaligned address\n", __func__); +- return -EINVAL; +- } +- +- if (mtd_mod_by_eb(instr->len, mtd)) { +- pr_debug("%s: unaligned length\n", __func__); +- return -EINVAL; +- } +- +- end = instr->addr + instr->len; +- +- down_write(&info->lock); +- for (addr = instr->addr; addr < end; addr += mtd->erasesize) { +- retval = rpc_hf_sector_erase(info, addr); +- +- if (retval) +- break; +- } +- +- rpc_hf_mode_ext(info); +- up_write(&info->lock); +- +- instr->state = retval ? MTD_ERASE_FAILED : MTD_ERASE_DONE; +- mtd_erase_callback(instr); +- +- return retval; +-} +- +-/* Copy memory to flash */ +-static int rpc_hf_mtd_write(struct mtd_info *mtd, loff_t offset, size_t len, +- size_t *retlen, const u_char *src) +-{ +- struct rpc_info *info = mtd->priv; +- union { +- u8 b[4]; +- u16 w[2]; +- u32 d; +- } data; +- loff_t addr; +- size_t size, cnt; +- int retval, idx; +- u8 last; +- +- retval = 0; +- *retlen = 0; +- cnt = len; +- idx = 0; +- +- down_write(&info->lock); +- +- /* Handle unaligned start */ +- if (offset & 0x1) { +- offset--; +- data.b[idx] = readb(info->flash_base + offset); +- idx++; +- } +- +- /* Handle unaligned end */ +- addr = offset + idx + len; +- last = addr & 0x1 ? readb(info->flash_base + addr) : 0xFF; +- +- addr = offset - mtd_mod_by_eb(offset, mtd); +- size = mtd->erasesize - (offset - addr); +- +- while (cnt) { +- if (size > cnt) +- size = cnt; +- +- cnt -= size; +- while (size) { +- rpc_hf_unlock(info, addr); +- rpc_hf_write_cmd(info, +- addr + RPC_CFI_UNLOCK1, +- RPC_CFI_CMD_WRITE); +- +- if (size > 0x7) { +- u32 wbuf = RPC_WBUF; +- int block = size >= RPC_WBUF_SIZE ? +- RPC_WBUF_SIZE : size & ~0x7; +- +- rpc_hf_wbuf_enable(info); +- +- rpc_writel(info, RPC_SMADR, offset >> 1); +- offset += block; +- +- block >>= 3; +- while (block--) { +- while (idx < 4) { +- data.b[idx++] = *src++; +- size--; +- } +- rpc_writel(info, wbuf, data.d); +- wbuf += 4; +- +- idx = 0; +- while (idx < 4) { +- data.b[idx++] = *src++; +- size--; +- } +- rpc_writel(info, wbuf, data.d); +- wbuf += 4; +- +- idx = 0; +- } +- +- rpc_writel(info, RPC_SMCR, +- RPC_SMCR_SPIWE | RPC_SMCR_SPIE); +- } else { +- enum rpc_hf_size bits; +- +- while (idx < 4) { +- data.b[idx++] = *src++; +- size--; +- +- if (!size) +- break; +- } +- +- if (idx & 0x1) +- data.b[idx++] = last; +- +- switch (idx) { +- case 2: +- bits = RPC_HF_SIZE_16BIT; +- break; +- default: +- bits = RPC_HF_SIZE_32BIT; +- break; +- } +- +- rpc_hf_write_mem(info, offset, data.w, bits); +- offset += idx; +- idx = 0; +- } +- +- retval = rpc_hf_status(info, addr, 1000000, 10); +- if (retval) +- goto out; +- } +- +- size = mtd->erasesize; +- addr += size; +- offset = addr; +- *retlen = len - cnt; +- } +- +-out: +- rpc_hf_mode_ext(info); +- up_write(&info->lock); +- return retval; +-} +- +-static struct mtd_partition partition_info[]={ +- { +- .name = "bootparam", +- .offset = 0, +- .size = 0x40000, +- }, { +- .name = "bl2", +- .offset = MTDPART_OFS_APPEND, +- .size = 0x140000 +- }, { +- .name = "cert_header", +- .offset = MTDPART_OFS_APPEND, +- .size = 0x40000, +- }, { +- .name = "bl31", +- .offset = MTDPART_OFS_APPEND, +- .size = 0x40000, +- }, { +- .name = "optee", +- .offset = MTDPART_OFS_APPEND, +- .size = 0x440000, +- }, { +- .name = "u-boot", +- .offset = MTDPART_OFS_APPEND, +- .size = 0x80000, +- }, { +- .name = "reserved", +- .offset = MTDPART_OFS_APPEND, +- .size = 0x80000, +- }, { +- .name = "u-boot-env", +- .offset = MTDPART_OFS_APPEND, +- .size = 0x40000, +- }, { +- .name = "dtb", +- .offset = MTDPART_OFS_APPEND, +- .size = 0x80000, +- }, { +- .name = "kernel", +- .offset = MTDPART_OFS_APPEND, +- .size = 0x1000000, +- }, { +- .name = "user", +- .offset = MTDPART_OFS_APPEND, +- .size = MTDPART_SIZ_FULL, +- }, +-}; +- +-static int rpc_hf_init_mtd(struct rpc_info *info) +-{ +- struct mtd_info *mtd = &info->mtd; +- u16 data[2] = { 0, 0 }; +- u32 id, size; +- int retval; +- +- rpc_hf_mode_ext(info); +- +- rpc_hf_wp(info, 0); +- +- rpc_hf_unlock(info, 0); +- rpc_hf_write_cmd(info, RPC_CFI_UNLOCK1, RPC_CFI_CMD_READ_ID); +- +- rpc_hf_read_reg(info, 0x0, data, RPC_HF_SIZE_32BIT); +- if ((data[0] & RPC_CFI_ID_MASK) != RPC_CFI_ID_MAN_SPANSION || +- (data[1] & RPC_CFI_ID_MASK) != RPC_CFI_ID_TYPE_HYPERFLASH) { +- retval = -ENODEV; +- goto out; +- } +- +- id = data[0] | data[1] << 16; +- +- rpc_hf_read_reg(info, 0x27 << 1, data, RPC_HF_SIZE_16BIT); +- size = 1 << data[0]; +- +- if (size > resource_size(info->flash_res)) +- size = resource_size(info->flash_res); +- +- if (size & (RPC_HF_ERASE_SIZE - 1)) { +- retval = -EINVAL; +- goto out; +- } +- +- init_rwsem(&info->lock); +- info->flash_id = id; +- mtd->name = "HyperFlash"; +- mtd->type = MTD_NORFLASH; +- mtd->flags = MTD_CAP_NORFLASH; +- mtd->size = size; +- mtd->writesize = 1; +- mtd->writebufsize = RPC_WBUF_SIZE; +- mtd->erasesize = RPC_HF_ERASE_SIZE; +- mtd->owner = THIS_MODULE; +- mtd->priv = info; +- mtd->_erase = rpc_hf_mtd_erase; +- mtd->_write = rpc_hf_mtd_write; +- mtd->_read = rpc_hf_mtd_read; +- retval = mtd_device_register(mtd, partition_info, +- ARRAY_SIZE(partition_info)); +-out: +- rpc_hf_write_cmd(info, 0, RPC_CFI_CMD_RESET); +- rpc_hf_mode_ext(info); +- return retval; +-} +- +-static int rpc_flash_init(void) +-{ +- struct rpc_info *info; +- struct resource *res; +- void __iomem *base; +- int retval = -ENODEV; +- +- if (!of_machine_is_compatible("renesas,r8a7795")) +- return -ENODEV; +- +- info = kzalloc(sizeof(*info), GFP_KERNEL); +- if (!info) +- return -ENOMEM; +- +- res = request_mem_region(RPC_BASE, RPC_SIZE, "RPC"); +- if (!res) +- goto out_info; +- +- info->rpc_res = res; +- base = ioremap(res->start, resource_size(res)); +- if (!base) +- goto out_rpc_res; +- +- info->rpc_base = base; +- res = request_mem_region(RPC_FLASH_BASE, RPC_FLASH_SIZE, "RPC-ext"); +- if (!res) +- goto out_rpc_base; +- +- info->flash_res = res; +- base = ioremap(res->start, resource_size(res)); +- if (!base) +- goto out_flash_res; +- +- info->flash_base = base; +- retval = rpc_hf_init_mtd(info); +- if (retval) +- goto out_flash_base; +- +- pr_info("HyperFlash Id: %x\n", info->flash_id); +- +- rpc_info = info; +- return 0; +- +-out_flash_base: +- iounmap(info->flash_base); +-out_flash_res: +- release_mem_region(info->flash_res->start, +- resource_size(info->flash_res)); +-out_rpc_base: +- iounmap(info->rpc_base); +-out_rpc_res: +- release_mem_region(info->rpc_res->start, +- resource_size(info->rpc_res)); +-out_info: +- kfree(info); +- return retval; +-} +- +-static void rpc_flash_exit(void) +-{ +- struct rpc_info *info = rpc_info; +- +- if (!info) +- return; +- +- rpc_info = NULL; +- +- mtd_device_unregister(&info->mtd); +- +- iounmap(info->flash_base); +- release_mem_region(info->flash_res->start, +- resource_size(info->flash_res)); +- iounmap(info->rpc_base); +- release_mem_region(info->rpc_res->start, +- resource_size(info->rpc_res)); +- kfree(info); +-} +- +-module_init(rpc_flash_init); +-module_exit(rpc_flash_exit); +- +-MODULE_LICENSE("GPL v2"); +-MODULE_DESCRIPTION("Renesas RPC HyperFlash MTD driver"); +diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig +index 2c73adb..bd316fd 100644 +--- a/drivers/mtd/spi-nor/Kconfig ++++ b/drivers/mtd/spi-nor/Kconfig +@@ -8,12 +8,26 @@ menuconfig MTD_SPI_NOR + if MTD_SPI_NOR + + +-config SPI_RENESAS_RPC ++config MTD_RENESAS_RPC + tristate "Renesas RPC controller" +- depends on ARCH_R8A7795 || ARCH_R8A7796 || ARCH_R8A77970 || ARCH_R8A77980 || COMPILE_TEST ++ depends on ARCH_RENESAS || COMPILE_TEST + help +- QSPI driver for Renesas SPI Multi I/O Bus controller. This controller +- supports normal, dual and quad spi for one or two SPI NOR Flashes. ++ Renesas RPC interface driver. This controller support QSPI and HyperFlash ++ devices. ++ ++config MTD_RENESAS_RPC_HYPERFLASH ++ tristate "Renesas RPC HyperFlash" ++ depends on ARCH_RENESAS || COMPILE_TEST ++ select MTD_RENESAS_RPC ++ help ++ HyperFlash driver for Renesas RPC Multi I/O Bus controller controller. ++ ++config MTD_RENESAS_RPC_QSPI ++ tristate "Renesas RPC QSPI" ++ depends on ARCH_RENESAS || COMPILE_TEST ++ select MTD_RENESAS_RPC ++ help ++ QSPI driver for Renesas RPC Multi I/O Bus controller. + + config MTD_MT81xx_NOR + tristate "Mediatek MT81xx SPI NOR flash controller" +diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile +index 0c46c9c..a10c6ab 100644 +--- a/drivers/mtd/spi-nor/Makefile ++++ b/drivers/mtd/spi-nor/Makefile +@@ -7,8 +7,10 @@ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o + obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o + obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o + obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o +-obj-$(CONFIG_SPI_RENESAS_RPC) += renesas-rpc.o + obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o + obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o + obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o + obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o ++obj-$(CONFIG_MTD_RENESAS_RPC) += renesas-rpc.o ++obj-$(CONFIG_MTD_RENESAS_RPC_QSPI) += renesas-rpc-qspi.o ++obj-$(CONFIG_MTD_RENESAS_RPC_HYPERFLASH) += renesas-rpc-hyperflash.o +diff --git a/drivers/mtd/spi-nor/renesas-rpc-hyperflash.c b/drivers/mtd/spi-nor/renesas-rpc-hyperflash.c +new file mode 100644 +index 0000000..aea42b6 +--- /dev/null ++++ b/drivers/mtd/spi-nor/renesas-rpc-hyperflash.c +@@ -0,0 +1,742 @@ ++/* ++ * Renesas RPC driver ++ * ++ * Copyright (C) 2018, Cogent Embedded Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/mtd/mtd.h> ++ ++#include "renesas-rpc.h" ++ ++/* RPC HyperFlash */ ++#define RPC_HF_CMD_CA47 (0x1 << 7) /* Read */ ++#define RPC_HF_CMD_CA46 (0x1 << 6) /* Register space */ ++#define RPC_HF_CMD_CA45 (0x1 << 5) /* Liner burst */ ++ ++#define RPC_HF_CMD_READ_REG (RPC_HF_CMD_CA47 | RPC_HF_CMD_CA46) ++#define RPC_HF_CMD_READ_MEM RPC_HF_CMD_CA47 ++#define RPC_HF_CMD_WRITE_REG RPC_HF_CMD_CA46 ++#define RPC_HF_CMD_WRITE_MEM 0x0 ++ ++#define RPC_HF_ERASE_SIZE 0x40000 ++ ++#define RPC_CFI_STATUS_DRB (0x1 << 7) ++#define RPC_CFI_STATUS_ESSB (0x1 << 6) ++#define RPC_CFI_STATUS_ESB (0x1 << 5) ++#define RPC_CFI_STATUS_PSB (0x1 << 4) ++#define RPC_CFI_STATUS_WBASB (0x1 << 3) ++#define RPC_CFI_STATUS_PSSB (0x1 << 2) ++#define RPC_CFI_STATUS_SLSB (0x1 << 1) ++#define RPC_CFI_STATUS_ESTAT (0x1 << 0) ++ ++#define RPC_CFI_UNLOCK1 (0x555 << 1) ++#define RPC_CFI_UNLOCK2 (0x2AA << 1) ++ ++#define RPC_CFI_CMD_UNLOCK_START 0xAA ++#define RPC_CFI_CMD_UNLOCK_ACK 0x55 ++#define RPC_CFI_CMD_RESET 0xF0 ++#define RPC_CFI_CMD_READ_STATUS 0x70 ++#define RPC_CFI_CMD_READ_ID 0x90 ++#define RPC_CFI_CMD_WRITE 0xA0 ++#define RPC_CFI_CMD_ERASE_START 0x80 ++#define RPC_CFI_CMD_ERASE_SECTOR 0x30 ++ ++#define RPC_CFI_ID_MASK 0x000F ++#define RPC_CFI_ID_MAN_SPANSION 0x0001 ++#define RPC_CFI_ID_TYPE_HYPERFLASH 0x000E ++ ++struct rpc_hf_info { ++ struct mtd_info mtd; ++ struct mutex lock; ++ void *priv; ++}; ++ ++static void rpc_hf_mode_man(struct rpc_info *rpc) ++{ ++ rpc_wait(rpc, RPC_TIMEOUT); ++ ++ /* ++ * RPC_PHYCNT = 0x80000263 ++ * bit31 CAL = 1 : PHY calibration ++ * bit1-0 PHYMEM[1:0] = 11 : HyperFlash ++ */ ++ rpc_clrsetl(rpc, RPC_PHYCNT, ++ RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3), ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); ++ ++ /* ++ * RPC_CMNCR = 0x81FFF301 ++ * bit31 MD = 1 : Manual mode ++ * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash ++ */ ++ rpc_clrsetl(rpc, RPC_CMNCR, ++ RPC_CMNCR_MD | RPC_CMNCR_BSZ(3), ++ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | ++ RPC_CMNCR_MD | RPC_CMNCR_BSZ(1)); ++} ++ ++static void rpc_hf_mode_ext(struct rpc_info *rpc) ++{ ++ rpc_wait(rpc, RPC_TIMEOUT); ++ ++ /* ++ * RPC_PHYCNT = 0x80000263 ++ * bit31 CAL = 1 : PHY calibration ++ * bit1-0 PHYMEM[1:0] = 11 : HyperFlash ++ */ ++ rpc_clrsetl(rpc, RPC_PHYCNT, ++ RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3), ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); ++ ++ /* ++ * RPC_CMNCR = 0x81FFF301 ++ * bit31 MD = 1 : Manual mode ++ * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash ++ */ ++ rpc_clrsetl(rpc, RPC_CMNCR, ++ RPC_CMNCR_MD | RPC_CMNCR_BSZ(3), ++ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | ++ RPC_CMNCR_BSZ(1)); ++ ++ /* ++ * RPC_DRCR = 0x001F0100 ++ * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units ++ * bit9 RCF = 1 : Clear cache ++ * bit8 RBE = 1 : Read burst enable ++ */ ++ rpc_writel(rpc, RPC_DRCR, ++ RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE); ++ ++ rpc_writel(rpc, RPC_DRCMR, RPC_DRCMR_CMD(0xA0)); ++ rpc_writel(rpc, RPC_DRENR, ++ RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) | ++ RPC_DRENR_ADB(2) | RPC_DRENR_DRDB(2) | ++ RPC_DRENR_CDE | RPC_DRENR_OCDE | ++ RPC_DRENR_DME | RPC_DRENR_ADE(4)); ++ rpc_writel(rpc, RPC_DRDMCR, RPC_DRDMCR_DMCYC(0xE)); ++ rpc_writel(rpc, RPC_DRDRENR, ++ RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE | RPC_DRDRENR_DRDRE); ++ ++ /* Dummy read */ ++ rpc_readl(rpc, RPC_DRCR); ++} ++ ++static void rpc_hf_xfer(struct rpc_info *rpc, u32 addr, u16 *data, ++ enum rpc_size size, u8 cmd) ++{ ++ u32 val; ++ ++ rpc_hf_mode_man(rpc); ++ ++ /* ++ * bit23-21 CMD[7:5] : CA47-45 ++ * CA47 = 0/1 : Write/Read ++ * CA46 = 0/1 : Memory Space/Register Space ++ * CA45 = 0/1 : Wrapped Burst/Linear Burst ++ */ ++ rpc_writel(rpc, RPC_SMCMR, RPC_SMCMR_CMD(cmd)); ++ ++ rpc_writel(rpc, RPC_SMADR, addr >> 1); ++ ++ rpc_writel(rpc, RPC_SMOPR, 0x0); ++ ++ /* ++ * RPC_SMDRENR = 0x00005101 ++ * bit14-12 HYPE = 101: Hyperflash mode ++ * bit8 ADDRE = 1 : Address DDR transfer ++ * bit0 SPIDRE = 1 : DATA DDR transfer ++ */ ++ rpc_writel(rpc, RPC_SMDRENR, ++ RPC_SMDRENR_HYPE_HF | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE); ++ ++ val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) | ++ RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) | ++ RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size; ++ ++ if (cmd & RPC_HF_CMD_CA47) ++ goto read_transfer; ++ ++ /* ++ * RPC_SMENR = 0xA222540x ++ * bit31-30 CDB[1:0] = 10 : 4bit width command ++ * bit25-24 ADB[1:0] = 10 : 4bit width address ++ * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data ++ * bit15 DME = 0 : dummy cycle disable ++ * bit14 CDE = 1 : Command enable ++ * bit12 OCDE = 1 : Option Command enable ++ * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output ++ * bit7-4 OPDE[3:0] = 0000 : Option data disable ++ * bit3-0 SPIDE[3:0] = xxxx : Transfer size ++ */ ++ rpc_writel(rpc, RPC_SMENR, val); ++ ++ switch (size) { ++ case RPC_SIZE_DUAL_64BIT: ++ val = cmd & RPC_HF_CMD_CA46 ? ++ cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 : ++ data[0] | data[1] << 16; ++ rpc_writel(rpc, RPC_SMWDR1, val); ++ val = cmd & RPC_HF_CMD_CA46 ? ++ cpu_to_be16(data[2]) | cpu_to_be16(data[3]) << 16 : ++ data[2] | data[3] << 16; ++ break; ++ case RPC_SIZE_DUAL_32BIT: ++ val = cmd & RPC_HF_CMD_CA46 ? ++ cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 : ++ data[0] | data[1] << 16; ++ break; ++ default: ++ val = cmd & RPC_HF_CMD_CA46 ? ++ cpu_to_be16(data[0]) << 16 : ++ data[0] << 16; ++ break; ++ } ++ ++ rpc_writel(rpc, RPC_SMWDR0, val); ++ /* ++ * RPC_SMCR = 0x00000003 ++ * bit1 SPIWE = 1 : Data write enable ++ * bit0 SPIE = 1 : SPI transfer start ++ */ ++ rpc_writel(rpc, RPC_SMCR, RPC_SMCR_SPIWE | RPC_SMCR_SPIE); ++ return; ++ ++read_transfer: ++ rpc_writel(rpc, RPC_SMDMCR, RPC_SMDMCR_DMCYC(0xE)); ++ val |= RPC_SMENR_DME; ++ ++ /* ++ * RPC_SMENR = 0xA222D40x ++ * bit31-30 CDB[1:0] = 10 : 4bit width command ++ * bit25-24 ADB[1:0] = 10 : 4bit width address ++ * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data ++ * bit15 DME = 1 : dummy cycle disable ++ * bit14 CDE = 1 : Command enable ++ * bit12 OCDE = 1 : Option Command enable ++ * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address) ++ * bit7-4 OPDE[3:0] = 0000 : Option data disable ++ * bit3-0 SPIDE[3:0] = xxxx : Transfer size ++ */ ++ rpc_writel(rpc, RPC_SMENR, val); ++ ++ /* ++ * RPC_SMCR = 0x00000005 ++ * bit2 SPIRE = 1 : Data read disable ++ * bit0 SPIE = 1 : SPI transfer start ++ */ ++ rpc_writel(rpc, RPC_SMCR, RPC_SMCR_SPIRE | RPC_SMCR_SPIE); ++ ++ rpc_wait(rpc, RPC_TIMEOUT); ++ val = rpc_readl(rpc, RPC_SMRDR0); ++ ++ /* ++ * Read data from either register or memory space. ++ * Register space is always big-endian. ++ */ ++ switch (size) { ++ case RPC_SIZE_DUAL_64BIT: ++ if (cmd & RPC_HF_CMD_CA46) { ++ data[3] = be16_to_cpu((val >> 16) & 0xFFFF); ++ data[2] = be16_to_cpu(val & 0xFFFF); ++ } else { ++ data[3] = (val >> 16) & 0xFFFF; ++ data[2] = val & 0xFFFF; ++ } ++ val = rpc_readl(rpc, RPC_SMRDR1); ++ if (cmd & RPC_HF_CMD_CA46) { ++ data[1] = be16_to_cpu((val >> 16) & 0xFFFF); ++ data[0] = be16_to_cpu(val & 0xFFFF); ++ } else { ++ data[1] = (val >> 16) & 0xFFFF; ++ data[0] = val & 0xFFFF; ++ } ++ break; ++ case RPC_SIZE_DUAL_32BIT: ++ if (cmd & RPC_HF_CMD_CA46) { ++ data[1] = be16_to_cpu((val >> 16) & 0xFFFF); ++ data[0] = be16_to_cpu(val & 0xFFFF); ++ } else { ++ data[1] = (val >> 16) & 0xFFFF; ++ data[0] = val & 0xFFFF; ++ } ++ break; ++ default: ++ data[0] = cmd & RPC_HF_CMD_CA46 ? ++ be16_to_cpu((val >> 16) & 0xFFFF) : ++ (val >> 16) & 0xFFFF; ++ break; ++ } ++} ++ ++static void rpc_hf_wbuf_enable(struct rpc_info *rpc, u32 addr) ++{ ++ rpc_wait(rpc, RPC_TIMEOUT); ++ ++ /* ++ * RPC_PHYCNT = 0x80000277 ++ * bit31 CAL = 1 : PHY calibration ++ * bit4 WBUF2 = 1 : Write buffer enable 2 ++ * bit2 WBUF = 1 : Write buffer enable ++ * bit1-0 PHYMEM[1:0] = 11 : HyperFlash ++ */ ++ rpc_clrsetl(rpc, RPC_PHYCNT, ++ RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF | ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3), ++ RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF | ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); ++ ++ /* ++ * RPC_DRCR = 0x001F0100 ++ * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units ++ * bit9 RCF = 1 : Clear cache ++ * bit8 RBE = 1 : Read burst enable ++ */ ++ rpc_writel(rpc, RPC_DRCR, ++ RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE); ++ ++ rpc_writel(rpc, RPC_SMCMR, RPC_SMCMR_CMD(RPC_HF_CMD_WRITE_MEM)); ++ ++ rpc_writel(rpc, RPC_SMADR, addr >> 1); ++ ++ rpc_writel(rpc, RPC_SMOPR, 0x0); ++ ++ /* ++ * RPC_SMDRENR = 0x00005101 ++ * bit14-12 HYPE = 101:Hyperflash mode ++ * bit8 ADDRE = 1 : Address DDR transfer ++ * bit0 SPIDRE = 1 : DATA DDR transfer ++ */ ++ rpc_writel(rpc, RPC_SMDRENR, ++ RPC_SMDRENR_HYPE_HF | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE); ++ ++ /* ++ * RPC_SMENR = 0xA222540F ++ * bit31-30 CDB[1:0] = 10 : 4bit width command ++ * bit25-24 ADB[1:0] = 10 : 4bit width address ++ * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data ++ * bit15 DME = 0 : dummy cycle disable ++ * bit14 CDE = 1 : Command enable ++ * bit12 OCDE = 1 : Option Command enable ++ * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address) ++ * bit7-4 OPDE[3:0] = 0000 : Option data disable ++ * bit3-0 SPIDE[3:0] = 1111 : 64-bit transfer size ++ */ ++ rpc_writel(rpc, RPC_SMENR, ++ RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) | ++ RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) | ++ RPC_SMENR_CDE | RPC_SMENR_OCDE | ++ RPC_SMENR_ADE(4) | RPC_SIZE_DUAL_64BIT); ++ ++ /* Dummy read */ ++ rpc_readl(rpc, RPC_DRCR); ++} ++ ++static inline void rpc_hf_write_cmd(struct rpc_info *rpc, u32 addr, u16 cmd) ++{ ++ rpc_hf_xfer(rpc, addr, &cmd, RPC_SIZE_DUAL_16BIT, RPC_HF_CMD_WRITE_REG); ++} ++ ++static inline void rpc_hf_read_reg(struct rpc_info *rpc, u32 addr, u16 *data, ++ enum rpc_size size) ++{ ++ rpc_hf_xfer(rpc, addr, data, size, RPC_HF_CMD_READ_REG); ++} ++ ++static inline void rpc_hf_write_reg(struct rpc_info *rpc, u32 addr, u16 *data, ++ enum rpc_size size) ++{ ++ rpc_hf_xfer(rpc, addr, data, size, RPC_HF_CMD_WRITE_REG); ++} ++ ++static inline void rpc_hf_read_mem(struct rpc_info *rpc, u32 addr, u16 *data, ++ enum rpc_size size) ++{ ++ rpc_hf_xfer(rpc, addr, data, size, RPC_HF_CMD_READ_MEM); ++} ++ ++static inline void rpc_hf_write_mem(struct rpc_info *rpc, u32 addr, u16 *data, ++ enum rpc_size size) ++{ ++ rpc_hf_xfer(rpc, addr, data, size, RPC_HF_CMD_WRITE_MEM); ++} ++ ++static void rpc_hf_wp(struct rpc_info *rpc, int enable) ++{ ++ rpc_clrsetl(rpc, RPC_PHYINT, RPC_PHYINT_WP, enable ? RPC_PHYINT_WP : 0); ++} ++ ++static void rpc_hf_unlock(struct rpc_info *rpc, u32 addr) ++{ ++ rpc_hf_write_cmd(rpc, addr + RPC_CFI_UNLOCK1, ++ RPC_CFI_CMD_UNLOCK_START); ++ rpc_hf_write_cmd(rpc, addr + RPC_CFI_UNLOCK2, ++ RPC_CFI_CMD_UNLOCK_ACK); ++} ++ ++static inline int rpc_hf_status(struct rpc_info *rpc, u32 addr, ++ int iterations, int delay) ++{ ++ int ret; ++ u16 status = 0; ++ ++ while (iterations-- > 0) { ++ rpc_hf_write_cmd(rpc, addr + RPC_CFI_UNLOCK1, ++ RPC_CFI_CMD_READ_STATUS); ++ rpc_hf_read_reg(rpc, addr, &status, RPC_SIZE_DUAL_16BIT); ++ ++ if (status & RPC_CFI_STATUS_DRB) ++ break; ++ ++ if (delay < 10000) ++ usleep_range(delay, delay * 2); ++ else ++ msleep(delay / 1000); ++ } ++ ++ if (!(status & RPC_CFI_STATUS_DRB)) { ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++ if (status & (RPC_CFI_STATUS_PSB | RPC_CFI_STATUS_ESB)) { ++ ret = -EIO; ++ goto out; ++ } ++ ++ return 0; ++ ++out: ++ /* Reset the flash */ ++ rpc_hf_write_cmd(rpc, 0, RPC_CFI_CMD_RESET); ++ return ret; ++} ++ ++static int rpc_hf_sector_erase(struct rpc_info *rpc, u32 addr) ++{ ++ rpc_hf_unlock(rpc, addr); ++ rpc_hf_write_cmd(rpc, addr + RPC_CFI_UNLOCK1, RPC_CFI_CMD_ERASE_START); ++ rpc_hf_unlock(rpc, addr); ++ rpc_hf_write_cmd(rpc, addr, RPC_CFI_CMD_ERASE_SECTOR); ++ ++ return rpc_hf_status(rpc, addr, 1000, 10000); ++} ++ ++/* Flash read */ ++static int rpc_hf_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, ++ size_t *retlen, u_char *buf) ++{ ++ struct rpc_hf_info *hf = mtd->priv; ++ struct rpc_info *rpc = hf->priv; ++ ++ mutex_lock(&hf->lock); ++ rpc_do_read_flash(rpc, from, len, buf, mtd->size > RPC_READ_ADDR_SIZE); ++ mutex_unlock(&hf->lock); ++ ++ *retlen = len; ++ return 0; ++} ++ ++/* Flash erase */ ++static int rpc_hf_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct rpc_hf_info *hf = mtd->priv; ++ struct rpc_info *rpc = hf->priv; ++ u32 addr, end; ++ int ret = 0; ++ ++ if (mtd_mod_by_eb(instr->addr, mtd)) { ++ dev_dbg(mtd->dev.parent, "%s: unaligned address\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (mtd_mod_by_eb(instr->len, mtd)) { ++ dev_dbg(mtd->dev.parent, "%s: unaligned length\n", __func__); ++ return -EINVAL; ++ } ++ ++ end = instr->addr + instr->len; ++ ++ mutex_lock(&hf->lock); ++ for (addr = instr->addr; addr < end; addr += mtd->erasesize) { ++ ret = rpc_hf_sector_erase(rpc, addr); ++ ++ if (ret) ++ break; ++ } ++ ++ rpc_hf_mode_ext(rpc); ++ mutex_unlock(&hf->lock); ++ ++ instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE; ++ mtd_erase_callback(instr); ++ ++ return ret; ++} ++ ++/* Copy memory to flash */ ++static int rpc_hf_mtd_write(struct mtd_info *mtd, loff_t offset, size_t len, ++ size_t *retlen, const u_char *src) ++{ ++ struct rpc_hf_info *hf = mtd->priv; ++ struct rpc_info *rpc = hf->priv; ++ union { ++ u8 b[4]; ++ u16 w[2]; ++ u32 d; ++ } data; ++ loff_t addr; ++ size_t size, cnt; ++ int ret, idx; ++ u8 last; ++ ++ ret = 0; ++ *retlen = 0; ++ cnt = len; ++ idx = 0; ++ ++ mutex_lock(&hf->lock); ++ ++ /* Handle unaligned start */ ++ if (offset & 0x1) { ++ offset--; ++ data.b[idx] = readb(rpc->read_area + offset); ++ idx++; ++ } ++ ++ /* Handle unaligned end */ ++ addr = offset + idx + len; ++ last = addr & 0x1 ? readb(rpc->read_area + addr) : 0xFF; ++ ++ addr = offset - mtd_mod_by_eb(offset, mtd); ++ size = mtd->erasesize - (offset - addr); ++ ++ while (cnt) { ++ if (size > cnt) ++ size = cnt; ++ ++ cnt -= size; ++ while (size) { ++ rpc_hf_unlock(rpc, addr); ++ rpc_hf_write_cmd(rpc, ++ addr + RPC_CFI_UNLOCK1, ++ RPC_CFI_CMD_WRITE); ++ ++ if (rpc_wbuf_available(rpc) && (size > 0x7)) { ++ u32 wbuf = 0; ++ int block = size >= RPC_WBUF_SIZE ? ++ RPC_WBUF_SIZE : size & ~0x7; ++ ++ rpc_hf_wbuf_enable(rpc, offset); ++ offset += block; ++ ++ block >>= 3; ++ while (block--) { ++ while (idx < 4) { ++ data.b[idx++] = *src++; ++ size--; ++ } ++ rpc_wbuf_writel(rpc, wbuf, data.d); ++ wbuf += 4; ++ ++ idx = 0; ++ while (idx < 4) { ++ data.b[idx++] = *src++; ++ size--; ++ } ++ rpc_wbuf_writel(rpc, wbuf, data.d); ++ wbuf += 4; ++ ++ idx = 0; ++ } ++ ++ rpc_writel(rpc, RPC_SMCR, ++ RPC_SMCR_SPIWE | RPC_SMCR_SPIE); ++ } else { ++ enum rpc_size bits; ++ ++ while (idx < 4) { ++ data.b[idx++] = *src++; ++ size--; ++ ++ if (!size) ++ break; ++ } ++ ++ if (idx & 0x1) ++ data.b[idx++] = last; ++ ++ switch (idx) { ++ case 2: ++ bits = RPC_SIZE_DUAL_16BIT; ++ break; ++ default: ++ bits = RPC_SIZE_DUAL_32BIT; ++ break; ++ } ++ ++ rpc_hf_write_mem(rpc, offset, data.w, bits); ++ offset += idx; ++ idx = 0; ++ } ++ ++ ret = rpc_hf_status(rpc, addr, 1000000, 10); ++ if (ret) ++ goto out; ++ } ++ ++ size = mtd->erasesize; ++ addr += size; ++ offset = addr; ++ *retlen = len - cnt; ++ } ++ ++out: ++ rpc_hf_mode_ext(rpc); ++ mutex_unlock(&hf->lock); ++ return ret; ++} ++ ++static int rpc_hf_hw_init(struct rpc_info *rpc, u32 *id, u32 *size) ++{ ++ u16 data[2] = { 0, 0 }; ++ u32 sz; ++ int ret = 0; ++ ++ rpc_hf_mode_ext(rpc); ++ ++ rpc_hf_wp(rpc, 0); ++ ++ rpc_hf_unlock(rpc, 0); ++ rpc_hf_write_cmd(rpc, RPC_CFI_UNLOCK1, RPC_CFI_CMD_READ_ID); ++ ++ rpc_hf_read_reg(rpc, 0x0, data, RPC_SIZE_DUAL_32BIT); ++ if ((data[0] & RPC_CFI_ID_MASK) != RPC_CFI_ID_MAN_SPANSION || ++ (data[1] & RPC_CFI_ID_MASK) != RPC_CFI_ID_TYPE_HYPERFLASH) { ++ ret = -ENXIO; ++ goto out; ++ } ++ ++ if (id) ++ *id = data[0] | data[1] << 16; ++ ++ rpc_hf_read_reg(rpc, 0x27 << 1, data, RPC_SIZE_DUAL_16BIT); ++ sz = 1 << data[0]; ++ ++ if (sz & (RPC_HF_ERASE_SIZE - 1)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (size) ++ *size = sz; ++out: ++ rpc_hf_write_cmd(rpc, 0, RPC_CFI_CMD_RESET); ++ rpc_hf_mode_ext(rpc); ++ return ret; ++} ++ ++int rpc_hf_probe(struct platform_device *pdev) ++{ ++ struct rpc_info *rpc; ++ struct rpc_hf_info *hf; ++ struct mtd_info *mtd; ++ u32 flash_id, flash_size; ++ int ret; ++ ++ rpc = dev_get_drvdata(pdev->dev.parent); ++ if (!rpc) { ++ dev_err(&pdev->dev, "invalid data\n"); ++ return -EINVAL; ++ } ++ ++ hf = devm_kzalloc(&pdev->dev, sizeof(*hf), GFP_KERNEL); ++ if (!hf) { ++ dev_err(&pdev->dev, "allocation failed\n"); ++ return -ENOMEM; ++ } ++ ++ mutex_init(&hf->lock); ++ mtd_set_of_node(&hf->mtd, rpc->flash); ++ hf->priv = rpc; ++ ++ ret = clk_prepare_enable(rpc->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot prepare clock\n"); ++ return ret; ++ } ++ ++ ret = rpc_hf_hw_init(rpc, &flash_id, &flash_size); ++ if (ret) { ++ dev_err(&pdev->dev, "initialization failed\n"); ++ goto error; ++ } ++ ++ mtd = &hf->mtd; ++ mtd->name = "HyperFlash"; ++ mtd->dev.parent = &pdev->dev; ++ mtd->type = MTD_NORFLASH; ++ mtd->flags = MTD_CAP_NORFLASH; ++ mtd->size = flash_size; ++ mtd->writesize = 1; ++ mtd->writebufsize = RPC_WBUF_SIZE; ++ mtd->erasesize = RPC_HF_ERASE_SIZE; ++ mtd->owner = THIS_MODULE; ++ mtd->priv = hf; ++ mtd->_erase = rpc_hf_mtd_erase; ++ mtd->_write = rpc_hf_mtd_write; ++ mtd->_read = rpc_hf_mtd_read; ++ ++ ret = mtd_device_register(mtd, NULL, 0); ++ if (ret) { ++ dev_err(&pdev->dev, "MTD registration failed\n"); ++ goto error; ++ } ++ ++ platform_set_drvdata(pdev, hf); ++ dev_info(&pdev->dev, "probed flash id:%x\n", flash_id); ++ return 0; ++ ++error: ++ clk_disable_unprepare(rpc->clk); ++ return ret; ++} ++ ++static int rpc_hf_remove(struct platform_device *pdev) ++{ ++ struct rpc_hf_info *hf = platform_get_drvdata(pdev); ++ struct rpc_info *rpc = hf->priv; ++ ++ mtd_device_unregister(&hf->mtd); ++ clk_disable_unprepare(rpc->clk); ++ return 0; ++} ++ ++/* platform driver interface */ ++static struct platform_driver rpc_hf_platform_driver = { ++ .probe = rpc_hf_probe, ++ .remove = rpc_hf_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "renesas-rpc-hyperflash", ++ }, ++}; ++ ++module_platform_driver(rpc_hf_platform_driver); ++ ++MODULE_ALIAS("renesas-rpc-hyperflash"); ++MODULE_AUTHOR("Cogent Embedded Inc. <sources@cogentembedded.com>"); ++MODULE_DESCRIPTION("Renesas RPC HyperFlash Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mtd/spi-nor/renesas-rpc-qspi.c b/drivers/mtd/spi-nor/renesas-rpc-qspi.c +new file mode 100644 +index 0000000..3d2d5db +--- /dev/null ++++ b/drivers/mtd/spi-nor/renesas-rpc-qspi.c +@@ -0,0 +1,794 @@ ++/* ++ * Renesas RPC QSPI driver ++ * ++ * Copyright (C) 2019, Cogent Embedded Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/spi-nor.h> ++ ++#include "renesas-rpc.h" ++ ++static void rpc_endisable_write_buf(struct rpc_info *rpc, bool en) ++{ ++ rpc_clrsetl(rpc, RPC_PHYCNT, ++ RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2, ++ en ? RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 : 0); ++} ++ ++static int rpc_begin(struct rpc_info *rpc, ++ bool rx, bool tx, bool last) ++{ ++ u32 val = RPC_SMCR_SPIE; ++ ++ if (rx) ++ val |= RPC_SMCR_SPIRE; ++ ++ if (tx) ++ val |= RPC_SMCR_SPIWE; ++ ++ if (!last) ++ val |= RPC_SMCR_SSLKP; ++ ++ rpc_writel(rpc, RPC_SMCR, val); ++ ++ return 0; ++} ++ ++static int rpc_setup_reg_mode(struct rpc_info *rpc) ++{ ++ rpc_wait(rpc, RPC_TIMEOUT); ++ ++ rpc_endisable_write_buf(rpc, false); ++ ++ /* ...setup manual mode */ ++ rpc_clrsetl(rpc, RPC_CMNCR, 0, RPC_CMNCR_MD); ++ ++ /* disable ddr */ ++ rpc_clrsetl(rpc, RPC_SMDRENR, ++ RPC_SMDRENR_ADDRE | RPC_SMDRENR_OPDRE | RPC_SMDRENR_SPIDRE, ++ 0); ++ ++ /* enable 1bit command */ ++ rpc_clrsetl(rpc, RPC_SMENR, ++ RPC_SMENR_CDB(3) | RPC_SMENR_OCDB(3) | RPC_SMENR_DME | ++ RPC_SMENR_OCDE | RPC_SMENR_SPIDB(3) | ++ RPC_SMENR_ADE(0xF) | RPC_SMENR_ADB(3) | ++ RPC_SMENR_OPDE(0xF) | RPC_SMENR_SPIDE(0xF), ++ RPC_SMENR_CDB(0) | RPC_SMENR_CDE | RPC_SIZE_SINGLE_32BIT); ++ ++ return 0; ++} ++ ++static inline void rpc_flush_cache(struct rpc_info *rpc) ++{ ++ rpc_clrsetl(rpc, RPC_DRCR, 0, RPC_DRCR_RCF); ++} ++ ++static int rpc_setup_ext_mode(struct rpc_info *rpc) ++{ ++ u32 val; ++ u32 cmncr; ++ ++ rpc_wait(rpc, RPC_TIMEOUT); ++ ++ rpc_endisable_write_buf(rpc, false); ++ ++ /* ...setup ext mode */ ++ val = rpc_readl(rpc, RPC_CMNCR); ++ cmncr = val; ++ val &= ~(RPC_CMNCR_MD); ++ rpc_writel(rpc, RPC_CMNCR, val); ++ ++ /* ...enable burst and clear cache */ ++ val = rpc_readl(rpc, RPC_DRCR); ++ val &= ~(RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RBE | RPC_DRCR_SSLE); ++ val |= RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RBE; ++ ++ if (cmncr & RPC_CMNCR_MD) ++ val |= RPC_DRCR_RCF; ++ ++ rpc_writel(rpc, RPC_DRCR, val); ++ ++ return 0; ++} ++ ++static int rpc_setup_data_size(struct rpc_info *rpc, u32 size, bool copy) ++{ ++ u32 val; ++ ++ val = rpc_readl(rpc, RPC_SMENR); ++ val &= ~(RPC_SMENR_SPIDE(0xF)); ++ ++ if (rpc->mtdtype == RPC_DUAL && !copy) ++ size >>= 1; ++ ++ switch (size) { ++ case 0: ++ break; ++ case 1: ++ val |= RPC_SIZE_SINGLE_8BIT; ++ break; ++ case 2: ++ val |= RPC_SIZE_SINGLE_16BIT; ++ break; ++ case 4: ++ val |= RPC_SIZE_SINGLE_32BIT; ++ break; ++ default: ++ dev_err(&rpc->pdev->dev, "Unsupported data width %d\n", size); ++ return -EINVAL; ++ } ++ rpc_writel(rpc, RPC_SMENR, val); ++ ++ return 0; ++} ++ ++static inline int rpc_get_read_addr_nbits(u8 opcode) ++{ ++ if (opcode == SPINOR_OP_READ_1_4_4_4B) ++ return 4; ++ return 1; ++} ++ ++#define RPC_NBITS_TO_VAL(v) ((v >> 1) & 3) ++static void rpc_setup_extmode_nbits(struct rpc_info *rpc, ++ int cnb, int anb, int dnb) ++{ ++ rpc_clrsetl(rpc, RPC_DRENR, ++ RPC_DRENR_CDB(3) | RPC_DRENR_ADB(3) | RPC_DRENR_DRDB(3), ++ RPC_DRENR_CDB(RPC_NBITS_TO_VAL(cnb)) | ++ RPC_DRENR_ADB(RPC_NBITS_TO_VAL(anb)) | ++ RPC_DRENR_DRDB(RPC_NBITS_TO_VAL(dnb))); ++} ++ ++static void rpc_setup_writemode_nbits(struct rpc_info *rpc, ++ int cnb, int anb, int dnb) ++{ ++ rpc_clrsetl(rpc, RPC_SMENR, ++ RPC_SMENR_CDB(3) | RPC_SMENR_ADB(3) | RPC_SMENR_SPIDB(3), ++ RPC_SMENR_CDB(RPC_NBITS_TO_VAL(cnb)) | ++ RPC_SMENR_ADB(RPC_NBITS_TO_VAL(anb)) | ++ RPC_SMENR_SPIDB(RPC_NBITS_TO_VAL(dnb))); ++} ++ ++static void rpc_setup_write_mode_command_and_adr(struct rpc_info *rpc, ++ int adr_width, bool ena) ++{ ++ u32 val; ++ ++ val = rpc_readl(rpc, RPC_SMENR); ++ val &= ~(RPC_SMENR_CDB(3) | RPC_SMENR_CDE | RPC_SMENR_ADE(0xF)); ++ ++ if (ena) { ++ /* enable 1bit command */ ++ val |= RPC_SMENR_CDB(0) | RPC_SMENR_CDE; ++ ++ if (adr_width == 4) ++ val |= RPC_SMENR_ADE(0xF); /* bits 31-0 */ ++ else ++ val |= RPC_SMENR_ADE(0x7); /* bits 23-0 */ ++ } ++ rpc_writel(rpc, RPC_SMENR, val); ++} ++ ++static void rpc_setup_write_mode(struct rpc_info *rpc, u8 opcode) ++{ ++ rpc_wait(rpc, RPC_TIMEOUT); ++ ++ rpc_endisable_write_buf(rpc, true); ++ ++ /* ...setup manual mode */ ++ rpc_clrsetl(rpc, RPC_CMNCR, 0, RPC_CMNCR_MD); ++ ++ /* disable ddr */ ++ rpc_clrsetl(rpc, RPC_SMDRENR, ++ RPC_SMDRENR_ADDRE | RPC_SMDRENR_OPDRE | RPC_SMDRENR_SPIDRE, ++ 0); ++ ++ rpc_clrsetl(rpc, RPC_SMENR, ++ RPC_SMENR_OCDB(3) | RPC_SMENR_DME | RPC_SMENR_OCDE | ++ RPC_SMENR_SPIDB(3) | RPC_SMENR_ADB(3) | ++ RPC_SMENR_OPDE(0xF) | RPC_SMENR_SPIDE(0xF), ++ opcode != SPINOR_OP_PP ? RPC_SIZE_SINGLE_32BIT : ++ RPC_SIZE_SINGLE_8BIT); ++} ++ ++static void rpc_read_manual_data(struct rpc_info *rpc, u32 *pv0, u32 *pv1) ++{ ++ u32 val0, val1, rd0, rd1; ++ ++ val0 = rpc_readl(rpc, RPC_SMRDR0); ++ val1 = rpc_readl(rpc, RPC_SMRDR1); ++ ++ if (rpc->mtdtype == RPC_DUAL) { ++ rd1 = (val0 & 0xFf000000) | ((val0 << 8) & 0xFf0000) | ++ ((val1 >> 16) & 0xff00) | ((val1 >> 8) & 0xff); ++ rd0 = ((val0 & 0xff0000) << 8) | ((val0 << 16) & 0xff0000) | ++ ((val1 >> 8) & 0xff00) | (val1 & 0xff); ++ } else ++ rd0 = val0; ++ ++ if (pv0) ++ *pv0 = rd0; ++ ++ if (pv1 && rpc->mtdtype == RPC_DUAL) ++ *pv1 = rd1; ++} ++ ++static int rpc_datalen2trancfersize(struct rpc_info *rpc, int len, bool copy) ++{ ++ int sz = len; ++ ++ if (len >= 2) ++ sz = 2; ++ ++ if (len >= 4) ++ sz = 4; ++ ++ if (rpc->mtdtype == RPC_DUAL && len >= 8 && !copy) ++ sz = 8; ++ ++ return sz; ++} ++ ++static int __rpc_write_data2reg(struct rpc_info *rpc, int off, ++ const u8 *buf, int sz) ++{ ++ const u32 *b32 = (const u32 *)buf; ++ const u16 *b16 = (const u16 *)buf; ++ ++ if (sz == 4) ++ rpc_writel(rpc, off, *b32); ++ else if (sz == 2) ++ writew(*b16, rpc->base + off); ++ else if (sz == 1) ++ writeb(*buf, rpc->base + off); ++ else if (sz != 0) { ++ dev_err(&rpc->pdev->dev, "incorrect data size %d\n", sz); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++#define RPC_SETVAL(x) ((((x) & 0xff) << 8) | ((x) & 0xff)) ++static int rpc_write_data2reg(struct rpc_info *rpc, const u8 *buf, ++ int sz, bool copy) ++{ ++ int i, ret; ++ u32 v = 0; ++ ++ if (rpc->mtdtype == RPC_DUAL) { ++ if (copy) { ++ for (i = 0; i < sz && i < 2; i++) ++ v |= (RPC_SETVAL(buf[i]) << 16*i); ++ ++ ret = __rpc_write_data2reg(rpc, ++ sz == 4 ? RPC_SMWDR1 : RPC_SMWDR0, ++ (u8 *)&v, ++ sz == 4 ? sz : sz * 2); ++ if (ret) ++ return ret; ++ ++ v = 0; ++ for (; i < sz; i++) ++ v |= (RPC_SETVAL(buf[i]) << 16*i); ++ ++ ++ ret = __rpc_write_data2reg(rpc, ++ sz == 4 ? RPC_SMWDR0 : RPC_SMWDR1, ++ (u8 *)&v, ++ sz == 4 ? sz : sz * 2); ++ if (ret) ++ return ret; ++ ++ return 0; ++ } ++ ++ sz >>= 1; ++ ret = __rpc_write_data2reg(rpc, ++ sz == 4 ? RPC_SMWDR1 : RPC_SMWDR0, ++ buf, ++ sz == 4 ? sz : sz * 2); ++ if (ret) ++ return ret; ++ buf += sz; ++ ++ return __rpc_write_data2reg(rpc, ++ sz == 4 ? RPC_SMWDR0 : RPC_SMWDR1, ++ buf, sz == 4 ? sz : sz * 2); ++ } ++ ++ return __rpc_write_data2reg(rpc, RPC_SMWDR0, buf, sz); ++} ++ ++static ssize_t rpc_write_unaligned(struct spi_nor *nor, loff_t to, size_t len, ++ const u_char *buf, size_t fullen) ++{ ++ int ret = len, dsize; ++ struct rpc_info *rpc = nor->priv; ++ bool copy = false, last; ++ loff_t _to; ++ ++ rpc_endisable_write_buf(rpc, false); ++ ++ while (len > 0) { ++ _to = to; ++ if (rpc->mtdtype == RPC_DUAL) ++ _to >>= 1; ++ rpc_writel(rpc, RPC_SMADR, _to); ++ dsize = rpc_datalen2trancfersize(rpc, len, copy); ++ ++ if (rpc_setup_data_size(rpc, dsize, copy)) ++ return -EINVAL; ++ ++ rpc_write_data2reg(rpc, buf, dsize, copy); ++ ++ last = (len <= dsize && fullen <= ret); ++ rpc_begin(rpc, false, true, last); ++ if (rpc_wait(rpc, RPC_TIMEOUT)) ++ return -ETIMEDOUT; ++ ++ /* ...disable command */ ++ rpc_setup_write_mode_command_and_adr(rpc, ++ nor->addr_width, false); ++ ++ buf += dsize; ++ len -= dsize; ++ to += dsize; ++ } ++ ++ return ret; ++} ++ ++static ssize_t rpc_write_flash(struct spi_nor *nor, loff_t to, size_t len, ++ const u_char *buf) ++{ ++ ssize_t res = len, full = len; ++ u32 val; ++ u8 rval[2]; ++ struct rpc_info *rpc = nor->priv; ++ loff_t bo; ++ loff_t offset; ++ bool is_rounded = false; ++ ++ /* ...len should be rounded to 2 bytes */ ++ if (rpc->mtdtype == RPC_DUAL && (len & 1)) { ++ is_rounded = true; ++ len &= ~(1); ++ } ++ ++ bo = to & RPC_WBUF_MASK; ++ ++ rpc_flush_cache(rpc); ++ rpc_setup_write_mode(rpc, nor->program_opcode); ++ rpc_setup_write_mode_command_and_adr(rpc, nor->addr_width, true); ++ rpc_setup_writemode_nbits(rpc, 1, 1, 1); ++ ++ /* ...setup command */ ++ val = rpc_readl(rpc, RPC_SMCMR); ++ val &= ~RPC_SMCMR_CMD(0xFF); ++ val |= RPC_SMCMR_CMD(nor->program_opcode); ++ rpc_writel(rpc, RPC_SMCMR, val); ++ ++ offset = to & ~RPC_WBUF_MASK; ++ ++ /* ...write unaligned first bytes */ ++ if (bo) { ++ size_t min = (len < (RPC_WBUF_SIZE - bo)) ? len : (RPC_WBUF_SIZE - bo); ++ ++ rpc_write_unaligned(nor, to, min, buf, full); ++ rpc_setup_write_mode(rpc, nor->program_opcode); ++ ++ len -= min; ++ buf += min; ++ to += min; ++ full -= min; ++ } ++ ++ /* ++ * TODO: Unfortunately RPC does not write properly in write buf mode ++ * without transferring command. Investigate this. ++ */ ++ ++ if (len) { ++ rpc_write_unaligned(nor, to, len, buf, full); ++ buf += len; ++ to += len; ++ full -= len; ++ len = 0; ++ } ++ ++ if (is_rounded) { ++ rval[0] = *buf; ++ rval[1] = 0xFF; ++ rpc_write_unaligned(nor, to, 2, rval, full); ++ } ++ ++ rpc_flush_cache(rpc); ++ ++ return res; ++} ++ ++static inline unsigned int rpc_rx_nbits(struct spi_nor *nor) ++{ ++ return spi_nor_get_protocol_data_nbits(nor->read_proto); ++} ++ ++static ssize_t rpc_read_flash(struct spi_nor *nor, loff_t from, size_t len, ++ u_char *buf) ++{ ++ u32 val; ++ struct rpc_info *rpc = nor->priv; ++ int opcode_nbits = 1; ++ int addr_nbits = rpc_get_read_addr_nbits(nor->read_opcode); ++ int data_nbits = rpc_rx_nbits(nor); ++ int dummy = nor->read_dummy - 1; ++ ssize_t ret = len; ++ ++ rpc_setup_ext_mode(rpc); ++ /* ...setup n bits */ ++ rpc_setup_extmode_nbits(rpc, opcode_nbits, addr_nbits, data_nbits); ++ ++ /* TODO: setup DDR */ ++ ++ /* ...setup command */ ++ val = rpc_readl(rpc, RPC_DRCMR); ++ val &= ~RPC_DRCMR_CMD(0xFF); ++ val |= RPC_DRCMR_CMD(nor->read_opcode); ++ rpc_writel(rpc, RPC_DRCMR, val); ++ ++ /* ...setup dummy cycles */ ++ val = rpc_readl(rpc, RPC_DRDMCR); ++ val &= ~RPC_DRDMCR_DMCYC(0x1F); ++ val |= RPC_DRDMCR_DMCYC(dummy); ++ rpc_writel(rpc, RPC_DRDMCR, val); ++ ++ /* ...setup read sequence */ ++ val = rpc_readl(rpc, RPC_DRENR); ++ val |= RPC_DRENR_DME | RPC_DRENR_CDE; ++ rpc_writel(rpc, RPC_DRENR, val); ++ ++ rpc_do_read_flash(rpc, from, len, buf, nor->addr_width > 3); ++ ++ return ret; ++} ++ ++static int __rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) ++{ ++ u32 val; ++ u32 val2 = 0; ++ u32 *buf32; ++ int i; ++ u32 mask = 0, type; ++ struct rpc_info *rpc = nor->priv; ++ ++ type = rpc->mtdtype; ++ ++ rpc_setup_reg_mode(rpc); ++ val = rpc_readl(rpc, RPC_SMCMR); ++ val &= ~RPC_SMCMR_CMD(0xFF); ++ val |= RPC_SMCMR_CMD(opcode); ++ rpc_writel(rpc, RPC_SMCMR, val); ++ ++ rpc_begin(rpc, true, false, len <= 4); ++ if (rpc_wait(rpc, RPC_TIMEOUT)) ++ return -ETIMEDOUT; ++ ++ /* ...disable command */ ++ val = rpc_readl(rpc, RPC_SMENR); ++ val &= ~(RPC_SMENR_CDE); ++ rpc_writel(rpc, RPC_SMENR, val); ++ ++ buf32 = (u32 *)buf; ++ ++ while (len > 0) { ++ rpc_read_manual_data(rpc, &val, &val2); ++ ++ if (mask) { ++ dev_warn(&rpc->pdev->dev, ++ "Using mask workaround (0x%x)\n", mask); ++ val &= ~(mask); ++ val2 &= ~(mask); ++ } ++ ++ /* ... spi flashes should be the same */ ++ if (type == RPC_DUAL && val != val2) { ++ /* clear cs */ ++ rpc_begin(rpc, true, false, true); ++ return -EAGAIN; ++ } ++ ++ if (len > 4) { ++ *buf32 = val; ++ buf32++; ++ len -= 4; ++ } else { ++ buf = (u8 *)buf32; ++ for (i = 0; i < len; i++) { ++ *buf = (val >> (8 * i)) & 0x000000ff; ++ buf++; ++ } ++ len = 0; ++ } ++ ++ if (!len) ++ break; ++ ++ mask = 0xff; ++ ++ rpc_begin(rpc, true, false, len <= 4); ++ if (rpc_wait(rpc, RPC_TIMEOUT)) ++ return -ETIMEDOUT; ++ ++ } ++ ++ return 0; ++} ++ ++#define RPC_REPEAT_TIMEOUT 200 ++static int rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) ++{ ++ unsigned long end = jiffies + msecs_to_jiffies(RPC_REPEAT_TIMEOUT); ++ ++ /* A few read commands like read status can ++ * generate different answers. We repeat reading ++ * in that case ++ */ ++ while (true) { ++ int ret = __rpc_read_reg(nor, opcode, buf, len); ++ ++ if (!ret || ret != -EAGAIN) ++ return ret; ++ ++ if (time_after(jiffies, end)) ++ return -ETIMEDOUT; ++ ++ msleep(20); ++ } ++} ++ ++static int rpc_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) ++{ ++ struct rpc_info *rpc = nor->priv; ++ u32 val; ++ int dsize; ++ bool copy = true; ++ ++ rpc_setup_reg_mode(rpc); ++ ++ val = rpc_readl(rpc, RPC_SMCMR); ++ val &= ~RPC_SMCMR_CMD(0xFF); ++ val |= RPC_SMCMR_CMD(opcode); ++ rpc_writel(rpc, RPC_SMCMR, val); ++ ++ dsize = rpc_datalen2trancfersize(rpc, len, copy); ++ ++ if (rpc_setup_data_size(rpc, dsize, copy)) ++ return -EINVAL; ++ ++ if (rpc_write_data2reg(rpc, buf, dsize, copy)) ++ return -EINVAL; ++ buf += dsize; ++ len -= dsize; ++ rpc_begin(rpc, false, dsize > 0, len == 0); ++ ++ if (rpc_wait(rpc, RPC_TIMEOUT)) ++ return -ETIMEDOUT; ++ ++ /* ...disable command */ ++ val = rpc_readl(rpc, RPC_SMENR); ++ val &= ~(RPC_SMENR_CDE); ++ rpc_writel(rpc, RPC_SMENR, val); ++ ++ while (len > 0) { ++ dsize = rpc_datalen2trancfersize(rpc, len, copy); ++ if (rpc_setup_data_size(rpc, dsize, copy)) ++ return -EINVAL; ++ rpc_write_data2reg(rpc, buf, dsize, copy); ++ buf += dsize; ++ len -= dsize; ++ ++ rpc_begin(rpc, false, dsize, len == 0); ++ ++ if (rpc_wait(rpc, RPC_TIMEOUT)) ++ return -ETIMEDOUT; ++ ++ } ++ ++ return 0; ++} ++ ++/* hw init for spi-nor flashes */ ++static int rpc_spi_hw_init(struct rpc_info *rpc) ++{ ++ /* Exec calibration */ ++ rpc_clrsetl(rpc, RPC_PHYCNT, ++ RPC_PHYCNT_OCTA(3) | RPC_PHYCNT_EXDS | RPC_PHYCNT_OCT | ++ RPC_PHYCNT_DDRCAL | RPC_PHYCNT_HS | RPC_PHYCNT_STRTIM(7) | ++ RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF | RPC_PHYCNT_MEM(3), ++ RPC_PHYCNT_CAL | RPC_PHYCNT_STRTIM(6)); ++ ++ /* Disable RPC pins */ ++ rpc_clrsetl(rpc, RPC_PHYINT, ++ RPC_PHYINT_INTIE | RPC_PHYINT_RSTEN | ++ RPC_PHYINT_WPEN | RPC_PHYINT_INTEN, ++ 0); ++ ++ rpc_clrsetl(rpc, RPC_SMDRENR, ++ RPC_SMDRENR_HYPE(7), ++ RPC_SMDRENR_HYPE_SPI); ++ ++ rpc_clrsetl(rpc, RPC_CMNCR, ++ RPC_CMNCR_BSZ(3), ++ rpc->mtdtype != RPC_SINGLE ? ++ RPC_CMNCR_BSZ(1) : ++ RPC_CMNCR_BSZ(0)); ++ ++ rpc_clrsetl(rpc, RPC_PHYOFFSET1, ++ RPC_PHYOFFSET1_DDRTMG(3), ++ RPC_PHYOFFSET1_DDRTMG_SDR); ++ ++ rpc_writel(rpc, RPC_SSLDR, ++ RPC_SSLDR_SPNDL(0) | RPC_SSLDR_SLNDL(4) | ++ RPC_SSLDR_SCKDL(0)); ++ ++ return 0; ++} ++ ++static int rpc_erase_sector(struct spi_nor *nor, loff_t addr) ++{ ++ struct rpc_info *rpc = nor->priv; ++ u8 buf[6]; ++ int i; ++ ++ if (rpc->mtdtype == RPC_DUAL) ++ addr >>= 1; ++ ++ for (i = nor->addr_width - 1; i >= 0; i--) { ++ buf[i] = addr & 0xff; ++ addr >>= 8; ++ } ++ ++ return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); ++} ++ ++int rpc_qspi_probe(struct platform_device *pdev) ++{ ++ struct rpc_info *rpc; ++ struct spi_nor *nor; ++ struct spi_nor_hwcaps hwcaps = { ++ .mask = SNOR_HWCAPS_READ | ++ SNOR_HWCAPS_READ_FAST | ++ SNOR_HWCAPS_PP, ++ }; ++ u32 property; ++ int ret; ++ ++ rpc = dev_get_drvdata(pdev->dev.parent); ++ if (!rpc || !rpc->flash) { ++ dev_err(&pdev->dev, "invalid data\n"); ++ return -EINVAL; ++ } ++ ++ if (!of_property_read_u32(rpc->flash, "spi-rx-bus-width", &property)) { ++ switch (property) { ++ case 1: ++ break; ++ case 2: ++ hwcaps.mask |= SNOR_HWCAPS_READ_DUAL; ++ break; ++ case 4: ++ hwcaps.mask |= SNOR_HWCAPS_READ_QUAD; ++ break; ++ default: ++ dev_err(&pdev->dev, "unsupported rx-bus-width\n"); ++ return -EINVAL; ++ } ++ } ++ ++ /* ... setup nor hooks */ ++ nor = devm_kzalloc(&pdev->dev, sizeof(*nor), GFP_KERNEL); ++ if (!nor) { ++ dev_err(&pdev->dev, "allocation failed\n"); ++ return -ENOMEM; ++ } ++ ++ nor->dev = &pdev->dev; ++ spi_nor_set_flash_node(nor, rpc->flash); ++ nor->read = rpc_read_flash; ++ nor->write = rpc_write_flash; ++ nor->read_reg = rpc_read_reg; ++ nor->write_reg = rpc_write_reg; ++ nor->priv = rpc; ++ ++ /* ... enable clk */ ++ ret = clk_prepare_enable(rpc->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot prepare clock\n"); ++ return ret; ++ } ++ ++ /* ...init device */ ++ ret = rpc_spi_hw_init(rpc); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "rpc_spi_hw_init error.\n"); ++ goto error; ++ } ++ ++ ret = spi_nor_scan(nor, NULL, &hwcaps); ++ if (ret) { ++ dev_err(&pdev->dev, "spi_nor_scan error.\n"); ++ goto error; ++ } ++ ++ /* Dual mode support */ ++ if (rpc->mtdtype == RPC_DUAL) { ++ nor->page_size <<= 1; ++ nor->mtd.erasesize <<= 1; ++ nor->mtd.size <<= 1; ++ nor->mtd.writebufsize <<= 1; ++ nor->erase = rpc_erase_sector; ++ } ++ ++ /* Workaround data size limitation */ ++ if (nor->page_size > RPC_WBUF_SIZE) { ++ nor->page_size = RPC_WBUF_SIZE; ++ nor->mtd.writebufsize = RPC_WBUF_SIZE; ++ } ++ ++ ret = mtd_device_register(&nor->mtd, NULL, 0); ++ if (ret) { ++ dev_err(&pdev->dev, "MTD registration failed\n"); ++ goto error; ++ } ++ ++ dev_info(&pdev->dev, "probed as %s\n", ++ rpc->mtdtype == RPC_SINGLE ? "single" : "dual"); ++ ++ platform_set_drvdata(pdev, nor); ++ return 0; ++ ++error: ++ clk_disable_unprepare(rpc->clk); ++ return ret; ++} ++ ++static int rpc_qspi_remove(struct platform_device *pdev) ++{ ++ struct spi_nor *nor = platform_get_drvdata(pdev); ++ struct rpc_info *rpc = nor->priv; ++ ++ mtd_device_unregister(&nor->mtd); ++ clk_disable_unprepare(rpc->clk); ++ return 0; ++} ++ ++/* platform driver interface */ ++static struct platform_driver rpc_qspi_platform_driver = { ++ .probe = rpc_qspi_probe, ++ .remove = rpc_qspi_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "renesas-rpc-qspi", ++ }, ++}; ++ ++module_platform_driver(rpc_qspi_platform_driver); ++ ++MODULE_ALIAS("renesas-rpc-qspi"); ++MODULE_AUTHOR("Cogent Embedded Inc. <sources@cogentembedded.com>"); ++MODULE_DESCRIPTION("Renesas RPC QSPI Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mtd/spi-nor/renesas-rpc.c b/drivers/mtd/spi-nor/renesas-rpc.c +index 0026b99..3aea0ae 100644 +--- a/drivers/mtd/spi-nor/renesas-rpc.c ++++ b/drivers/mtd/spi-nor/renesas-rpc.c +@@ -1,7 +1,7 @@ + /* + * Renesas RPC driver + * +- * Copyright (C) 2018, Cogent Embedded Inc. ++ * Copyright (C) 2019, Cogent Embedded Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -13,268 +13,28 @@ + * GNU General Public License for more details. + */ + +-#include <linux/clk.h> ++#include <linux/delay.h> + #include <linux/dma-mapping.h> +-#include <linux/dmaengine.h> +-#include <linux/module.h> +-#include <linux/of.h> +-#include <linux/of_device.h> + #include <linux/interrupt.h> +-#include <linux/platform_device.h> +-#include <linux/delay.h> +-#include <linux/mtd/spi-nor.h> +- +-/* regs offsets */ +-#define CMNCR 0x0000 +-#define SSLDR 0x0004 +-#define DRCR 0x000C +-#define DRCMR 0x0010 +-#define DREAR 0x0014 +-#define DROPR 0x0018 +-#define DRENR 0x001C +-#define SMCR 0x0020 +-#define SMCMR 0x0024 +-#define SMADR 0x0028 +-#define SMOPR 0x002C +-#define SMENR 0x0030 +-#define SMRDR0 0x0038 +-#define SMRDR1 0x003C +-#define SMWDR0 0x0040 +-#define SMWDR1 0x0044 +-#define CMNSR 0x0048 +-#define DRDMCR 0x0058 +-#define DRDRENR 0x005C +-#define SMDMCR 0x0060 +-#define SMDRENR 0x0064 +-#define PHYCNT 0x007C +-#define PHYOFFSET1 0x0080 +-#define PHYOFFSET2 0x0084 +-#define PHYINT 0x0088 +-#define DIV_REG 0x00A8 +- +-/* CMNCR */ +-#define CMNCR_BSZ_MASK (0x03) +-#define CMNCR_BSZ_4x1 (0x0) +-#define CMNCR_BSZ_8x1 (0x1) +-#define CMNCR_BSZ_4x2 (0x1) +-#define CMNCR_MD (0x1 << 31) +-#define CMNCR_MOIIO3_MASK (0x3 << 22) +-#define CMNCR_MOIIO3_HIZ (0x3 << 22) +-#define CMNCR_MOIIO2_MASK (0x3 << 20) +-#define CMNCR_MOIIO2_HIZ (0x3 << 20) +-#define CMNCR_MOIIO1_MASK (0x3 << 18) +-#define CMNCR_MOIIO1_HIZ (0x3 << 18) +-#define CMNCR_MOIIO0_MASK (0x3 << 16) +-#define CMNCR_MOIIO0_HIZ (0x3 << 16) +-#define CMNCR_IO0FV_MASK (0x3 << 8) +-#define CMNCR_IO0FV_HIZ (0x3 << 8) +- +-/* DRCR */ +-#define DRCR_RBURST_MASK (0x1f << 16) +-#define DRCR_RBURST(v) (((v) & 0x1f) << 16) +-#define DRCR_SSLE (0x1) +-#define DRCR_RBE (0x1 << 8) +-#define DRCR_RCF (0x1 << 9) +-#define DRCR_RBURST_32 (0x1f) +- +-/* SMENR */ +-#define SMENR_CDB_MASK (0x03 << 30) +-#define SMENR_CDB(v) (((v) & 0x03) << 30) +-#define SMENR_CDB_1B (0) +-#define SMENR_CDB_2B (0x1 << 30) +-#define SMENR_CDB_4B (0x2 << 30) +-#define SMENR_OCDB_MASK (0x03 << 28) +-#define SMENR_OCDB_1B (0) +-#define SMENR_OCDB_2B (0x1 << 28) +-#define SMENR_OCDB_4B (0x2 << 28) +-#define SMENR_ADB_MASK (0x03 << 24) +-#define SMENR_ADB(v) (((v) & 0x03) << 24) +-#define SMENR_ADB_1B (0) +-#define SMENR_ADB_2B (0x1 << 24) +-#define SMENR_ADB_4B (0x2 << 24) +-#define SMENR_OPDB_MASK (0x03 << 20) +-#define SMENR_OPDB_1B (0) +-#define SMENR_OPDB_2B (0x1 << 20) +-#define SMENR_OPDB_4B (0x2 << 20) +-#define SMENR_SPIDB_MASK (0x03 << 16) +-#define SMENR_SPIDB(v) (((v) & 0x03) << 16) +-#define SMENR_SPIDB_1B (0) +-#define SMENR_SPIDB_2B (0x1 << 16) +-#define SMENR_SPIDB_4B (0x2 << 16) +-#define SMENR_OPDE_MASK (0xf << 4) +-#define SMENR_OPDE_DISABLE (0) +-#define SMENR_OPDE3 (0x8 << 4) +-#define SMENR_OPDE32 (0xC << 4) +-#define SMENR_OPDE321 (0xE << 4) +-#define SMENR_OPDE3210 (0xF << 4) +-#define SMENR_SPIDE_MASK (0x0F) +-#define SMENR_SPIDE_DISABLE (0) +-#define SMENR_SPIDE_8B (0x08) +-#define SMENR_SPIDE_16B (0x0C) +-#define SMENR_SPIDE_32B (0x0F) +-#define SMENR_DME (1<<15) +-#define SMENR_CDE (1<<14) +-#define SMENR_OCDE (1<<12) +-#define SMENR_ADE_MASK (0xf << 8) +-#define SMENR_ADE_DISABLE (0) +-#define SMENR_ADE_23_16 (0x4 << 8) +-#define SMENR_ADE_23_8 (0x6 << 8) +-#define SMENR_ADE_23_0 (0x7 << 8) +-#define SMENR_ADE_31_0 (0xf << 8) +- +-/* SMCMR */ +-#define SMCMR_CMD(cmd) (((cmd) & 0xff) << 16) +-#define SMCMR_CMD_MASK (0xff << 16) +-#define SMCMR_OCMD(cmd) (((cmd) & 0xff)) +-#define SMCMR_OCMD_MASK (0xff) +- +-/* SMDRENR */ +-#define SMDRENR_HYPE_MASK (0x7 << 12) +-#define SMDRENR_HYPE_SPI_FLASH (0x0) +-#define SMDRENR_ADDRE (0x1 << 8) +-#define SMDRENR_OPDRE (0x1 << 4) +-#define SMDRENR_SPIDRE (0x1) +- +-/* PHYCNT */ +-#define PHYCNT_CAL (0x1 << 31) +-#define PHYCNT_OCTA_MASK (0x3 << 22) +-#define PHYCNT_EXDS (0x1 << 21) +-#define PHYCNT_OCT (0x1 << 20) +-#define PHYCNT_DDRCAL (0x1 << 19) +-#define PHYCNT_HS (0x1 << 18) +-#define PHYCNT_STREAM_MASK (0x7 << 15) +-#define PHYCNT_STREAM(o) (((o) & 0x7) << 15) +-#define PHYCNT_WBUF2 (0x1 << 4) +-#define PHYCNT_WBUF (0x1 << 2) +-#define PHYCNT_PHYMEM_MASK (0x3) +- +-/* SMCR */ +-#define SMCR_SSLKP (0x1 << 8) +-#define SMCR_SPIRE (0x1 << 2) +-#define SMCR_SPIWE (0x1 << 1) +-#define SMCR_SPIE (0x1) +- +-/* CMNSR */ +-#define CMNSR_TEND (0x1 << 0) +- +-/* SSLDR */ +-#define SSLDR_SPNDL(v) (((v) & 0x7) << 16) +-#define SSLDR_SLNDL(v) ((((v) | 0x4) & 0x7) << 8) +-#define SSLDR_SCKDL(v) ((v) & 0x7) +- +-/* DREAR */ +-#define DREAR_EAV_MASK (0xff << 16) +-#define DREAR_EAV(v) (((v) & 0xff) << 16) +-#define DREAR_EAC_MASK (0x7) +-#define DREAR_24B (0) +-#define DREAR_25B (1) +- +-/* DRENR */ +-#define DRENR_CDB_MASK (0x03 << 30) +-#define DRENR_CDB(v) (((v) & 0x3) << 30) +-#define DRENR_CDB_1B (0) +-#define DRENR_CDB_2B (0x1 << 30) +-#define DRENR_CDB_4B (0x2 << 30) +-#define DRENR_OCDB_MASK (0x03 << 28) +-#define DRENR_OCDB_1B (0) +-#define DRENR_OCDB_2B (0x1 << 28) +-#define DRENR_OCDB_4B (0x2 << 28) +-#define DRENR_ADB_MASK (0x03 << 24) +-#define DRENR_ADB(v) (((v) & 0x3) << 24) +-#define DRENR_ADB_1B (0) +-#define DRENR_ADB_2B (0x1 << 24) +-#define DRENR_ADB_4B (0x2 << 24) +-#define DRENR_OPDB_MASK (0x03 << 20) +-#define DRENR_OPDB_1B (0) +-#define DRENR_OPDB_2B (0x1 << 20) +-#define DRENR_OPDB_4B (0x2 << 20) +-#define DRENR_DRDB_MASK (0x03 << 16) +-#define DRENR_DRDB(v) (((v) & 0x3) << 16) +-#define DRENR_DRDB_1B (0) +-#define DRENR_DRDB_2B (0x1 << 16) +-#define DRENR_DRDB_4B (0x2 << 16) +-#define DRENR_OPDE_MASK (0xf << 4) +-#define DRENR_OPDE_DISABLE (0) +-#define DRENR_OPDE3 (0x8 << 4) +-#define DRENR_OPDE32 (0xC << 4) +-#define DRENR_OPDE321 (0xE << 4) +-#define DRENR_OPDE3210 (0xF << 4) +-#define DRENR_DME (1<<15) +-#define DRENR_CDE (1<<14) +-#define DRENR_OCDE (1<<12) +-#define DRENR_ADE_MASK (0xf << 8) +-#define DRENR_ADE_DISABLE (0) +-#define DRENR_ADE_23_0 (0x7 << 8) +-#define DRENR_ADE_31_0 (0xf << 8) +- +-/* DRCMR */ +-#define DRCMR_CMD(cmd) (((cmd) & 0xff) << 16) +-#define DRCMR_CMD_MASK (0xff << 16) +-#define DRCMR_OCMD(cmd) (((cmd) & 0xff)) +-#define DRCMR_OCMD_MASK (0xff) +- +-/* DRCMR */ +-#define DRDMCR_DMCYC(v) ((v) & 0x1f) +-#define DRDMCR_DMCYC_MASK (0x1f) +- +-/* SMDMCR */ +-#define SMDMCR_DMCYC(v) ((v) & 0x0f) +-#define SMDMCR_DMCYC_MASK (0x0f) +- +-/* PHYOFFSET1 */ +-#define PHYOFFSET1_DDRTMG (1 << 28) +- +-/* DIVREG */ +-#define DIVREG_RATIO_MASK (0x03) +-#define DIVREG_RATIO(v) ((v) & 0x03) +-#define DIVREG_RATIO_MAX (0x2) +- +- +-#define DEFAULT_TO (100) +-#define WRITE_BUF_SIZE (0x100) +-#define WRITE_BUF_ADR_MASK (0xff) +- +-#define REPEAT_MAX (20) +-#define REPEAT_TIME (10) +- +-struct rpc_spi { +- struct platform_device *pdev; +- void __iomem *base; +- void __iomem *read_area; +- void __iomem *write_area; +- dma_addr_t read_area_dma; +- struct completion comp; +- struct dma_chan *dma_chan; +- struct clk *clk; +- unsigned int irq; +- struct spi_nor spi_nor; +- +-#define MTD_QSPI_1x 0 +-#define MTD_QSPI_2x 1 +- +- u32 mtdtype; +-}; +- +-/* IP block use it's own clock divigion register */ +-#define OWN_CLOCK_DIVIDER BIT(0) ++#include <linux/of_device.h> + +-#define RPC_DMA_BURST ((DRCR_RBURST_32 + 1) << 3) +-#define RPC_DMA_SIZE_MIN (RPC_DMA_BURST << 3) ++#include "renesas-rpc.h" + + static bool use_dma = true; + module_param(use_dma, bool, 0); + MODULE_PARM_DESC(use_dma, "DMA support. 0 = Disable, 1 = Enable"); + +-/* debug */ +-static void __maybe_unused regs_dump(struct rpc_spi *rpc) ++/* Debug */ ++#ifdef DEBUG ++void rpc_regs_dump(struct rpc_info *rpc) + { + static u32 regs[] = { +- CMNCR, SSLDR, DRCR, DRCMR, DREAR, +- DROPR, DRENR, SMCR, SMCMR, SMADR, +- SMOPR, SMENR, SMRDR0, SMRDR1, SMWDR0, +- SMWDR1, CMNSR, DRDMCR, DRDRENR, SMDMCR, +- SMDRENR, PHYCNT, PHYOFFSET1, PHYOFFSET2, +- PHYINT ++ RPC_CMNCR, RPC_SSLDR, RPC_DRCR, RPC_DRCMR, RPC_DREAR, ++ RPC_DROPR, RPC_DRENR, RPC_SMCR, RPC_SMCMR, RPC_SMADR, ++ RPC_SMOPR, RPC_SMENR, RPC_SMRDR0, RPC_SMRDR1, RPC_SMWDR0, ++ RPC_SMWDR1, RPC_CMNSR, RPC_DRDMCR, RPC_DRDRENR, RPC_SMDMCR, ++ RPC_SMDRENR, RPC_PHYCNT, RPC_PHYOFFSET1, RPC_PHYOFFSET2, ++ RPC_PHYINT + }; + + static const char *const names[] = { +@@ -291,23 +51,43 @@ static void __maybe_unused regs_dump(struct rpc_spi *rpc) + dev_dbg(&rpc->pdev->dev, "RPC regs dump:\n"); + for (i = 0; i < ARRAY_SIZE(regs); i++) + dev_dbg(&rpc->pdev->dev, "%s = 0x%08x\n", names[i], +- readl(rpc->base + regs[i])); ++ rpc_readl(rpc, regs[i])); ++} ++EXPORT_SYMBOL(rpc_regs_dump); ++#endif ++ ++/* Poll operation end */ ++int rpc_wait(struct rpc_info *rpc, int timeout) ++{ ++ unsigned long end = jiffies + msecs_to_jiffies(timeout); ++ ++ while (!(rpc_readl(rpc, RPC_CMNSR) & RPC_CMNSR_TEND)) { ++ if (time_after(jiffies, end)) { ++ dev_err(&rpc->pdev->dev, "timed out\n"); ++ return -ETIMEDOUT; ++ } ++ ++ cpu_relax(); ++ } ++ ++ return 0; + } ++EXPORT_SYMBOL(rpc_wait); + ++/* DMA support */ + static void rpc_dma_complete_func(void *completion) + { + complete(completion); + } + +-static int rpc_dma_read(struct rpc_spi *rpc, void *buf, +- loff_t from, ssize_t *plen) ++int rpc_dma_read(struct rpc_info *rpc, void *buf, loff_t from, ssize_t *plen) + { + struct dma_device *dma_dev; + enum dma_ctrl_flags flags; + dma_addr_t dma_dst_addr; + struct dma_async_tx_descriptor *tx = NULL; + dma_cookie_t cookie; +- int retval = 0; ++ int ret = 0; + ssize_t len; + + len = *plen; +@@ -322,7 +102,7 @@ static int rpc_dma_read(struct rpc_spi *rpc, void *buf, + + dma_dst_addr = dma_map_single(dma_dev->dev, buf, len, DMA_FROM_DEVICE); + if (dma_mapping_error(dma_dev->dev, dma_dst_addr)) { +- dev_err(&rpc->pdev->dev, "Failed to dma_map_single\n"); ++ dev_err(&rpc->pdev->dev, "DMA map single failed\n"); + return -ENXIO; + } + +@@ -331,8 +111,8 @@ static int rpc_dma_read(struct rpc_spi *rpc, void *buf, + rpc->read_area_dma + from, + len, flags); + if (!tx) { +- dev_err(&rpc->pdev->dev, "Failed to prepare DMA memcpy\n"); +- retval = -EIO; ++ dev_err(&rpc->pdev->dev, "DMA prepare memcpy failed\n"); ++ ret = -EIO; + goto out_dma; + } + +@@ -341,9 +121,9 @@ static int rpc_dma_read(struct rpc_spi *rpc, void *buf, + tx->callback_param = &rpc->comp; + + cookie = tx->tx_submit(tx); +- retval = dma_submit_error(cookie); +- if (retval) { +- dev_err(&rpc->pdev->dev, "Failed to do DMA tx_submit\n"); ++ ret = dma_submit_error(cookie); ++ if (ret) { ++ dev_err(&rpc->pdev->dev, "DMA tx submit failed\n"); + goto out_dma; + } + +@@ -355,968 +135,154 @@ static int rpc_dma_read(struct rpc_spi *rpc, void *buf, + + out_dma: + dma_unmap_single(dma_dev->dev, dma_dst_addr, len, DMA_FROM_DEVICE); +- return retval; +-} +- +-/* register acces */ +-static u32 rpc_read(struct rpc_spi *rpc, unsigned int reg) +-{ +- u32 val; +- +- val = readl(rpc->base + reg); +- return val; +-} +- +-static void rpc_write(struct rpc_spi *rpc, unsigned int reg, u32 val) +-{ +- writel(val, rpc->base + reg); +-} +- +-static int rpc_wait(struct rpc_spi *rpc, u32 to) +-{ +- u32 val; +- int i; +- +- for (i = 0; i < to; i++) { +- val = rpc_read(rpc, CMNSR); +- val &= CMNSR_TEND; +- if (val) +- break; +- +- udelay(100); +- } +- +- if (i == to) { +- dev_err(&rpc->pdev->dev, "timeout waiting for operation end %d\n", +- rpc_read(rpc, CMNSR)); +- return -ETIMEDOUT; +- } +- +- return 0; +-} +- +-static int rpc_setup_clk_ratio(struct rpc_spi *rpc, u32 max_clk_rate) +-{ +- unsigned long rate = clk_get_rate(rpc->clk); +- u32 ratio; +- u32 val; +- +- ratio = DIV_ROUND_UP(rate, max_clk_rate * 2) >> 1; +- if (ratio > DIVREG_RATIO_MAX) +- ratio = DIVREG_RATIO_MAX; +- +- val = rpc_read(rpc, DIV_REG); +- val &= DIVREG_RATIO_MASK; +- val |= DIVREG_RATIO(ratio); +- rpc_write(rpc, DIV_REG, val); +- +- return 0; +-} +- +-static int rpc_endisable_write_buf(struct rpc_spi *rpc, bool en) +-{ +- u32 val; +- +- val = rpc_read(rpc, PHYCNT); +- +- if (en) +- val |= PHYCNT_WBUF | PHYCNT_WBUF2; +- else +- val &= ~(PHYCNT_WBUF | PHYCNT_WBUF2); +- +- rpc_write(rpc, PHYCNT, val); +- +- return 0; +-} +- +-static int rpc_begin(struct rpc_spi *rpc, +- bool rx, bool tx, bool last) +-{ +- u32 val = SMCR_SPIE; +- +- if (rx) +- val |= SMCR_SPIRE; +- +- if (tx) +- val |= SMCR_SPIWE; +- +- if (!last) +- val |= SMCR_SSLKP; +- +- rpc_write(rpc, SMCR, val); +- +- return 0; +-} +- +-static int rpc_setup_reg_mode(struct rpc_spi *rpc) +-{ +- u32 val; +- +- rpc_wait(rpc, DEFAULT_TO); +- +- rpc_endisable_write_buf(rpc, false); +- +- /* ...setup manual mode */ +- val = rpc_read(rpc, CMNCR); +- val |= CMNCR_MD; +- rpc_write(rpc, CMNCR, val); +- +- /* disable ddr */ +- val = rpc_read(rpc, SMDRENR); +- val &= ~(SMDRENR_ADDRE | SMDRENR_OPDRE | SMDRENR_SPIDRE); +- rpc_write(rpc, SMDRENR, val); +- +- /* enable 1bit command */ +- val = rpc_read(rpc, SMENR); +- val &= ~(SMENR_CDB_MASK | SMENR_OCDB_MASK | SMENR_DME +- | SMENR_OCDE | SMENR_SPIDB_MASK +- | SMENR_ADE_MASK | SMENR_ADB_MASK +- | SMENR_OPDE_MASK | SMENR_SPIDE_MASK); +- val |= SMENR_CDB_1B | SMENR_CDE | SMENR_SPIDE_32B; +- rpc_write(rpc, SMENR, val); +- +- +- return 0; +-} +- +-static void rpc_flush_cache(struct rpc_spi *rpc) +-{ +- u32 val; +- +- val = rpc_read(rpc, DRCR); +- val |= DRCR_RCF; +- rpc_write(rpc, DRCR, val); +-} +- +-static int rpc_setup_ext_mode(struct rpc_spi *rpc) +-{ +- u32 val; +- u32 cmncr; +- +- rpc_wait(rpc, DEFAULT_TO); +- +- rpc_endisable_write_buf(rpc, false); +- +- /* ...setup ext mode */ +- val = rpc_read(rpc, CMNCR); +- cmncr = val; +- val &= ~(CMNCR_MD); +- rpc_write(rpc, CMNCR, val); +- +- /* ...enable burst and clear cache */ +- val = rpc_read(rpc, DRCR); +- val &= ~(DRCR_RBURST_MASK | DRCR_RBE | DRCR_SSLE); +- val |= DRCR_RBURST(DRCR_RBURST_32) | DRCR_RBE; +- +- if (cmncr & CMNCR_MD) +- val |= DRCR_RCF; +- +- rpc_write(rpc, DRCR, val); +- +- return 0; +-} +- +-static int rpc_setup_data_size(struct rpc_spi *rpc, u32 size, bool copy) +-{ +- u32 val; +- +- val = rpc_read(rpc, SMENR); +- val &= ~(SMENR_SPIDE_MASK); +- +- if (rpc->mtdtype == MTD_QSPI_2x && !copy) +- size >>= 1; +- +- switch (size) { +- case 0: +- break; +- case 1: +- val |= SMENR_SPIDE_8B; +- break; +- case 2: +- val |= SMENR_SPIDE_16B; +- break; +- case 4: +- val |= SMENR_SPIDE_32B; +- break; +- default: +- dev_err(&rpc->pdev->dev, "Unsupported data width %d\n", size); +- return -EINVAL; +- } +- rpc_write(rpc, SMENR, val); +- +- return 0; +-} +- +-static int rpc_setup_extmode_read_addr(struct rpc_spi *rpc, +- int adr_width, loff_t adr) +-{ +- u32 val; +- u32 v; +- +- val = rpc_read(rpc, DREAR); +- val &= ~(DREAR_EAV_MASK | DREAR_EAC_MASK); +- +- if (adr_width == 4) { +- v = adr >> 25; +- val |= DREAR_EAV(v) | DREAR_25B; +- } +- rpc_write(rpc, DREAR, val); +- +- val = rpc_read(rpc, DRENR); +- val &= ~(DRENR_ADE_MASK); +- if (adr_width == 4) +- val |= DRENR_ADE_31_0; +- else +- val |= DRENR_ADE_23_0; +- rpc_write(rpc, DRENR, val); +- +- return 0; +-} +- +-static inline int rpc_get_read_addr_nbits(u8 opcode) +-{ +- if (opcode == SPINOR_OP_READ_1_4_4_4B) +- return 4; +- return 1; +-} +- +-#define NBITS_TO_VAL(v) ((v >> 1) & 3) +-static int rpc_setup_extmode_nbits(struct rpc_spi *rpc, int cnb, +- int anb, int dnb) +-{ +- u32 val; +- +- val = rpc_read(rpc, DRENR); +- val &= ~(DRENR_CDB_MASK | DRENR_ADB_MASK | DRENR_DRDB_MASK); +- val |= DRENR_CDB(NBITS_TO_VAL(cnb)) +- | DRENR_ADB(NBITS_TO_VAL(anb)) +- | DRENR_DRDB(NBITS_TO_VAL(dnb)); +- rpc_write(rpc, DRENR, val); +- +- return 0; +-} +- +-static int rpc_setup_writemode_nbits(struct rpc_spi *rpc, int cnb, +- int anb, int dnb) +-{ +- u32 val; +- +- val = rpc_read(rpc, SMENR); +- val &= ~(SMENR_CDB_MASK | SMENR_ADB_MASK | SMENR_SPIDB_MASK); +- val |= SMENR_CDB(NBITS_TO_VAL(cnb)) +- | SMENR_ADB(NBITS_TO_VAL(anb)) +- | SMENR_SPIDB(NBITS_TO_VAL(dnb)); +- rpc_write(rpc, SMENR, val); +- +- return 0; +-} +- +-static void rpc_setup_write_mode_command_and_adr(struct rpc_spi *rpc, +- int adr_width, bool ena) +-{ +- u32 val; +- +- val = rpc_read(rpc, SMENR); +- val &= ~(SMENR_CDB_MASK | SMENR_CDE | SMENR_ADE_MASK); +- +- if (ena) { +- /* enable 1bit command */ +- val |= SMENR_CDB_1B | SMENR_CDE; +- +- if (adr_width == 4) +- val |= SMENR_ADE_31_0; +- else +- val |= SMENR_ADE_23_0; +- } +- rpc_write(rpc, SMENR, val); +-} +- +-static int rpc_setup_write_mode(struct rpc_spi *rpc, u8 opcode) +-{ +- u32 val; +- +- rpc_wait(rpc, DEFAULT_TO); +- +- rpc_endisable_write_buf(rpc, true); +- +- /* ...setup manual mode */ +- val = rpc_read(rpc, CMNCR); +- val |= CMNCR_MD; +- rpc_write(rpc, CMNCR, val); +- +- /* disable ddr */ +- val = rpc_read(rpc, SMDRENR); +- val &= ~(SMDRENR_ADDRE | SMDRENR_OPDRE | SMDRENR_SPIDRE); +- rpc_write(rpc, SMDRENR, val); +- +- val = rpc_read(rpc, SMENR); +- val &= ~(SMENR_OCDB_MASK | SMENR_DME | SMENR_OCDE | SMENR_SPIDB_MASK +- | SMENR_ADB_MASK | SMENR_OPDE_MASK | SMENR_SPIDE_MASK); +- if (opcode != SPINOR_OP_PP) +- val |= SMENR_SPIDE_32B; +- else +- val |= SMENR_SPIDE_8B; +- +- rpc_write(rpc, SMENR, val); +- +- return 0; +-} +- +-static void rpc_read_manual_data(struct rpc_spi *rpc, u32 *pv0, u32 *pv1) +-{ +- u32 val0, val1, rd0, rd1; +- +- val0 = rpc_read(rpc, SMRDR0); +- val1 = rpc_read(rpc, SMRDR1); +- +- if (rpc->mtdtype == MTD_QSPI_2x) { +- rd1 = (val0 & 0xff000000) | ((val0 << 8) & 0xff0000) | +- ((val1 >> 16) & 0xff00) | ((val1 >> 8) & 0xff); +- rd0 = ((val0 & 0xff0000) << 8) | ((val0 << 16) & 0xff0000) | +- ((val1 >> 8) & 0xff00) | (val1 & 0xff); +- } else +- rd0 = val0; +- +- if (pv0) +- *pv0 = rd0; +- +- if (pv1 && rpc->mtdtype == MTD_QSPI_2x) +- *pv1 = rd1; +-} +- +-static int rpc_datalen2trancfersize(struct rpc_spi *rpc, int len, bool copy) +-{ +- int sz = len; +- +- if (len >= 2) +- sz = 2; +- +- if (len >= 4) +- sz = 4; +- +- if (rpc->mtdtype == MTD_QSPI_2x && len >= 8 && !copy) +- sz = 8; +- +- return sz; +-} +- +-static int __rpc_write_data2reg(struct rpc_spi *rpc, int off, +- const u8 *buf, int sz) +-{ +- const u32 *b32 = (const u32 *)buf; +- const u16 *b16 = (const u16 *)buf; +- +- if (sz == 4) +- rpc_write(rpc, off, *b32); +- else if (sz == 2) +- writew(*b16, rpc->base + off); +- else if (sz == 1) +- writeb(*buf, rpc->base + off); +- else if (sz != 0) { +- dev_err(&rpc->pdev->dev, "incorrect data size %d\n", sz); +- return -EINVAL; +- } +- +- return 0; +-} +- +-#define __SETVAL(x) ((((x) & 0xff) << 8) | ((x) & 0xff)) +-static int rpc_write_data2reg(struct rpc_spi *rpc, const u8 *buf, +- int sz, bool copy) +-{ +- int i, ret; +- u32 v = 0; +- +- if (rpc->mtdtype == MTD_QSPI_2x) { +- if (copy) { +- for (i = 0; i < sz && i < 2; i++) +- v |= (__SETVAL(buf[i]) << 16*i); +- +- ret = __rpc_write_data2reg(rpc, +- sz == 4 ? SMWDR1 : SMWDR0, +- (u8 *)&v, +- sz == 4 ? sz : sz * 2); +- if (ret) +- return ret; +- +- v = 0; +- for (; i < sz; i++) +- v |= (__SETVAL(buf[i]) << 16*i); +- +- +- ret = __rpc_write_data2reg(rpc, +- sz == 4 ? SMWDR0 : SMWDR1, +- (u8 *)&v, +- sz == 4 ? sz : sz * 2); +- if (ret) +- return ret; +- +- return 0; +- } +- +- sz >>= 1; +- ret = __rpc_write_data2reg(rpc, +- sz == 4 ? SMWDR1 : SMWDR0, +- buf, +- sz == 4 ? sz : sz * 2); +- if (ret) +- return ret; +- buf += sz; +- +- return __rpc_write_data2reg(rpc, +- sz == 4 ? SMWDR0 : SMWDR1, +- buf, sz == 4 ? sz : sz * 2); +- } +- +- return __rpc_write_data2reg(rpc, SMWDR0, buf, sz); +-} +- +-static ssize_t rpc_write_unaligned(struct spi_nor *nor, loff_t to, size_t len, +- const u_char *buf, size_t fullen) +-{ +- int ret = len, dsize; +- struct rpc_spi *rpc = nor->priv; +- bool copy = false, last; +- loff_t _to; +- +- rpc_endisable_write_buf(rpc, false); +- +- while (len > 0) { +- _to = to; +- if (rpc->mtdtype == MTD_QSPI_2x) +- _to >>= 1; +- rpc_write(rpc, SMADR, _to); +- dsize = rpc_datalen2trancfersize(rpc, len, copy); +- +- if (rpc_setup_data_size(rpc, dsize, copy)) +- return -EINVAL; +- +- rpc_write_data2reg(rpc, buf, dsize, copy); +- +- last = (len <= dsize && fullen <= ret); +- rpc_begin(rpc, false, true, last); +- if (rpc_wait(rpc, DEFAULT_TO)) +- return -ETIMEDOUT; +- +- /* ...disable command */ +- rpc_setup_write_mode_command_and_adr(rpc, +- nor->addr_width, false); +- +- buf += dsize; +- len -= dsize; +- to += dsize; +- } +- + return ret; + } ++EXPORT_SYMBOL(rpc_dma_read); + +-static ssize_t rpc_write_flash(struct spi_nor *nor, loff_t to, size_t len, +- const u_char *buf) +-{ +- ssize_t res = len, full = len; +- u32 val; +- u8 rval[2]; +- struct rpc_spi *rpc = nor->priv; +- loff_t bo; +- loff_t offset; +- bool is_rounded = false; +- +- /* ...len should be rounded to 2 bytes */ +- if (rpc->mtdtype == MTD_QSPI_2x && (len & 1)) { +- is_rounded = true; +- len &= ~(1); +- } +- +- bo = to & (WRITE_BUF_ADR_MASK); +- +- rpc_flush_cache(rpc); +- rpc_setup_write_mode(rpc, nor->program_opcode); +- rpc_setup_write_mode_command_and_adr(rpc, nor->addr_width, true); +- rpc_setup_writemode_nbits(rpc, 1, 1, 1); +- +- /* ...setup command */ +- val = rpc_read(rpc, SMCMR); +- val &= ~(SMCMR_CMD_MASK); +- val |= SMCMR_CMD(nor->program_opcode); +- rpc_write(rpc, SMCMR, val); +- +- offset = (to & (~WRITE_BUF_ADR_MASK)); +- +- /* ...write unaligned first bytes */ +- if (bo) { +- size_t min = (len < (WRITE_BUF_SIZE - bo)) ? len : (WRITE_BUF_SIZE - bo); +- +- rpc_write_unaligned(nor, to, min, buf, full); +- rpc_setup_write_mode(rpc, nor->program_opcode); +- +- len -= min; +- buf += min; +- to += min; +- full -= min; +- } +- +- /* +- * TODO: Unfortunately RPC does not write properly in write buf mode +- * without transferring command. Investigate this. +- */ +- +- if (len) { +- rpc_write_unaligned(nor, to, len, buf, full); +- buf += len; +- to += len; +- full -= len; +- len = 0; +- } +- +- if (is_rounded) { +- rval[0] = *buf; +- rval[1] = 0xFF; +- rpc_write_unaligned(nor, to, 2, rval, full); +- } +- +- rpc_flush_cache(rpc); +- +- return res; +-} +- +-static inline unsigned int rpc_rx_nbits(struct spi_nor *nor) +-{ +- return spi_nor_get_protocol_data_nbits(nor->read_proto); +-} +- +-#define READ_ADR_MASK (BIT(26) - 1) +-static ssize_t rpc_read_flash(struct spi_nor *nor, loff_t from, size_t len, +- u_char *buf) ++/* Read */ ++void rpc_do_read_flash(struct rpc_info *rpc, loff_t from, ++ size_t len, u_char *buf, bool addr32) + { +- u32 val; +- struct rpc_spi *rpc = nor->priv; +- int adr_width = nor->addr_width; +- int opcode_nbits = 1; +- int addr_nbits = rpc_get_read_addr_nbits(nor->read_opcode); +- int data_nbits = rpc_rx_nbits(nor); +- int dummy = nor->read_dummy - 1; +- ssize_t ret = len; +- ssize_t readlen; +- loff_t _from; +- +- rpc_setup_ext_mode(rpc); +- /* ...setup n bits */ +- rpc_setup_extmode_nbits(rpc, opcode_nbits, addr_nbits, data_nbits); +- +- /* TODO: setup DDR */ +- +- /* ...setup command */ +- val = rpc_read(rpc, DRCMR); +- val &= ~(DRCMR_CMD_MASK); +- val |= DRCMR_CMD(nor->read_opcode); +- rpc_write(rpc, DRCMR, val); +- +- /* ...setup dummy cycles */ +- val = rpc_read(rpc, DRDMCR); +- val &= ~(DRDMCR_DMCYC_MASK); +- val |= DRDMCR_DMCYC(dummy); +- rpc_write(rpc, DRDMCR, val); +- +- /* ...setup read sequence */ +- val = rpc_read(rpc, DRENR); +- val |= DRENR_DME | DRENR_CDE; +- rpc_write(rpc, DRENR, val); +- + while (len > 0) { +- int retval; +- +- /* ...setup address */ +- rpc_setup_extmode_read_addr(rpc, adr_width, from); +- /* ...use adr [25...0] */ +- _from = from & READ_ADR_MASK; +- +- readlen = READ_ADR_MASK - _from + 1; ++ ssize_t readlen; ++ loff_t _from; ++ int ret; ++ ++ /* Setup ext mode address */ ++ rpc_clrsetl(rpc, RPC_DREAR, ++ RPC_DREAR_EAV(0xFF) | RPC_DREAR_EAC(7), ++ addr32 ? ++ RPC_DREAR_EAV(from >> 25) | RPC_DREAR_EAC(1) : ++ 0); ++ ++ rpc_clrsetl(rpc, RPC_DRENR, ++ RPC_DRENR_ADE(0xF), ++ addr32 ? ++ /* bits 31-0 */ ++ RPC_DRENR_ADE(0xF) : ++ /* bits 23-0 */ ++ RPC_DRENR_ADE(0x7)); ++ ++ /* Use address bits [25...0] */ ++ _from = from & RPC_READ_ADDR_MASK; ++ ++ readlen = RPC_READ_ADDR_MASK - _from + 1; + readlen = readlen > len ? len : readlen; + +- retval = rpc_dma_read(rpc, buf, _from, &readlen); +- if (retval) ++ ret = rpc_dma_read(rpc, buf, _from, &readlen); ++ if (ret) + memcpy_fromio(buf, rpc->read_area + _from, readlen); + + buf += readlen; + from += readlen; + len -= readlen; + } +- +- return ret; +-} +- +-static int __rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) +-{ +- u32 val; +- u32 val2 = 0; +- u32 *buf32; +- int i; +- u32 mask = 0, type; +- struct rpc_spi *rpc = nor->priv; +- +- type = rpc->mtdtype; +- +- rpc_setup_reg_mode(rpc); +- val = rpc_read(rpc, SMCMR); +- val &= ~(SMCMR_CMD_MASK); +- val |= SMCMR_CMD(opcode); +- rpc_write(rpc, SMCMR, val); +- +- rpc_begin(rpc, true, false, len <= 4); +- if (rpc_wait(rpc, DEFAULT_TO)) +- return -ETIMEDOUT; +- +- /* ...disable command */ +- val = rpc_read(rpc, SMENR); +- val &= ~(SMENR_CDE); +- rpc_write(rpc, SMENR, val); +- +- buf32 = (u32 *)buf; +- +- while (len > 0) { +- rpc_read_manual_data(rpc, &val, &val2); +- +- if (mask) { +- dev_warn(&rpc->pdev->dev, +- "Using mask workaround (0x%x)\n", mask); +- val &= ~(mask); +- val2 &= ~(mask); +- } +- +- /* ... spi flashes should be the same */ +- if (type == MTD_QSPI_2x && val != val2) { +- /* clear cs */ +- rpc_begin(rpc, true, false, true); +- return -EAGAIN; +- } +- +- if (len > 4) { +- *buf32 = val; +- buf32++; +- len -= 4; +- } else { +- buf = (u8 *)buf32; +- for (i = 0; i < len; i++) { +- *buf = (val >> (8 * i)) & 0x000000ff; +- buf++; +- } +- len = 0; +- } +- +- if (!len) +- break; +- +- mask = 0xff; +- +- rpc_begin(rpc, true, false, len <= 4); +- if (rpc_wait(rpc, DEFAULT_TO)) +- return -ETIMEDOUT; +- +- } +- +- return 0; +-} +- +-static int rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) +-{ +- int i, ret; +- +- /* A few read commands like read status can +- * generate different answers. We repeat reading +- * in that case +- */ +- for (i = 0; i < REPEAT_MAX; i++) { +- ret = __rpc_read_reg(nor, opcode, buf, len); +- if (!ret || ret != -EAGAIN) +- break; +- mdelay(REPEAT_TIME); +- } +- +- return ret; +-} +- +-static int rpc_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) +-{ +- struct rpc_spi *rpc = nor->priv; +- u32 val; +- int dsize; +- bool copy = true; +- +- rpc_setup_reg_mode(rpc); +- +- val = rpc_read(rpc, SMCMR); +- val &= ~(SMCMR_CMD_MASK); +- val |= SMCMR_CMD(opcode); +- rpc_write(rpc, SMCMR, val); +- +- dsize = rpc_datalen2trancfersize(rpc, len, copy); +- +- if (rpc_setup_data_size(rpc, dsize, copy)) +- return -EINVAL; +- +- if (rpc_write_data2reg(rpc, buf, dsize, copy)) +- return -EINVAL; +- buf += dsize; +- len -= dsize; +- rpc_begin(rpc, false, dsize > 0, len == 0); +- +- if (rpc_wait(rpc, DEFAULT_TO)) +- return -ETIMEDOUT; +- +- /* ...disable command */ +- val = rpc_read(rpc, SMENR); +- val &= ~(SMENR_CDE); +- rpc_write(rpc, SMENR, val); +- +- while (len > 0) { +- dsize = rpc_datalen2trancfersize(rpc, len, copy); +- if (rpc_setup_data_size(rpc, dsize, copy)) +- return -EINVAL; +- rpc_write_data2reg(rpc, buf, dsize, copy); +- buf += dsize; +- len -= dsize; +- +- rpc_begin(rpc, false, dsize, len == 0); +- +- if (rpc_wait(rpc, DEFAULT_TO)) +- return -ETIMEDOUT; +- +- } +- +- return 0; + } ++EXPORT_SYMBOL(rpc_do_read_flash); + +-/* hw init for spi-nor flashes */ +-static int rpc_hw_init_1x2x(struct rpc_spi *rpc) ++/* Own clock setup */ ++static int rpc_own_clk_set_rate(struct rpc_info *rpc, u32 max_clk_rate) + { +- u32 val; +- +- /* Exec calibration */ +- val = rpc_read(rpc, PHYCNT); +- val &= ~(PHYCNT_OCTA_MASK | PHYCNT_EXDS | PHYCNT_OCT +- | PHYCNT_DDRCAL | PHYCNT_HS | PHYCNT_STREAM_MASK +- | PHYCNT_WBUF2 | PHYCNT_WBUF | PHYCNT_PHYMEM_MASK); +- val |= (PHYCNT_CAL) | PHYCNT_STREAM(6); +- rpc_write(rpc, PHYCNT, val); +- +- /* disable rpc_* pins */ +- val = rpc_read(rpc, PHYINT); +- val &= ~((1<<24) | (7<<16)); +- rpc_write(rpc, PHYINT, val); +- +- val = rpc_read(rpc, SMDRENR); +- val &= ~(SMDRENR_HYPE_MASK); +- val |= SMDRENR_HYPE_SPI_FLASH; +- rpc_write(rpc, SMDRENR, val); +- +- val = rpc_read(rpc, CMNCR); +- val &= ~(CMNCR_BSZ_MASK); +- if (rpc->mtdtype != MTD_QSPI_1x) +- val |= CMNCR_BSZ_4x2; +- rpc_write(rpc, CMNCR, val); +- +- val = rpc_read(rpc, PHYOFFSET1); +- val |= PHYOFFSET1_DDRTMG; +- rpc_write(rpc, PHYOFFSET1, val); ++ unsigned long rate = clk_get_rate(rpc->clk); ++ u32 ratio; + +- val = SSLDR_SPNDL(0) | SSLDR_SLNDL(4) | SSLDR_SCKDL(0); +- rpc_write(rpc, SSLDR, val); ++ ratio = DIV_ROUND_UP(rate, max_clk_rate * 2) >> 1; ++ if (ratio > RPC_DIVREG_RATIO_MAX) ++ ratio = RPC_DIVREG_RATIO_MAX; + ++ rpc_clrsetl(rpc, RPC_DIVREG, ++ RPC_DIVREG_RATIO(0x3), ++ RPC_DIVREG_RATIO(ratio)); + return 0; + } + +-static int rpc_hw_init(struct rpc_spi *rpc) +-{ +- switch (rpc->mtdtype) { +- case MTD_QSPI_1x: +- case MTD_QSPI_2x: +- return rpc_hw_init_1x2x(rpc); +- +- default: +- dev_err(&rpc->pdev->dev, "Unsupported connection mode\n"); +- return -ENODEV; +- } +-} +- +-static int rpc_erase_sector(struct spi_nor *nor, loff_t addr) +-{ +- struct rpc_spi *rpc = nor->priv; +- u8 buf[6]; +- int i; +- +- if (rpc->mtdtype == MTD_QSPI_2x) +- addr >>= 1; +- +- for (i = nor->addr_width - 1; i >= 0; i--) { +- buf[i] = addr & 0xff; +- addr >>= 8; +- } +- +- return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); +-} +- +-static const struct of_device_id rpc_of_match[] = { +- { .compatible = "renesas,qspi-rpc-r8a77980" }, +- { .compatible = "renesas,qspi-rpc-r8a77970", .data = (void *)OWN_CLOCK_DIVIDER }, +- { }, +-}; +- +-MODULE_DEVICE_TABLE(of, rpc_of_match); +- +-static int rpc_spi_probe(struct platform_device *pdev) ++static int rpc_probe(struct platform_device *pdev) + { +- struct device_node *flash_np; +- struct spi_nor *nor; +- struct rpc_spi *rpc; ++ struct rpc_info *rpc; + struct resource *res; +- struct spi_nor_hwcaps hwcaps = { +- .mask = SNOR_HWCAPS_READ | +- SNOR_HWCAPS_READ_FAST | +- SNOR_HWCAPS_PP, +- }; +- u32 max_clk_rate = 50000000; +- u32 property; ++ const char *name = NULL; ++ u32 rate = 0; + int ret; +- int own_clk; +- +- +- flash_np = of_get_next_available_child(pdev->dev.of_node, NULL); +- if (!flash_np) { +- dev_err(&pdev->dev, "no SPI flash device to configure\n"); +- return -ENODEV; +- } +- +- if (!of_property_read_u32(flash_np, "spi-rx-bus-width", &property)) { +- switch (property) { +- case 1: +- break; +- case 2: +- hwcaps.mask |= SNOR_HWCAPS_READ_DUAL; +- break; +- case 4: +- hwcaps.mask |= SNOR_HWCAPS_READ_QUAD; +- break; +- default: +- dev_err(&pdev->dev, "unsupported rx-bus-width\n"); +- return -EINVAL; +- } +- } +- +- of_property_read_u32(flash_np, "spi-max-frequency", &max_clk_rate); +- own_clk = (of_device_get_match_data(&pdev->dev) == (void *)OWN_CLOCK_DIVIDER); + + rpc = devm_kzalloc(&pdev->dev, sizeof(*rpc), GFP_KERNEL); +- if (!rpc) ++ if (!rpc) { ++ dev_err(&pdev->dev, "allocation failed\n"); + return -ENOMEM; +- +- rpc->pdev = pdev; +- +- /* ... setup nor hooks */ +- nor = &rpc->spi_nor; +- nor->dev = &pdev->dev; +- spi_nor_set_flash_node(nor, flash_np); +- nor->read = rpc_read_flash; +- nor->write = rpc_write_flash; +- nor->read_reg = rpc_read_reg; +- nor->write_reg = rpc_write_reg; +- nor->priv = rpc; +- rpc->mtdtype = MTD_QSPI_1x; +- +- if (of_find_property(pdev->dev.of_node, "dual", NULL)) { +- rpc->mtdtype = MTD_QSPI_2x; +- nor->erase = rpc_erase_sector; + } + +- /* ...get memory */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rpc->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rpc->base)) { +- dev_err(&pdev->dev, "cannot get resources\n"); +- ret = PTR_ERR(rpc->base); +- goto error; ++ dev_err(&pdev->dev, "cannot get base resource\n"); ++ return PTR_ERR(rpc->base); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- +- rpc->read_area_dma = res->start; + rpc->read_area = devm_ioremap_resource(&pdev->dev, res); +- if (IS_ERR(rpc->base)) { +- dev_err(&pdev->dev, "cannot get resources\n"); +- ret = PTR_ERR(rpc->base); +- goto error; ++ if (IS_ERR(rpc->read_area)) { ++ dev_err(&pdev->dev, "cannot get read resource\n"); ++ return PTR_ERR(rpc->read_area); ++ } ++ ++ if (resource_size(res) & RPC_READ_ADDR_MASK) { ++ dev_err(&pdev->dev, "invalid read resource\n"); ++ return -EINVAL; + } + +- /* ...get memory */ ++ rpc->read_area_dma = res->start; ++ + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + rpc->write_area = devm_ioremap_resource(&pdev->dev, res); +- if (IS_ERR(rpc->base)) { +- dev_err(&pdev->dev, "cannot get resources\n"); +- ret = PTR_ERR(rpc->base); +- goto error; ++ if (IS_ERR(rpc->write_area)) { ++ dev_warn(&pdev->dev, "cannot get write resource\n"); ++ rpc->write_area = NULL; + } + +- /* ...get clk */ + rpc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(rpc->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); +- ret = PTR_ERR(rpc->clk); +- goto error; ++ return PTR_ERR(rpc->clk); + } + +- /* ...set max clk rate */ +- if (!own_clk) { +- ret = clk_set_rate(rpc->clk, max_clk_rate); +- if (ret) { +- dev_err(&pdev->dev, "cannot set clock rate\n"); +- goto error; +- } ++ rpc->flash = of_get_next_available_child(pdev->dev.of_node, NULL); ++ if (!rpc->flash) { ++ dev_err(&pdev->dev, "no flash device to configure\n"); ++ return -ENOTSUPP; + } + +- /* ... enable clk */ +- ret = clk_prepare_enable(rpc->clk); +- if (ret) { +- dev_err(&pdev->dev, "cannot prepare clock\n"); +- goto error; ++ rpc->mtdtype = of_find_property(pdev->dev.of_node, "dual", NULL) ? ++ RPC_DUAL : RPC_SINGLE; ++ ++ of_property_read_u32(rpc->flash, "spi-max-frequency", &rate); ++ ++ if (of_device_is_compatible(rpc->flash, "jedec,spi-nor")) { ++ name = "renesas-rpc-qspi"; ++ if (!rate) ++ rate = 50000000; ++ } else if (of_device_is_compatible(rpc->flash, "cfi-flash")) { ++ rpc->mtdtype = RPC_DUAL; ++ name = "renesas-rpc-hyperflash"; ++ if (!rate) ++ rate = 80000000; + } + +- /* ...init device */ +- ret = rpc_hw_init(rpc); +- if (ret < 0) { +- dev_err(&pdev->dev, "rpc_hw_init error.\n"); +- goto error_clk_disable; ++ if (!name) { ++ dev_err(&pdev->dev, "no supported flash device detected\n"); ++ ret = -ENODEV; ++ goto error; + } + +- /* ...set clk ratio */ +- if (own_clk) { +- ret = rpc_setup_clk_ratio(rpc, max_clk_rate); ++ if (rate) { ++ ret = of_device_is_compatible(pdev->dev.of_node, ++ "renesas,rpc-r8a77970") ? ++ rpc_own_clk_set_rate(rpc, rate) : ++ clk_set_rate(rpc->clk, rate); + if (ret) { +- dev_err(&pdev->dev, "cannot set clock ratio\n"); ++ dev_err(&pdev->dev, "clock rate setup failed\n"); + goto error; + } + } + +- platform_set_drvdata(pdev, rpc); +- +- ret = spi_nor_scan(nor, NULL, &hwcaps); +- if (ret) { +- dev_err(&pdev->dev, "spi_nor_scan error.\n"); +- goto error_clk_disable; +- } +- +- /* Dual mode support */ +- if (rpc->mtdtype == MTD_QSPI_2x) { +- nor->page_size <<= 1; +- nor->mtd.erasesize <<= 1; +- nor->mtd.size <<= 1; +- nor->mtd.writebufsize <<= 1; +- } +- +- /* Workaround data size limitation */ +- if (nor->page_size > WRITE_BUF_SIZE) { +- nor->page_size = WRITE_BUF_SIZE; +- nor->mtd.writebufsize = WRITE_BUF_SIZE; +- } +- + if (use_dma) { + dma_cap_mask_t mask; + +@@ -1324,58 +290,70 @@ static int rpc_spi_probe(struct platform_device *pdev) + dma_cap_set(DMA_MEMCPY, mask); + rpc->dma_chan = dma_request_channel(mask, NULL, NULL); + if (!rpc->dma_chan) +- dev_warn(&pdev->dev, "Failed to request DMA channel\n"); ++ dev_warn(&pdev->dev, "DMA channel request failed\n"); + else +- dev_info(&pdev->dev, "Using DMA read (%s)\n", ++ dev_info(&pdev->dev, "using DMA read (%s)\n", + dma_chan_name(rpc->dma_chan)); + } + +- ret = mtd_device_register(&nor->mtd, NULL, 0); +- if (ret) { +- dev_err(&pdev->dev, "mtd_device_register error.\n"); +- goto error_dma; ++ platform_set_drvdata(pdev, rpc); ++ rpc->pdev = platform_device_register_data(&pdev->dev, name, -1, NULL, 0); ++ if (IS_ERR(rpc->pdev)) { ++ dev_err(&pdev->dev, "%s device registration failed\n", name); ++ ret = PTR_ERR(rpc->pdev); ++ goto error; + } + +- dev_info(&pdev->dev, "probed as %s\n", +- rpc->mtdtype == MTD_QSPI_1x ? "single" : "dual"); +- + return 0; + +-error_dma: ++error: + if (rpc->dma_chan) + dma_release_channel(rpc->dma_chan); +-error_clk_disable: +- clk_disable_unprepare(rpc->clk); +-error: ++ ++ of_node_put(rpc->flash); + return ret; + } + +-static int rpc_spi_remove(struct platform_device *pdev) ++static int rpc_remove(struct platform_device *pdev) + { +- struct rpc_spi *rpc = platform_get_drvdata(pdev); ++ struct rpc_info *rpc = platform_get_drvdata(pdev); + +- /* HW shutdown */ +- clk_disable_unprepare(rpc->clk); +- mtd_device_unregister(&rpc->spi_nor.mtd); ++ if (rpc->pdev) ++ platform_device_unregister(rpc->pdev); + if (rpc->dma_chan) + dma_release_channel(rpc->dma_chan); ++ if (rpc->flash) ++ of_node_put(rpc->flash); ++ + return 0; + } + ++static const struct of_device_id rpc_of_match[] = { ++ { .compatible = "renesas,rpc-r8a7795" }, ++ { .compatible = "renesas,rpc-r8a7796" }, ++ { .compatible = "renesas,rpc-r8a77965" }, ++ { ++ .compatible = "renesas,rpc-r8a77970", ++ .data = (void *)RPC_OWN_CLOCK_DIVIDER, ++ }, ++ { .compatible = "renesas,rpc-r8a77980" }, ++ { }, ++}; ++ + /* platform driver interface */ + static struct platform_driver rpc_platform_driver = { +- .probe = rpc_spi_probe, +- .remove = rpc_spi_remove, ++ .probe = rpc_probe, ++ .remove = rpc_remove, + .driver = { + .owner = THIS_MODULE, +- .name = "rpc", ++ .name = "renesas-rpc", + .of_match_table = of_match_ptr(rpc_of_match), + }, + }; + + module_platform_driver(rpc_platform_driver); + +-MODULE_ALIAS("rpc"); ++MODULE_ALIAS("renesas-rpc"); + MODULE_AUTHOR("Cogent Embedded Inc. <sources@cogentembedded.com>"); + MODULE_DESCRIPTION("Renesas RPC Driver"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/mtd/spi-nor/renesas-rpc.h b/drivers/mtd/spi-nor/renesas-rpc.h +new file mode 100644 +index 0000000..e500a62 +--- /dev/null ++++ b/drivers/mtd/spi-nor/renesas-rpc.h +@@ -0,0 +1,267 @@ ++/* ++ * Renesas RPC driver ++ * ++ * Copyright (C) 2019, Cogent Embedded Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef __RENESAS_RPC_H__ ++#define __RENESAS_RPC_H__ ++ ++#include <linux/clk.h> ++#include <linux/dmaengine.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++ ++/* RPC */ ++#define RPC_CMNCR 0x0000 /* R/W */ ++#define RPC_CMNCR_MD (0x1 << 31) ++#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) ++#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) ++#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) ++#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) ++#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \ ++ RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3)) ++#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8) ++#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12) ++#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14) ++#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \ ++ RPC_CMNCR_IO3FV(3)) ++#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0) ++ ++#define RPC_SSLDR 0x0004 /* R/W */ ++#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16) ++#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8) ++#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0) ++ ++#define RPC_DRCR 0x000C /* R/W */ ++#define RPC_DRCR_SSLN (0x1 << 24) ++#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16) ++#define RPC_DRCR_RCF (0x1 << 9) ++#define RPC_DRCR_RBE (0x1 << 8) ++#define RPC_DRCR_SSLE (0x1 << 0) ++ ++#define RPC_DRCMR 0x0010 /* R/W */ ++#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16) ++#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0) ++ ++#define RPC_DREAR 0x0014 /* R/W */ ++#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16) ++#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0) ++ ++#define RPC_DROPR 0x0018 /* R/W */ ++#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24) ++#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16) ++#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8) ++#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0) ++ ++#define RPC_DRENR 0x001C /* R/W */ ++#define RPC_DRENR_CDB(o) (((o) & 0x3) << 30) ++#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28) ++#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24) ++#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20) ++#define RPC_DRENR_DRDB(o) (((o) & 0x3) << 16) ++#define RPC_DRENR_DME (0x1 << 15) ++#define RPC_DRENR_CDE (0x1 << 14) ++#define RPC_DRENR_OCDE (0x1 << 12) ++#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8) ++#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4) ++ ++#define RPC_SMCR 0x0020 /* R/W */ ++#define RPC_SMCR_SSLKP (0x1 << 8) ++#define RPC_SMCR_SPIRE (0x1 << 2) ++#define RPC_SMCR_SPIWE (0x1 << 1) ++#define RPC_SMCR_SPIE (0x1 << 0) ++ ++#define RPC_SMCMR 0x0024 /* R/W */ ++#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16) ++#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0) ++ ++#define RPC_SMADR 0x0028 /* R/W */ ++#define RPC_SMOPR 0x002C /* R/W */ ++#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0) ++#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8) ++#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16) ++#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24) ++ ++#define RPC_SMENR 0x0030 /* R/W */ ++#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30) ++#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28) ++#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24) ++#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20) ++#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16) ++#define RPC_SMENR_DME (0x1 << 15) ++#define RPC_SMENR_CDE (0x1 << 14) ++#define RPC_SMENR_OCDE (0x1 << 12) ++#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8) ++#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4) ++#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0) ++ ++#define RPC_SMRDR0 0x0038 /* R */ ++#define RPC_SMRDR1 0x003C /* R */ ++#define RPC_SMWDR0 0x0040 /* R/W */ ++#define RPC_SMWDR1 0x0044 /* R/W */ ++#define RPC_CMNSR 0x0048 /* R */ ++#define RPC_CMNSR_SSLF (0x1 << 1) ++#define RPC_CMNSR_TEND (0x1 << 0) ++ ++#define RPC_DRDMCR 0x0058 /* R/W */ ++#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0) ++ ++#define RPC_DRDRENR 0x005C /* R/W */ ++#define RPC_DRDRENR_HYPE (0x5 << 12) ++#define RPC_DRDRENR_ADDRE (0x1 << 0x8) ++#define RPC_DRDRENR_OPDRE (0x1 << 0x4) ++#define RPC_DRDRENR_DRDRE (0x1 << 0x0) ++ ++#define RPC_SMDMCR 0x0060 /* R/W */ ++#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0) ++ ++#define RPC_SMDRENR 0x0064 /* R/W */ ++#define RPC_SMDRENR_HYPE(v) (((v) & 0x7) << 12) ++#define RPC_SMDRENR_HYPE_HF RPC_SMDRENR_HYPE(0x5) ++#define RPC_SMDRENR_HYPE_SPI RPC_SMDRENR_HYPE(0) ++#define RPC_SMDRENR_ADDRE (0x1 << 0x8) ++#define RPC_SMDRENR_OPDRE (0x1 << 0x4) ++#define RPC_SMDRENR_SPIDRE (0x1 << 0x0) ++ ++#define RPC_PHYCNT 0x007C /* R/W */ ++#define RPC_PHYCNT_CAL (0x1 << 31) ++#define RPC_PHYCNT_OCTA(v) (((v) & 0x3) << 22) ++#define RPC_PHYCNT_OCTA_AA (0x1 << 22) ++#define RPC_PHYCNT_OCTA_SA (0x2 << 22) ++#define RPC_PHYCNT_EXDS (0x1 << 21) ++#define RPC_PHYCNT_OCT (0x1 << 20) ++#define RPC_PHYCNT_DDRCAL (0x1 << 19) ++#define RPC_PHYCNT_HS (0x1 << 18) ++#define RPC_PHYCNT_STRTIM(v) (((v) & 0x7) << 15) ++#define RPC_PHYCNT_WBUF2 (0x1 << 4) ++#define RPC_PHYCNT_WBUF (0x1 << 2) ++#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0) ++ ++#define RPC_PHYINT 0x0088 /* R/W */ ++#define RPC_PHYINT_INTIE (0x1 << 24) ++#define RPC_PHYINT_RSTEN (0x1 << 18) ++#define RPC_PHYINT_WPEN (0x1 << 17) ++#define RPC_PHYINT_INTEN (0x1 << 16) ++#define RPC_PHYINT_RST (0x1 << 2) ++#define RPC_PHYINT_WP (0x1 << 1) ++#define RPC_PHYINT_INT (0x1 << 0) ++ ++#define RPC_PHYOFFSET1 0x0080 ++#define RPC_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28) ++#define RPC_PHYOFFSET1_DDRTMG_SDR RPC_PHYOFFSET1_DDRTMG(3) ++#define RPC_PHYOFFSET1_DDRTMG_DDR RPC_PHYOFFSET1_DDRTMG(2) ++ ++#define RPC_PHYOFFSET2 0x0084 ++#define RPC_PHYOFFSET2_OCTTMG(v) (((v) & 0x7) << 8) ++#define RPC_PHYOFFSET2_OCTAL RPC_PHYOFFSET2_OCTTMG(3) ++#define RPC_PHYOFFSET2_SERIAL RPC_PHYOFFSET2_OCTTMG(4) ++ ++#define RPC_DIVREG 0x00A8 ++#define RPC_DIVREG_RATIO(v) ((v) & 0x03) ++#define RPC_DIVREG_RATIO_MAX (0x2) ++ ++#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */ ++#define RPC_WBUF_SIZE 0x100 ++#define RPC_WBUF_MASK (RPC_WBUF_SIZE - 1) ++ ++/* DMA transfer */ ++#define RPC_DMA_BURST (0x20 << 3) ++#define RPC_DMA_SIZE_MIN (RPC_DMA_BURST << 3) ++ ++#define RPC_READ_ADDR_SIZE BIT(26) ++#define RPC_READ_ADDR_MASK (RPC_READ_ADDR_SIZE - 1) ++ ++/* Default timeout in mS */ ++#define RPC_TIMEOUT 5000 ++ ++/* Device flags */ ++#define RPC_OWN_CLOCK_DIVIDER BIT(0) ++ ++enum rpc_size { ++ /* singe flash: 8 bit; dual flash: 16 bit */ ++ RPC_SIZE_SINGLE_8BIT = RPC_SMENR_SPIDE(0x8), ++ RPC_SIZE_DUAL_16BIT = RPC_SMENR_SPIDE(0x8), ++ /* singe flash: 16 bit; dual flash: 32 bit */ ++ RPC_SIZE_SINGLE_16BIT = RPC_SMENR_SPIDE(0xC), ++ RPC_SIZE_DUAL_32BIT = RPC_SMENR_SPIDE(0xC), ++ /* singe flash: 32 bit; dual flash: 64 bit */ ++ RPC_SIZE_SINGLE_32BIT = RPC_SMENR_SPIDE(0xF), ++ RPC_SIZE_DUAL_64BIT = RPC_SMENR_SPIDE(0xF), ++}; ++ ++enum rpc_type { ++ RPC_SINGLE = 0, ++ RPC_DUAL, ++}; ++ ++struct rpc_info { ++ struct platform_device *pdev; ++ struct device_node *flash; ++ void __iomem *base; ++ void __iomem *read_area; ++ void __iomem *write_area; ++ dma_addr_t read_area_dma; ++ struct completion comp; ++ struct dma_chan *dma_chan; ++ struct clk *clk; ++ unsigned int irq; ++ enum rpc_type mtdtype; ++}; ++ ++/* Register access */ ++static inline u32 rpc_readl(struct rpc_info *rpc, u32 offset) ++{ ++ return readl(rpc->base + offset); ++} ++ ++static inline void rpc_writel(struct rpc_info *rpc, u32 offset, u32 val) ++{ ++ writel(val, rpc->base + offset); ++} ++ ++static inline void rpc_clrsetl(struct rpc_info *rpc, u32 offset, ++ u32 clr, u32 set) ++{ ++ void __iomem *addr = rpc->base + offset; ++ u32 val = readl(addr); ++ ++ val &= ~clr; ++ val |= set; ++ writel(val, addr); ++} ++ ++static inline void rpc_wbuf_writel(struct rpc_info *rpc, u32 offset, u32 val) ++{ ++ writel(val, rpc->write_area + offset); ++} ++ ++/* Check whether write buffer should be used */ ++static inline bool rpc_wbuf_available(struct rpc_info *rpc) ++{ ++ return rpc->write_area; ++} ++ ++#ifdef DEBUG ++extern void rpc_regs_dump(struct rpc_info *rpc); ++#else ++static inline void rpc_regs_dump(struct rpc_info *rpc) { } ++#endif ++ ++extern int rpc_wait(struct rpc_info *rpc, int timeout); ++extern int rpc_dma_read(struct rpc_info *rpc, void *buf, ++ loff_t from, ssize_t *plen); ++extern void rpc_do_read_flash(struct rpc_info *rpc, loff_t from, ++ size_t len, u_char *buf, bool addr32); ++#endif +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0440-arm64-dts-renesas-r8a77970-Update-RPC-device-nodes.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0440-arm64-dts-renesas-r8a77970-Update-RPC-device-nodes.patch new file mode 100644 index 00000000..fba99bf0 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0440-arm64-dts-renesas-r8a77970-Update-RPC-device-nodes.patch @@ -0,0 +1,72 @@ +From 0bfdc760d2cfb3e2c3800310018ac561df458337 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 01:11:03 +0300 +Subject: [PATCH 06/12] arm64: dts: renesas: r8a77970: Update RPC device nodes + +This updates RPC device nodes for the consolidated RPC driver. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a77970-eagle.dts | 2 +- + arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts | 2 +- + arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts | 2 +- + arch/arm64/boot/dts/renesas/r8a77970.dtsi | 4 ++-- + 4 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts +index aa4c65a..5a736aa 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts +@@ -421,7 +421,7 @@ + }; + }; + +-&qspi0 { ++&rpc0 { + pinctrl-0 = <&qspi0_pins &qspi1_pins>; + pinctrl-names = "default"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts +index d6deffe..fad6654 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts +@@ -195,7 +195,7 @@ + }; + }; + +-&qspi0 { ++&rpc0 { + pinctrl-0 = <&qspi0_pins &qspi1_pins>; + pinctrl-names = "default"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts b/arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts +index caecf8c..cabbb0f 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts +@@ -399,7 +399,7 @@ + }; + }; + +-&qspi0 { ++&rpc0 { + pinctrl-0 = <&qspi0_pins &qspi1_pins>; + pinctrl-names = "default"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a77970.dtsi b/arch/arm64/boot/dts/renesas/r8a77970.dtsi +index 456eeb6..603efeb 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77970.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a77970.dtsi +@@ -767,8 +767,8 @@ + status = "disabled"; + }; + +- qspi0: qspi@ee200000 { +- compatible = "renesas,qspi-rpc-r8a77970"; ++ rpc0: qspi@ee200000 { ++ compatible = "renesas,rpc-r8a77970"; + reg = <0 0xee200000 0 0x1f0>, + <0 0x08000000 0 0x04000000>, + <0 0xee208000 0 0x100>; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0441-arm64-dts-renesas-r8a77980-Update-RPC-device-nodes.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0441-arm64-dts-renesas-r8a77980-Update-RPC-device-nodes.patch new file mode 100644 index 00000000..4268ffa4 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0441-arm64-dts-renesas-r8a77980-Update-RPC-device-nodes.patch @@ -0,0 +1,58 @@ +From a7ac55ef8c0a09f15977a5ea6d7d8558e6d23c93 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 01:22:47 +0300 +Subject: [PATCH 07/12] arm64: dts: renesas: r8a77980: Update RPC device nodes + +This updates RPC device nodes for the consolidated RPC driver. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a77980-condor.dts | 2 +- + arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts | 2 +- + arch/arm64/boot/dts/renesas/r8a77980.dtsi | 4 ++-- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-condor.dts b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts +index a60482a..1ba48ad 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-condor.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts +@@ -651,7 +651,7 @@ + }; + }; + +-&qspi0 { ++&rpc0 { + pinctrl-0 = <&qspi0_pins &qspi1_pins>; + pinctrl-names = "default"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts +index 5c8ded5..c8d94e4 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts +@@ -265,7 +265,7 @@ + }; + }; + +-&qspi0 { ++&rpc0 { + pinctrl-0 = <&qspi0_pins &qspi1_pins>; + pinctrl-names = "default"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi +index 0d25b35..23c39c1 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi +@@ -823,8 +823,8 @@ + status = "disabled"; + }; + +- qspi0: qspi@ee200000 { +- compatible = "renesas,qspi-rpc-r8a77980"; ++ rpc0: rpc0@ee200000 { ++ compatible = "renesas,rpc-r8a77980", "renesas,rpc"; + reg = <0 0xee200000 0 0x1f0>, + <0 0x08000000 0 0x04000000>, + <0 0xee208000 0 0x100>; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0442-arm64-dts-renesas-r8a7795-Add-RPC-device-node.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0442-arm64-dts-renesas-r8a7795-Add-RPC-device-node.patch new file mode 100644 index 00000000..51300f63 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0442-arm64-dts-renesas-r8a7795-Add-RPC-device-node.patch @@ -0,0 +1,39 @@ +From 77361fe676437e194091d927125ec3821bfc9eea Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 01:24:39 +0300 +Subject: [PATCH 08/12] arm64: dts: renesas: r8a7795: Add RPC device node + +This adds RPC device node to the r8a7795.dtsi file. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a7795.dtsi | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi +index e1b57e9..cc5844f 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi +@@ -1947,6 +1947,19 @@ + status = "disabled"; + }; + ++ rpc0: rpc0@ee200000 { ++ compatible = "renesas,rpc-r8a7795", "renesas,rpc"; ++ reg = <0 0xee200000 0 0x1f0>, ++ <0 0x08000000 0 0x04000000>, ++ <0 0xee208000 0 0x100>; ++ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&cpg CPG_MOD 917>; ++ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + vin0: video@e6ef0000 { + compatible = "renesas,vin-r8a7795"; + reg = <0 0xe6ef0000 0 0x1000>; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0443-arm64-dts-renesas-r8a7796-Add-RPC-device-node.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0443-arm64-dts-renesas-r8a7796-Add-RPC-device-node.patch new file mode 100644 index 00000000..6b7e7543 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0443-arm64-dts-renesas-r8a7796-Add-RPC-device-node.patch @@ -0,0 +1,39 @@ +From 156743895046cd24f950a3f6790a19b5ba417f92 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 01:25:40 +0300 +Subject: [PATCH 09/12] arm64: dts: renesas: r8a7796: Add RPC device node + +This adds RPC device node to the r8a7796.dtsi file. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a7796.dtsi | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi +index 7fcac8f..c50f5e9 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi +@@ -1853,6 +1853,19 @@ + status = "disabled"; + }; + ++ rpc0: rpc0@ee200000 { ++ compatible = "renesas,rpc-r8a7796", "renesas,rpc"; ++ reg = <0 0xee200000 0 0x1f0>, ++ <0 0x08000000 0 0x04000000>, ++ <0 0xee208000 0 0x100>; ++ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&cpg CPG_MOD 917>; ++ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + vin0: video@e6ef0000 { + compatible = "renesas,vin-r8a7796"; + reg = <0 0xe6ef0000 0 0x1000>; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0444-arm64-dts-renesas-r8a77965-Add-RPC-device-node.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0444-arm64-dts-renesas-r8a77965-Add-RPC-device-node.patch new file mode 100644 index 00000000..e683e929 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0444-arm64-dts-renesas-r8a77965-Add-RPC-device-node.patch @@ -0,0 +1,39 @@ +From df5a5e4ee2a2059cc4fa06bf17a9e2c547afd540 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 01:25:58 +0300 +Subject: [PATCH 10/12] arm64: dts: renesas: r8a77965: Add RPC device node + +This adds RPC device node to the r8a77965.dtsi file. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a77965.dtsi | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi +index b5926ff..0a41a13 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi +@@ -1267,6 +1267,19 @@ + status = "disabled"; + }; + ++ rpc0: rpc0@ee200000 { ++ compatible = "renesas,rpc-r8a77965", "renesas,rpc"; ++ reg = <0 0xee200000 0 0x1f0>, ++ <0 0x08000000 0 0x04000000>, ++ <0 0xee208000 0 0x100>; ++ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&cpg CPG_MOD 917>; ++ power-domains = <&sysc R8A77965_PD_ALWAYS_ON>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + vin0: video@e6ef0000 { + compatible = "renesas,vin-r8a77965"; + reg = <0 0xe6ef0000 0 0x1000>; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0445-arm64-dts-renesas-ulcb-Add-RPC-HyperFlash-device-nod.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0445-arm64-dts-renesas-ulcb-Add-RPC-HyperFlash-device-nod.patch new file mode 100644 index 00000000..52a08ec1 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0445-arm64-dts-renesas-ulcb-Add-RPC-HyperFlash-device-nod.patch @@ -0,0 +1,77 @@ +From 094c3d4eff875eee4009cac9c2fe0cc748a54394 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Nov 2019 01:26:23 +0300 +Subject: [PATCH 11/12] arm64: dts: renesas: ulcb: Add RPC HyperFlash device + node + +This adds RPC HyperFlash device node along with +its partitions to the ULCB device tree. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/ulcb.dtsi | 49 +++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/arch/arm64/boot/dts/renesas/ulcb.dtsi b/arch/arm64/boot/dts/renesas/ulcb.dtsi +index 7e546d3..924b7a0 100644 +--- a/arch/arm64/boot/dts/renesas/ulcb.dtsi ++++ b/arch/arm64/boot/dts/renesas/ulcb.dtsi +@@ -422,6 +422,55 @@ + }; + }; + ++&rpc0 { ++ status = "okay"; ++ ++ flash@0 { ++ compatible = "cfi-flash"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ bootparam@0 { ++ reg = <0x00000000 0x040000>; ++ read-only; ++ }; ++ bl2@00040000 { ++ reg = <0x00040000 0x140000>; ++ read-only; ++ }; ++ cert_header_sa6@00180000 { ++ reg = <0x00180000 0x040000>; ++ read-only; ++ }; ++ bl31@001C0000 { ++ reg = <0x001C0000 0x480000>; ++ read-only; ++ }; ++ uboot@00640000 { ++ reg = <0x00640000 0x0C0000>; ++ read-only; ++ }; ++ uboot-env@00700000 { ++ reg = <0x00700000 0x040000>; ++ read-only; ++ }; ++ dtb@00740000 { ++ reg = <0x00740000 0x080000>; ++ }; ++ kernel@007C0000 { ++ reg = <0x007C0000 0x1400000>; ++ }; ++ user@01BC0000 { ++ reg = <0x01BC0000 0x2440000>; ++ }; ++ }; ++ }; ++}; ++ + &rwdt { + timeout-sec = <60>; + status = "okay"; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0446-arm64-dts-renesas-salvator-common-Add-RPC-HyperFlash.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0446-arm64-dts-renesas-salvator-common-Add-RPC-HyperFlash.patch new file mode 100644 index 00000000..a4a8db97 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0446-arm64-dts-renesas-salvator-common-Add-RPC-HyperFlash.patch @@ -0,0 +1,77 @@ +From 02ad9fb42936a698726a824550305ea7e6dd9b14 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Wed, 6 Nov 2019 03:02:20 +0300 +Subject: [PATCH 12/12] arm64: dts: renesas: salvator-common: Add RPC + HyperFlash device node + +This adds RPC HyperFlash device node along with +its partitions to the common Salvator device tree. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/salvator-common.dtsi | 49 ++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +index 788d38f..6215545 100644 +--- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi ++++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +@@ -823,6 +823,55 @@ + }; + }; + ++&rpc0 { ++ status = "okay"; ++ ++ flash@0 { ++ compatible = "cfi-flash"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ bootparam@0 { ++ reg = <0x00000000 0x040000>; ++ read-only; ++ }; ++ bl2@00040000 { ++ reg = <0x00040000 0x140000>; ++ read-only; ++ }; ++ cert_header_sa6@00180000 { ++ reg = <0x00180000 0x040000>; ++ read-only; ++ }; ++ bl31@001C0000 { ++ reg = <0x001C0000 0x480000>; ++ read-only; ++ }; ++ uboot@00640000 { ++ reg = <0x00640000 0x0C0000>; ++ read-only; ++ }; ++ uboot-env@00700000 { ++ reg = <0x00700000 0x040000>; ++ read-only; ++ }; ++ dtb@00740000 { ++ reg = <0x00740000 0x080000>; ++ }; ++ kernel@007C0000 { ++ reg = <0x007C0000 0x1400000>; ++ }; ++ user@01BC0000 { ++ reg = <0x01BC0000 0x2440000>; ++ }; ++ }; ++ }; ++}; ++ + &rwdt { + timeout-sec = <60>; + status = "okay"; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch new file mode 100644 index 00000000..c6b384e8 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch @@ -0,0 +1,75 @@ +From b7b603c33d7cc369f1165773a0f3fa14f7f71baf Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Sun, 8 Dec 2019 01:30:38 +0300 +Subject: [PATCH] media: soc_camera: rcar_vin: Fix crash when the module is + removed + +The kernel may crash when removing rcar_csi2 or re-inserting +rcar_vin module after having removed it. This happens when +multiple ports are used. Multiple async clients are created +in this case. Each client registers a notifier which is added +to the notifier_list. However, only the last one, referenced +by the async_client pointer, is removed form the notifier_list +later when the rcar_vin module is removed. + +Fix this issue by using a linked list and removing all the +async clients in the list when removing rcar_vin device. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/media/platform/soc_camera/rcar_vin.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c +index 501598c..e13a046 100644 +--- a/drivers/media/platform/soc_camera/rcar_vin.c ++++ b/drivers/media/platform/soc_camera/rcar_vin.c +@@ -922,7 +922,7 @@ struct rcar_vin_priv { + bool deser_sync; + int lut_updated; + +- struct rcar_vin_async_client *async_client; ++ struct list_head async_client; + /* Asynchronous CSI2 linking */ + struct v4l2_subdev *csi2_sd; + /* Asynchronous Deserializer linking */ +@@ -3032,7 +3032,7 @@ static int rcar_vin_soc_of_bind(struct rcar_vin_priv *priv, + sasc->notifier.num_subdevs = 1; + sasc->notifier.ops = &rcar_vin_sensor_ops; + +- priv->async_client = sasc; ++ list_add(&sasc->list, &priv->async_client); + + client = of_find_i2c_device_by_node(remote); + +@@ -3368,6 +3368,7 @@ static int rcar_vin_probe(struct platform_device *pdev) + + spin_lock_init(&priv->lock); + INIT_LIST_HEAD(&priv->capture); ++ INIT_LIST_HEAD(&priv->async_client); + + priv->state = STOPPED; + +@@ -3417,11 +3418,16 @@ static int rcar_vin_remove(struct platform_device *pdev) + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct rcar_vin_priv *priv = container_of(soc_host, + struct rcar_vin_priv, ici); ++ struct rcar_vin_async_client *sasc, *tmp; + +- platform_device_del(priv->async_client->pdev); +- platform_device_put(priv->async_client->pdev); ++ list_for_each_entry_safe(sasc, tmp, &priv->async_client, list) { ++ v4l2_async_notifier_unregister(&sasc->notifier); ++ v4l2_async_notifier_cleanup(&sasc->notifier); ++ list_del(&sasc->list); + +- v4l2_async_notifier_unregister(&priv->async_client->notifier); ++ platform_device_del(sasc->pdev); ++ platform_device_put(sasc->pdev); ++ } + + soc_camera_host_unregister(soc_host); + pm_runtime_disable(&pdev->dev); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0448-media-i2c-ar0xxx-append-embedded-data-stats-into-frame.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0448-media-i2c-ar0xxx-append-embedded-data-stats-into-frame.patch new file mode 100644 index 00000000..b2ce7fe9 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0448-media-i2c-ar0xxx-append-embedded-data-stats-into-frame.patch @@ -0,0 +1,252 @@ +From 294a1931ebc209c2950120c0f2cf24419dd8a1af Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Fri, 13 Dec 2019 23:10:27 +0300 +Subject: [PATCH] media: i2c: ar0xxx: append embedded data/stats into frame + +This allows to append embedded data/stats into active frame +after setup via sysfs of valeu emb_enable + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ar0220_rev2.h | 8 ++-- + drivers/media/i2c/soc_camera/ar0231_rev7.h | 8 ++-- + drivers/media/i2c/soc_camera/ar0233.c | 60 +++++++++++++++++++++++++----- + drivers/media/i2c/soc_camera/ar0233_rev1.h | 8 ++-- + drivers/media/i2c/soc_camera/ar0233_rev2.h | 8 ++-- + drivers/media/i2c/soc_camera/ov106xx.c | 4 +- + 6 files changed, 67 insertions(+), 29 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ar0220_rev2.h b/drivers/media/i2c/soc_camera/ar0220_rev2.h +index c66872d..12845cd 100644 +--- a/drivers/media/i2c/soc_camera/ar0220_rev2.h ++++ b/drivers/media/i2c/soc_camera/ar0220_rev2.h +@@ -311,10 +311,10 @@ static const struct ar0xxx_reg ar0220_rev2_hdr_12bit_output[] = { + + static const struct ar0xxx_reg ar0220_rev2_mipi_12bit_4lane[] = { + {0x31AE, 0x204}, // serial_format: MIPI 4 lanes +-//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C ++{0x3342, 0x2c2c}, // default, DT=0x12, DT=0x2C ++{0x3346, 0x2c2c}, // default, DT=0x12, DT=0x2C ++{0x334A, 0x2c2c}, // default, DT=0x12, DT=0x2C ++{0x334E, 0x2c2c}, // default, DT=0x12, DT=0x2C + //{0x3344, 0x0011}, // default, VC=0 + //{0x3348, 0x0111}, // default, VC=1 + //{0x334C, 0x0211}, // default, VC=2 +diff --git a/drivers/media/i2c/soc_camera/ar0231_rev7.h b/drivers/media/i2c/soc_camera/ar0231_rev7.h +index 704024a..b4c11c3 100644 +--- a/drivers/media/i2c/soc_camera/ar0231_rev7.h ++++ b/drivers/media/i2c/soc_camera/ar0231_rev7.h +@@ -367,10 +367,10 @@ static const struct ar0231_reg ar0231_regs_wizard_rev7[] = { + + #if 1 /* MIPI 12 bit Settings */ + {0x31AE, 0x204}, // serial_format: MIPI 4 lanes +-//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C +-//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C ++{0x3342, 0x2c2c}, // default, DT=0x12, DT=0x2C ++{0x3346, 0x2c2c}, // default, DT=0x12, DT=0x2C ++{0x334A, 0x2c2c}, // default, DT=0x12, DT=0x2C ++{0x334E, 0x2c2c}, // default, DT=0x12, DT=0x2C + //{0x3344, 0x0011}, // default, VC=0 + //{0x3348, 0x0111}, // default, VC=1 + //{0x334C, 0x0211}, // default, VC=2 +diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c +index 312b9fe..b62fb77 100644 +--- a/drivers/media/i2c/soc_camera/ar0233.c ++++ b/drivers/media/i2c/soc_camera/ar0233.c +@@ -23,6 +23,7 @@ + #define AR_DELAY 0xffff + static int AR_MAX_WIDTH; + static int AR_MAX_HEIGHT; ++#define AR_MAX_HEIGHT_EMB (AR_MAX_HEIGHT + priv->emb_enable * 4) /* embedded data (SOF) and stats (EOF) */ + static int AR_X_START; + static int AR_Y_START; + static int AR_X_END; +@@ -55,6 +56,7 @@ struct ar0233_priv { + struct v4l2_rect rect; + int init_complete; + u8 id[6]; ++ bool emb_enable; + /* serializers */ + int ti9x4_addr; + int ti9x3_addr; +@@ -121,7 +123,8 @@ static int ar0233_set_window(struct v4l2_subdev *sd) + /* vert crop start */ + reg16_write16(client, 0x3002, priv->rect.top + AR_Y_START); + /* vert crop end */ +- reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START); ++ /* limit window for embedded data/stats */ ++ reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START - priv->emb_enable * 4); + + return 0; + }; +@@ -207,7 +210,7 @@ static int ar0233_set_selection(struct v4l2_subdev *sd, + rect->height = ALIGN(rect->height, 2); + + if ((rect->left + rect->width > AR_MAX_WIDTH) || +- (rect->top + rect->height > AR_MAX_HEIGHT)) ++ (rect->top + rect->height > AR_MAX_HEIGHT_EMB)) + *rect = priv->rect; + + priv->rect.left = rect->left; +@@ -235,13 +238,13 @@ static int ar0233_get_selection(struct v4l2_subdev *sd, + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = AR_MAX_WIDTH; +- sel->r.height = AR_MAX_HEIGHT; ++ sel->r.height = AR_MAX_HEIGHT_EMB; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = AR_MAX_WIDTH; +- sel->r.height = AR_MAX_HEIGHT; ++ sel->r.height = AR_MAX_HEIGHT_EMB; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r = priv->rect; +@@ -413,7 +416,42 @@ static ssize_t ar0233_otp_id_show(struct device *dev, + priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + } + +-static DEVICE_ATTR(otp_id_ar0233, S_IRUGO, ar0233_otp_id_show, NULL); ++static ssize_t ar0233_emb_enable_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0233_priv *priv = to_ar0233(client); ++ u32 val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ priv->emb_enable = !!val; ++ ++ switch (chipid) { ++ case AR0220_PID: ++ reg16_write16(client, 0x3064, priv->emb_enable ? 0x1982 : 0x1802); break; ++ case AR0233_PID: ++ reg16_write16(client, 0x3064, priv->emb_enable ? 0x0180 : 0); break; ++ default: ++ return -EINVAL; ++ } ++ ++ return count; ++} ++ ++static ssize_t ar0233_emb_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0233_priv *priv = to_ar0233(client); ++ ++ return snprintf(buf, 4, "%d\n", priv->emb_enable); ++} ++ ++static DEVICE_ATTR(otp_id, S_IRUGO, ar0233_otp_id_show, NULL); ++static DEVICE_ATTR(emb_enable, S_IRUGO|S_IWUSR, ar0233_emb_enable_show, ar0233_emb_enable_store); + + static int ar0233_initialize(struct i2c_client *client) + { +@@ -454,7 +492,7 @@ static int ar0233_initialize(struct i2c_client *client) + + switch (pid) { + case AR0220_PID: +- chipid = ID_AR0220; ++ chipid = AR0220_PID; + strncpy(chip_name, "AR0220", 10); + AR_MAX_WIDTH = AR0220_MAX_WIDTH; + AR_MAX_HEIGHT = AR0220_MAX_HEIGHT; +@@ -490,7 +528,7 @@ static int ar0233_initialize(struct i2c_client *client) + } + break; + case AR0233_PID: +- chipid = ID_AR0233; ++ chipid = AR0233_PID; + strncpy(chip_name, "AR0233", 10); + AR_MAX_WIDTH = AR0233_MAX_WIDTH; + AR_MAX_HEIGHT = AR0233_MAX_HEIGHT; +@@ -662,8 +700,9 @@ static int ar0233_probe(struct i2c_client *client, + if (ret) + goto cleanup; + +- if (device_create_file(&client->dev, &dev_attr_otp_id_ar0233) != 0) { +- dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ if (device_create_file(&client->dev, &dev_attr_otp_id) != 0 || ++ device_create_file(&client->dev, &dev_attr_emb_enable) != 0) { ++ dev_err(&client->dev, "sysfs entry creation failed\n"); + goto cleanup; + } + +@@ -686,7 +725,8 @@ static int ar0233_remove(struct i2c_client *client) + { + struct ar0233_priv *priv = i2c_get_clientdata(client); + +- device_remove_file(&client->dev, &dev_attr_otp_id_ar0233); ++ device_remove_file(&client->dev, &dev_attr_otp_id); ++ device_remove_file(&client->dev, &dev_attr_emb_enable); + v4l2_async_unregister_subdev(&priv->sd); + media_entity_cleanup(&priv->sd.entity); + v4l2_ctrl_handler_free(&priv->hdl); +diff --git a/drivers/media/i2c/soc_camera/ar0233_rev1.h b/drivers/media/i2c/soc_camera/ar0233_rev1.h +index 0389e51..3ff944f 100644 +--- a/drivers/media/i2c/soc_camera/ar0233_rev1.h ++++ b/drivers/media/i2c/soc_camera/ar0233_rev1.h +@@ -1138,10 +1138,10 @@ static const struct ar0xxx_reg ar0233_rev1_MIPI_4Lane_12BITS[] = { + {0x31B8, 0x4047}, //mipi_timing_2 + {0x31BA, 0x105}, //mipi_timing_3 + {0x31BC, 0x704}, //mipi_timing_4 +-{0x3342, 0x122C}, // MIPI_F1_PDT_EDT +-{0x3346, 0x122C}, // MIPI_F2_PDT_EDT +-{0x334A, 0x122C}, // MIPI_F3_PDT_EDT +-{0x334E, 0x122C}, // MIPI_F4_PDT_EDT ++{0x3342, 0x2c2c}, // MIPI_F1_PDT_EDT ++{0x3346, 0x2c2c}, // MIPI_F2_PDT_EDT ++{0x334A, 0x2c2c}, // MIPI_F3_PDT_EDT ++{0x334E, 0x2c2c}, // MIPI_F4_PDT_EDT + { } + }; /* MIPI_4Lane_12BITS */ + +diff --git a/drivers/media/i2c/soc_camera/ar0233_rev2.h b/drivers/media/i2c/soc_camera/ar0233_rev2.h +index 7f71056..80572ff 100644 +--- a/drivers/media/i2c/soc_camera/ar0233_rev2.h ++++ b/drivers/media/i2c/soc_camera/ar0233_rev2.h +@@ -2341,10 +2341,10 @@ static const struct ar0xxx_reg ar0233_rev2_mipi_12bit_4lane[] = { + {0x31B8, 0xB04D}, //mipi_timing_2 + {0x31BA, 0x411}, //mipi_timing_3 + {0x31BC, 0x940E}, //mipi_timing_4 +-{0x3342, 0x122C}, // MIPI_F1_PDT_EDT +-{0x3346, 0x122C}, // MIPI_F2_PDT_EDT +-{0x334A, 0x122C}, // MIPI_F3_PDT_EDT +-{0x334E, 0x122C}, // MIPI_F4_PDT_EDT ++{0x3342, 0x2c2c}, // MIPI_F1_PDT_EDT ++{0x3346, 0x2c2c}, // MIPI_F2_PDT_EDT ++{0x334A, 0x2c2c}, // MIPI_F3_PDT_EDT ++{0x334E, 0x2c2c}, // MIPI_F4_PDT_EDT + { } + }; /* mipi_12bit_4lane */ + +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c +index 876b3c1..4d5e084 100644 +--- a/drivers/media/i2c/soc_camera/ov106xx.c ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -79,10 +79,8 @@ static int ov106xx_probe(struct i2c_client *client, + } + + ret = ar0233_probe(client, did); +- if (!ret) { +- chip_id = ID_AR0233; ++ if (!ret) + goto out; +- } + + ret = ar0323_probe(client, did); + if (!ret) { +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0449-media-i2c-soc_camera-ov495_ov2775-Remove-early_param.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0449-media-i2c-soc_camera-ov495_ov2775-Remove-early_param.patch new file mode 100644 index 00000000..0c4c5335 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0449-media-i2c-soc_camera-ov495_ov2775-Remove-early_param.patch @@ -0,0 +1,55 @@ +From 63e509e237f058679dd4a04012f53c8c56aaafb0 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Thu, 19 Dec 2019 15:08:14 +0300 +Subject: [PATCH] media: i2c: soc_camera: ov495_ov2775: Remove early_param + parser +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use conf_link variable instead of force_conf_link, +and remove eaarly_param() parser altogether. +This fixes the following module compilation error: + + expected declaration specifiers or ‘...’ before ‘ov495_force_conf_link’ + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov495_ov2775.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ov495_ov2775.c b/drivers/media/i2c/soc_camera/ov495_ov2775.c +index aee8145..c40970c 100644 +--- a/drivers/media/i2c/soc_camera/ov495_ov2775.c ++++ b/drivers/media/i2c/soc_camera/ov495_ov2775.c +@@ -57,17 +57,6 @@ struct ov495_priv { + + }; + +-static int force_conf_link; +- +-static __init int ov495_force_conf_link(char *str) +-{ +- /* force configuration link */ +- /* used only if robust firmware flashing required (f.e. recovery) */ +- force_conf_link = 1; +- return 0; +-} +-early_param("force_conf_link", ov495_force_conf_link); +- + static inline struct ov495_priv *to_ov495(const struct i2c_client *client) + { + return container_of(i2c_get_clientdata(client), struct ov495_priv, sd); +@@ -429,7 +418,7 @@ static int ov495_initialize(struct i2c_client *client) + client->addr = tmp_addr; + #endif + +- if (unlikely(force_conf_link)) ++ if (unlikely(conf_link)) + goto out; + + #if 0 +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0450-arm64-dts-renesas-ulcb-Add-tee-MTD-RPC-HyperFlash-pa.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0450-arm64-dts-renesas-ulcb-Add-tee-MTD-RPC-HyperFlash-pa.patch new file mode 100644 index 00000000..a272501d --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0450-arm64-dts-renesas-ulcb-Add-tee-MTD-RPC-HyperFlash-pa.patch @@ -0,0 +1,33 @@ +From c70a41608dfebff4bcc98c5e164dc0bd24ecd37a Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Fri, 20 Dec 2019 00:30:53 +0300 +Subject: [PATCH 1/2] arm64: dts: renesas: ulcb: Add "tee" MTD RPC HyperFlash + partition + +This reduces "bl31" partition size, and inserts "tee" partition. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/ulcb.dtsi | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/renesas/ulcb.dtsi b/arch/arm64/boot/dts/renesas/ulcb.dtsi +index 924b7a0..4b22551 100644 +--- a/arch/arm64/boot/dts/renesas/ulcb.dtsi ++++ b/arch/arm64/boot/dts/renesas/ulcb.dtsi +@@ -447,7 +447,11 @@ + read-only; + }; + bl31@001C0000 { +- reg = <0x001C0000 0x480000>; ++ reg = <0x001C0000 0x040000>; ++ read-only; ++ }; ++ tee@00200000 { ++ reg = <0x00200000 0x440000>; + read-only; + }; + uboot@00640000 { +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0451-arm64-dts-renesas-salvator-common-Add-tee-MTD-RPC-Hy.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0451-arm64-dts-renesas-salvator-common-Add-tee-MTD-RPC-Hy.patch new file mode 100644 index 00000000..bf122dd1 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0451-arm64-dts-renesas-salvator-common-Add-tee-MTD-RPC-Hy.patch @@ -0,0 +1,33 @@ +From e88ff4d294af995c671760e2a0741a646a52edca Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Fri, 20 Dec 2019 00:34:16 +0300 +Subject: [PATCH 2/2] arm64: dts: renesas: salvator-common: Add "tee" MTD RPC + HyperFlash partition + +This reduces "bl31" partition size, and inserts "tee" partition. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/salvator-common.dtsi | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +index 6215545..5083d92 100644 +--- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi ++++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +@@ -848,7 +848,11 @@ + read-only; + }; + bl31@001C0000 { +- reg = <0x001C0000 0x480000>; ++ reg = <0x001C0000 0x040000>; ++ read-only; ++ }; ++ tee@00200000 { ++ reg = <0x00200000 0x440000>; + read-only; + }; + uboot@00640000 { +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0452-arm64-dts-renesas-ulcb-Increase-U-Boot-partition-siz.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0452-arm64-dts-renesas-ulcb-Increase-U-Boot-partition-siz.patch new file mode 100644 index 00000000..0ff0f918 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0452-arm64-dts-renesas-ulcb-Increase-U-Boot-partition-siz.patch @@ -0,0 +1,54 @@ +From b45d7c8d45ca94b4e0ac2ad6df8b4f9b56cf3b38 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Fri, 20 Dec 2019 14:09:00 +0300 +Subject: [PATCH 1/2] arm64: dts: renesas: ulcb: Increase U-Boot partition size + +Increase U-Boot partition size according to its actual size. +This involves moving the "u-boot-env", "kernel", "dtb" and +"user" partitions further by one sector which is safe +at this point because they are not used yet. U-Boot +environment is located on the eMMC flash. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/ulcb.dtsi | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/ulcb.dtsi b/arch/arm64/boot/dts/renesas/ulcb.dtsi +index 4b22551..f33027c 100644 +--- a/arch/arm64/boot/dts/renesas/ulcb.dtsi ++++ b/arch/arm64/boot/dts/renesas/ulcb.dtsi +@@ -455,21 +455,21 @@ + read-only; + }; + uboot@00640000 { +- reg = <0x00640000 0x0C0000>; ++ reg = <0x00640000 0x100000>; + read-only; + }; +- uboot-env@00700000 { +- reg = <0x00700000 0x040000>; ++ uboot-env@00740000 { ++ reg = <0x00740000 0x040000>; + read-only; + }; +- dtb@00740000 { +- reg = <0x00740000 0x080000>; ++ dtb@00780000 { ++ reg = <0x00780000 0x080000>; + }; +- kernel@007C0000 { +- reg = <0x007C0000 0x1400000>; ++ kernel@00800000 { ++ reg = <0x00800000 0x1400000>; + }; +- user@01BC0000 { +- reg = <0x01BC0000 0x2440000>; ++ user@01C00000 { ++ reg = <0x01C00000 0x2400000>; + }; + }; + }; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0453-arm64-dts-renesas-salvator-common-Increase-U-Boot-pa.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0453-arm64-dts-renesas-salvator-common-Increase-U-Boot-pa.patch new file mode 100644 index 00000000..bfed8a06 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0453-arm64-dts-renesas-salvator-common-Increase-U-Boot-pa.patch @@ -0,0 +1,55 @@ +From 4bba9d3777068ee97982c4b6c60a5eb29d06baab Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Fri, 20 Dec 2019 14:05:20 +0300 +Subject: [PATCH 2/2] arm64: dts: renesas: salvator-common: Increase U-Boot + partition size + +Increase U-Boot partition size according to its actual size. +This involves moving the "u-boot-env", "kernel", "dtb" and +"user" partitions further by one sector which is safe +at this point because they are not used yet. U-Boot +environment is located on the eMMC flash. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/salvator-common.dtsi | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +index 5083d92..6bc9c6e 100644 +--- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi ++++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +@@ -856,21 +856,21 @@ + read-only; + }; + uboot@00640000 { +- reg = <0x00640000 0x0C0000>; ++ reg = <0x00640000 0x100000>; + read-only; + }; +- uboot-env@00700000 { +- reg = <0x00700000 0x040000>; ++ uboot-env@00740000 { ++ reg = <0x00740000 0x040000>; + read-only; + }; +- dtb@00740000 { +- reg = <0x00740000 0x080000>; ++ dtb@00780000 { ++ reg = <0x00780000 0x080000>; + }; +- kernel@007C0000 { +- reg = <0x007C0000 0x1400000>; ++ kernel@00800000 { ++ reg = <0x00800000 0x1400000>; + }; +- user@01BC0000 { +- reg = <0x01BC0000 0x2440000>; ++ user@01C00000 { ++ reg = <0x01C00000 0x2400000>; + }; + }; + }; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0454-media-i2c-imx390-fix-refclk.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0454-media-i2c-imx390-fix-refclk.patch new file mode 100644 index 00000000..af31b486 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0454-media-i2c-imx390-fix-refclk.patch @@ -0,0 +1,47 @@ +From 602dbaa9bc1794fe50d522dbef5a2ffde9eea202 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 25 Dec 2019 17:02:13 +0300 +Subject: [PATCH] media: i2c: imx390: fix refclk + +The rflck for IMX390 must be ether 24MHz or 27Mhz +The deserializer on Cogent ECU provides 23Mhz, hence use +serizlizer PLL to adjust refclk to 24MHz + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imx390.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imx390.c b/drivers/media/i2c/soc_camera/imx390.c +index b1df1ba..c1e5680 100644 +--- a/drivers/media/i2c/soc_camera/imx390.c ++++ b/drivers/media/i2c/soc_camera/imx390.c +@@ -428,17 +428,18 @@ static int imx390_initialize(struct i2c_client *client) + goto err; + } + +-#if 0 +- /* setup XCLK */ + tmp_addr = client->addr; + if (priv->ti9x4_addr) { +- /* CLK_OUT=22.5792*160*M/N/CLKDIV -> CLK_OUT=25MHz: CLKDIV=4, M=7, N=253: 22.5792*160/4*7/253=24.989MHz=CLK_OUT */ +- client->addr = priv->ti9x3_addr; /* Serializer I2C address */ +- reg8_write(client, 0x06, 0x47); /* Set CLKDIV and M */ +- reg8_write(client, 0x07, 0xfd); /* Set N */ ++ /* Setup XCLK: ++ CLK_OUT=23MHz*160*M/N/CLKDIV ++ CLK_OUT=24MHz (desired), CLKDIV=4, M=6, N=230 ++ 23*160/4*6/230 = 24MHz = CLK_OUT ++ */ ++ client->addr = priv->ti9x3_addr; ++ reg8_write(client, 0x06, 0x46); /* Set CLKDIV and M */ ++ reg8_write(client, 0x07, 0xe6); /* Set N */ + } + client->addr = tmp_addr; +-#endif + + /* Read OTP IDs */ + imx390_otp_id_read(client); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0455-media-i2c-ox01d10-add-imager-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0455-media-i2c-ox01d10-add-imager-support.patch new file mode 100644 index 00000000..3551d572 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0455-media-i2c-ox01d10-add-imager-support.patch @@ -0,0 +1,1162 @@ +From fc00b90bd8aa659028e73364f6bef6789da95cc6 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 25 Dec 2019 21:03:24 +0300 +Subject: [PATCH] media: i2c: ox01d10: add imager support + +This adds OVT OX01D10 imager support + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov106xx.c | 8 + + drivers/media/i2c/soc_camera/ox01d10.c | 611 +++++++++++++++++++++++++++++++++ + drivers/media/i2c/soc_camera/ox01d10.h | 487 ++++++++++++++++++++++++++ + 3 files changed, 1106 insertions(+) + create mode 100644 drivers/media/i2c/soc_camera/ox01d10.c + create mode 100644 drivers/media/i2c/soc_camera/ox01d10.h + +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c +index 4d5e084..841861c 100644 +--- a/drivers/media/i2c/soc_camera/ov106xx.c ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -27,6 +27,7 @@ static enum { + ID_GW5200_IMX390, + ID_OV2775, + ID_IMX390, ++ ID_OX01D10, + ID_OX03A, + ID_ISX016, + ID_ISX019, +@@ -48,6 +49,7 @@ static enum { + #include "gw5200_imx390.c" + #include "ov2775.c" + #include "imx390.c" ++#include "ox01d10.c" + #include "ox03a.c" + #include "isx016.c" + #include "isx019.c" +@@ -172,6 +174,12 @@ static int ov106xx_probe(struct i2c_client *client, + goto out; + } + ++ ret = ox01d10_probe(client, did); ++ if (!ret) { ++ chip_id = ID_OX01D10; ++ goto out; ++ } ++ + ret = ox03a_probe(client, did); + if (!ret) { + chip_id = ID_OX03A; +diff --git a/drivers/media/i2c/soc_camera/ox01d10.c b/drivers/media/i2c/soc_camera/ox01d10.c +new file mode 100644 +index 0000000..3ea3fef +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ox01d10.c +@@ -0,0 +1,611 @@ ++/* ++ * OmniVision OX01D10 sensor camera driver ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++#include "ox01d10.h" ++ ++#define OX01D10_I2C_ADDR 0x36 ++ ++#define OX01D10_PID_REGA 0x300A ++#define OX01D10_PID_REGB 0x300B ++#define OX01D10_PID 0x5801 ++ ++#define OX01D10_MEDIA_BUS_FMT MEDIA_BUS_FMT_SBGGR12_1X12 ++ ++struct ox01d10_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int init_complete; ++ u8 id[6]; ++ int exposure; ++ int gain; ++ int again; ++ int autogain; ++ /* serializers */ ++ int ti9x4_addr; ++ int ti9x3_addr; ++ int port; ++ int gpio_resetb; ++ int gpio_fsin; ++}; ++ ++static inline struct ox01d10_priv *to_ox01d10(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ox01d10_priv, sd); ++} ++ ++static int ox01d10_set_regs(struct i2c_client *client, ++ const struct ox01d10_reg *regs, int nr_regs) ++{ ++ int i; ++ ++ for (i = 0; i < nr_regs; i++) { ++ if (regs[i].reg == OX01D10_DELAY) { ++ mdelay(regs[i].val); ++ continue; ++ } ++ ++ reg16_write(client, regs[i].reg, regs[i].val); ++ } ++ ++ return 0; ++} ++ ++static int ox01d10_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int ox01d10_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ox01d10_priv *priv = to_ox01d10(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = OX01D10_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ox01d10_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ ++ mf->code = OX01D10_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int ox01d10_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = OX01D10_MEDIA_BUS_FMT; ++ ++ return 0; ++} ++ ++static int ox01d10_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ox01d10_priv *priv = to_ox01d10(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = OX01D10_PID >> 8; ++ edid->edid[9] = OX01D10_PID & 0xff; ++ ++ return 0; ++} ++ ++static int ox01d10_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ox01d10_priv *priv = to_ox01d10(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > OX01D10_MAX_WIDTH) || ++ (rect->top + rect->height > OX01D10_MAX_HEIGHT)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ return 0; ++} ++ ++static int ox01d10_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ox01d10_priv *priv = to_ox01d10(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = OX01D10_MAX_WIDTH; ++ sel->r.height = OX01D10_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = OX01D10_MAX_WIDTH; ++ sel->r.height = OX01D10_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ox01d10_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ox01d10_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ u8 val = 0; ++ ++ ret = reg16_read(client, (u16)reg->reg, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = sizeof(u8); ++ ++ return 0; ++} ++ ++static int ox01d10_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ return reg16_write(client, (u16)reg->reg, (u8)reg->val); ++} ++#endif ++ ++static struct v4l2_subdev_core_ops ox01d10_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ox01d10_g_register, ++ .s_register = ox01d10_s_register, ++#endif ++}; ++ ++static int ox01d10_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ox01d10_priv *priv = to_ox01d10(client); ++ int ret = -EINVAL; ++ u8 val = 0; ++ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ case V4L2_CID_SHARPNESS: ++ case V4L2_CID_AUTOGAIN: ++ break; ++ case V4L2_CID_GAIN: ++ /* start recording group3 */ ++ ret = reg16_write(client, 0x3208, 0x03); ++ /* HCG digital gain */ ++ ret |= reg16_write(client, 0x350a, ctrl->val >> 8); ++ ret |= reg16_write(client, 0x350b, ctrl->val & 0xff); ++ /* LCG digital gain */ ++ ret |= reg16_write(client, 0x354a, ctrl->val/8 >> 8); ++ ret |= reg16_write(client, 0x354b, ctrl->val/8 & 0xff); ++ /* VS digital gain */ ++ ret |= reg16_write(client, 0x358a, ctrl->val/64 >> 8); ++ ret |= reg16_write(client, 0x358b, ctrl->val/64 & 0xff); ++ /* stop recording and launch group3 */ ++ ret |= reg16_write(client, 0x3208, 0x13); ++ ret |= reg16_write(client, 0x3208, 0xe3); ++ break; ++ case V4L2_CID_ANALOGUE_GAIN: ++ /* start recording group3 */ ++ ret = reg16_write(client, 0x3208, 0x03); ++ /* HCG real gain */ ++ ret |= reg16_write(client, 0x3508, ctrl->val >> 8); ++ ret |= reg16_write(client, 0x3509, ctrl->val & 0xff); ++ /* LCG real gain */ ++ ret |= reg16_write(client, 0x3548, ctrl->val/8 >> 8); ++ ret |= reg16_write(client, 0x3549, ctrl->val/8 & 0xff); ++ /* VS real gain */ ++ ret |= reg16_write(client, 0x3588, ctrl->val/64 >> 8); ++ ret |= reg16_write(client, 0x3589, ctrl->val/64 & 0xff); ++ /* stop recording and launch group3 */ ++ ret |= reg16_write(client, 0x3208, 0x13); ++ ret |= reg16_write(client, 0x3208, 0xe3); ++ break; ++ case V4L2_CID_EXPOSURE: ++ /* start recording group3 */ ++ ret = reg16_write(client, 0x3208, 0x03); ++ /* HCG (long) exposure time */ ++ ret |= reg16_write(client, 0x3501, ctrl->val >> 8); ++ ret |= reg16_write(client, 0x3502, ctrl->val & 0xff); ++ /* LCG (short) exposure time */ ++ ret |= reg16_write(client, 0x3541, ctrl->val/4 >> 8); ++ ret |= reg16_write(client, 0x3542, ctrl->val/4 & 0xff); ++ /* VS exposure time */ ++ ret |= reg16_write(client, 0x3581, ctrl->val/16 >> 8); ++ ret |= reg16_write(client, 0x3582, ctrl->val/16 & 0xff); ++ /* stop recording and launch group3 */ ++ ret |= reg16_write(client, 0x3208, 0x13); ++ ret |= reg16_write(client, 0x3208, 0xe3); ++ break; ++ case V4L2_CID_HFLIP: ++ /* start recording group3 */ ++ ret = reg16_write(client, 0x3208, 0x03); ++ ret = reg16_read(client, 0x3821, &val); ++ if (ctrl->val) ++ val |= 0x04; ++ else ++ val &= ~0x04; ++ ret |= reg16_write(client, 0x3821, val); ++ /* hflip channges CFA, hence compensate it by moving crop window over bayer matrix */ ++ ret |= reg16_read(client, 0x3811, &val); ++ if (ctrl->val) ++ val++; ++ else ++ val--; ++ ret |= reg16_write(client, 0x3811, val); ++ /* stop recording and launch group3 */ ++ ret |= reg16_write(client, 0x3208, 0x13); ++ ret |= reg16_write(client, 0x3208, 0xe3); ++ break; ++ case V4L2_CID_VFLIP: ++ ret = reg16_read(client, 0x3820, &val); ++ if (ctrl->val) ++ val |= 0x44; ++ else ++ val &= ~0x44; ++ ret |= reg16_write(client, 0x3820, val); ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ox01d10_ctrl_ops = { ++ .s_ctrl = ox01d10_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops ox01d10_video_ops = { ++ .s_stream = ox01d10_s_stream, ++ .g_mbus_config = ox01d10_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops ox01d10_subdev_pad_ops = { ++ .get_edid = ox01d10_get_edid, ++ .enum_mbus_code = ox01d10_enum_mbus_code, ++ .get_selection = ox01d10_get_selection, ++ .set_selection = ox01d10_set_selection, ++ .get_fmt = ox01d10_get_fmt, ++ .set_fmt = ox01d10_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops ox01d10_subdev_ops = { ++ .core = &ox01d10_core_ops, ++ .video = &ox01d10_video_ops, ++ .pad = &ox01d10_subdev_pad_ops, ++}; ++ ++static void ox01d10_otp_id_read(struct i2c_client *client) ++{ ++} ++ ++static ssize_t ox01d10_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ox01d10_priv *priv = to_ox01d10(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_ox01d10, S_IRUGO, ox01d10_otp_id_show, NULL); ++ ++static int ox01d10_initialize(struct i2c_client *client) ++{ ++ struct ox01d10_priv *priv = to_ox01d10(client); ++ char chip_name[10] = "unknown"; ++ u8 val = 0; ++ u16 pid; ++ int ret = 0; ++ int tmp_addr = 0; ++ ++ /* check and show model ID */ ++ reg16_read(client, OX01D10_PID_REGA, &val); ++ pid = val; ++ reg16_read(client, OX01D10_PID_REGB, &val); ++ pid = (pid << 8) | val; ++ ++ if (pid != OX01D10_PID) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ tmp_addr = client->addr; ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x3_addr; ++ reg8_write(client, 0x02, 0x13); /* MIPI 2-lanes */ ++ ++ /* Setup XCLK: CLK_OUT=23MHz*160*M/N/CLKDIV, CLK_OUT=24MHz (desired), CLKDIV=4, M=6, N=230, 23*160/4*6/230 = 24MHz = CLK_OUT */ ++ reg8_write(client, 0x06, 0x46); /* Set CLKDIV and M */ ++ reg8_write(client, 0x07, 0xe6); /* Set N */ ++ } ++ client->addr = tmp_addr; ++ ++ /* Program wizard registers */ ++ ox01d10_set_regs(client, ox01d10_regs_wizard_r1b_hdr3, ARRAY_SIZE(ox01d10_regs_wizard_r1b_hdr3)); ++ /* Read OTP IDs */ ++ ox01d10_otp_id_read(client); ++ ++ dev_info(&client->dev, "ox01d10 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, OX01D10_MAX_WIDTH, OX01D10_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++err: ++ return ret; ++} ++ ++static int ox01d10_parse_dt(struct device_node *np, struct ox01d10_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ int i; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ int tmp_addr = 0; ++ ++ for (i = 0; ; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; ++ ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; ++ ++ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && ++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") && ++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) && ++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) ++ break; ++ } ++ ++ of_node_put(endpoint); ++ ++ if (!priv->ti9x4_addr) { ++ dev_err(&client->dev, "deserializer does not present\n"); ++ return -EINVAL; ++ } ++ ++ /* setup I2C translator address */ ++ tmp_addr = client->addr; ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ ++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ ++ reg8_write(client, 0x5d, OX01D10_I2C_ADDR << 1); /* Sensor native I2C address */ ++ } ++ client->addr = tmp_addr; ++ ++ mdelay(10); ++ ++ return 0; ++} ++ ++static int ox01d10_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ox01d10_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &ox01d10_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ priv->exposure = 0x200; ++ priv->gain = 0x200; ++ priv->again = 0x200; ++ priv->autogain = 1; ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_GAIN, 1, 0xfff, 1, priv->gain); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 1, 0xfff, 1, priv->again); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 0xffff, 1, priv->exposure); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 1); ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = ox01d10_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = ox01d10_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = OX01D10_MAX_WIDTH; ++ priv->rect.height = OX01D10_MAX_HEIGHT; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ox01d10) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++#ifdef CONFIG_SOC_CAMERA_OX01D10 ++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", ++ client->addr, client->adapter->name); ++#endif ++ return ret; ++} ++ ++static int ox01d10_remove(struct i2c_client *client) ++{ ++ struct ox01d10_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_ox01d10); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SOC_CAMERA_OX01D10 ++static const struct i2c_device_id ox01d10_id[] = { ++ { "ox01d10", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ox01d10_id); ++ ++static const struct of_device_id ox01d10_of_ids[] = { ++ { .compatible = "ovti,ox01d10", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ox01d10_of_ids); ++ ++static struct i2c_driver ox01d10_i2c_driver = { ++ .driver = { ++ .name = "ox01d10", ++ .of_match_table = ox01d10_of_ids, ++ }, ++ .probe = ox01d10_probe, ++ .remove = ox01d10_remove, ++ .id_table = ox01d10_id, ++}; ++ ++module_i2c_driver(ox01d10_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for OX01D10"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); ++#endif +diff --git a/drivers/media/i2c/soc_camera/ox01d10.h b/drivers/media/i2c/soc_camera/ox01d10.h +new file mode 100644 +index 0000000..fd50e55 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ox01d10.h +@@ -0,0 +1,487 @@ ++/* ++ * OmniVision OX01D10 sensor camera wizard 1336x1036@30/RGGB/MIPI ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++//#define OX01D10_DISPLAY_PATTERN_COLOR_BAR ++ ++#define OX01D10_MAX_WIDTH 1280 ++#define OX01D10_MAX_HEIGHT 960 ++ ++#define OX01D10_SENSOR_WIDTH 1336 ++#define OX01D10_SENSOR_HEIGHT 1036 ++ ++#define OX01D10_X_START ((OX01D10_SENSOR_WIDTH - OX01D10_MAX_WIDTH) / 2) ++#define OX01D10_Y_START ((OX01D10_SENSOR_HEIGHT - OX01D10_MAX_HEIGHT) / 2) ++#define OX01D10_X_END (OX01D10_X_START + OX01D10_MAX_WIDTH - 1) ++#define OX01D10_Y_END (OX01D10_Y_START + OX01D10_MAX_HEIGHT - 1) ++ ++#define OX01D10_DELAY 0xffff ++ ++struct ox01d10_reg { ++ u16 reg; ++ u8 val; ++}; ++ ++/* wizard: MIPI 1280x960 HDR3_COMB RAW 30fps A02 */ ++static const struct ox01d10_reg ox01d10_regs_wizard_r1b_hdr3[] = { ++{0x107, 0x01}, // s/w reset ++{OX01D10_DELAY, 100}, // Wait 10ms ++{0x3002, 0x00}, ++{0x3009, 0x26}, ++{0x3012, 0x21}, // MIPI, 2 lanes ++{0x3016, 0xd0}, ++{0x3018, 0x50}, ++{0x301a, 0xb0}, ++{0x301e, 0x30}, ++{0x301f, 0x61}, ++{0x3020, 0x01}, ++{0x3022, 0x88}, ++{0x3023, 0x80}, ++{0x3024, 0x80}, ++{0x3028, 0x10}, ++{0x3600, 0x02}, ++{0x3602, 0x42}, ++{0x3603, 0x13}, ++{0x3604, 0xb3}, ++{0x3605, 0xff}, ++{0x3606, 0x90}, ++{0x3607, 0x59}, ++{0x360d, 0x88}, ++{0x3611, 0x49}, ++{0x3612, 0x49}, ++{0x3613, 0xbe}, ++{0x3614, 0xa9}, ++{0x3615, 0x89}, ++{0x3619, 0x00}, ++{0x3620, 0x60}, ++{0x362a, 0x18}, ++{0x362b, 0x18}, ++{0x362c, 0x18}, ++{0x362d, 0x18}, ++{0x3643, 0x12}, ++{0x3644, 0x00}, ++{0x3645, 0x17}, ++{0x3646, 0x1c}, ++{0x3647, 0x12}, ++{0x3648, 0x00}, ++{0x3649, 0x17}, ++{0x364a, 0x1c}, ++{0x364c, 0x18}, ++{0x364d, 0x18}, ++{0x364e, 0x18}, ++{0x364f, 0x18}, ++{0x3652, 0xca}, ++{0x3660, 0x43}, ++{0x3661, 0x31}, ++{0x3662, 0x00}, ++{0x3663, 0x00}, ++{0x3665, 0x13}, ++{0x3668, 0x80}, ++{0x366f, 0x00}, ++{0x3671, 0xe7}, ++{0x3674, 0x80}, ++{0x3678, 0x00}, ++{0x303, 0x02}, ++{0x305, 0x50}, ++{0x306, 0x03}, ++{0x307, 0x00}, ++{0x308, 0x07}, ++{0x30a, 0x01}, ++{0x316, 0x00}, ++{0x317, 0x41}, ++{0x323, 0x04}, ++{0x325, 0x50}, ++{0x326, 0x00}, ++{0x327, 0x03}, ++{0x328, 0x07}, ++{0x329, 0x00}, ++{0x32a, 0x00}, ++{0x32b, 0x00}, ++{0x32c, 0x02}, ++{0x3106, 0x10}, ++{0x3d8a, 0x03}, ++{0x3d8b, 0xff}, ++{0x4580, 0xf8}, ++{0x4581, 0xc7}, ++{0x458f, 0x00}, ++{0x4590, 0x20}, ++{0x4d0a, 0x68}, ++{0x4d0b, 0x78}, ++{0x4d0c, 0xa6}, ++{0x4d0d, 0x0c}, ++{0x4f00, 0xfa}, ++{0x4f01, 0x3f}, ++{0x3501, 0x00}, ++{0x3502, 0x18}, ++{0x3504, 0x28}, ++{0x3508, 0x01}, ++{0x3509, 0x00}, ++{0x350a, 0x01}, ++{0x350b, 0x00}, ++{0x350c, 0x00}, ++{0x3541, 0x00}, ++{0x3542, 0x14}, ++{0x3544, 0x28}, ++{0x3548, 0x01}, ++{0x3549, 0x00}, ++{0x354a, 0x01}, ++{0x354b, 0x00}, ++{0x354c, 0x00}, ++{0x3581, 0x00}, ++{0x3582, 0x10}, ++{0x3584, 0x28}, ++{0x3586, 0x01}, ++{0x3587, 0x69}, ++{0x3588, 0x01}, ++{0x3589, 0x00}, ++{0x358a, 0x01}, ++{0x358b, 0x00}, ++{0x358c, 0x00}, ++{0x358d, 0x0c}, ++{0x3700, 0x16}, ++{0x3701, 0x2c}, ++{0x3703, 0x19}, ++{0x3705, 0x00}, ++{0x3706, 0x35}, ++{0x3707, 0x16}, ++{0x3709, 0x29}, ++{0x370a, 0x00}, ++{0x370b, 0x85}, ++{0x370d, 0x08}, ++{0x3717, 0x03}, ++{0x3718, 0x08}, ++{0x371a, 0x04}, ++{0x371b, 0x14}, ++{0x371d, 0x00}, ++{0x3720, 0x03}, ++{0x372c, 0x10}, ++{0x372d, 0x04}, ++{0x3738, 0x4f}, ++{0x3739, 0x4f}, ++{0x373a, 0x2b}, ++{0x373b, 0x24}, ++{0x373f, 0x49}, ++{0x3740, 0x49}, ++{0x3741, 0x25}, ++{0x3742, 0x20}, ++{0x3747, 0x16}, ++{0x3748, 0x16}, ++{0x374b, 0x03}, ++{0x374c, 0x14}, ++{0x3752, 0x03}, ++{0x3756, 0x10}, ++{0x3757, 0x2e}, ++{0x3758, 0x00}, ++{0x3759, 0x35}, ++{0x375a, 0x00}, ++{0x375b, 0x85}, ++{0x375e, 0x12}, ++{0x3760, 0x09}, ++{0x376c, 0x01}, ++{0x376d, 0x08}, ++{0x376e, 0x08}, ++{0x376f, 0x08}, ++{0x3771, 0x08}, ++{0x3773, 0x00}, ++{0x3777, 0x00}, ++{0x3779, 0x02}, ++{0x377a, 0x00}, ++{0x377b, 0x00}, ++{0x377c, 0xc8}, ++{0x3785, 0x08}, ++{0x3790, 0x10}, ++{0x3797, 0x00}, ++{0x3798, 0x00}, ++{0x3799, 0x00}, ++{0x379c, 0x01}, ++{0x379d, 0x00}, ++{0x37a2, 0x02}, ++{0x37a3, 0x02}, ++{0x37a4, 0x02}, ++{0x37a5, 0x09}, ++{0x37a6, 0x09}, ++{0x37a7, 0x09}, ++{0x37a8, 0x03}, ++{0x37a9, 0x03}, ++{0x37ab, 0x03}, ++{0x37ad, 0x05}, ++{0x37ae, 0x05}, ++{0x37b0, 0x05}, ++{0x37b2, 0x04}, ++{0x37b3, 0x04}, ++{0x37b4, 0x04}, ++{0x37b5, 0x03}, ++{0x37b6, 0x03}, ++{0x37b7, 0x03}, ++{0x37bd, 0x01}, ++{0x37be, 0x36}, ++{0x37c0, 0xd0}, ++{0x37c4, 0x57}, ++{0x37c5, 0x57}, ++{0x37c6, 0x33}, ++{0x37c7, 0x29}, ++{0x37ce, 0x01}, ++{0x37d0, 0x00}, ++{0x37d1, 0x35}, ++{0x37d2, 0x00}, ++{0x37d3, 0x85}, ++{0x37d4, 0x00}, ++{0x37d5, 0x35}, ++{0x37d6, 0x00}, ++{0x37d7, 0x85}, ++{0x37d8, 0x01}, ++{0x37da, 0x02}, ++{0x37db, 0x00}, ++{0x37dc, 0x4c}, ++{0x3c00, 0x04}, ++{0x3c0b, 0x26}, ++{0x3c12, 0x88}, ++{0x3c1f, 0x12}, ++{0x3c20, 0x04}, ++{0x3c24, 0x0f}, ++{0x3c25, 0x14}, ++{0x3c26, 0x07}, ++{0x3c27, 0x10}, ++{0x3c28, 0x06}, ++{0x3c29, 0x0b}, ++{0x3c2b, 0x09}, ++{0x3c2c, 0x0e}, ++{0x3c2d, 0x07}, ++{0x3c2e, 0x0a}, ++{0x3c2f, 0x05}, ++{0x3c30, 0x0c}, ++{0x3c31, 0x08}, ++{0x3c32, 0x0f}, ++{0x3c33, 0x0a}, ++{0x3c34, 0x0d}, ++{0x3c3c, 0x00}, ++{0x3c3d, 0x0b}, ++{0x3c53, 0xe8}, ++{0x3c55, 0x28}, ++{0x3c5b, 0x20}, ++{0x3ce0, 0x02}, ++{0x3ce1, 0x3a}, ++{0x3ce2, 0x00}, ++{0x3ce3, 0x03}, ++/* window start */ ++{0x3800, 0x00}, ++{0x3801, 0x14}, ++{0x3802, 0x00}, ++{0x3803, 0x22}, ++{0x3804, 0x05}, ++{0x3805, 0x23}, ++{0x3806, 0x03}, ++{0x3807, 0xf1}, ++{0x3808, OX01D10_MAX_WIDTH >> 8}, //0x508=1288 ++{0x3809, OX01D10_MAX_WIDTH & 0xff}, ++{0x380a, OX01D10_MAX_HEIGHT >> 8}, //0x3c8=968 ++{0x380b, OX01D10_MAX_HEIGHT & 0xff}, ++{0x380c, 0x06}, ++{0x380d, 0xa0}, ++{0x380e, 0x03}, // VTS=0x3f2 ++{0x380f, 0xf2}, // VTS ++{0x3810, 0x00}, ++{0x3811, 0x04}, ++{0x3812, 0x00}, ++{0x3813, 0x04}, ++/* window end */ ++{0x381c, 0x08}, ++{0x3820, 0x44}, /* VPLIP on */ ++{0x3821, 0x00}, /* HFLIP off */ ++{0x3832, 0x00}, ++{0x3834, 0x00}, ++{0x383c, 0x48}, ++{0x383d, 0x20}, ++{0x384c, 0x03}, ++{0x384d, 0x88}, ++{0x3850, 0x00}, ++{0x3851, 0x42}, ++{0x3852, 0x00}, ++{0x3853, 0x40}, ++{0x3856, 0x04}, ++{0x3857, 0x6b}, ++{0x3858, 0x04}, ++{0x385b, 0x04}, ++{0x385c, 0x6a}, ++{0x3861, 0x00}, ++{0x3862, 0x40}, ++{0x388c, 0x03}, ++{0x388d, 0x5c}, ++{0x4502, 0x00}, ++{0x4504, 0x01}, ++{0x4507, 0x10}, ++{0x450b, 0x14}, ++{0x450c, 0x04}, ++{0x3b84, 0x45}, ++{0x3b85, 0x00}, ++{0x3409, 0x02}, ++{0x3304, 0x04}, ++{0x3306, 0x03}, ++{0x3307, 0x00}, ++{0x3308, 0x00}, ++{0x3309, 0x00}, ++{0x330a, 0x00}, ++{0x330b, 0x00}, ++{0x330c, 0x00}, ++{0x330d, 0x00}, ++{0x330e, 0x00}, ++{0x330f, 0x00}, ++{0x3310, 0x06}, ++{0x3311, 0x05}, ++{0x3312, 0x55}, ++{0x3313, 0x02}, ++{0x3314, 0xaa}, ++{0x3315, 0x07}, ++{0x3316, 0xf0}, ++{0x3317, 0x00}, ++{0x4001, 0x2b}, ++{0x4004, 0x00}, ++{0x4005, 0x40}, ++{0x4008, 0x02}, ++{0x4009, 0x09}, ++{0x400a, 0x02}, ++{0x400b, 0x00}, ++{0x4020, 0x00}, ++{0x4021, 0x00}, ++{0x4022, 0x00}, ++{0x4023, 0x00}, ++{0x402e, 0x00}, ++{0x402f, 0x40}, ++{0x4030, 0x00}, ++{0x4031, 0x40}, ++{0x405c, 0x20}, ++{0x5000, 0x3d}, ++{0x5001, 0x05}, ++{0x5030, 0x00}, ++{0x5038, 0x10}, ++{0x5039, 0x04}, ++{0x503a, 0x04}, ++#ifdef OX01D10_DISPLAY_PATTERN_COLOR_BAR ++{0x5080, 0xc0}, /* Rolling test pattern for HCG */ ++{0x5083, 0x0f}, ++{0x50c0, 0xc0}, /* Rolling test pattern for LCG */ ++{0x50c3, 0x0f}, ++{0x5100, 0xc0}, /* Rolling test pattern for VS */ ++#else ++{0x5080, 0x00}, ++{0x5083, 0x0f}, ++{0x50c0, 0x00}, ++{0x50c3, 0x0f}, ++{0x5100, 0x00}, ++#endif ++{0x5103, 0x0f}, ++{0x5140, 0x10}, ++{0x5142, 0x10}, ++{0x5144, 0x10}, ++{0x5146, 0x10}, ++{0x5147, 0x08}, ++{0x5148, 0x08}, ++{0x5149, 0x08}, ++{0x514a, 0x08}, ++{0x514b, 0x10}, ++{0x514c, 0x10}, ++{0x514d, 0x08}, ++{0x514e, 0x00}, ++{0x5150, 0x08}, ++{0x5154, 0x00}, ++{0x5157, 0x10}, ++{0x5159, 0x08}, ++{0x515b, 0x08}, ++{0x515d, 0x10}, ++{0x5160, 0x10}, ++{0x5162, 0x10}, ++{0x5163, 0x10}, ++{0x5164, 0xaa}, ++{0x5165, 0xaa}, ++{0x5166, 0xaa}, ++{0x5167, 0xaa}, ++{0x5169, 0xaa}, ++{0x516c, 0x99}, ++{0x516d, 0xaa}, ++{0x516e, 0xaa}, ++{0x5174, 0x99}, ++{0x5176, 0x99}, ++{0x5179, 0xaa}, ++{0x517a, 0xaa}, ++{0x517d, 0x88}, ++{0x517e, 0x40}, ++{0x517f, 0x20}, ++{0x5182, 0x00}, ++{0x5183, 0xee}, ++{0x5184, 0x01}, ++{0x5185, 0x3d}, ++{0x5186, 0x01}, ++{0x5188, 0x00}, ++{0x5189, 0xd3}, ++{0x5220, 0x4b}, ++{0x5240, 0x4b}, ++{0x5260, 0x4b}, ++{0x5280, 0x00}, ++{0x5281, 0x5e}, ++{0x5282, 0x01}, ++{0x5283, 0xfd}, ++{0x5285, 0x01}, ++{0x5422, 0x10}, ++{0x54a2, 0x10}, ++{0x5522, 0x10}, ++{0x559e, 0x03}, ++{0x559f, 0x00}, ++{0x55a0, 0x40}, ++{0x6008, 0xcf}, ++{0x6009, 0x00}, ++{0x4903, 0x80}, ++{0x4601, 0x30}, ++{0x4602, 0x02}, ++{0x4603, 0x01}, ++{0x4605, 0x03}, ++{0x460a, 0x36}, ++{0x460c, 0x60}, ++{0x4800, 0x04}, ++{0x480e, 0x04}, ++{0x4813, 0x12}, // VC ++{0x481b, 0x50}, ++{0x481f, 0x30}, ++{0x482b, 0x04}, ++{0x482e, 0x34}, ++{0x4837, 0x10}, ++{0x484b, 0x27}, ++{0x4880, 0x00}, ++{0x4881, 0x00}, ++{0x4885, 0x03}, ++{0x4886, 0x00}, ++{0x4708, 0x00}, ++{0x470b, 0x0f}, ++{0x380e, 0x04}, // VTS=0x400 ++{0x380f, 0x00}, // ++/* patch start */ ++//{0x3208, 0x03}, // start recording group3 ++{0x3501, 0x02}, // HCG exposure integration time MSB ++{0x3502, 0x00}, // HCG exposure integration time LSB ++{0x3541, 0x00}, // LCG exposure integration time MSB ++{0x3542, 0x40}, // LCG exposure integration time LSB ++{0x3581, 0x00}, // VS exposure integration time MSB ++{0x3582, 0x08}, // VS exposure integration time LSB ++{0x3508, 0x02}, // HCG real gain MSB ++{0x3509, 0x00}, // HCG real gain LSB ++{0x350a, 0x02}, // HCG digital gain MSB ++{0x350b, 0x00}, // HCG digital gain LSB ++{0x3548, 0x00}, // LCG real gain MSB ++{0x3549, 0x40}, // LCG real gain LSB ++{0x354a, 0x00}, // LCG digital gain MSB ++{0x354b, 0x40}, // LCG digital gain LSB ++{0x3588, 0x00}, // VS real gain MSB ++{0x3589, 0x08}, // VS real gain LSB ++{0x358a, 0x00}, // VS digital gain ++{0x358b, 0x08}, // VS digital gain ++//{0x3208, 0x13}, // stop recording group3 ++//{0x3208, 0xe3}, // launch group3 ++/* patch2 end */ ++{0x100, 0x01}, ++}; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0456-media-i2c-max9286-fix-resetb-handling.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0456-media-i2c-max9286-fix-resetb-handling.patch new file mode 100644 index 00000000..2cffe362 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0456-media-i2c-max9286-fix-resetb-handling.patch @@ -0,0 +1,36 @@ +From f3e07cec62fb10d0c09d4bb96309ebe01a8f3fae Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 26 Dec 2019 15:26:45 +0300 +Subject: [PATCH] media: i2c: max9286: fix resetb handling + +This fixed the RESETB handling for other then GPIOn=1 pins + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/max9286.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c +index b185566..f6c6b0a 100644 +--- a/drivers/media/i2c/soc_camera/max9286.c ++++ b/drivers/media/i2c/soc_camera/max9286.c +@@ -232,10 +232,12 @@ static void max9286_sensor_reset(struct i2c_client *client, int addr, int reset_ + if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) + return; + +- /* sensor reset/unreset */ +- client->addr = addr; /* MAX9271-CAMx I2C */ +- reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */ +- ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on)); ++ if (priv->active_low_resetb) ++ reset_on = !reset_on; ++ ++ /* sensor reset/unreset using serializer gpio */ ++ client->addr = addr; ++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | (reset_on ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value */ + reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ + } + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0457-media-i2c-ov10640-fix-dvp-order-and-soft-reset.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0457-media-i2c-ov10640-fix-dvp-order-and-soft-reset.patch new file mode 100644 index 00000000..71c116d2 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0457-media-i2c-ov10640-fix-dvp-order-and-soft-reset.patch @@ -0,0 +1,67 @@ +From f35b83dbb68c5c9d01b9c10f8afc95f436a0a40c Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 26 Dec 2019 15:27:34 +0300 +Subject: [PATCH] media: i2c: ov10640: fix dvp order and soft reset + +1) the s/w reset must be removed since some comeras have +serizlizer connected to imager gpio and the address of imager +may change after soft reset + +2) add dvp order + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov10640.c | 6 ++++++ + drivers/media/i2c/soc_camera/ov10640.h | 6 +++--- + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c +index 89dac1b..6414c6e 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.c ++++ b/drivers/media/i2c/soc_camera/ov10640.c +@@ -481,6 +481,8 @@ static int ov10640_initialize(struct i2c_client *client) + ov10640_otp_id_read(client); + /* Program wizard registers */ + ov10640_set_regs(client, ov10640_regs_wizard_r1e, ARRAY_SIZE(ov10640_regs_wizard_r1e)); ++ /* Set DVP bit swap */ ++ reg16_write(client, 0x3124, priv->dvp_order << 4); + + dev_info(&client->dev, "ov10640 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", + pid, OV10640_MAX_WIDTH, OV10640_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +@@ -552,6 +554,10 @@ static int ov10640_parse_dt(struct device_node *np, struct ov10640_priv *priv) + } + client->addr = tmp_addr; + ++ /* module params override dts */ ++ if (dvp_order != -1) ++ priv->dvp_order = dvp_order; ++ + return 0; + } + +diff --git a/drivers/media/i2c/soc_camera/ov10640.h b/drivers/media/i2c/soc_camera/ov10640.h +index dbc6c0b..32cdb2c 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.h ++++ b/drivers/media/i2c/soc_camera/ov10640.h +@@ -1,7 +1,7 @@ + /* +- * OmniVision ov10640 sensor camera wizard 1280x800@30/UYVY/BT601/8bit ++ * OmniVision ov10640 sensor camera wizard 1280x1080@30/BGGR/BT601/12bit + * +- * Copyright (C) 2015-2017 Cogent Embedded, Inc. ++ * Copyright (C) 2015-2019 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the +@@ -1185,7 +1185,7 @@ static const struct ov10640_reg ov10640_regs_wizard_r1f[] = { + /* DVP_1280x1080_COMB12_raw 30fps */ + static const struct ov10640_reg ov10640_regs_wizard_r1e[] = { + /* ov10640_R1E_setting_3x12_1280x1080_MIPIin_4lane_raw */ +-{0x3013, 0x01}, ++//{0x3013, 0x01}, + {OV10640_DELAY, 10}, + {0x328a, 0x11}, + {0x313f, 0x80}, +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0458-arm64-dts-renesas-Add-V3x-VideoBox-GMSL-8ch-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0458-arm64-dts-renesas-Add-V3x-VideoBox-GMSL-8ch-support.patch new file mode 100644 index 00000000..3d73bd27 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0458-arm64-dts-renesas-Add-V3x-VideoBox-GMSL-8ch-support.patch @@ -0,0 +1,866 @@ +From 593e1916da8aa0ff0f4d8d25aa483358d190badb Mon Sep 17 00:00:00 2001 +From: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +Date: Wed, 25 Dec 2019 16:42:09 +0300 +Subject: [PATCH] arm64: dts: renesas: Add V3x VideoBox GMSL 8ch support + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/Makefile | 1 + + .../renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts | 834 ++++++++++++++++++ + 2 files changed, 835 insertions(+) + create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts + +diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile +index 05b164e09f0a..4b2f4fb73bed 100644 +--- a/arch/arm64/boot/dts/renesas/Makefile ++++ b/arch/arm64/boot/dts/renesas/Makefile +@@ -41,5 +41,6 @@ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v2.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-8ch.dtb r8a77980-v3hsk-vb-4ch.dtb ++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl-8ch.dtb + + always := $(dtb-y) +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts +new file mode 100644 +index 000000000000..f90951d0e230 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts +@@ -0,0 +1,834 @@ ++/* ++ * Device Tree Source for the V3HSK Videobox Mini board on r8a7798 ++ * ++ * Copyright (C) 2018 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "r8a77980-v3hsk.dts" ++#include <dt-bindings/gpio/gpio.h> ++/* FDPLink output */ ++//#include "vb-fdplink-output.dtsi" ++ ++/ { ++ model = "Renesas V3HSK 8ch GMSL Videobox board based on r8a7798"; ++ ++ aliases { ++ serial1 = &scif3; ++ ethernet1 = &avb; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led0 { ++ label = "board:status"; ++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "none"; ++ }; ++ }; ++ ++ mpcie_1v8: regulator2 { ++ compatible = "regulator-fixed"; ++ regulator-name = "mPCIe 1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ mpcie_3v3: regulator3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "mPCIe 3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ common_3v3: regulator4 { ++ compatible = "regulator-fixed"; ++ regulator-name = "main 3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&canfd { ++ pinctrl-0 = <&canfd0_pins &canfd1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ channel0 { ++ status = "okay"; ++ }; ++ ++ channel1 { ++ status = "okay"; ++ }; ++}; ++ ++&avb { ++ pinctrl-0 = <&avb_pins>; ++ pinctrl-names = "default"; ++ renesas,no-ether-link; ++ phy-handle = <&avb_phy0>; ++ status = "okay"; ++ phy-int-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>; ++ ++ avb_phy0: eavb-phy@0 { ++ rxc-skew-ps = <1500>; ++ rxdv-skew-ps = <420>; /* default */ ++ rxd0-skew-ps = <420>; /* default */ ++ rxd1-skew-ps = <420>; /* default */ ++ rxd2-skew-ps = <420>; /* default */ ++ rxd3-skew-ps = <420>; /* default */ ++ txc-skew-ps = <900>; /* default */ ++ txen-skew-ps = <420>; /* default */ ++ txd0-skew-ps = <420>; /* default */ ++ txd1-skew-ps = <420>; /* default */ ++ txd2-skew-ps = <420>; /* default */ ++ txd3-skew-ps = <420>; /* default */ ++ reg = <3>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>; ++ max-speed = <1000>; ++ }; ++}; ++ ++&csi40 { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi40_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <700>; ++ }; ++ }; ++}; ++ ++&csi41 { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi41_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <700>; ++ }; ++ }; ++}; ++ ++&i2c1 { ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ clock-frequency = <400000>; ++ ++ i2cswitch1: i2c-switch@74 { ++ compatible = "nxp,pca9548"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x74>; ++ reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; ++ ++ /* CTL0_SDA and CTL0_SCL */ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ gpio_exp: gpio_exp@76 { ++ compatible = "nxp,pca9539"; ++ reg = <0x76>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ des0_shdn { ++ gpio-hog; ++ gpios = <1 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Des0SHDN"; ++ }; ++ des1_shdn { ++ gpio-hog; ++ gpios = <0 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Des1SHDN"; ++ }; ++ cmr_pwen { ++ gpio-hog; ++ gpios = <3 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CmrPEN"; ++ }; ++ }; ++ ++ dac_vcam: dac_vcam@60 { ++ compatible = "microchip,mcp4725"; ++ reg = <0x60>; ++ vdd-supply = <&common_3v3>; ++ }; ++ }; ++ ++ /* DS0_SDA and DS0_SCL */ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ /* Deser #0 nodes here */ ++ ov106xx@0 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x60>; ++ ++ port@0 { ++ ov106xx_in0: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin0ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des0ep0: endpoint@1 { ++ remote-endpoint = <&max9286_des0ep0>; ++ }; ++ }; ++ }; ++ ++ ov106xx@1 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x61>; ++ ++ port@0 { ++ ov106xx_in1: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin1ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des0ep1: endpoint@1 { ++ remote-endpoint = <&max9286_des0ep1>; ++ }; ++ }; ++ }; ++ ++ ov106xx@2 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x62>; ++ ++ port@0 { ++ ov106xx_in2: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin2ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des0ep2: endpoint@1 { ++ remote-endpoint = <&max9286_des0ep2>; ++ }; ++ }; ++ }; ++ ++ ov106xx@3 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x63>; ++ ++ port@0 { ++ ov106xx_in3: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin3ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des0ep3: endpoint@1 { ++ remote-endpoint = <&max9286_des0ep3>; ++ }; ++ }; ++ }; ++ ++ max9286@0 { ++ compatible = "maxim,max9286"; ++ reg = <0x2c>; ++ maxim,links = <4>; ++ maxim,lanes = <4>; ++ maxim,resetb-gpio = <1>; ++ maxim,fsync-mode = "automatic"; ++ maxim,timeout = <100>; ++ ++ POC0-gpios = <&gpio_exp 11 GPIO_ACTIVE_HIGH>; ++ POC1-gpios = <&gpio_exp 10 GPIO_ACTIVE_HIGH>; ++ POC2-gpios = <&gpio_exp 8 GPIO_ACTIVE_HIGH>; ++ POC3-gpios = <&gpio_exp 9 GPIO_ACTIVE_HIGH>; ++ ++ port@0 { ++ max9286_des0ep0: endpoint@0 { ++ max9271-addr = <0x50>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in0>; ++ }; ++ max9286_des0ep1: endpoint@1 { ++ max9271-addr = <0x51>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in1>; ++ }; ++ max9286_des0ep2: endpoint@2 { ++ max9271-addr = <0x52>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in2>; ++ }; ++ max9286_des0ep3: endpoint@3 { ++ max9271-addr = <0x53>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in3>; ++ }; ++ }; ++ port@1 { ++ max9286_csi0ep0: endpoint { ++ csi-rate = <700>; ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ }; ++ }; ++ ++ /* DS1_SDA and DS1_SCL */ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ /* Deser #1 nodes here */ ++ ov106xx@4 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x60>; ++ ++ port@0 { ++ ov106xx_in4: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin4ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des1ep0: endpoint@1 { ++ remote-endpoint = <&max9286_des1ep0>; ++ }; ++ }; ++ }; ++ ++ ov106xx@5 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x61>; ++ ++ port@0 { ++ ov106xx_in5: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin5ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des1ep1: endpoint@1 { ++ remote-endpoint = <&max9286_des1ep1>; ++ }; ++ }; ++ }; ++ ++ ov106xx@6 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x62>; ++ ++ port@0 { ++ ov106xx_in6: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin6ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des1ep2: endpoint@1 { ++ remote-endpoint = <&max9286_des1ep2>; ++ }; ++ }; ++ }; ++ ++ ov106xx@7 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x63>; ++ ++ port@0 { ++ ov106xx_in7: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin7ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des1ep3: endpoint@1 { ++ remote-endpoint = <&max9286_des1ep3>; ++ }; ++ }; ++ }; ++ ++ max9286@0 { ++ compatible = "maxim,max9286"; ++ reg = <0x2c>; ++ maxim,links = <4>; ++ maxim,lanes = <4>; ++ maxim,resetb-gpio = <1>; ++ maxim,fsync-mode = "automatic"; ++ maxim,timeout = <100>; ++ ++ POC0-gpios = <&gpio_exp 15 GPIO_ACTIVE_HIGH>; ++ POC1-gpios = <&gpio_exp 14 GPIO_ACTIVE_HIGH>; ++ POC2-gpios = <&gpio_exp 12 GPIO_ACTIVE_HIGH>; ++ POC3-gpios = <&gpio_exp 13 GPIO_ACTIVE_HIGH>; ++ ++ port@0 { ++ max9286_des1ep0: endpoint@0 { ++ max9271-addr = <0x50>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in4>; ++ }; ++ max9286_des1ep1: endpoint@1 { ++ max9271-addr = <0x51>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in5>; ++ }; ++ max9286_des1ep2: endpoint@2 { ++ max9271-addr = <0x52>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in6>; ++ }; ++ max9286_des1ep3: endpoint@3 { ++ max9271-addr = <0x53>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in7>; ++ }; ++ }; ++ port@1 { ++ max9286_csi1ep0: endpoint { ++ csi-rate = <700>; ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ }; ++ }; ++ ++ /* ESDA and ESCL */ ++ i2c@5 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <5>; ++ ++ /* fan node - lm96063 */ ++ fan_ctrl: lm96063@4c { ++ compatible = "lm96163"; ++ reg = <0x4c>; ++ }; ++ }; ++ ++ /* Disp_SDA and Disp_SCL */ ++ i2c@6 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <6>; ++ ++ /* ext I2C bus nodes */ ++ }; ++ ++ /* RTC_SDA and RTC_SCL */ ++ i2c@7 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <7>; ++ ++ rtc: mcp79411@6f { ++ compatible = "microchip,mcp7941x"; ++ reg = <0x6f>; ++ }; ++ }; ++ ++ }; ++}; ++ ++&gpio0 { ++ wake_pin_8 { ++ gpio-hog; ++ gpios = <8 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "WAKE INPUT PIN 8"; ++ }; ++ ++ can0_load { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN0Loff"; ++ }; ++ ++ fpdl_shdn { ++ gpio-hog; ++ gpios = <21 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "FPDL_SHDN"; ++ }; ++}; ++ ++&gpio1 { ++ md_buf_en { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CPLD_If_En"; ++ }; ++}; ++ ++&gpio2 { ++ m2_rst { ++ gpio-hog; ++ gpios = <11 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "M.2 RST#"; ++ }; ++ ++ rst_vin01 { ++ gpio-hog; ++ gpios = <16 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CCTRL_RSTn_VIN01"; ++ }; ++ ++ can0_stby { ++ gpio-hog; ++ gpios = <27 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN0STBY"; ++ }; ++ ++ can1_load { ++ gpio-hog; ++ gpios = <29 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN1Loff"; ++ }; ++ ++ can1_stby { ++ gpio-hog; ++ gpios = <22 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN1STBY"; ++ }; ++ ++ wake_pin_7 { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "WAKE INPUT PIN 7"; ++ }; ++}; ++ ++&pcie_bus_clk { ++ clock-frequency = <100000000>; ++ status = "okay"; ++}; ++ ++&pciec { ++ pcie3v3-supply = <&mpcie_3v3>; ++ pcie1v8-supply = <&mpcie_1v8>; ++ status = "okay"; ++}; ++ ++&pcie_phy { ++ status = "okay"; ++}; ++ ++&pfc { ++ canfd0_pins: canfd0 { ++ groups = "canfd0_data_a"; ++ function = "canfd0"; ++ }; ++ ++ canfd1_pins: canfd1 { ++ groups = "canfd1_data"; ++ function = "canfd1"; ++ }; ++ ++ avb_pins: avb { ++ groups = "avb_mdio", "avb_rgmii"; ++ function = "avb"; ++ }; ++ ++ i2c1_pins: i2c1 { ++ groups = "i2c1"; ++ function = "i2c1"; ++ }; ++ ++ pwm0_pins: pwm0 { ++ groups = "pwm0_a"; ++ function = "pwm0"; ++ }; ++ ++ scif3_pins: scif3 { ++ groups = "scif3_data"; ++ function = "scif3"; ++ }; ++}; ++ ++&pwm0 { ++ pinctrl-0 = <&pwm0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&scif3 { ++ pinctrl-0 = <&scif3_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&tpu { ++ status = "disabled"; ++}; ++ ++&vin0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin0ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&ov106xx_in0>; ++ }; ++ }; ++ port@1 { ++ csi0ep0: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin0_max9286_des0ep0: endpoint@1 { ++ remote-endpoint = <&max9286_des0ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin1 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin1ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <1>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&ov106xx_in1>; ++ }; ++ }; ++ port@1 { ++ csi0ep1: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin1_max9286_des0ep1: endpoint@1 { ++ remote-endpoint = <&max9286_des0ep1>; ++ }; ++ }; ++ }; ++}; ++ ++&vin2 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin2ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <2>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&ov106xx_in2>; ++ }; ++ }; ++ port@1 { ++ csi0ep2: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin6_max9286_des0ep2: endpoint@1 { ++ remote-endpoint = <&max9286_des0ep2>; ++ }; ++ }; ++ }; ++}; ++ ++&vin3 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin3ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <3>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&ov106xx_in3>; ++ }; ++ }; ++ port@1 { ++ csi0ep3: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin7_max9286_des0ep3: endpoint@1 { ++ remote-endpoint = <&max9286_des0ep3>; ++ }; ++ }; ++ }; ++}; ++ ++&vin4 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin4ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&ov106xx_in4>; ++ }; ++ }; ++ port@1 { ++ csi1ep0: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin4_max9286_des0ep0: endpoint@1 { ++ remote-endpoint = <&max9286_des1ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin5 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin5ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <1>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&ov106xx_in5>; ++ }; ++ }; ++ port@1 { ++ csi1ep1: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin5_max9286_des1ep1: endpoint@1 { ++ remote-endpoint = <&max9286_des1ep1>; ++ }; ++ }; ++ }; ++}; ++ ++&vin6 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin6ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <2>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&ov106xx_in6>; ++ }; ++ }; ++ port@1 { ++ csi1ep2: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin6_max9286_des1ep2: endpoint@1 { ++ remote-endpoint = <&max9286_des1ep2>; ++ }; ++ }; ++ }; ++}; ++ ++&vin7 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin7ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <3>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&ov106xx_in7>; ++ }; ++ }; ++ port@1 { ++ csi1ep3: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin7_max9286_des1ep3: endpoint@1 { ++ remote-endpoint = <&max9286_des1ep3>; ++ }; ++ }; ++ }; ++}; +-- +2.20.1 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0459-media-i2c-ov10640-support-different-revisions.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0459-media-i2c-ov10640-support-different-revisions.patch new file mode 100644 index 00000000..7df38d8c --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0459-media-i2c-ov10640-support-different-revisions.patch @@ -0,0 +1,6345 @@ +From a5fcfd1f74e05c70308262091be3d9035150bfc6 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Sun, 29 Dec 2019 04:12:59 +0300 +Subject: [PATCH] media: i2c: ov10640: support different revisions + +1) support r1d/r1e/r1f revisions +2) fix exposure/gain, add AEC/AEG +3) adjust ADV_DEBUG to support u8/u16/u32/u64 access + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Signed-off-by: Petr Nechaev <petr.nechaev@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov10640.c | 134 +- + drivers/media/i2c/soc_camera/ov10640.h | 2378 +--------------------------- + drivers/media/i2c/soc_camera/ov10640_r1d.h | 1240 +++++++++++++++ + drivers/media/i2c/soc_camera/ov10640_r1e.h | 1235 +++++++++++++++ + drivers/media/i2c/soc_camera/ov10640_r1f.h | 1198 ++++++++++++++ + 5 files changed, 3752 insertions(+), 2433 deletions(-) + create mode 100644 drivers/media/i2c/soc_camera/ov10640_r1d.h + create mode 100644 drivers/media/i2c/soc_camera/ov10640_r1e.h + create mode 100644 drivers/media/i2c/soc_camera/ov10640_r1f.h + +diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c +index 6414c6e..40058b7 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.c ++++ b/drivers/media/i2c/soc_camera/ov10640.c +@@ -25,9 +25,10 @@ + + #define OV10640_I2C_ADDR 0x30 + +-#define OV10640_PID 0x300a +-#define OV10640_VER 0x300b +-#define OV10640_VERSION_REG 0xa640 ++#define OV10640_PIDA_REG 0x300a ++#define OV10640_PIDB_REG 0x300b ++#define OV10640_REV_REG 0x300d ++#define OV10640_PID 0xa640 + + #define OV10640_MEDIA_BUS_FMT MEDIA_BUS_FMT_SBGGR12_1X12 + +@@ -190,8 +191,8 @@ static int ov10640_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) + + edid->edid[6] = 0xff; + edid->edid[7] = client->addr; +- edid->edid[8] = OV10640_VERSION_REG >> 8; +- edid->edid[9] = OV10640_VERSION_REG & 0xff; ++ edid->edid[8] = OV10640_PID >> 8; ++ edid->edid[9] = OV10640_PID & 0xff; + + return 0; + } +@@ -274,24 +275,36 @@ static int ov10640_g_register(struct v4l2_subdev *sd, + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u8 val = 0; ++ __be64 be_val; + +- ret = reg16_read(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u8); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ov10640_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ __be64 be_val; + +- return reg16_write(client, (u16)reg->reg, (u8)reg->val); ++ if (!size) ++ size = sizeof(u8); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); ++ ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ++ return reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); + } + #endif + +@@ -309,7 +322,7 @@ static int ov10640_s_ctrl(struct v4l2_ctrl *ctrl) + struct ov10640_priv *priv = to_ov10640(client); + int ret = -EINVAL; + u8 val = 0; +- u16 val16 = 0; ++ static char again[8] = {0, 1, 4, 2, 5, 3, 6, 7}; + + if (!priv->init_complete) + return 0; +@@ -321,38 +334,35 @@ static int ov10640_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_HUE: + case V4L2_CID_GAMMA: + break; ++ case V4L2_CID_AUTOGAIN: ++ /* automatic gain/exposure */ ++ reg16_read(client, 0x30FA, &val); ++ val &= ~(0x1 << 6); ++ val |= (ctrl->val << 6); ++ ret = reg16_write(client, 0x30FA, val); ++ break; + case V4L2_CID_GAIN: +- reg16_write(client, 0x30EC, ctrl->val); // L +- reg16_write(client, 0x30EE, ctrl->val); // S +- ret = reg16_write(client, 0x30F0, ctrl->val); // VS ++ reg16_write(client, 0x30EC, ctrl->val >> 8); // L ++ reg16_write(client, 0x30ED, ctrl->val & 0xff); // L ++ reg16_write(client, 0x30EE, ctrl->val >> 8); // S ++ reg16_write(client, 0x30EF, ctrl->val & 0xff); // S ++ reg16_write(client, 0x30F0, ctrl->val >> 8); // VS ++ ret = reg16_write(client, 0x30F1, ctrl->val & 0xff); // VS + break; + case V4L2_CID_ANALOGUE_GAIN: +- reg16_read(client, 0x30EB, &val); +- val &= ~(0x3f << 0); // VS, S, L - Gauss curve +- val |= ((ctrl->val / 2) << 0); // L +- val |= (ctrl->val << 2); // S +- val |= ((ctrl->val / 2) << 4); // VS ++ val = again[ctrl->val] & 0x4 ? 0xC0 : 0; // High conversion gain is x2.57, low conversion gain is x1 ++ val |= ((again[ctrl->val] & 0x3) << 0); // L ++ val |= ((again[ctrl->val] & 0x3) << 2); // S ++ val |= ((again[ctrl->val] & 0x3) << 4); // VS + ret = reg16_write(client, 0x30EB, val); + break; + case V4L2_CID_EXPOSURE: +- val16 = 0xfff - ctrl->val; +- +- reg16_write(client, 0x30E6, val16 >> 8); // L +- reg16_write(client, 0x30E7, val16 & 0xff); // L +- +- reg16_write(client, 0x30E8, val16 >> 8); // S +- ret = reg16_write(client, 0x30E9, val16 & 0xff);// S +- +-// ret = reg16_write(client, 0x30EA, val >> 8); // VS - fractional ... ++ reg16_write(client, 0x30E6, ctrl->val >> 8); // L ++ reg16_write(client, 0x30E7, ctrl->val & 0xff); // L ++ reg16_write(client, 0x30E8, ctrl->val/16 >> 8); // S ++ reg16_write(client, 0x30E9, ctrl->val/16 & 0xff);// S ++ ret = reg16_write(client, 0x30EA, ctrl->val/256 >> 8); // VS + break; +-#if 0 +- case V4L2_CID_EXPOSURE_AUTO: +- reg16_read(client, 0x30FA, &val); +- val &= ~(0x1 << 6); +- val |= (ctrl->val << 6); +- ret = reg16_write(client, 0x30FA, val); +- break; +-#endif + case V4L2_CID_HFLIP: + reg16_read(client, 0x3128, &val); + val &= ~(0x1 << 0); +@@ -460,19 +470,21 @@ static int ov10640_initialize(struct i2c_client *client) + { + struct ov10640_priv *priv = to_ov10640(client); + u16 pid; +- u8 val = 0; ++ u8 val = 0, rev; + int ret = 0; + + ov10640_s_port(client, 1); + + /* check and show product ID and manufacturer ID */ +- reg16_read(client, OV10640_PID, &val); ++ reg16_read(client, OV10640_PIDA_REG, &val); + pid = val; +- reg16_read(client, OV10640_VER, &val); ++ reg16_read(client, OV10640_PIDB_REG, &val); + pid = (pid << 8) | val; ++ reg16_read(client, OV10640_REV_REG, &val); ++ rev = 0x10 | ((val & 0xf) + 0xa); + +- if (pid != OV10640_VERSION_REG) { +- dev_err(&client->dev, "Product ID error %x\n", pid); ++ if (pid != OV10640_PID) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); + ret = -ENODEV; + goto out; + } +@@ -480,12 +492,25 @@ static int ov10640_initialize(struct i2c_client *client) + /* Read OTP IDs */ + ov10640_otp_id_read(client); + /* Program wizard registers */ +- ov10640_set_regs(client, ov10640_regs_wizard_r1e, ARRAY_SIZE(ov10640_regs_wizard_r1e)); ++ switch (rev) { ++ case 0x1d: ++ ov10640_set_regs(client, ov10640_regs_wizard_r1d, ARRAY_SIZE(ov10640_regs_wizard_r1d)); ++ break; ++ case 0x1e: ++ ov10640_set_regs(client, ov10640_regs_wizard_r1e, ARRAY_SIZE(ov10640_regs_wizard_r1e)); ++ break; ++ case 0x1f: ++ ov10640_set_regs(client, ov10640_regs_wizard_r1f, ARRAY_SIZE(ov10640_regs_wizard_r1f)); ++ break; ++ default: ++ dev_err(&client->dev, "Unsupported chip revision\n"); ++ return -EINVAL; ++ } + /* Set DVP bit swap */ + reg16_write(client, 0x3124, priv->dvp_order << 4); + +- dev_info(&client->dev, "ov10640 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", +- pid, OV10640_MAX_WIDTH, OV10640_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ dev_info(&client->dev, "ov10640 PID %x (r%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, rev, OV10640_MAX_WIDTH, OV10640_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + out: + ov10640_s_port(client, 0); + +@@ -535,7 +560,6 @@ static int ov10640_parse_dt(struct device_node *np, struct ov10640_priv *priv) + tmp_addr = client->addr; + if (priv->max9286_addr) { + client->addr = priv->max9271_addr; /* Serializer I2C address */ +- + reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */ + reg8_write(client, 0x0A, OV10640_I2C_ADDR << 1); /* Sensor native I2C address */ + usleep_range(2000, 2500); /* wait 2ms */ +@@ -543,14 +567,10 @@ static int ov10640_parse_dt(struct device_node *np, struct ov10640_priv *priv) + + if (priv->ti9x4_addr) { + client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ +- + reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ + usleep_range(2000, 2500); /* wait 2ms */ + reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ + reg8_write(client, 0x5d, OV10640_I2C_ADDR << 1); /* Sensor native I2C address */ +- +-// reg8_write(client, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - resetb */ +-// udelay(100); + } + client->addr = tmp_addr; + +@@ -592,15 +612,13 @@ static int ov10640_probe(struct i2c_client *client, + v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops, + V4L2_CID_GAMMA, 0, 0xffff, 1, 0x233); + v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops, +- V4L2_CID_GAIN, 0, 0x3f, 1, 0x1); ++ V4L2_CID_AUTOGAIN, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops, +- V4L2_CID_ANALOGUE_GAIN, 0, 3, 1, 1); ++ V4L2_CID_GAIN, 0, 0x3fff, 1, 0x100); + v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops, +- V4L2_CID_EXPOSURE, 0, 0xfff, 1, 0x448); +-#if 0 ++ V4L2_CID_ANALOGUE_GAIN, 0, 7, 1, 1); + v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops, +- V4L2_CID_EXPOSURE_AUTO, 0, 1, 1, 0); +-#endif ++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, 0x400); + v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 1); + v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops, +diff --git a/drivers/media/i2c/soc_camera/ov10640.h b/drivers/media/i2c/soc_camera/ov10640.h +index 32cdb2c..3d2de3d 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.h ++++ b/drivers/media/i2c/soc_camera/ov10640.h +@@ -30,2378 +30,6 @@ struct ov10640_reg { + u8 val; + }; + +-/* DVP_1280x1080_COMB12_raw 60fps */ +-static const struct ov10640_reg ov10640_regs_wizard_r1f[] = { +-{0x3013, 0x01}, +-{OV10640_DELAY, 10}, +-{0x31be, 0x01}, +-{0x3133, 0xb7}, +-{0x3134, 0xca}, +-{0x3135, 0xcc}, +-{0x313f, 0x80}, +-{0x3132, 0x24}, +-{0x3000, 0x03}, +-{0x3001, 0x62}, +-{0x3002, 0x07}, +-//{0x3002, 0x0f}, // for 30fps wizard +-{0x3004, 0x03}, +-#if 0 +-{0x3005, 0x62}, +-#else +-{0x3005, 0x48}, +-#endif +-{0x3006, 0x07}, +-{0x3007, 0x01}, +-{0x3023, 0x05}, +-{0x3032, 0x35}, +-{0x3033, 0x04}, +-{0x3054, 0x00}, +-{0x3055, 0x0f}, +-{0x3056, 0x01}, +-{0x3057, 0xff}, +-{0x3058, 0xaf}, +-{0x3059, 0x44}, +-{0x305a, 0x02}, +-{0x305b, 0x00}, +-{0x305c, 0x30}, +-{0x305d, 0x9e}, +-{0x305e, 0x19}, +-{0x305f, 0x18}, +-{0x3060, 0xf9}, +-{0x3061, 0xf0}, +-#ifdef OV10640_FSIN_ENABLE +-{0x308c, 0xb2}, +-#else +-{0x308c, 0x03}, +-#endif +-{0x308f, 0x10}, +-{0x3090, 0x00}, +-{0x3091, 0x00}, +-{0x30eb, 0x00}, +-{0x30a3, 0x08}, +-{0x30ad, 0x03}, +-{0x30ae, 0x80}, +-{0x30af, 0x80}, +-{0x30b0, 0xff}, +-{0x30b1, 0x3f}, +-{0x30b2, 0x22}, +-{0x30b9, 0x22}, +-{0x30bb, 0x00}, +-{0x30bc, 0x00}, +-{0x30bd, 0x00}, +-{0x30be, 0x00}, +-{0x30bf, 0x00}, +-{0x30c0, 0x00}, +-{0x30c1, 0x00}, +-{0x30c2, 0x00}, +-{0x30c3, 0x00}, +-{0x30c4, 0x80}, +-{0x30c5, 0x00}, +-{0x30c6, 0x80}, +-{0x30c7, 0x00}, +-{0x30c8, 0x80}, +-{0x3119, 0x44}, +-{0x311a, 0x01}, +-{0x311b, 0x4a}, +-{0x3074, 0x00}, +-{0x3075, 0x00}, +-{0x3076, 0x00}, +-{0x3077, 0x02}, +-{0x3078, 0x05}, +-{0x3079, 0x07}, +-{0x307a, 0x04}, +-{0x307b, 0x41}, +-{0x307c, 0x05}, +-{0x307d, 0x00}, +-{0x307e, 0x04}, +-{0x307f, 0x38}, +-#if 0 +-{0x3080, 0x05}, +-{0x3081, 0xbe}, +-#else +-{0x3080, 0x06}, // minimal VTS for FPDLINK3 +-{0x3081, 0xe0}, +-#endif +-{0x3082, 0x04}, +-{0x3083, 0x57}, +-{0x3084, 0x00}, +-{0x3085, 0x04}, +-{0x3086, 0x00}, +-{0x3087, 0x04}, +-{0x3088, 0x00}, +-{0x3089, 0x40}, +-{0x308d, 0x92}, +-{0x3094, 0xa5}, +-{0x30e6, 0x04}, +-{0x30e7, 0x48}, +-{0x30e8, 0x04}, +-{0x30e9, 0x48}, +-{0x30ea, 0x11}, +-{0x30ec, 0x01}, +-{0x30fa, 0x06}, +-{0x3120, 0x00}, +-{0x3121, 0x01}, +-{0x3122, 0x00}, +-{0x3127, 0x63}, +-{0x3128, 0xc0}, +-#ifdef OV10640_DISPLAY_PATTERN +-{0x3129, 0x80}, +-#else +-{0x3129, 0x00}, +-#endif +-{0x31be, 0x01}, +-{0x30a5, 0x78}, +-{0x30a6, 0x40}, +-{0x30a7, 0x78}, +-{0x30a8, 0x80}, +-{0x30a9, 0x79}, +-{0x30aa, 0x00}, +-{0x30ab, 0x79}, +-{0x30ac, 0xf8}, +-{0x3440, 0x04}, +-{0x3444, 0x28}, +-{0x344e, 0x2c}, +-{0x3457, 0x33}, +-{0x345e, 0x38}, +-{0x3461, 0xa8}, +-{0x7002, 0xaa}, +-{0x7001, 0xdf}, +-{0x7048, 0x00}, +-{0x7049, 0x02}, +-{0x704a, 0x02}, +-{0x704b, 0x00}, +-{0x704c, 0x01}, +-{0x704d, 0x00}, +-{0x7043, 0x04}, +-{0x7040, 0x3c}, +-{0x7047, 0x00}, +-{0x7044, 0x01}, +-{0x7000, 0x1f}, +-{0x7084, 0x01}, +-{0x7085, 0x03}, +-{0x7086, 0x02}, +-{0x7087, 0x40}, +-{0x7088, 0x01}, +-{0x7089, 0x20}, +-{0x707f, 0x04}, +-{0x707c, 0x3c}, +-{0x7083, 0x00}, +-{0x7080, 0x01}, +-{0x7003, 0xdf}, +-{0x70c0, 0x00}, +-{0x70c1, 0x02}, +-{0x70c2, 0x02}, +-{0x70c3, 0x00}, +-{0x70c4, 0x01}, +-{0x70c5, 0x00}, +-{0x70b8, 0x03}, +-{0x70b9, 0x98}, +-{0x70bc, 0x00}, +-{0x70bd, 0x80}, +-{0x7004, 0x02}, +-{0x7005, 0x00}, +-{0x7006, 0x01}, +-{0x7007, 0x80}, +-{0x7008, 0x02}, +-{0x7009, 0x00}, +-{0x700a, 0x04}, +-{0x700b, 0x00}, +-{0x700e, 0x00}, +-{0x700f, 0x60}, +-{0x701a, 0x02}, +-{0x701b, 0x00}, +-{0x701c, 0x01}, +-{0x701d, 0x80}, +-{0x701e, 0x02}, +-{0x701f, 0x00}, +-{0x7020, 0x04}, +-{0x7021, 0x00}, +-{0x7024, 0x00}, +-{0x7025, 0x60}, +-{0x70e7, 0x00}, +-{0x70e4, 0x10}, +-{0x70e5, 0x00}, +-{0x70e6, 0x00}, +-{0x70eb, 0x00}, +-{0x70e8, 0x10}, +-{0x70e9, 0x00}, +-{0x70ea, 0x00}, +-{0x70ef, 0x00}, +-{0x70ec, 0xfd}, +-{0x70ed, 0x00}, +-{0x70ee, 0x00}, +-{0x70eb, 0x00}, +-{0x70f0, 0xfd}, +-{0x70f1, 0x00}, +-{0x70f2, 0x00}, +-{0x30fb, 0x06}, +-{0x30fc, 0x80}, +-{0x30fd, 0x02}, +-{0x30fe, 0x93}, +-{0x6000, 0xc1}, +-{0x6001, 0xb9}, +-{0x6002, 0xba}, +-{0x6003, 0xa4}, +-{0x6004, 0xa4}, +-{0x6005, 0xb5}, +-{0x6006, 0xa0}, +-{0x6007, 0x82}, +-{0x6008, 0xa7}, +-{0x6009, 0xa7}, +-{0x600a, 0xb7}, +-{0x600b, 0x5c}, +-{0x600c, 0x9e}, +-{0x600d, 0xc0}, +-{0x600e, 0xd2}, +-{0x600f, 0x33}, +-{0x6010, 0xcc}, +-{0x6011, 0xe2}, +-{0x6012, 0xc1}, +-{0x6013, 0xab}, +-{0x6014, 0xab}, +-{0x6015, 0xb7}, +-{0x6016, 0x00}, +-{0x6017, 0x00}, +-{0x6018, 0x00}, +-{0x6019, 0x00}, +-{0x601a, 0x00}, +-{0x601b, 0x00}, +-{0x601c, 0x00}, +-{0x601d, 0x00}, +-{0x601e, 0x00}, +-{0x601f, 0x00}, +-{0x6020, 0x00}, +-{0x6021, 0x00}, +-{0x6022, 0x00}, +-{0x6023, 0x9c}, +-{0x6024, 0x94}, +-{0x6025, 0x90}, +-{0x6026, 0xc5}, +-{0x6027, 0x00}, +-{0x6028, 0x54}, +-{0x6029, 0x2a}, +-{0x602a, 0x61}, +-{0x602b, 0xd2}, +-{0x602c, 0xcc}, +-{0x602d, 0x04}, +-{0x602e, 0x35}, +-{0x602f, 0xb1}, +-{0x6030, 0xb2}, +-{0x6031, 0xb3}, +-{0x6032, 0xd2}, +-{0x6033, 0xd3}, +-{0x6034, 0x11}, +-{0x6035, 0x31}, +-{0x6036, 0xcc}, +-{0x6037, 0x06}, +-{0x6038, 0xd2}, +-{0x6039, 0x00}, +-{0x603a, 0xce}, +-{0x603b, 0x18}, +-{0x603c, 0xcf}, +-{0x603d, 0x1e}, +-{0x603e, 0xd0}, +-{0x603f, 0x24}, +-{0x6040, 0xc5}, +-{0x6041, 0xd2}, +-{0x6042, 0xbc}, +-{0x6043, 0xcc}, +-{0x6044, 0x52}, +-{0x6045, 0x2b}, +-{0x6046, 0xd2}, +-{0x6047, 0xd3}, +-{0x6048, 0x01}, +-{0x6049, 0xcc}, +-{0x604a, 0x0a}, +-{0x604b, 0xd2}, +-{0x604c, 0xd3}, +-{0x604d, 0x0f}, +-{0x604e, 0x1a}, +-{0x604f, 0x2a}, +-{0x6050, 0xd4}, +-{0x6051, 0xe3}, +-{0x6052, 0xba}, +-{0x6053, 0x56}, +-{0x6054, 0xd3}, +-{0x6055, 0x2e}, +-{0x6056, 0x54}, +-{0x6057, 0x26}, +-{0x6058, 0xd2}, +-{0x6059, 0xcc}, +-{0x605a, 0x60}, +-{0x605b, 0xd2}, +-{0x605c, 0xd3}, +-{0x605d, 0x27}, +-{0x605e, 0x27}, +-{0x605f, 0x08}, +-{0x6060, 0x1a}, +-{0x6061, 0xcc}, +-{0x6062, 0x88}, +-{0x6063, 0x00}, +-{0x6064, 0x12}, +-{0x6065, 0x2c}, +-{0x6066, 0x60}, +-{0x6067, 0xc2}, +-{0x6068, 0xb9}, +-{0x6069, 0xa5}, +-{0x606a, 0xa5}, +-{0x606b, 0xb5}, +-{0x606c, 0xa0}, +-{0x606d, 0x82}, +-{0x606e, 0x5c}, +-{0x606f, 0xd4}, +-{0x6070, 0xab}, +-{0x6071, 0xd4}, +-{0x6072, 0xab}, +-{0x6073, 0xd3}, +-{0x6074, 0x01}, +-{0x6075, 0x7c}, +-{0x6076, 0x74}, +-{0x6077, 0x00}, +-{0x6078, 0x61}, +-{0x6079, 0x2a}, +-{0x607a, 0xd2}, +-{0x607b, 0xcc}, +-{0x607c, 0xdf}, +-{0x607d, 0xc6}, +-{0x607e, 0x35}, +-{0x607f, 0xd2}, +-{0x6080, 0xcc}, +-{0x6081, 0x06}, +-{0x6082, 0x31}, +-{0x6083, 0xd2}, +-{0x6084, 0x00}, +-{0x6085, 0xbb}, +-{0x6086, 0xcc}, +-{0x6087, 0x18}, +-{0x6088, 0xc6}, +-{0x6089, 0xd2}, +-{0x608a, 0xbd}, +-{0x608b, 0xcc}, +-{0x608c, 0x52}, +-{0x608d, 0x2b}, +-{0x608e, 0xd2}, +-{0x608f, 0xd3}, +-{0x6090, 0x01}, +-{0x6091, 0xcc}, +-{0x6092, 0x0a}, +-{0x6093, 0xd2}, +-{0x6094, 0xd3}, +-{0x6095, 0x0f}, +-{0x6096, 0x1a}, +-{0x6097, 0x71}, +-{0x6098, 0x2a}, +-{0x6099, 0xd4}, +-{0x609a, 0xe3}, +-{0x609b, 0xd3}, +-{0x609c, 0x22}, +-{0x609d, 0x70}, +-{0x609e, 0xca}, +-{0x609f, 0x26}, +-{0x60a0, 0xd2}, +-{0x60a1, 0xcc}, +-{0x60a2, 0x60}, +-{0x60a3, 0xd2}, +-{0x60a4, 0xd3}, +-{0x60a5, 0x27}, +-{0x60a6, 0x27}, +-{0x60a7, 0x08}, +-{0x60a8, 0x1a}, +-{0x60a9, 0xcc}, +-{0x60aa, 0x88}, +-{0x60ab, 0x00}, +-{0x60ac, 0x12}, +-{0x60ad, 0x2c}, +-{0x60ae, 0x60}, +-{0x60af, 0x00}, +-{0x60b0, 0x00}, +-{0x60b1, 0xc0}, +-{0x60b2, 0xb9}, +-{0x60b3, 0xa3}, +-{0x60b4, 0xa3}, +-{0x60b5, 0xb5}, +-{0x60b6, 0x00}, +-{0x60b7, 0xa0}, +-{0x60b8, 0x82}, +-{0x60b9, 0x5c}, +-{0x60ba, 0xd4}, +-{0x60bb, 0x8b}, +-{0x60bc, 0x9d}, +-{0x60bd, 0xd3}, +-{0x60be, 0x21}, +-{0x60bf, 0xb0}, +-{0x60c0, 0xb0}, +-{0x60c1, 0xb7}, +-{0x60c2, 0x05}, +-{0x60c3, 0xd3}, +-{0x60c4, 0x0a}, +-{0x60c5, 0xd3}, +-{0x60c6, 0x10}, +-{0x60c7, 0x9c}, +-{0x60c8, 0x94}, +-{0x60c9, 0x90}, +-{0x60ca, 0xc8}, +-{0x60cb, 0xba}, +-{0x60cc, 0x7c}, +-{0x60cd, 0x74}, +-{0x60ce, 0x00}, +-{0x60cf, 0x61}, +-{0x60d0, 0x2a}, +-{0x60d1, 0x00}, +-{0x60d2, 0xd2}, +-{0x60d3, 0xcc}, +-{0x60d4, 0xdf}, +-{0x60d5, 0xc4}, +-{0x60d6, 0x35}, +-{0x60d7, 0xd3}, +-{0x60d8, 0x13}, +-{0x60d9, 0xd2}, +-{0x60da, 0xcc}, +-{0x60db, 0x06}, +-{0x60dc, 0x31}, +-{0x60dd, 0xd2}, +-{0x60de, 0xcc}, +-{0x60df, 0x15}, +-{0x60e0, 0xd2}, +-{0x60e1, 0xbb}, +-{0x60e2, 0xcc}, +-{0x60e3, 0x1a}, +-{0x60e4, 0xd2}, +-{0x60e5, 0xbe}, +-{0x60e6, 0xce}, +-{0x60e7, 0x52}, +-{0x60e8, 0xcf}, +-{0x60e9, 0x56}, +-{0x60ea, 0xd0}, +-{0x60eb, 0x5b}, +-{0x60ec, 0x2b}, +-{0x60ed, 0xd2}, +-{0x60ee, 0xd3}, +-{0x60ef, 0x01}, +-{0x60f0, 0xcc}, +-{0x60f1, 0x0a}, +-{0x60f2, 0xd2}, +-{0x60f3, 0xd3}, +-{0x60f4, 0x0f}, +-{0x60f5, 0xd9}, +-{0x60f6, 0xb4}, +-{0x60f7, 0xda}, +-{0x60f8, 0xbb}, +-{0x60f9, 0x1a}, +-{0x60fa, 0xd4}, +-{0x60fb, 0xe3}, +-{0x60fc, 0xd4}, +-{0x60fd, 0x96}, +-{0x60fe, 0x27}, +-{0x60ff, 0x00}, +-{0x6100, 0xd2}, +-{0x6101, 0xcc}, +-{0x6102, 0x60}, +-{0x6103, 0xd2}, +-{0x6104, 0xd3}, +-{0x6105, 0x2d}, +-{0x6106, 0xd9}, +-{0x6107, 0xcc}, +-{0x6108, 0xda}, +-{0x6109, 0xd2}, +-{0x610a, 0x1a}, +-{0x610b, 0x12}, +-{0x610c, 0xcc}, +-{0x610d, 0x88}, +-{0x610e, 0xd6}, +-{0x610f, 0x9e}, +-{0x6110, 0xb9}, +-{0x6111, 0xba}, +-{0x6112, 0xaf}, +-{0x6113, 0xdc}, +-{0x6114, 0x00}, +-{0x6115, 0xd5}, +-{0x6116, 0xba}, +-{0x6117, 0x00}, +-{0x6118, 0x00}, +-{0x6119, 0x00}, +-{0x611a, 0x00}, +-{0x611b, 0x00}, +-{0x611c, 0x00}, +-{0x611d, 0x00}, +-{0x611e, 0x00}, +-{0x611f, 0xaa}, +-{0x6120, 0xaa}, +-{0x6121, 0xb7}, +-{0x6122, 0x00}, +-{0x6123, 0x00}, +-{0x6124, 0x00}, +-{0x6125, 0x00}, +-{0x6126, 0x00}, +-{0x6127, 0xa6}, +-{0x6128, 0xa6}, +-{0x6129, 0xb7}, +-{0x612a, 0x00}, +-{0x612b, 0xd5}, +-{0x612c, 0x71}, +-{0x612d, 0xd3}, +-{0x612e, 0x30}, +-{0x612f, 0xba}, +-{0x6130, 0x00}, +-{0x6131, 0x00}, +-{0x6132, 0x00}, +-{0x6133, 0x00}, +-{0x6134, 0xd3}, +-{0x6135, 0x10}, +-{0x6136, 0x70}, +-{0x6137, 0x00}, +-{0x6138, 0x00}, +-{0x6139, 0x00}, +-{0x613a, 0x00}, +-{0x613b, 0xd5}, +-{0x613c, 0xba}, +-{0x613d, 0xb0}, +-{0x613e, 0xb0}, +-{0x613f, 0xb7}, +-{0x6140, 0x9d}, +-{0x6141, 0x02}, +-{0x6142, 0xd3}, +-{0x6143, 0x0a}, +-{0x6144, 0x9d}, +-{0x6145, 0x9d}, +-{0x6146, 0xd3}, +-{0x6147, 0x10}, +-{0x6148, 0x9c}, +-{0x6149, 0x94}, +-{0x614a, 0x90}, +-{0x614b, 0xc8}, +-{0x614c, 0xba}, +-{0x614d, 0xd2}, +-{0x614e, 0x60}, +-{0x614f, 0x2c}, +-{0x6150, 0x50}, +-{0x6151, 0x11}, +-{0x6152, 0xcc}, +-{0x6153, 0x00}, +-{0x6154, 0x30}, +-{0x6155, 0xd5}, +-{0x6156, 0xba}, +-{0x6157, 0xb0}, +-{0x6158, 0xb0}, +-{0x6159, 0xb7}, +-{0x615a, 0x9d}, +-{0x615b, 0x02}, +-{0x615c, 0xd3}, +-{0x615d, 0x0a}, +-{0x615e, 0x9d}, +-{0x615f, 0x9d}, +-{0x6160, 0xd3}, +-{0x6161, 0x10}, +-{0x6162, 0x9c}, +-{0x6163, 0x94}, +-{0x6164, 0x90}, +-{0x6165, 0xc8}, +-{0x6166, 0xba}, +-{0x6167, 0xd5}, +-{0x6168, 0x01}, +-{0x6169, 0x1a}, +-{0x616a, 0xcc}, +-{0x616b, 0x12}, +-{0x616c, 0x12}, +-{0x616d, 0x00}, +-{0x616e, 0xcc}, +-{0x616f, 0x9c}, +-{0x6170, 0xd2}, +-{0x6171, 0xcc}, +-{0x6172, 0x60}, +-{0x6173, 0xd2}, +-{0x6174, 0x04}, +-{0x6175, 0xd5}, +-{0x6176, 0x1a}, +-{0x6177, 0xcc}, +-{0x6178, 0x12}, +-{0x6179, 0x00}, +-{0x617a, 0x12}, +-{0x617b, 0xcc}, +-{0x617c, 0x9c}, +-{0x617d, 0xd2}, +-{0x617e, 0xcc}, +-{0x617f, 0x60}, +-{0x6180, 0xd2}, +-{0x6181, 0x1a}, +-{0x6182, 0xcc}, +-{0x6183, 0x12}, +-{0x6184, 0x00}, +-{0x6185, 0x12}, +-{0x6186, 0xcc}, +-{0x6187, 0x9c}, +-{0x6188, 0xd2}, +-{0x6189, 0xcc}, +-{0x618a, 0x60}, +-{0x618b, 0xd2}, +-{0x618c, 0x1a}, +-{0x618d, 0xcc}, +-{0x618e, 0x12}, +-{0x618f, 0x00}, +-{0x6190, 0x12}, +-{0x6191, 0xcc}, +-{0x6192, 0x9c}, +-{0x6193, 0xd2}, +-{0x6194, 0xcc}, +-{0x6195, 0x60}, +-{0x6196, 0xd2}, +-{0x6197, 0xd5}, +-{0x6198, 0x1a}, +-{0x6199, 0xcc}, +-{0x619a, 0x12}, +-{0x619b, 0x12}, +-{0x619c, 0x00}, +-{0x619d, 0xcc}, +-{0x619e, 0x8a}, +-{0x619f, 0xd2}, +-{0x61a0, 0xcc}, +-{0x61a1, 0x74}, +-{0x61a2, 0xd2}, +-{0x61a3, 0xd5}, +-{0x61a4, 0x1a}, +-{0x61a5, 0xcc}, +-{0x61a6, 0x12}, +-{0x61a7, 0x00}, +-{0x61a8, 0x12}, +-{0x61a9, 0xcc}, +-{0x61aa, 0x8a}, +-{0x61ab, 0xd2}, +-{0x61ac, 0xcc}, +-{0x61ad, 0x74}, +-{0x61ae, 0xd2}, +-{0x61af, 0x1a}, +-{0x61b0, 0xcc}, +-{0x61b1, 0x12}, +-{0x61b2, 0x00}, +-{0x61b3, 0x12}, +-{0x61b4, 0xcc}, +-{0x61b5, 0x8a}, +-{0x61b6, 0xd2}, +-{0x61b7, 0xcc}, +-{0x61b8, 0x74}, +-{0x61b9, 0xd2}, +-{0x61ba, 0x1a}, +-{0x61bb, 0xcc}, +-{0x61bc, 0x12}, +-{0x61bd, 0x00}, +-{0x61be, 0x12}, +-{0x61bf, 0xcc}, +-{0x61c0, 0x8a}, +-{0x61c1, 0xd2}, +-{0x61c2, 0xcc}, +-{0x61c3, 0x74}, +-{0x61c4, 0xd2}, +-{0x61c5, 0xd5}, +-{0x61c6, 0xcc}, +-{0x61c7, 0x12}, +-{0x61c8, 0x00}, +-{0x61c9, 0x12}, +-{0x61ca, 0xcc}, +-{0x61cb, 0x9c}, +-{0x61cc, 0xd5}, +-{0x6400, 0x04}, +-{0x6401, 0x04}, +-{0x6402, 0x00}, +-{0x6403, 0xff}, +-{0x6404, 0x00}, +-{0x6405, 0x08}, +-{0x6406, 0x00}, +-{0x6407, 0xff}, +-{0x6408, 0x04}, +-{0x6409, 0x70}, +-{0x640a, 0x00}, +-{0x640b, 0xff}, +-{0x640c, 0x05}, +-{0x640d, 0x14}, +-{0x640e, 0x04}, +-{0x640f, 0x71}, +-{0x6410, 0x05}, +-{0x6411, 0x74}, +-{0x6412, 0x00}, +-{0x6413, 0xff}, +-{0x6414, 0x05}, +-{0x6415, 0x54}, +-{0x6416, 0x05}, +-{0x6417, 0x44}, +-{0x6418, 0x04}, +-{0x6419, 0x30}, +-{0x641a, 0x05}, +-{0x641b, 0x46}, +-{0x641c, 0x00}, +-{0x641d, 0xff}, +-{0x641e, 0x04}, +-{0x641f, 0x31}, +-{0x6420, 0x04}, +-{0x6421, 0x30}, +-{0x6422, 0x00}, +-{0x6423, 0xff}, +-{0x6424, 0x04}, +-{0x6425, 0x20}, +-{0x6426, 0x05}, +-{0x6427, 0x06}, +-{0x6428, 0x00}, +-{0x6429, 0xff}, +-{0x642a, 0x08}, +-{0x642b, 0x2a}, +-{0x642c, 0x08}, +-{0x642d, 0x31}, +-{0x642e, 0x00}, +-{0x642f, 0xff}, +-{0x6430, 0x08}, +-{0x6431, 0x2a}, +-{0x6432, 0x08}, +-{0x6433, 0x31}, +-{0x6434, 0x06}, +-{0x6435, 0x20}, +-{0x6436, 0x07}, +-{0x6437, 0x00}, +-{0x6438, 0x08}, +-{0x6439, 0x40}, +-{0x643a, 0x00}, +-{0x643b, 0xff}, +-{0x643c, 0x08}, +-{0x643d, 0x2a}, +-{0x643e, 0x08}, +-{0x643f, 0x36}, +-{0x6440, 0x06}, +-{0x6441, 0x10}, +-{0x6442, 0x07}, +-{0x6443, 0x00}, +-{0x6444, 0x08}, +-{0x6445, 0x40}, +-{0x6446, 0x00}, +-{0x6447, 0xff}, +-{0x6448, 0x08}, +-{0x6449, 0x2a}, +-{0x644a, 0x08}, +-{0x644b, 0x3b}, +-{0x644c, 0x06}, +-{0x644d, 0x00}, +-{0x644e, 0x07}, +-{0x644f, 0x00}, +-{0x6450, 0x08}, +-{0x6451, 0x40}, +-{0x6452, 0x00}, +-{0x6453, 0xff}, +-{0x6454, 0x06}, +-{0x6455, 0x00}, +-{0x6456, 0x07}, +-{0x6457, 0x05}, +-{0x6458, 0x01}, +-{0x6459, 0xaf}, +-{0x645a, 0x01}, +-{0x645b, 0x0f}, +-{0x645c, 0x01}, +-{0x645d, 0x90}, +-{0x645e, 0x01}, +-{0x645f, 0xc8}, +-{0x6460, 0x00}, +-{0x6461, 0xff}, +-{0x6462, 0x01}, +-{0x6463, 0xac}, +-{0x6464, 0x01}, +-{0x6465, 0x0c}, +-{0x6466, 0x01}, +-{0x6467, 0x90}, +-{0x6468, 0x01}, +-{0x6469, 0xe8}, +-{0x646a, 0x00}, +-{0x646b, 0xff}, +-{0x646c, 0x01}, +-{0x646d, 0xad}, +-{0x646e, 0x01}, +-{0x646f, 0x0d}, +-{0x6470, 0x01}, +-{0x6471, 0x90}, +-{0x6472, 0x01}, +-{0x6473, 0xe8}, +-{0x6474, 0x00}, +-{0x6475, 0xff}, +-{0x6476, 0x01}, +-{0x6477, 0xae}, +-{0x6478, 0x01}, +-{0x6479, 0x0e}, +-{0x647a, 0x01}, +-{0x647b, 0x90}, +-{0x647c, 0x01}, +-{0x647d, 0xe8}, +-{0x647e, 0x00}, +-{0x647f, 0xff}, +-{0x6480, 0x01}, +-{0x6481, 0xb0}, +-{0x6482, 0x01}, +-{0x6483, 0xb1}, +-{0x6484, 0x01}, +-{0x6485, 0xb2}, +-{0x6486, 0x01}, +-{0x6487, 0xb3}, +-{0x6488, 0x01}, +-{0x6489, 0xb4}, +-{0x648a, 0x01}, +-{0x648b, 0xb5}, +-{0x648c, 0x01}, +-{0x648d, 0xb6}, +-{0x648e, 0x01}, +-{0x648f, 0xb7}, +-{0x6490, 0x01}, +-{0x6491, 0xb8}, +-{0x6492, 0x01}, +-{0x6493, 0xb9}, +-{0x6494, 0x01}, +-{0x6495, 0xba}, +-{0x6496, 0x01}, +-{0x6497, 0xbb}, +-{0x6498, 0x01}, +-{0x6499, 0xbc}, +-{0x649a, 0x01}, +-{0x649b, 0xbd}, +-{0x649c, 0x01}, +-{0x649d, 0xbe}, +-{0x649e, 0x01}, +-{0x649f, 0xbf}, +-{0x64a0, 0x01}, +-{0x64a1, 0xc0}, +-{0x64a2, 0x00}, +-{0x64a3, 0xff}, +-{0x64a4, 0x06}, +-{0x64a5, 0x00}, +-{0x64a6, 0x01}, +-{0x64a7, 0xf6}, +-{0x64a8, 0x04}, +-{0x64a9, 0x30}, +-{0x64aa, 0x00}, +-{0x64ab, 0xff}, +-{0x64ac, 0x06}, +-{0x64ad, 0x10}, +-{0x64ae, 0x01}, +-{0x64af, 0xf6}, +-{0x64b0, 0x04}, +-{0x64b1, 0x30}, +-{0x64b2, 0x06}, +-{0x64b3, 0x00}, +-{0x64b4, 0x00}, +-{0x64b5, 0xff}, +-{0x64b6, 0x06}, +-{0x64b7, 0x20}, +-{0x64b8, 0x01}, +-{0x64b9, 0xf6}, +-{0x64ba, 0x04}, +-{0x64bb, 0x30}, +-{0x64bc, 0x06}, +-{0x64bd, 0x00}, +-{0x64be, 0x00}, +-{0x64bf, 0xff}, +-{0x64c0, 0x04}, +-{0x64c1, 0x31}, +-{0x64c2, 0x04}, +-{0x64c3, 0x30}, +-{0x64c4, 0x01}, +-{0x64c5, 0x20}, +-{0x64c6, 0x01}, +-{0x64c7, 0x31}, +-{0x64c8, 0x01}, +-{0x64c9, 0x32}, +-{0x64ca, 0x01}, +-{0x64cb, 0x33}, +-{0x64cc, 0x01}, +-{0x64cd, 0x34}, +-{0x64ce, 0x01}, +-{0x64cf, 0x35}, +-{0x64d0, 0x01}, +-{0x64d1, 0x36}, +-{0x64d2, 0x01}, +-{0x64d3, 0x37}, +-{0x64d4, 0x01}, +-{0x64d5, 0x38}, +-{0x64d6, 0x01}, +-{0x64d7, 0x39}, +-{0x64d8, 0x01}, +-{0x64d9, 0x3a}, +-{0x64da, 0x01}, +-{0x64db, 0x3b}, +-{0x64dc, 0x01}, +-{0x64dd, 0x3c}, +-{0x64de, 0x01}, +-{0x64df, 0x3d}, +-{0x64e0, 0x01}, +-{0x64e1, 0x3e}, +-{0x64e2, 0x01}, +-{0x64e3, 0x3f}, +-{0x64e4, 0x02}, +-{0x64e5, 0xa0}, +-{0x64e6, 0x00}, +-{0x64e7, 0xff}, +-{0x64e8, 0x04}, +-{0x64e9, 0x31}, +-{0x64ea, 0x04}, +-{0x64eb, 0x30}, +-{0x64ec, 0x01}, +-{0x64ed, 0x00}, +-{0x64ee, 0x01}, +-{0x64ef, 0x11}, +-{0x64f0, 0x01}, +-{0x64f1, 0x12}, +-{0x64f2, 0x01}, +-{0x64f3, 0x13}, +-{0x64f4, 0x01}, +-{0x64f5, 0x14}, +-{0x64f6, 0x01}, +-{0x64f7, 0x15}, +-{0x64f8, 0x01}, +-{0x64f9, 0x16}, +-{0x64fa, 0x01}, +-{0x64fb, 0x17}, +-{0x64fc, 0x01}, +-{0x64fd, 0x18}, +-{0x64fe, 0x01}, +-{0x64ff, 0x19}, +-{0x6500, 0x01}, +-{0x6501, 0x1a}, +-{0x6502, 0x01}, +-{0x6503, 0x1b}, +-{0x6504, 0x01}, +-{0x6505, 0x1c}, +-{0x6506, 0x01}, +-{0x6507, 0x1d}, +-{0x6508, 0x01}, +-{0x6509, 0x1e}, +-{0x650a, 0x01}, +-{0x650b, 0x1f}, +-{0x650c, 0x02}, +-{0x650d, 0xa0}, +-{0x650e, 0x00}, +-{0x650f, 0xff}, +-{0x6510, 0x04}, +-{0x6511, 0x20}, +-{0x6512, 0x05}, +-{0x6513, 0x86}, +-{0x6514, 0x03}, +-{0x6515, 0x0b}, +-{0x6516, 0x05}, +-{0x6517, 0x86}, +-{0x6518, 0x00}, +-{0x6519, 0x00}, +-{0x651a, 0x05}, +-{0x651b, 0x06}, +-{0x651c, 0x00}, +-{0x651d, 0x04}, +-{0x651e, 0x05}, +-{0x651f, 0x04}, +-{0x6520, 0x00}, +-{0x6521, 0x04}, +-{0x6522, 0x05}, +-{0x6523, 0x00}, +-{0x6524, 0x05}, +-{0x6525, 0x0a}, +-{0x6526, 0x03}, +-{0x6527, 0x9a}, +-{0x6528, 0x05}, +-{0x6529, 0x86}, +-{0x652a, 0x00}, +-{0x652b, 0x00}, +-{0x652c, 0x05}, +-{0x652d, 0x06}, +-{0x652e, 0x00}, +-{0x652f, 0x01}, +-{0x6530, 0x05}, +-{0x6531, 0x04}, +-{0x6532, 0x00}, +-{0x6533, 0x04}, +-{0x6534, 0x05}, +-{0x6535, 0x00}, +-{0x6536, 0x05}, +-{0x6537, 0x0a}, +-{0x6538, 0x03}, +-{0x6539, 0x99}, +-{0x653a, 0x05}, +-{0x653b, 0x06}, +-{0x653c, 0x00}, +-{0x653d, 0x00}, +-{0x653e, 0x05}, +-{0x653f, 0x04}, +-{0x6540, 0x00}, +-{0x6541, 0x04}, +-{0x6542, 0x05}, +-{0x6543, 0x00}, +-{0x6544, 0x05}, +-{0x6545, 0x0a}, +-{0x6546, 0x03}, +-{0x6547, 0x98}, +-{0x6548, 0x05}, +-{0x6549, 0x06}, +-{0x654a, 0x00}, +-{0x654b, 0x00}, +-{0x654c, 0x05}, +-{0x654d, 0x04}, +-{0x654e, 0x00}, +-{0x654f, 0x04}, +-{0x6550, 0x05}, +-{0x6551, 0x00}, +-{0x6552, 0x05}, +-{0x6553, 0x0a}, +-{0x6554, 0x03}, +-{0x6555, 0x97}, +-{0x6556, 0x05}, +-{0x6557, 0x06}, +-{0x6558, 0x05}, +-{0x6559, 0x04}, +-{0x655a, 0x00}, +-{0x655b, 0x04}, +-{0x655c, 0x05}, +-{0x655d, 0x00}, +-{0x655e, 0x05}, +-{0x655f, 0x0a}, +-{0x6560, 0x03}, +-{0x6561, 0x96}, +-{0x6562, 0x05}, +-{0x6563, 0x06}, +-{0x6564, 0x05}, +-{0x6565, 0x04}, +-{0x6566, 0x00}, +-{0x6567, 0x04}, +-{0x6568, 0x05}, +-{0x6569, 0x00}, +-{0x656a, 0x05}, +-{0x656b, 0x0a}, +-{0x656c, 0x03}, +-{0x656d, 0x95}, +-{0x656e, 0x05}, +-{0x656f, 0x06}, +-{0x6570, 0x05}, +-{0x6571, 0x04}, +-{0x6572, 0x00}, +-{0x6573, 0x04}, +-{0x6574, 0x05}, +-{0x6575, 0x00}, +-{0x6576, 0x05}, +-{0x6577, 0x0a}, +-{0x6578, 0x03}, +-{0x6579, 0x94}, +-{0x657a, 0x05}, +-{0x657b, 0x06}, +-{0x657c, 0x00}, +-{0x657d, 0x00}, +-{0x657e, 0x05}, +-{0x657f, 0x04}, +-{0x6580, 0x00}, +-{0x6581, 0x04}, +-{0x6582, 0x05}, +-{0x6583, 0x00}, +-{0x6584, 0x05}, +-{0x6585, 0x0a}, +-{0x6586, 0x03}, +-{0x6587, 0x93}, +-{0x6588, 0x05}, +-{0x6589, 0x06}, +-{0x658a, 0x00}, +-{0x658b, 0x00}, +-{0x658c, 0x05}, +-{0x658d, 0x04}, +-{0x658e, 0x00}, +-{0x658f, 0x04}, +-{0x6590, 0x05}, +-{0x6591, 0x00}, +-{0x6592, 0x05}, +-{0x6593, 0x0a}, +-{0x6594, 0x03}, +-{0x6595, 0x92}, +-{0x6596, 0x05}, +-{0x6597, 0x06}, +-{0x6598, 0x05}, +-{0x6599, 0x04}, +-{0x659a, 0x00}, +-{0x659b, 0x04}, +-{0x659c, 0x05}, +-{0x659d, 0x00}, +-{0x659e, 0x05}, +-{0x659f, 0x0a}, +-{0x65a0, 0x03}, +-{0x65a1, 0x91}, +-{0x65a2, 0x05}, +-{0x65a3, 0x06}, +-{0x65a4, 0x05}, +-{0x65a5, 0x04}, +-{0x65a6, 0x00}, +-{0x65a7, 0x04}, +-{0x65a8, 0x05}, +-{0x65a9, 0x00}, +-{0x65aa, 0x05}, +-{0x65ab, 0x0a}, +-{0x65ac, 0x03}, +-{0x65ad, 0x90}, +-{0x65ae, 0x05}, +-{0x65af, 0x06}, +-{0x65b0, 0x05}, +-{0x65b1, 0x04}, +-{0x65b2, 0x00}, +-{0x65b3, 0x04}, +-{0x65b4, 0x05}, +-{0x65b5, 0x00}, +-{0x65b6, 0x05}, +-{0x65b7, 0x0a}, +-{0x65b8, 0x02}, +-{0x65b9, 0x90}, +-{0x65ba, 0x05}, +-{0x65bb, 0x06}, +-{0x65bc, 0x00}, +-{0x65bd, 0xff}, +-{0x65be, 0x04}, +-{0x65bf, 0x70}, +-{0x65c0, 0x08}, +-{0x65c1, 0x76}, +-{0x65c2, 0x00}, +-{0x65c3, 0xff}, +-{0x65c4, 0x08}, +-{0x65c5, 0x76}, +-{0x65c6, 0x04}, +-{0x65c7, 0x0c}, +-{0x65c8, 0x05}, +-{0x65c9, 0x07}, +-{0x65ca, 0x04}, +-{0x65cb, 0x04}, +-{0x65cc, 0x00}, +-{0x65cd, 0xff}, +-{0x65ce, 0x00}, +-{0x65cf, 0xff}, +-{0x65d0, 0x00}, +-{0x65d1, 0xff}, +-{0x30eb, 0x04}, +-{0x30ed, 0x5a}, +-{0x30ee, 0x01}, +-{0x30ef, 0x80}, +-{0x30f1, 0x5a}, +-{0x303a, 0x04}, +-{0x303b, 0x7f}, +-{0x303c, 0xfe}, +-{0x303d, 0x19}, +-{0x303e, 0xd7}, +-{0x303f, 0x09}, +-{0x3040, 0x78}, +-{0x3042, 0x05}, +-{0x328a, 0x10}, +-{0x3012, 0x01}, // stream on +-}; +- +-/* DVP_1280x1080_COMB12_raw 30fps */ +-static const struct ov10640_reg ov10640_regs_wizard_r1e[] = { +-/* ov10640_R1E_setting_3x12_1280x1080_MIPIin_4lane_raw */ +-//{0x3013, 0x01}, +-{OV10640_DELAY, 10}, +-{0x328a, 0x11}, +-{0x313f, 0x80}, +-{0x3132, 0x24}, +- +-/* PLL settings */ +-{0x3000, 0x03}, +-{0x3001, 0x60}, +-{0x3002, 0x0f}, +-{0x3004, 0x03}, +-{0x3005, 0x44}, +-{0x3006, 0x07}, +-{0x3007, 0x01}, +- +-{0x3014, 0x03}, +-{0x3023, 0x05}, +-{0x3032, 0x35}, +-{0x3033, 0x04}, +-{0x3054, 0x00}, +-{0x3055, 0x03}, +-{0x3056, 0x01}, +-{0x3057, 0xff}, +-{0x3058, 0xaf}, +-{0x3059, 0x44}, +-{0x305a, 0x02}, +-{0x305b, 0x00}, +-{0x305c, 0x30}, +-{0x305d, 0x9c}, +-{0x305e, 0x19}, +-{0x305f, 0x18}, +-{0x3060, 0xf9}, +-{0x3061, 0xf0}, +-{0x308a, 0x00}, +-{0x308b, 0x00}, +-#ifdef OV10640_FSIN_ENABLE +-{0x308c, 0xb2}, +-#else +-{0x308c, 0x03}, +-#endif +-{0x308f, 0x10}, +-{0x3090, 0x04}, /* c:enable flip and mirror */ +-{0x3091, 0x00}, +-{0x30eb, 0x00}, +-{0x30a3, 0x08}, +-{0x30ad, 0x03}, +-{0x30ae, 0x80}, +-{0x30af, 0x80}, +-{0x30b0, 0xff}, +-{0x30b1, 0x3f}, +-{0x30b2, 0x22}, +-{0x30b9, 0x22}, +-{0x30bb, 0x00}, +-{0x30bc, 0x00}, +-{0x30bd, 0x00}, +-{0x30be, 0x00}, +-{0x30bf, 0x00}, +-{0x30c0, 0x00}, +-{0x30c1, 0x00}, +-{0x30c2, 0x00}, +-{0x30c3, 0x00}, +-{0x30c4, 0x80}, +-{0x30c5, 0x00}, +-{0x30c6, 0x80}, +-{0x30c7, 0x00}, +-{0x30c8, 0x80}, +-{0x3119, 0x49}, +-{0x311a, 0x01}, +-{0x311b, 0x4a}, +- +-/* Crop Setting */ +-{0x3074, 0x00}, // crop_h_start +-{0x3075, 0x00}, +-{0x3076, 0x00}, // crop_v_start +-{0x3077, 0xf0}, +-{0x3078, 0x05}, // crop_h_end +-{0x3079, 0x09}, +-{0x307a, 0x04}, // crop_v_end +-{0x307b, 0x18}, +-{0x307c, 0x05}, // dvp_h_size +-{0x307d, 0x08}, +-{0x307e, 0x03}, // dvp_v_size +-{0x307f, 0x28}, +-{0x3080, 0x07}, // hts +-{0x3081, 0x44}, +-{0x3082, 0x03}, // vts +-{0x3083, 0x5c}, +-{0x3084, 0x00}, // win_hoffs +-{0x3085, 0x00}, +-{0x3086, 0x00}, // win_voffs +-{0x3087, 0x00}, +- +-{0x3088, 0x00}, +-{0x3089, 0x40}, +-{0x308d, 0x92}, +-{0x3094, 0xa5}, +-{0x30e6, 0x04}, +-{0x30e7, 0x48}, +-{0x30e8, 0x04}, +-{0x30e9, 0x48}, +-{0x30e9, 0x05}, +-{0x30ec, 0x01}, +-{0x30fa, 0x06}, +-{0x3120, 0x00}, +-{0x3121, 0x20}, /* VSYNC delay */ +-{0x3122, 0x00}, +-{0x3127, 0x43}, /* 43 :dpc off, 63 */ +-{0x3128, 0xc0}, +-#ifdef OV10640_DISPLAY_PATTERN +-{0x3129, 0x80}, +-#else +-{0x3129, 0x00}, +-#endif +-{0x31be, 0x00}, +-{0x30a5, 0x78}, +-{0x30a6, 0x40}, +-{0x30a7, 0x78}, +-{0x30a8, 0x80}, +-{0x30a9, 0x78}, +-{0x30aa, 0xe0}, +-{0x30ab, 0xf9}, +-{0x30ac, 0xc0}, +-{0x3440, 0x04}, +-{0x3444, 0x28}, +-{0x344e, 0x2c}, +-{0x3457, 0x33}, +-{0x345e, 0x38}, +-{0x3461, 0xa8}, +-{0x7002, 0xaa}, +-{0x7001, 0xdf}, +-{0x7048, 0x00}, +-{0x7049, 0x02}, +-{0x704a, 0x02}, +-{0x704b, 0x00}, +-{0x704c, 0x01}, +-{0x704d, 0x00}, +-{0x7043, 0x04}, +-{0x7040, 0x3c}, +-{0x7047, 0x00}, +-{0x7044, 0x01}, +-{0x7000, 0x1f}, +-{0x7084, 0x01}, +-{0x7085, 0x03}, +-{0x7086, 0x02}, +-{0x7087, 0x40}, +-{0x7088, 0x01}, +-{0x7089, 0x20}, +-{0x707f, 0x04}, +-{0x707c, 0x3c}, +-{0x7083, 0x00}, +-{0x7080, 0x01}, +-{0x7003, 0xdf}, +-{0x70c0, 0x00}, +-{0x70c1, 0x02}, +-{0x70c2, 0x02}, +-{0x70c3, 0x00}, +-{0x70c4, 0x01}, +-{0x70c5, 0x00}, +-{0x70b8, 0x03}, +-{0x70b9, 0x98}, +-{0x70bc, 0x00}, +-{0x70bd, 0x80}, +-{0x7004, 0x02}, +-{0x7005, 0x00}, +-{0x7006, 0x01}, +-{0x7007, 0x80}, +-{0x7008, 0x02}, +-{0x7009, 0x00}, +-{0x700a, 0x04}, +-{0x700b, 0x00}, +-{0x700e, 0x00}, +-{0x700f, 0x60}, +-{0x701a, 0x02}, +-{0x701b, 0x00}, +-{0x701c, 0x01}, +-{0x701d, 0x80}, +-{0x701e, 0x02}, +-{0x701f, 0x00}, +-{0x7020, 0x04}, +-{0x7021, 0x00}, +-{0x7024, 0x00}, +-{0x7025, 0x60}, +-{0x70e7, 0x00}, +-{0x70e4, 0x10}, +-{0x70e5, 0x00}, +-{0x70e6, 0x00}, +-{0x70eb, 0x00}, +-{0x70e8, 0x10}, +-{0x70e9, 0x00}, +-{0x70ea, 0x00}, +-{0x70ef, 0x00}, +-{0x70ec, 0xfd}, +-{0x70ed, 0x00}, +-{0x70ee, 0x00}, +-{0x70eb, 0x00}, +-{0x70f0, 0xfd}, +-{0x70f1, 0x00}, +-{0x70f2, 0x00}, +-{0x30fb, 0x06}, +-{0x30fc, 0x80}, +-{0x30fd, 0x02}, +-{0x30fe, 0x93}, +-{0x6000, 0xc1}, +-{0x6001, 0xb9}, +-{0x6002, 0xba}, +-{0x6003, 0xa4}, +-{0x6004, 0xb5}, +-{0x6005, 0xa0}, +-{0x6006, 0x82}, +-{0x6007, 0xa7}, +-{0x6008, 0xb7}, +-{0x6009, 0x5c}, +-{0x600a, 0x9e}, +-{0x600b, 0xc0}, +-{0x600c, 0xd2}, +-{0x600d, 0x33}, +-{0x600e, 0xcc}, +-{0x600f, 0xe2}, +-{0x6010, 0xc1}, +-{0x6011, 0xab}, +-{0x6012, 0xb7}, +-{0x6013, 0x00}, +-{0x6014, 0x00}, +-{0x6015, 0x00}, +-{0x6016, 0x00}, +-{0x6017, 0x00}, +-{0x6018, 0x00}, +-{0x6019, 0x00}, +-{0x601a, 0x00}, +-{0x601b, 0x00}, +-{0x601c, 0x00}, +-{0x601d, 0x00}, +-{0x601e, 0x9c}, +-{0x601f, 0x94}, +-{0x6020, 0x90}, +-{0x6021, 0xc5}, +-{0x6022, 0x01}, +-{0x6023, 0x54}, +-{0x6024, 0x2a}, +-{0x6025, 0x61}, +-{0x6026, 0xd2}, +-{0x6027, 0xcc}, +-{0x6028, 0x04}, +-{0x6029, 0x35}, +-{0x602a, 0xb1}, +-{0x602b, 0xb2}, +-{0x602c, 0xb3}, +-{0x602d, 0xd2}, +-{0x602e, 0xd3}, +-{0x602f, 0x12}, +-{0x6030, 0x31}, +-{0x6031, 0xcc}, +-{0x6032, 0x06}, +-{0x6033, 0xd2}, +-{0x6034, 0xc4}, +-{0x6035, 0xce}, +-{0x6036, 0x18}, +-{0x6037, 0xcf}, +-{0x6038, 0x1e}, +-{0x6039, 0xd0}, +-{0x603a, 0x24}, +-{0x603b, 0xc5}, +-{0x603c, 0xd2}, +-{0x603d, 0xbc}, +-{0x603e, 0xcc}, +-{0x603f, 0x52}, +-{0x6040, 0x2b}, +-{0x6041, 0xd2}, +-{0x6042, 0xd3}, +-{0x6043, 0x02}, +-{0x6044, 0xcc}, +-{0x6045, 0x0a}, +-{0x6046, 0xd2}, +-{0x6047, 0xd3}, +-{0x6048, 0x0f}, +-{0x6049, 0x1a}, +-{0x604a, 0x2a}, +-{0x604b, 0xd4}, +-{0x604c, 0xf6}, +-{0x604d, 0xba}, +-{0x604e, 0x56}, +-{0x604f, 0xd3}, +-{0x6050, 0x2e}, +-{0x6051, 0x54}, +-{0x6052, 0x26}, +-{0x6053, 0xd2}, +-{0x6054, 0xcc}, +-{0x6055, 0x60}, +-{0x6056, 0xd2}, +-{0x6057, 0xd3}, +-{0x6058, 0x27}, +-{0x6059, 0x27}, +-{0x605a, 0x08}, +-{0x605b, 0x1a}, +-{0x605c, 0xcc}, +-{0x605d, 0x88}, +-{0x605e, 0x00}, +-{0x605f, 0x12}, +-{0x6060, 0x2c}, +-{0x6061, 0x60}, +-{0x6062, 0xc2}, +-{0x6063, 0xb9}, +-{0x6064, 0xa5}, +-{0x6065, 0xb5}, +-{0x6066, 0xa0}, +-{0x6067, 0x82}, +-{0x6068, 0x5c}, +-{0x6069, 0xd4}, +-{0x606a, 0xbe}, +-{0x606b, 0xd4}, +-{0x606c, 0xbe}, +-{0x606d, 0xd3}, +-{0x606e, 0x01}, +-{0x606f, 0x7c}, +-{0x6070, 0x74}, +-{0x6071, 0x00}, +-{0x6072, 0x61}, +-{0x6073, 0x2a}, +-{0x6074, 0xd2}, +-{0x6075, 0xcc}, +-{0x6076, 0xdf}, +-{0x6077, 0xc6}, +-{0x6078, 0x35}, +-{0x6079, 0xd2}, +-{0x607a, 0xcc}, +-{0x607b, 0x06}, +-{0x607c, 0x31}, +-{0x607d, 0xd2}, +-{0x607e, 0xc5}, +-{0x607f, 0xbb}, +-{0x6080, 0xcc}, +-{0x6081, 0x18}, +-{0x6082, 0xc6}, +-{0x6083, 0xd2}, +-{0x6084, 0xbd}, +-{0x6085, 0xcc}, +-{0x6086, 0x52}, +-{0x6087, 0x2b}, +-{0x6088, 0xd2}, +-{0x6089, 0xd3}, +-{0x608a, 0x01}, +-{0x608b, 0xcc}, +-{0x608c, 0x0a}, +-{0x608d, 0xd2}, +-{0x608e, 0xd3}, +-{0x608f, 0x0f}, +-{0x6090, 0x1a}, +-{0x6091, 0x71}, +-{0x6092, 0x2a}, +-{0x6093, 0xd4}, +-{0x6094, 0xf6}, +-{0x6095, 0xd3}, +-{0x6096, 0x22}, +-{0x6097, 0x70}, +-{0x6098, 0xca}, +-{0x6099, 0x26}, +-{0x609a, 0xd2}, +-{0x609b, 0xcc}, +-{0x609c, 0x60}, +-{0x609d, 0xd2}, +-{0x609e, 0xd3}, +-{0x609f, 0x27}, +-{0x60a0, 0x27}, +-{0x60a1, 0x08}, +-{0x60a2, 0x1a}, +-{0x60a3, 0xcc}, +-{0x60a4, 0x88}, +-{0x60a5, 0x12}, +-{0x60a6, 0x2c}, +-{0x60a7, 0x60}, +-{0x60a8, 0x00}, +-{0x60a9, 0x00}, +-{0x60aa, 0xc0}, +-{0x60ab, 0xb9}, +-{0x60ac, 0xa3}, +-{0x60ad, 0xb5}, +-{0x60ae, 0x00}, +-{0x60af, 0xa0}, +-{0x60b0, 0x82}, +-{0x60b1, 0x5c}, +-{0x60b2, 0xd4}, +-{0x60b3, 0xa0}, +-{0x60b4, 0x9d}, +-{0x60b5, 0xd3}, +-{0x60b6, 0x26}, +-{0x60b7, 0xb0}, +-{0x60b8, 0xb7}, +-{0x60b9, 0x00}, +-{0x60ba, 0xd3}, +-{0x60bb, 0x0a}, +-{0x60bc, 0xd3}, +-{0x60bd, 0x10}, +-{0x60be, 0x9c}, +-{0x60bf, 0x94}, +-{0x60c0, 0x90}, +-{0x60c1, 0xc8}, +-{0x60c2, 0xba}, +-{0x60c3, 0x7c}, +-{0x60c4, 0x74}, +-{0x60c5, 0x00}, +-{0x60c6, 0x61}, +-{0x60c7, 0x2a}, +-{0x60c8, 0x00}, +-{0x60c9, 0xd2}, +-{0x60ca, 0xcc}, +-{0x60cb, 0xdf}, +-{0x60cc, 0xc4}, +-{0x60cd, 0x35}, +-{0x60ce, 0xd2}, +-{0x60cf, 0xcc}, +-{0x60d0, 0x06}, +-{0x60d1, 0x31}, +-{0x60d2, 0xd2}, +-{0x60d3, 0xcc}, +-{0x60d4, 0x15}, +-{0x60d5, 0xd2}, +-{0x60d6, 0xbb}, +-{0x60d7, 0xcc}, +-{0x60d8, 0x1a}, +-{0x60d9, 0xd2}, +-{0x60da, 0xbe}, +-{0x60db, 0xce}, +-{0x60dc, 0x52}, +-{0x60dd, 0xcf}, +-{0x60de, 0x56}, +-{0x60df, 0xd0}, +-{0x60e0, 0x5b}, +-{0x60e1, 0x2b}, +-{0x60e2, 0xd2}, +-{0x60e3, 0xd3}, +-{0x60e4, 0x01}, +-{0x60e5, 0xcc}, +-{0x60e6, 0x0a}, +-{0x60e7, 0xd2}, +-{0x60e8, 0xd3}, +-{0x60e9, 0x0f}, +-{0x60ea, 0xd9}, +-{0x60eb, 0xc7}, +-{0x60ec, 0xda}, +-{0x60ed, 0xce}, +-{0x60ee, 0x1a}, +-{0x60ef, 0xd4}, +-{0x60f0, 0xf6}, +-{0x60f1, 0xd4}, +-{0x60f2, 0xa9}, +-{0x60f3, 0x27}, +-{0x60f4, 0x00}, +-{0x60f5, 0xd2}, +-{0x60f6, 0xcc}, +-{0x60f7, 0x60}, +-{0x60f8, 0xd2}, +-{0x60f9, 0xd3}, +-{0x60fa, 0x2d}, +-{0x60fb, 0xd9}, +-{0x60fc, 0xdf}, +-{0x60fd, 0xda}, +-{0x60fe, 0xe5}, +-{0x60ff, 0x1a}, +-{0x6100, 0x12}, +-{0x6101, 0xcc}, +-{0x6102, 0x88}, +-{0x6103, 0xd6}, +-{0x6104, 0xb1}, +-{0x6105, 0xb9}, +-{0x6106, 0xba}, +-{0x6107, 0xaf}, +-{0x6108, 0xdc}, +-{0x6109, 0x00}, +-{0x610a, 0xcb}, +-{0x610b, 0xc3}, +-{0x610c, 0xb9}, +-{0x610d, 0xa4}, +-{0x610e, 0xb5}, +-{0x610f, 0x5c}, +-{0x6110, 0x12}, +-{0x6111, 0x2a}, +-{0x6112, 0x61}, +-{0x6113, 0xd2}, +-{0x6114, 0xcc}, +-{0x6115, 0xdf}, +-{0x6116, 0xc7}, +-{0x6117, 0x35}, +-{0x6118, 0xd2}, +-{0x6119, 0xcc}, +-{0x611a, 0x06}, +-{0x611b, 0x31}, +-{0x611c, 0xc6}, +-{0x611d, 0xbb}, +-{0x611e, 0xd2}, +-{0x611f, 0xcc}, +-{0x6120, 0x18}, +-{0x6121, 0xd2}, +-{0x6122, 0xbe}, +-{0x6123, 0xcc}, +-{0x6124, 0x52}, +-{0x6125, 0xc7}, +-{0x6126, 0xd2}, +-{0x6127, 0xcc}, +-{0x6128, 0x0a}, +-{0x6129, 0xb4}, +-{0x612a, 0xb7}, +-{0x612b, 0x94}, +-{0x612c, 0xd2}, +-{0x612d, 0x12}, +-{0x612e, 0x26}, +-{0x612f, 0x42}, +-{0x6130, 0x46}, +-{0x6131, 0x42}, +-{0x6132, 0xd3}, +-{0x6133, 0x20}, +-{0x6134, 0x27}, +-{0x6135, 0x00}, +-{0x6136, 0x1a}, +-{0x6137, 0xcc}, +-{0x6138, 0x88}, +-{0x6139, 0x60}, +-{0x613a, 0x2c}, +-{0x613b, 0x12}, +-{0x613c, 0x40}, +-{0x613d, 0xb8}, +-{0x613e, 0x90}, +-{0x613f, 0xd5}, +-{0x6140, 0xba}, +-{0x6141, 0x00}, +-{0x6142, 0x00}, +-{0x6143, 0x00}, +-{0x6144, 0x00}, +-{0x6145, 0x00}, +-{0x6146, 0x00}, +-{0x6147, 0xaa}, +-{0x6148, 0xb7}, +-{0x6149, 0x00}, +-{0x614a, 0x00}, +-{0x614b, 0x00}, +-{0x614c, 0x00}, +-{0x614d, 0xa6}, +-{0x614e, 0xb7}, +-{0x614f, 0x00}, +-{0x6150, 0xd5}, +-{0x6151, 0x00}, +-{0x6152, 0x71}, +-{0x6153, 0xd3}, +-{0x6154, 0x30}, +-{0x6155, 0xba}, +-{0x6156, 0x00}, +-{0x6157, 0x00}, +-{0x6158, 0x00}, +-{0x6159, 0x00}, +-{0x615a, 0xd3}, +-{0x615b, 0x10}, +-{0x615c, 0x70}, +-{0x615d, 0x00}, +-{0x615e, 0x00}, +-{0x615f, 0x00}, +-{0x6160, 0x00}, +-{0x6161, 0xd5}, +-{0x6162, 0xba}, +-{0x6163, 0xb0}, +-{0x6164, 0xb7}, +-{0x6165, 0x00}, +-{0x6166, 0x9d}, +-{0x6167, 0xd3}, +-{0x6168, 0x0a}, +-{0x6169, 0x9d}, +-{0x616a, 0x9d}, +-{0x616b, 0xd3}, +-{0x616c, 0x10}, +-{0x616d, 0x9c}, +-{0x616e, 0x94}, +-{0x616f, 0x90}, +-{0x6170, 0xc8}, +-{0x6171, 0xba}, +-{0x6172, 0xd2}, +-{0x6173, 0x60}, +-{0x6174, 0x2c}, +-{0x6175, 0x50}, +-{0x6176, 0x11}, +-{0x6177, 0xcc}, +-{0x6178, 0x00}, +-{0x6179, 0x30}, +-{0x617a, 0xd5}, +-{0x617b, 0x00}, +-{0x617c, 0xba}, +-{0x617d, 0xb0}, +-{0x617e, 0xb7}, +-{0x617f, 0x00}, +-{0x6180, 0x9d}, +-{0x6181, 0xd3}, +-{0x6182, 0x0a}, +-{0x6183, 0x9d}, +-{0x6184, 0x9d}, +-{0x6185, 0xd3}, +-{0x6186, 0x10}, +-{0x6187, 0x9c}, +-{0x6188, 0x94}, +-{0x6189, 0x90}, +-{0x618a, 0xc8}, +-{0x618b, 0xba}, +-{0x618c, 0xd5}, +-{0x618d, 0x00}, +-{0x618e, 0x01}, +-{0x618f, 0x1a}, +-{0x6190, 0xcc}, +-{0x6191, 0x12}, +-{0x6192, 0x12}, +-{0x6193, 0x00}, +-{0x6194, 0xcc}, +-{0x6195, 0x9c}, +-{0x6196, 0xd2}, +-{0x6197, 0xcc}, +-{0x6198, 0x60}, +-{0x6199, 0xd2}, +-{0x619a, 0x04}, +-{0x619b, 0xd5}, +-{0x619c, 0x1a}, +-{0x619d, 0xcc}, +-{0x619e, 0x12}, +-{0x619f, 0x00}, +-{0x61a0, 0x12}, +-{0x61a1, 0xcc}, +-{0x61a2, 0x9c}, +-{0x61a3, 0xd2}, +-{0x61a4, 0xcc}, +-{0x61a5, 0x60}, +-{0x61a6, 0xd2}, +-{0x61a7, 0x1a}, +-{0x61a8, 0xcc}, +-{0x61a9, 0x12}, +-{0x61aa, 0x00}, +-{0x61ab, 0x12}, +-{0x61ac, 0xcc}, +-{0x61ad, 0x9c}, +-{0x61ae, 0xd2}, +-{0x61af, 0xcc}, +-{0x61b0, 0x60}, +-{0x61b1, 0xd2}, +-{0x61b2, 0x1a}, +-{0x61b3, 0xcc}, +-{0x61b4, 0x12}, +-{0x61b5, 0x00}, +-{0x61b6, 0x12}, +-{0x61b7, 0xcc}, +-{0x61b8, 0x9c}, +-{0x61b9, 0xd2}, +-{0x61ba, 0xcc}, +-{0x61bb, 0x60}, +-{0x61bc, 0xd2}, +-{0x61bd, 0xd5}, +-{0x61be, 0x1a}, +-{0x61bf, 0xcc}, +-{0x61c0, 0x12}, +-{0x61c1, 0x12}, +-{0x61c2, 0x00}, +-{0x61c3, 0xcc}, +-{0x61c4, 0x8a}, +-{0x61c5, 0xd2}, +-{0x61c6, 0xcc}, +-{0x61c7, 0x74}, +-{0x61c8, 0xd2}, +-{0x61c9, 0xd5}, +-{0x61ca, 0x1a}, +-{0x61cb, 0xcc}, +-{0x61cc, 0x12}, +-{0x61cd, 0x00}, +-{0x61ce, 0x12}, +-{0x61cf, 0xcc}, +-{0x61d0, 0x8a}, +-{0x61d1, 0xd2}, +-{0x61d2, 0xcc}, +-{0x61d3, 0x74}, +-{0x61d4, 0xd2}, +-{0x61d5, 0x1a}, +-{0x61d6, 0xcc}, +-{0x61d7, 0x12}, +-{0x61d8, 0x00}, +-{0x61d9, 0x12}, +-{0x61da, 0xcc}, +-{0x61db, 0x8a}, +-{0x61dc, 0xd2}, +-{0x61dd, 0xcc}, +-{0x61de, 0x74}, +-{0x61df, 0xd2}, +-{0x61e0, 0x1a}, +-{0x61e1, 0xcc}, +-{0x61e2, 0x12}, +-{0x61e3, 0x00}, +-{0x61e4, 0x12}, +-{0x61e5, 0xcc}, +-{0x61e6, 0x8a}, +-{0x61e7, 0xd2}, +-{0x61e8, 0xcc}, +-{0x61e9, 0x74}, +-{0x61ea, 0xd2}, +-{0x61eb, 0xd5}, +-{0x61ec, 0xcc}, +-{0x61ed, 0x12}, +-{0x61ee, 0x00}, +-{0x61ef, 0x12}, +-{0x61f0, 0xcc}, +-{0x61f1, 0x9c}, +-{0x61f2, 0xd5}, +-{0x6400, 0x04}, +-{0x6401, 0x04}, +-{0x6402, 0x00}, +-{0x6403, 0xff}, +-{0x6404, 0x00}, +-{0x6405, 0x08}, +-{0x6406, 0x00}, +-{0x6407, 0xff}, +-{0x6408, 0x04}, +-{0x6409, 0x70}, +-{0x640a, 0x00}, +-{0x640b, 0xff}, +-{0x640c, 0x05}, +-{0x640d, 0x14}, +-{0x640e, 0x04}, +-{0x640f, 0x71}, +-{0x6410, 0x05}, +-{0x6411, 0x74}, +-{0x6412, 0x00}, +-{0x6413, 0xff}, +-{0x6414, 0x05}, +-{0x6415, 0x54}, +-{0x6416, 0x05}, +-{0x6417, 0x44}, +-{0x6418, 0x04}, +-{0x6419, 0x30}, +-{0x641a, 0x05}, +-{0x641b, 0x46}, +-{0x641c, 0x00}, +-{0x641d, 0xff}, +-{0x641e, 0x04}, +-{0x641f, 0x31}, +-{0x6420, 0x04}, +-{0x6421, 0x30}, +-{0x6422, 0x00}, +-{0x6423, 0xff}, +-{0x6424, 0x04}, +-{0x6425, 0x20}, +-{0x6426, 0x05}, +-{0x6427, 0x06}, +-{0x6428, 0x00}, +-{0x6429, 0xff}, +-{0x642a, 0x08}, +-{0x642b, 0x2a}, +-{0x642c, 0x08}, +-{0x642d, 0x31}, +-{0x642e, 0x00}, +-{0x642f, 0xff}, +-{0x6430, 0x08}, +-{0x6431, 0x2a}, +-{0x6432, 0x08}, +-{0x6433, 0x31}, +-{0x6434, 0x06}, +-{0x6435, 0x20}, +-{0x6436, 0x07}, +-{0x6437, 0x00}, +-{0x6438, 0x08}, +-{0x6439, 0x40}, +-{0x643a, 0x00}, +-{0x643b, 0xff}, +-{0x643c, 0x08}, +-{0x643d, 0x2a}, +-{0x643e, 0x08}, +-{0x643f, 0x36}, +-{0x6440, 0x06}, +-{0x6441, 0x10}, +-{0x6442, 0x07}, +-{0x6443, 0x00}, +-{0x6444, 0x08}, +-{0x6445, 0x40}, +-{0x6446, 0x00}, +-{0x6447, 0xff}, +-{0x6448, 0x08}, +-{0x6449, 0x2a}, +-{0x644a, 0x08}, +-{0x644b, 0x3b}, +-{0x644c, 0x06}, +-{0x644d, 0x00}, +-{0x644e, 0x07}, +-{0x644f, 0x00}, +-{0x6450, 0x08}, +-{0x6451, 0x40}, +-{0x6452, 0x00}, +-{0x6453, 0xff}, +-{0x6454, 0x06}, +-{0x6455, 0x00}, +-{0x6456, 0x07}, +-{0x6457, 0x05}, +-{0x6458, 0x01}, +-{0x6459, 0xaf}, +-{0x645a, 0x01}, +-{0x645b, 0x0f}, +-{0x645c, 0x01}, +-{0x645d, 0x90}, +-{0x645e, 0x01}, +-{0x645f, 0xc8}, +-{0x6460, 0x00}, +-{0x6461, 0xff}, +-{0x6462, 0x01}, +-{0x6463, 0xac}, +-{0x6464, 0x01}, +-{0x6465, 0x0c}, +-{0x6466, 0x01}, +-{0x6467, 0x90}, +-{0x6468, 0x01}, +-{0x6469, 0xe8}, +-{0x646a, 0x00}, +-{0x646b, 0xff}, +-{0x646c, 0x01}, +-{0x646d, 0xad}, +-{0x646e, 0x01}, +-{0x646f, 0x0d}, +-{0x6470, 0x01}, +-{0x6471, 0x90}, +-{0x6472, 0x01}, +-{0x6473, 0xe8}, +-{0x6474, 0x00}, +-{0x6475, 0xff}, +-{0x6476, 0x01}, +-{0x6477, 0xae}, +-{0x6478, 0x01}, +-{0x6479, 0x0e}, +-{0x647a, 0x01}, +-{0x647b, 0x90}, +-{0x647c, 0x01}, +-{0x647d, 0xe8}, +-{0x647e, 0x00}, +-{0x647f, 0xff}, +-{0x6480, 0x01}, +-{0x6481, 0xb0}, +-{0x6482, 0x01}, +-{0x6483, 0xb1}, +-{0x6484, 0x01}, +-{0x6485, 0xb2}, +-{0x6486, 0x01}, +-{0x6487, 0xb3}, +-{0x6488, 0x01}, +-{0x6489, 0xb4}, +-{0x648a, 0x01}, +-{0x648b, 0xb5}, +-{0x648c, 0x01}, +-{0x648d, 0xb6}, +-{0x648e, 0x01}, +-{0x648f, 0xb7}, +-{0x6490, 0x01}, +-{0x6491, 0xb8}, +-{0x6492, 0x01}, +-{0x6493, 0xb9}, +-{0x6494, 0x01}, +-{0x6495, 0xba}, +-{0x6496, 0x01}, +-{0x6497, 0xbb}, +-{0x6498, 0x01}, +-{0x6499, 0xbc}, +-{0x649a, 0x01}, +-{0x649b, 0xbd}, +-{0x649c, 0x01}, +-{0x649d, 0xbe}, +-{0x649e, 0x01}, +-{0x649f, 0xbf}, +-{0x64a0, 0x01}, +-{0x64a1, 0xc0}, +-{0x64a2, 0x00}, +-{0x64a3, 0xff}, +-{0x64a4, 0x06}, +-{0x64a5, 0x00}, +-{0x64a6, 0x01}, +-{0x64a7, 0xf6}, +-{0x64a8, 0x04}, +-{0x64a9, 0x30}, +-{0x64aa, 0x00}, +-{0x64ab, 0xff}, +-{0x64ac, 0x06}, +-{0x64ad, 0x10}, +-{0x64ae, 0x01}, +-{0x64af, 0xf6}, +-{0x64b0, 0x04}, +-{0x64b1, 0x30}, +-{0x64b2, 0x06}, +-{0x64b3, 0x00}, +-{0x64b4, 0x00}, +-{0x64b5, 0xff}, +-{0x64b6, 0x06}, +-{0x64b7, 0x20}, +-{0x64b8, 0x01}, +-{0x64b9, 0xf6}, +-{0x64ba, 0x04}, +-{0x64bb, 0x30}, +-{0x64bc, 0x06}, +-{0x64bd, 0x00}, +-{0x64be, 0x00}, +-{0x64bf, 0xff}, +-{0x64c0, 0x04}, +-{0x64c1, 0x31}, +-{0x64c2, 0x04}, +-{0x64c3, 0x30}, +-{0x64c4, 0x01}, +-{0x64c5, 0x20}, +-{0x64c6, 0x01}, +-{0x64c7, 0x31}, +-{0x64c8, 0x01}, +-{0x64c9, 0x32}, +-{0x64ca, 0x01}, +-{0x64cb, 0x33}, +-{0x64cc, 0x01}, +-{0x64cd, 0x34}, +-{0x64ce, 0x01}, +-{0x64cf, 0x35}, +-{0x64d0, 0x01}, +-{0x64d1, 0x36}, +-{0x64d2, 0x01}, +-{0x64d3, 0x37}, +-{0x64d4, 0x01}, +-{0x64d5, 0x38}, +-{0x64d6, 0x01}, +-{0x64d7, 0x39}, +-{0x64d8, 0x01}, +-{0x64d9, 0x3a}, +-{0x64da, 0x01}, +-{0x64db, 0x3b}, +-{0x64dc, 0x01}, +-{0x64dd, 0x3c}, +-{0x64de, 0x01}, +-{0x64df, 0x3d}, +-{0x64e0, 0x01}, +-{0x64e1, 0x3e}, +-{0x64e2, 0x01}, +-{0x64e3, 0x3f}, +-{0x64e4, 0x02}, +-{0x64e5, 0xa0}, +-{0x64e6, 0x00}, +-{0x64e7, 0xff}, +-{0x64e8, 0x04}, +-{0x64e9, 0x31}, +-{0x64ea, 0x04}, +-{0x64eb, 0x30}, +-{0x64ec, 0x01}, +-{0x64ed, 0x00}, +-{0x64ee, 0x01}, +-{0x64ef, 0x11}, +-{0x64f0, 0x01}, +-{0x64f1, 0x12}, +-{0x64f2, 0x01}, +-{0x64f3, 0x13}, +-{0x64f4, 0x01}, +-{0x64f5, 0x14}, +-{0x64f6, 0x01}, +-{0x64f7, 0x15}, +-{0x64f8, 0x01}, +-{0x64f9, 0x16}, +-{0x64fa, 0x01}, +-{0x64fb, 0x17}, +-{0x64fc, 0x01}, +-{0x64fd, 0x18}, +-{0x64fe, 0x01}, +-{0x64ff, 0x19}, +-{0x6500, 0x01}, +-{0x6501, 0x1a}, +-{0x6502, 0x01}, +-{0x6503, 0x1b}, +-{0x6504, 0x01}, +-{0x6505, 0x1c}, +-{0x6506, 0x01}, +-{0x6507, 0x1d}, +-{0x6508, 0x01}, +-{0x6509, 0x1e}, +-{0x650a, 0x01}, +-{0x650b, 0x1f}, +-{0x650c, 0x02}, +-{0x650d, 0xa0}, +-{0x650e, 0x00}, +-{0x650f, 0xff}, +-{0x6510, 0x04}, +-{0x6511, 0x20}, +-{0x6512, 0x05}, +-{0x6513, 0x86}, +-{0x6514, 0x03}, +-{0x6515, 0x0b}, +-{0x6516, 0x05}, +-{0x6517, 0x86}, +-{0x6518, 0x00}, +-{0x6519, 0x00}, +-{0x651a, 0x05}, +-{0x651b, 0x06}, +-{0x651c, 0x00}, +-{0x651d, 0x04}, +-{0x651e, 0x05}, +-{0x651f, 0x04}, +-{0x6520, 0x00}, +-{0x6521, 0x04}, +-{0x6522, 0x05}, +-{0x6523, 0x00}, +-{0x6524, 0x05}, +-{0x6525, 0x0a}, +-{0x6526, 0x03}, +-{0x6527, 0x9a}, +-{0x6528, 0x05}, +-{0x6529, 0x86}, +-{0x652a, 0x00}, +-{0x652b, 0x00}, +-{0x652c, 0x05}, +-{0x652d, 0x06}, +-{0x652e, 0x00}, +-{0x652f, 0x01}, +-{0x6530, 0x05}, +-{0x6531, 0x04}, +-{0x6532, 0x00}, +-{0x6533, 0x04}, +-{0x6534, 0x05}, +-{0x6535, 0x00}, +-{0x6536, 0x05}, +-{0x6537, 0x0a}, +-{0x6538, 0x03}, +-{0x6539, 0x99}, +-{0x653a, 0x05}, +-{0x653b, 0x06}, +-{0x653c, 0x00}, +-{0x653d, 0x00}, +-{0x653e, 0x05}, +-{0x653f, 0x04}, +-{0x6540, 0x00}, +-{0x6541, 0x04}, +-{0x6542, 0x05}, +-{0x6543, 0x00}, +-{0x6544, 0x05}, +-{0x6545, 0x0a}, +-{0x6546, 0x03}, +-{0x6547, 0x98}, +-{0x6548, 0x05}, +-{0x6549, 0x06}, +-{0x654a, 0x00}, +-{0x654b, 0x00}, +-{0x654c, 0x05}, +-{0x654d, 0x04}, +-{0x654e, 0x00}, +-{0x654f, 0x04}, +-{0x6550, 0x05}, +-{0x6551, 0x00}, +-{0x6552, 0x05}, +-{0x6553, 0x0a}, +-{0x6554, 0x03}, +-{0x6555, 0x97}, +-{0x6556, 0x05}, +-{0x6557, 0x06}, +-{0x6558, 0x05}, +-{0x6559, 0x04}, +-{0x655a, 0x00}, +-{0x655b, 0x04}, +-{0x655c, 0x05}, +-{0x655d, 0x00}, +-{0x655e, 0x05}, +-{0x655f, 0x0a}, +-{0x6560, 0x03}, +-{0x6561, 0x96}, +-{0x6562, 0x05}, +-{0x6563, 0x06}, +-{0x6564, 0x05}, +-{0x6565, 0x04}, +-{0x6566, 0x00}, +-{0x6567, 0x04}, +-{0x6568, 0x05}, +-{0x6569, 0x00}, +-{0x656a, 0x05}, +-{0x656b, 0x0a}, +-{0x656c, 0x03}, +-{0x656d, 0x95}, +-{0x656e, 0x05}, +-{0x656f, 0x06}, +-{0x6570, 0x05}, +-{0x6571, 0x04}, +-{0x6572, 0x00}, +-{0x6573, 0x04}, +-{0x6574, 0x05}, +-{0x6575, 0x00}, +-{0x6576, 0x05}, +-{0x6577, 0x0a}, +-{0x6578, 0x03}, +-{0x6579, 0x94}, +-{0x657a, 0x05}, +-{0x657b, 0x06}, +-{0x657c, 0x00}, +-{0x657d, 0x00}, +-{0x657e, 0x05}, +-{0x657f, 0x04}, +-{0x6580, 0x00}, +-{0x6581, 0x04}, +-{0x6582, 0x05}, +-{0x6583, 0x00}, +-{0x6584, 0x05}, +-{0x6585, 0x0a}, +-{0x6586, 0x03}, +-{0x6587, 0x93}, +-{0x6588, 0x05}, +-{0x6589, 0x06}, +-{0x658a, 0x00}, +-{0x658b, 0x00}, +-{0x658c, 0x05}, +-{0x658d, 0x04}, +-{0x658e, 0x00}, +-{0x658f, 0x04}, +-{0x6590, 0x05}, +-{0x6591, 0x00}, +-{0x6592, 0x05}, +-{0x6593, 0x0a}, +-{0x6594, 0x03}, +-{0x6595, 0x92}, +-{0x6596, 0x05}, +-{0x6597, 0x06}, +-{0x6598, 0x05}, +-{0x6599, 0x04}, +-{0x659a, 0x00}, +-{0x659b, 0x04}, +-{0x659c, 0x05}, +-{0x659d, 0x00}, +-{0x659e, 0x05}, +-{0x659f, 0x0a}, +-{0x65a0, 0x03}, +-{0x65a1, 0x91}, +-{0x65a2, 0x05}, +-{0x65a3, 0x06}, +-{0x65a4, 0x05}, +-{0x65a5, 0x04}, +-{0x65a6, 0x00}, +-{0x65a7, 0x04}, +-{0x65a8, 0x05}, +-{0x65a9, 0x00}, +-{0x65aa, 0x05}, +-{0x65ab, 0x0a}, +-{0x65ac, 0x03}, +-{0x65ad, 0x90}, +-{0x65ae, 0x05}, +-{0x65af, 0x06}, +-{0x65b0, 0x05}, +-{0x65b1, 0x04}, +-{0x65b2, 0x00}, +-{0x65b3, 0x04}, +-{0x65b4, 0x05}, +-{0x65b5, 0x00}, +-{0x65b6, 0x05}, +-{0x65b7, 0x0a}, +-{0x65b8, 0x02}, +-{0x65b9, 0x90}, +-{0x65ba, 0x05}, +-{0x65bb, 0x06}, +-{0x65bc, 0x00}, +-{0x65bd, 0xff}, +-{0x65be, 0x04}, +-{0x65bf, 0x70}, +-{0x65c0, 0x08}, +-{0x65c1, 0x76}, +-{0x65c2, 0x00}, +-{0x65c3, 0xff}, +-{0x65c4, 0x08}, +-{0x65c5, 0x76}, +-{0x65c6, 0x04}, +-{0x65c7, 0x0c}, +-{0x65c8, 0x05}, +-{0x65c9, 0x07}, +-{0x65ca, 0x04}, +-{0x65cb, 0x04}, +-{0x65cc, 0x00}, +-{0x65cd, 0xff}, +-{0x65ce, 0x00}, +-{0x65cf, 0xff}, +-{0x65d0, 0x00}, +-{0x65d1, 0xff}, +-{0x30eb, 0x04}, +-{0x30ed, 0x5a}, +-{0x30ee, 0x01}, +-{0x30ef, 0x80}, +-{0x30f1, 0x5a}, +-{0x303a, 0x04}, +-{0x303b, 0x7f}, +-{0x303c, 0xfe}, +-{0x303d, 0x19}, +-{0x303e, 0xd7}, +-{0x303f, 0x09}, +-{0x3040, 0x78}, +-{0x3042, 0x05}, +-{0x328a, 0x10}, +- +-{0x3291, 0x03}, /* 7:enable flip and mirror offset may on 20150330 */ +- +-/* change settings to 1280x1080 COMB12 30 fps, 96MHz */ +-{0x3012, 0x0}, +-{0x3000, 0x3}, +-{0x3001, 0x50}, +-{0x3002, 0x0a}, +-{0x3004, 0x3}, +-{0x3005, 0x48}, +-{0x3006, 0x7}, +-{0x308f, 0x10}, +-{0x3127, 0x63}, +-{0x3074, OV10640_X_START >> 8}, +-{0x3075, OV10640_X_START & 0xff}, +-{0x3076, OV10640_Y_START >> 8}, +-{0x3077, OV10640_Y_START & 0xff}, +-{0x3078, OV10640_X_END >> 8}, +-{0x3079, OV10640_X_END & 0xff}, +-{0x307a, OV10640_Y_END >> 8}, +-{0x307b, OV10640_Y_END & 0xff}, +-{0x307c, OV10640_MAX_WIDTH >> 8}, +-{0x307d, OV10640_MAX_WIDTH & 0xff}, +-{0x307e, OV10640_MAX_HEIGHT >> 8}, +-{0x307f, OV10640_MAX_HEIGHT & 0xff}, +-{0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS +-{0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff}, +-{0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS +-{0x3083, (OV10640_SENSOR_HEIGHT + 208) & 0xff}, +-{0x3084, 0x0}, +-{0x3085, 0x0}, +-{0x3086, 0x0}, +-{0x3087, 0x0}, +-{0x346d, 0x14}, +-{0x3444, 0x28}, +-{0x3091, 0x0}, +-{0x3119, 0x44}, // COMB12 +-{0x3012, 0x1}, +-}; ++#include "ov10640_r1d.h" ++#include "ov10640_r1e.h" ++#include "ov10640_r1f.h" +diff --git a/drivers/media/i2c/soc_camera/ov10640_r1d.h b/drivers/media/i2c/soc_camera/ov10640_r1d.h +new file mode 100644 +index 0000000..374b6d1 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ov10640_r1d.h +@@ -0,0 +1,1240 @@ ++/* ++ * OmniVision ov10640 sensor camera wizard 1280x1080@30/BGGR/BT601/12bit ++ * ++ * Copyright (C) 2015-2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++/* DVP_1280x960_COMB12_raw 30fps */ ++static const struct ov10640_reg ov10640_regs_wizard_r1d[] = { ++//{0x3013, 0x01}, ++//{OV10640_DELAY, 10}, ++{0x328a, 0x01}, ++{0x313f, 0x80}, ++{0x3132, 0x24}, ++{0x3000, 0x03}, ++{0x3001, 0x38}, ++{0x3002, 0x07}, ++{0x3004, 0x03}, ++{0x3005, 0x38}, ++{0x3006, 0x07}, ++{0x3007, 0x01}, ++{0x3014, 0x03}, ++{0x3023, 0x05}, ++{0x3032, 0x34}, ++{0x3033, 0xfb}, ++{0x3054, 0x00}, ++{0x3055, 0x0f}, ++{0x3056, 0x01}, ++{0x3057, 0xff}, ++{0x3058, 0xbf}, ++{0x3059, 0x44}, ++{0x305a, 0x02}, ++{0x305b, 0x00}, ++{0x305c, 0x30}, ++{0x305d, 0x1d}, ++{0x305e, 0x16}, ++{0x305f, 0x18}, ++{0x3060, 0xf9}, ++{0x3061, 0xf0}, ++#ifdef OV10640_FSIN_ENABLE ++{0x308c, 0xb2}, ++#else ++{0x308c, 0x03}, ++#endif ++{0x308f, 0x20}, ++{0x3090, 0x00}, ++{0x3091, 0x00}, ++{0x30eb, 0x00}, ++{0x30a3, 0x08}, ++{0x30ad, 0x03}, ++{0x30ae, 0x80}, ++{0x30af, 0x80}, ++{0x30b0, 0xff}, ++{0x30b1, 0x3f}, ++{0x30b2, 0x22}, ++{0x30b9, 0x22}, ++{0x30bb, 0x00}, ++{0x30bc, 0x00}, ++{0x30bd, 0x00}, ++{0x30be, 0x00}, ++{0x30bf, 0x00}, ++{0x30c0, 0x00}, ++{0x30c1, 0x00}, ++{0x30c2, 0x00}, ++{0x30c3, 0x00}, ++{0x30c4, 0x80}, ++{0x30c5, 0x00}, ++{0x30c6, 0x80}, ++{0x30c7, 0x00}, ++{0x30c8, 0x80}, ++{0x3119, 0x45}, ++{0x311a, 0x01}, ++{0x311b, 0x4a}, ++{0x3074, 0x00}, ++{0x3075, 0x00}, ++{0x3076, 0x00}, ++{0x3077, 0x3e}, ++{0x3078, 0x05}, ++{0x3079, 0x07}, ++{0x307a, 0x04}, ++{0x307b, 0x05}, ++{0x307c, 0x05}, ++{0x307d, 0x00}, ++{0x307e, 0x03}, ++{0x307f, 0xc0}, ++{0x3080, 0x07}, ++{0x3081, 0x43}, ++{0x3082, 0x03}, ++{0x3083, 0xec}, ++{0x3084, 0x00}, ++{0x3085, 0x02}, ++{0x3086, 0x00}, ++{0x3087, 0x04}, ++{0x3088, 0x00}, ++{0x3089, 0x40}, ++{0x308d, 0x92}, ++{0x3094, 0xa5}, ++{0x30e6, 0x03}, ++{0x30e7, 0xe8}, ++{0x30e8, 0x03}, ++{0x30e9, 0xe8}, ++{0x30e9, 0x05}, ++{0x30ec, 0x01}, ++{0x30fa, 0x06}, ++{0x3120, 0x00}, ++{0x3121, 0x01}, ++{0x3122, 0x00}, ++{0x3127, 0x63}, ++{0x3128, 0xc0}, ++#ifdef OV10640_DISPLAY_PATTERN ++{0x3129, 0x80}, ++#else ++{0x3129, 0x00}, ++#endif ++{0x31be, 0x00}, ++{0x30a5, 0x78}, ++{0x30a6, 0x40}, ++{0x30a7, 0x78}, ++{0x30a8, 0x80}, ++{0x30a9, 0x78}, ++{0x30aa, 0xe0}, ++{0x30ab, 0x79}, ++{0x30ac, 0xc0}, ++{0x3440, 0x04}, ++{0x3444, 0x28}, ++{0x344e, 0x2c}, ++{0x3457, 0x33}, ++{0x345e, 0x38}, ++{0x3461, 0xa8}, ++{0x7002, 0xaa}, ++{0x7001, 0xdf}, ++{0x7048, 0x00}, ++{0x7049, 0x02}, ++{0x704a, 0x02}, ++{0x704b, 0x00}, ++{0x704c, 0x01}, ++{0x704d, 0x00}, ++{0x7043, 0x04}, ++{0x7040, 0x3c}, ++{0x7047, 0x00}, ++{0x7044, 0x01}, ++{0x7000, 0x1f}, ++{0x7084, 0x01}, ++{0x7085, 0x03}, ++{0x7086, 0x02}, ++{0x7087, 0x40}, ++{0x7088, 0x01}, ++{0x7089, 0x20}, ++{0x707f, 0x04}, ++{0x707c, 0x3c}, ++{0x7083, 0x00}, ++{0x7080, 0x01}, ++{0x7003, 0xdf}, ++{0x70c0, 0x00}, ++{0x70c1, 0x02}, ++{0x70c2, 0x02}, ++{0x70c3, 0x00}, ++{0x70c4, 0x01}, ++{0x70c5, 0x00}, ++{0x70b8, 0x03}, ++{0x70b9, 0x98}, ++{0x70bc, 0x00}, ++{0x70bd, 0x80}, ++{0x7004, 0x02}, ++{0x7005, 0x00}, ++{0x7006, 0x01}, ++{0x7007, 0x80}, ++{0x7008, 0x02}, ++{0x7009, 0x00}, ++{0x700a, 0x04}, ++{0x700b, 0x00}, ++{0x700e, 0x00}, ++{0x700f, 0x60}, ++{0x701a, 0x02}, ++{0x701b, 0x00}, ++{0x701c, 0x01}, ++{0x701d, 0x80}, ++{0x701e, 0x02}, ++{0x701f, 0x00}, ++{0x7020, 0x04}, ++{0x7021, 0x00}, ++{0x7024, 0x00}, ++{0x7025, 0x60}, ++{0x70e7, 0x00}, ++{0x70e4, 0x10}, ++{0x70e5, 0x00}, ++{0x70e6, 0x00}, ++{0x70eb, 0x00}, ++{0x70e8, 0x10}, ++{0x70e9, 0x00}, ++{0x70ea, 0x00}, ++{0x70ef, 0x00}, ++{0x70ec, 0xfd}, ++{0x70ed, 0x00}, ++{0x70ee, 0x00}, ++{0x70eb, 0x00}, ++{0x70f0, 0xfd}, ++{0x70f1, 0x00}, ++{0x70f2, 0x00}, ++{0x30fb, 0x06}, ++{0x30fc, 0x80}, ++{0x30fd, 0x02}, ++{0x30fe, 0x93}, ++{0x6000, 0xc1}, ++{0x6001, 0xb9}, ++{0x6002, 0xba}, ++{0x6003, 0xa4}, ++{0x6004, 0xb5}, ++{0x6005, 0xa0}, ++{0x6006, 0x82}, ++{0x6007, 0xa7}, ++{0x6008, 0xb7}, ++{0x6009, 0x5c}, ++{0x600a, 0x9e}, ++{0x600b, 0xc0}, ++{0x600c, 0xd2}, ++{0x600d, 0x33}, ++{0x600e, 0xcc}, ++{0x600f, 0xde}, ++{0x6010, 0xc1}, ++{0x6011, 0xab}, ++{0x6012, 0xb7}, ++{0x6013, 0x00}, ++{0x6014, 0x00}, ++{0x6015, 0x00}, ++{0x6016, 0x00}, ++{0x6017, 0x00}, ++{0x6018, 0x00}, ++{0x6019, 0x00}, ++{0x601a, 0x00}, ++{0x601b, 0x00}, ++{0x601c, 0x00}, ++{0x601d, 0xc5}, ++{0x601e, 0x54}, ++{0x601f, 0x9c}, ++{0x6020, 0x94}, ++{0x6021, 0x90}, ++{0x6022, 0x2a}, ++{0x6023, 0x61}, ++{0x6024, 0xd2}, ++{0x6025, 0xcc}, ++{0x6026, 0x02}, ++{0x6027, 0x35}, ++{0x6028, 0xb1}, ++{0x6029, 0xb2}, ++{0x602a, 0xb3}, ++{0x602b, 0xd2}, ++{0x602c, 0xd3}, ++{0x602d, 0x0a}, ++{0x602e, 0x31}, ++{0x602f, 0xcc}, ++{0x6030, 0x05}, ++{0x6031, 0xc4}, ++{0x6032, 0xd2}, ++{0x6033, 0xce}, ++{0x6034, 0x17}, ++{0x6035, 0xcf}, ++{0x6036, 0x1d}, ++{0x6037, 0xd0}, ++{0x6038, 0x23}, ++{0x6039, 0xd2}, ++{0x603a, 0xbc}, ++{0x603b, 0xcc}, ++{0x603c, 0x51}, ++{0x603d, 0xc5}, ++{0x603e, 0xd2}, ++{0x603f, 0x00}, ++{0x6040, 0x2b}, ++{0x6041, 0xcc}, ++{0x6042, 0x09}, ++{0x6043, 0xd2}, ++{0x6044, 0x1a}, ++{0x6045, 0xcc}, ++{0x6046, 0xeb}, ++{0x6047, 0x12}, ++{0x6048, 0x2a}, ++{0x6049, 0xba}, ++{0x604a, 0x56}, ++{0x604b, 0xd3}, ++{0x604c, 0x27}, ++{0x604d, 0x54}, ++{0x604e, 0xd4}, ++{0x604f, 0xc1}, ++{0x6050, 0x26}, ++{0x6051, 0xd2}, ++{0x6052, 0x01}, ++{0x6053, 0xd3}, ++{0x6054, 0x2f}, ++{0x6055, 0x27}, ++{0x6056, 0x08}, ++{0x6057, 0x1a}, ++{0x6058, 0xcc}, ++{0x6059, 0xd9}, ++{0x605a, 0x12}, ++{0x605b, 0x2c}, ++{0x605c, 0x11}, ++{0x605d, 0x60}, ++{0x605e, 0x50}, ++{0x605f, 0xc2}, ++{0x6060, 0xb9}, ++{0x6061, 0xa5}, ++{0x6062, 0xb5}, ++{0x6063, 0xa0}, ++{0x6064, 0x82}, ++{0x6065, 0x5c}, ++{0x6066, 0xd4}, ++{0x6067, 0xc1}, ++{0x6068, 0xd4}, ++{0x6069, 0xc1}, ++{0x606a, 0xd3}, ++{0x606b, 0x01}, ++{0x606c, 0x7c}, ++{0x606d, 0x74}, ++{0x606e, 0x00}, ++{0x606f, 0x2a}, ++{0x6070, 0x61}, ++{0x6071, 0xd2}, ++{0x6072, 0xcc}, ++{0x6073, 0xde}, ++{0x6074, 0xc6}, ++{0x6075, 0xd2}, ++{0x6076, 0xcc}, ++{0x6077, 0x02}, ++{0x6078, 0x35}, ++{0x6079, 0xd3}, ++{0x607a, 0x0f}, ++{0x607b, 0x31}, ++{0x607c, 0xcc}, ++{0x607d, 0x05}, ++{0x607e, 0xc5}, ++{0x607f, 0xd2}, ++{0x6080, 0xbb}, ++{0x6081, 0xcc}, ++{0x6082, 0x17}, ++{0x6083, 0xd2}, ++{0x6084, 0xbd}, ++{0x6085, 0xcc}, ++{0x6086, 0x51}, ++{0x6087, 0xc6}, ++{0x6088, 0xd2}, ++{0x6089, 0x2b}, ++{0x608a, 0xcc}, ++{0x608b, 0x09}, ++{0x608c, 0xd2}, ++{0x608d, 0x1a}, ++{0x608e, 0xcc}, ++{0x608f, 0xeb}, ++{0x6090, 0x71}, ++{0x6091, 0x12}, ++{0x6092, 0x2a}, ++{0x6093, 0xd3}, ++{0x6094, 0x24}, ++{0x6095, 0x00}, ++{0x6096, 0x00}, ++{0x6097, 0x70}, ++{0x6098, 0xca}, ++{0x6099, 0x26}, ++{0x609a, 0xd2}, ++{0x609b, 0x01}, ++{0x609c, 0xd3}, ++{0x609d, 0x2f}, ++{0x609e, 0x27}, ++{0x609f, 0x08}, ++{0x60a0, 0x1a}, ++{0x60a1, 0x12}, ++{0x60a2, 0xcc}, ++{0x60a3, 0xd9}, ++{0x60a4, 0x60}, ++{0x60a5, 0x2c}, ++{0x60a6, 0x11}, ++{0x60a7, 0x50}, ++{0x60a8, 0x00}, ++{0x60a9, 0x00}, ++{0x60aa, 0xc0}, ++{0x60ab, 0xb9}, ++{0x60ac, 0xa3}, ++{0x60ad, 0xb5}, ++{0x60ae, 0xb5}, ++{0x60af, 0x00}, ++{0x60b0, 0xa0}, ++{0x60b1, 0x82}, ++{0x60b2, 0x5c}, ++{0x60b3, 0xd4}, ++{0x60b4, 0xa6}, ++{0x60b5, 0x9d}, ++{0x60b6, 0xd3}, ++{0x60b7, 0x34}, ++{0x60b8, 0xb0}, ++{0x60b9, 0xb7}, ++{0x60ba, 0x00}, ++{0x60bb, 0xd3}, ++{0x60bc, 0x0a}, ++{0x60bd, 0xd3}, ++{0x60be, 0x10}, ++{0x60bf, 0x9c}, ++{0x60c0, 0x94}, ++{0x60c1, 0x90}, ++{0x60c2, 0xc8}, ++{0x60c3, 0xba}, ++{0x60c4, 0x7c}, ++{0x60c5, 0x74}, ++{0x60c6, 0x00}, ++{0x60c7, 0x2a}, ++{0x60c8, 0x61}, ++{0x60c9, 0x00}, ++{0x60ca, 0xd2}, ++{0x60cb, 0xcc}, ++{0x60cc, 0xde}, ++{0x60cd, 0xc4}, ++{0x60ce, 0xd2}, ++{0x60cf, 0xcc}, ++{0x60d0, 0x02}, ++{0x60d1, 0x35}, ++{0x60d2, 0xd2}, ++{0x60d3, 0xcc}, ++{0x60d4, 0x14}, ++{0x60d5, 0xd3}, ++{0x60d6, 0x09}, ++{0x60d7, 0x31}, ++{0x60d8, 0xd2}, ++{0x60d9, 0xcc}, ++{0x60da, 0x05}, ++{0x60db, 0xd2}, ++{0x60dc, 0xbb}, ++{0x60dd, 0xcc}, ++{0x60de, 0x19}, ++{0x60df, 0xd2}, ++{0x60e0, 0xbe}, ++{0x60e1, 0xce}, ++{0x60e2, 0x51}, ++{0x60e3, 0xcf}, ++{0x60e4, 0x54}, ++{0x60e5, 0xd0}, ++{0x60e6, 0x58}, ++{0x60e7, 0xd3}, ++{0x60e8, 0x01}, ++{0x60e9, 0x2b}, ++{0x60ea, 0xcc}, ++{0x60eb, 0x09}, ++{0x60ec, 0xd2}, ++{0x60ed, 0xd9}, ++{0x60ee, 0xd3}, ++{0x60ef, 0xda}, ++{0x60f0, 0xd7}, ++{0x60f1, 0x1a}, ++{0x60f2, 0xcc}, ++{0x60f3, 0xeb}, ++{0x60f4, 0x12}, ++{0x60f5, 0xd4}, ++{0x60f6, 0xaf}, ++{0x60f7, 0x27}, ++{0x60f8, 0x00}, ++{0x60f9, 0xd2}, ++{0x60fa, 0xd3}, ++{0x60fb, 0x3b}, ++{0x60fc, 0xd9}, ++{0x60fd, 0xe0}, ++{0x60fe, 0xda}, ++{0x60ff, 0xe4}, ++{0x6100, 0x1a}, ++{0x6101, 0x12}, ++{0x6102, 0xcc}, ++{0x6103, 0xd9}, ++{0x6104, 0x60}, ++{0x6105, 0x10}, ++{0x6106, 0x2c}, ++{0x6107, 0x5d}, ++{0x6108, 0xd3}, ++{0x6109, 0x0a}, ++{0x610a, 0x5c}, ++{0x610b, 0x01}, ++{0x610c, 0x50}, ++{0x610d, 0x11}, ++{0x610e, 0xd6}, ++{0x610f, 0xb7}, ++{0x6110, 0xb9}, ++{0x6111, 0xba}, ++{0x6112, 0xaf}, ++{0x6113, 0xdc}, ++{0x6114, 0xcb}, ++{0x6115, 0xc3}, ++{0x6116, 0xb9}, ++{0x6117, 0xa4}, ++{0x6118, 0xb5}, ++{0x6119, 0x5c}, ++{0x611a, 0x12}, ++{0x611b, 0x2a}, ++{0x611c, 0x61}, ++{0x611d, 0xd2}, ++{0x611e, 0xcc}, ++{0x611f, 0xe2}, ++{0x6120, 0x35}, ++{0x6121, 0xc7}, ++{0x6122, 0xd2}, ++{0x6123, 0x31}, ++{0x6124, 0xcc}, ++{0x6125, 0x05}, ++{0x6126, 0xc6}, ++{0x6127, 0xbb}, ++{0x6128, 0xd2}, ++{0x6129, 0xcc}, ++{0x612a, 0x17}, ++{0x612b, 0xd2}, ++{0x612c, 0xbe}, ++{0x612d, 0xcc}, ++{0x612e, 0x51}, ++{0x612f, 0xc7}, ++{0x6130, 0xd2}, ++{0x6131, 0xcc}, ++{0x6132, 0x09}, ++{0x6133, 0xb4}, ++{0x6134, 0xb7}, ++{0x6135, 0x94}, ++{0x6136, 0xd2}, ++{0x6137, 0x12}, ++{0x6138, 0x26}, ++{0x6139, 0x42}, ++{0x613a, 0x46}, ++{0x613b, 0x42}, ++{0x613c, 0xd3}, ++{0x613d, 0x20}, ++{0x613e, 0x27}, ++{0x613f, 0x00}, ++{0x6140, 0x1a}, ++{0x6141, 0xcc}, ++{0x6142, 0xd9}, ++{0x6143, 0x60}, ++{0x6144, 0x2c}, ++{0x6145, 0x11}, ++{0x6146, 0x40}, ++{0x6147, 0x50}, ++{0x6148, 0xb8}, ++{0x6149, 0x90}, ++{0x614a, 0xd5}, ++{0x614b, 0x00}, ++{0x614c, 0xba}, ++{0x614d, 0x00}, ++{0x614e, 0x00}, ++{0x614f, 0x00}, ++{0x6150, 0x00}, ++{0x6151, 0x00}, ++{0x6152, 0x00}, ++{0x6153, 0xaa}, ++{0x6154, 0xb7}, ++{0x6155, 0x00}, ++{0x6156, 0x00}, ++{0x6157, 0x00}, ++{0x6158, 0x00}, ++{0x6159, 0xa6}, ++{0x615a, 0xb7}, ++{0x615b, 0x00}, ++{0x615c, 0xd5}, ++{0x615d, 0x00}, ++{0x615e, 0x71}, ++{0x615f, 0xd3}, ++{0x6160, 0x3e}, ++{0x6161, 0xba}, ++{0x6162, 0x00}, ++{0x6163, 0x00}, ++{0x6164, 0x00}, ++{0x6165, 0x00}, ++{0x6166, 0xd3}, ++{0x6167, 0x10}, ++{0x6168, 0x70}, ++{0x6169, 0x00}, ++{0x616a, 0x00}, ++{0x616b, 0x00}, ++{0x616c, 0x00}, ++{0x616d, 0xd5}, ++{0x616e, 0xba}, ++{0x616f, 0xb0}, ++{0x6170, 0xb7}, ++{0x6171, 0x00}, ++{0x6172, 0x9d}, ++{0x6173, 0xd3}, ++{0x6174, 0x0a}, ++{0x6175, 0x9d}, ++{0x6176, 0x9d}, ++{0x6177, 0xd3}, ++{0x6178, 0x10}, ++{0x6179, 0x9c}, ++{0x617a, 0x94}, ++{0x617b, 0x90}, ++{0x617c, 0xc8}, ++{0x617d, 0xba}, ++{0x617e, 0xd2}, ++{0x617f, 0x30}, ++{0x6180, 0xd5}, ++{0x6181, 0x00}, ++{0x6182, 0xba}, ++{0x6183, 0xb0}, ++{0x6184, 0xb7}, ++{0x6185, 0x00}, ++{0x6186, 0x9d}, ++{0x6187, 0xd3}, ++{0x6188, 0x0a}, ++{0x6189, 0x9d}, ++{0x618a, 0x9d}, ++{0x618b, 0xd3}, ++{0x618c, 0x10}, ++{0x618d, 0x9c}, ++{0x618e, 0x94}, ++{0x618f, 0x90}, ++{0x6190, 0xc8}, ++{0x6191, 0xba}, ++{0x6192, 0xd5}, ++{0x6193, 0x00}, ++{0x6194, 0xba}, ++{0x6195, 0xb0}, ++{0x6196, 0xb7}, ++{0x6197, 0x00}, ++{0x6198, 0x9d}, ++{0x6199, 0xd3}, ++{0x619a, 0x0a}, ++{0x619b, 0x9d}, ++{0x619c, 0x9d}, ++{0x619d, 0xd3}, ++{0x619e, 0x10}, ++{0x619f, 0x9c}, ++{0x61a0, 0x94}, ++{0x61a1, 0x90}, ++{0x61a2, 0xc9}, ++{0x61a3, 0xba}, ++{0x61a4, 0xd5}, ++{0x61a5, 0x00}, ++{0x61a6, 0x00}, ++{0x61a7, 0x1a}, ++{0x61a8, 0x12}, ++{0x61a9, 0xcc}, ++{0x61aa, 0xeb}, ++{0x61ab, 0xd2}, ++{0x61ac, 0xd5}, ++{0x61ad, 0x00}, ++{0x61ae, 0x00}, ++{0x61af, 0x1a}, ++{0x61b0, 0x12}, ++{0x61b1, 0xcc}, ++{0x61b2, 0xeb}, ++{0x61b3, 0xd2}, ++{0x61b4, 0x1a}, ++{0x61b5, 0x12}, ++{0x61b6, 0xcc}, ++{0x61b7, 0xeb}, ++{0x61b8, 0xd2}, ++{0x61b9, 0x1a}, ++{0x61ba, 0x12}, ++{0x61bb, 0xcc}, ++{0x61bc, 0xeb}, ++{0x61bd, 0xd2}, ++{0x61be, 0xd5}, ++{0x61bf, 0x00}, ++{0x61c0, 0x00}, ++{0x61c1, 0x1a}, ++{0x61c2, 0xcc}, ++{0x61c3, 0xf0}, ++{0x61c4, 0x12}, ++{0x61c5, 0xd2}, ++{0x61c6, 0xd5}, ++{0x61c7, 0x00}, ++{0x61c8, 0x00}, ++{0x61c9, 0x1a}, ++{0x61ca, 0xcc}, ++{0x61cb, 0xf0}, ++{0x61cc, 0x12}, ++{0x61cd, 0xd2}, ++{0x61ce, 0x1a}, ++{0x61cf, 0xcc}, ++{0x61d0, 0xf0}, ++{0x61d1, 0x12}, ++{0x61d2, 0xd2}, ++{0x61d3, 0x1a}, ++{0x61d4, 0xcc}, ++{0x61d5, 0xf0}, ++{0x61d6, 0x12}, ++{0x61d7, 0xd2}, ++{0x61d8, 0xd5}, ++{0x6400, 0x00}, ++{0x6401, 0x08}, ++{0x6402, 0x00}, ++{0x6403, 0xff}, ++{0x6404, 0x04}, ++{0x6405, 0x61}, ++{0x6406, 0x04}, ++{0x6407, 0x70}, ++{0x6408, 0x00}, ++{0x6409, 0xff}, ++{0x640a, 0x05}, ++{0x640b, 0x14}, ++{0x640c, 0x04}, ++{0x640d, 0x70}, ++{0x640e, 0x05}, ++{0x640f, 0x74}, ++{0x6410, 0x00}, ++{0x6411, 0xff}, ++{0x6412, 0x05}, ++{0x6413, 0x54}, ++{0x6414, 0x04}, ++{0x6415, 0x30}, ++{0x6416, 0x05}, ++{0x6417, 0x44}, ++{0x6418, 0x05}, ++{0x6419, 0x47}, ++{0x641a, 0x00}, ++{0x641b, 0xff}, ++{0x641c, 0x04}, ++{0x641d, 0x31}, ++{0x641e, 0x04}, ++{0x641f, 0x30}, ++{0x6420, 0x00}, ++{0x6421, 0xff}, ++{0x6422, 0x04}, ++{0x6423, 0x20}, ++{0x6424, 0x05}, ++{0x6425, 0x06}, ++{0x6426, 0x00}, ++{0x6427, 0xff}, ++{0x6428, 0x08}, ++{0x6429, 0x29}, ++{0x642a, 0x08}, ++{0x642b, 0x30}, ++{0x642c, 0x00}, ++{0x642d, 0xff}, ++{0x642e, 0x08}, ++{0x642f, 0x29}, ++{0x6430, 0x08}, ++{0x6431, 0x30}, ++{0x6432, 0x06}, ++{0x6433, 0x20}, ++{0x6434, 0x07}, ++{0x6435, 0x00}, ++{0x6436, 0x08}, ++{0x6437, 0x3f}, ++{0x6438, 0x00}, ++{0x6439, 0xff}, ++{0x643a, 0x08}, ++{0x643b, 0x29}, ++{0x643c, 0x08}, ++{0x643d, 0x35}, ++{0x643e, 0x06}, ++{0x643f, 0x10}, ++{0x6440, 0x07}, ++{0x6441, 0x00}, ++{0x6442, 0x08}, ++{0x6443, 0x3f}, ++{0x6444, 0x00}, ++{0x6445, 0xff}, ++{0x6446, 0x08}, ++{0x6447, 0x29}, ++{0x6448, 0x08}, ++{0x6449, 0x3a}, ++{0x644a, 0x06}, ++{0x644b, 0x00}, ++{0x644c, 0x07}, ++{0x644d, 0x00}, ++{0x644e, 0x08}, ++{0x644f, 0x3f}, ++{0x6450, 0x00}, ++{0x6451, 0xff}, ++{0x6452, 0x06}, ++{0x6453, 0x00}, ++{0x6454, 0x07}, ++{0x6455, 0x05}, ++{0x6456, 0x01}, ++{0x6457, 0xaf}, ++{0x6458, 0x01}, ++{0x6459, 0x0f}, ++{0x645a, 0x01}, ++{0x645b, 0x90}, ++{0x645c, 0x01}, ++{0x645d, 0xc8}, ++{0x645e, 0x00}, ++{0x645f, 0xff}, ++{0x6460, 0x01}, ++{0x6461, 0xac}, ++{0x6462, 0x01}, ++{0x6463, 0x0c}, ++{0x6464, 0x01}, ++{0x6465, 0x90}, ++{0x6466, 0x01}, ++{0x6467, 0xe8}, ++{0x6468, 0x00}, ++{0x6469, 0xff}, ++{0x646a, 0x01}, ++{0x646b, 0xad}, ++{0x646c, 0x01}, ++{0x646d, 0x0d}, ++{0x646e, 0x01}, ++{0x646f, 0x90}, ++{0x6470, 0x01}, ++{0x6471, 0xe8}, ++{0x6472, 0x00}, ++{0x6473, 0xff}, ++{0x6474, 0x01}, ++{0x6475, 0xae}, ++{0x6476, 0x01}, ++{0x6477, 0x0e}, ++{0x6478, 0x01}, ++{0x6479, 0x90}, ++{0x647a, 0x01}, ++{0x647b, 0xe8}, ++{0x647c, 0x00}, ++{0x647d, 0xff}, ++{0x647e, 0x01}, ++{0x647f, 0xb0}, ++{0x6480, 0x01}, ++{0x6481, 0xb1}, ++{0x6482, 0x01}, ++{0x6483, 0xb2}, ++{0x6484, 0x01}, ++{0x6485, 0xb3}, ++{0x6486, 0x01}, ++{0x6487, 0xb4}, ++{0x6488, 0x01}, ++{0x6489, 0xb5}, ++{0x648a, 0x01}, ++{0x648b, 0xb6}, ++{0x648c, 0x01}, ++{0x648d, 0xb7}, ++{0x648e, 0x01}, ++{0x648f, 0xb8}, ++{0x6490, 0x01}, ++{0x6491, 0xb9}, ++{0x6492, 0x01}, ++{0x6493, 0xba}, ++{0x6494, 0x01}, ++{0x6495, 0xbb}, ++{0x6496, 0x01}, ++{0x6497, 0xbc}, ++{0x6498, 0x01}, ++{0x6499, 0xbd}, ++{0x649a, 0x01}, ++{0x649b, 0xbe}, ++{0x649c, 0x01}, ++{0x649d, 0xbf}, ++{0x649e, 0x01}, ++{0x649f, 0xc0}, ++{0x64a0, 0x00}, ++{0x64a1, 0xff}, ++{0x64a2, 0x06}, ++{0x64a3, 0x00}, ++{0x64a4, 0x01}, ++{0x64a5, 0xf6}, ++{0x64a6, 0x00}, ++{0x64a7, 0xff}, ++{0x64a8, 0x06}, ++{0x64a9, 0x10}, ++{0x64aa, 0x01}, ++{0x64ab, 0xf6}, ++{0x64ac, 0x06}, ++{0x64ad, 0x00}, ++{0x64ae, 0x00}, ++{0x64af, 0xff}, ++{0x64b0, 0x06}, ++{0x64b1, 0x20}, ++{0x64b2, 0x01}, ++{0x64b3, 0xf6}, ++{0x64b4, 0x06}, ++{0x64b5, 0x00}, ++{0x64b6, 0x00}, ++{0x64b7, 0xff}, ++{0x64b8, 0x04}, ++{0x64b9, 0x31}, ++{0x64ba, 0x04}, ++{0x64bb, 0x30}, ++{0x64bc, 0x01}, ++{0x64bd, 0x20}, ++{0x64be, 0x01}, ++{0x64bf, 0x31}, ++{0x64c0, 0x01}, ++{0x64c1, 0x32}, ++{0x64c2, 0x01}, ++{0x64c3, 0x33}, ++{0x64c4, 0x01}, ++{0x64c5, 0x34}, ++{0x64c6, 0x01}, ++{0x64c7, 0x35}, ++{0x64c8, 0x01}, ++{0x64c9, 0x36}, ++{0x64ca, 0x01}, ++{0x64cb, 0x37}, ++{0x64cc, 0x01}, ++{0x64cd, 0x38}, ++{0x64ce, 0x01}, ++{0x64cf, 0x39}, ++{0x64d0, 0x01}, ++{0x64d1, 0x3a}, ++{0x64d2, 0x01}, ++{0x64d3, 0x3b}, ++{0x64d4, 0x01}, ++{0x64d5, 0x3c}, ++{0x64d6, 0x01}, ++{0x64d7, 0x3d}, ++{0x64d8, 0x01}, ++{0x64d9, 0x3e}, ++{0x64da, 0x01}, ++{0x64db, 0x3f}, ++{0x64dc, 0x02}, ++{0x64dd, 0xa0}, ++{0x64de, 0x00}, ++{0x64df, 0xff}, ++{0x64e0, 0x04}, ++{0x64e1, 0x31}, ++{0x64e2, 0x04}, ++{0x64e3, 0x30}, ++{0x64e4, 0x01}, ++{0x64e5, 0x00}, ++{0x64e6, 0x01}, ++{0x64e7, 0x11}, ++{0x64e8, 0x01}, ++{0x64e9, 0x12}, ++{0x64ea, 0x01}, ++{0x64eb, 0x13}, ++{0x64ec, 0x01}, ++{0x64ed, 0x14}, ++{0x64ee, 0x01}, ++{0x64ef, 0x15}, ++{0x64f0, 0x01}, ++{0x64f1, 0x16}, ++{0x64f2, 0x01}, ++{0x64f3, 0x17}, ++{0x64f4, 0x01}, ++{0x64f5, 0x18}, ++{0x64f6, 0x01}, ++{0x64f7, 0x19}, ++{0x64f8, 0x01}, ++{0x64f9, 0x1a}, ++{0x64fa, 0x01}, ++{0x64fb, 0x1b}, ++{0x64fc, 0x01}, ++{0x64fd, 0x1c}, ++{0x64fe, 0x01}, ++{0x64ff, 0x1d}, ++{0x6500, 0x01}, ++{0x6501, 0x1e}, ++{0x6502, 0x01}, ++{0x6503, 0x1f}, ++{0x6504, 0x02}, ++{0x6505, 0xa0}, ++{0x6506, 0x00}, ++{0x6507, 0xff}, ++{0x6508, 0x03}, ++{0x6509, 0x0b}, ++{0x650a, 0x05}, ++{0x650b, 0x86}, ++{0x650c, 0x00}, ++{0x650d, 0x00}, ++{0x650e, 0x05}, ++{0x650f, 0x06}, ++{0x6510, 0x00}, ++{0x6511, 0x04}, ++{0x6512, 0x05}, ++{0x6513, 0x04}, ++{0x6514, 0x00}, ++{0x6515, 0x04}, ++{0x6516, 0x05}, ++{0x6517, 0x00}, ++{0x6518, 0x05}, ++{0x6519, 0x08}, ++{0x651a, 0x03}, ++{0x651b, 0x9a}, ++{0x651c, 0x05}, ++{0x651d, 0x86}, ++{0x651e, 0x00}, ++{0x651f, 0x00}, ++{0x6520, 0x05}, ++{0x6521, 0x06}, ++{0x6522, 0x00}, ++{0x6523, 0x01}, ++{0x6524, 0x05}, ++{0x6525, 0x04}, ++{0x6526, 0x00}, ++{0x6527, 0x04}, ++{0x6528, 0x05}, ++{0x6529, 0x00}, ++{0x652a, 0x05}, ++{0x652b, 0x08}, ++{0x652c, 0x03}, ++{0x652d, 0x99}, ++{0x652e, 0x05}, ++{0x652f, 0x06}, ++{0x6530, 0x00}, ++{0x6531, 0x00}, ++{0x6532, 0x05}, ++{0x6533, 0x04}, ++{0x6534, 0x00}, ++{0x6535, 0x04}, ++{0x6536, 0x05}, ++{0x6537, 0x00}, ++{0x6538, 0x05}, ++{0x6539, 0x08}, ++{0x653a, 0x03}, ++{0x653b, 0x98}, ++{0x653c, 0x05}, ++{0x653d, 0x06}, ++{0x653e, 0x00}, ++{0x653f, 0x00}, ++{0x6540, 0x05}, ++{0x6541, 0x04}, ++{0x6542, 0x00}, ++{0x6543, 0x04}, ++{0x6544, 0x05}, ++{0x6545, 0x00}, ++{0x6546, 0x05}, ++{0x6547, 0x08}, ++{0x6548, 0x03}, ++{0x6549, 0x97}, ++{0x654a, 0x05}, ++{0x654b, 0x06}, ++{0x654c, 0x05}, ++{0x654d, 0x04}, ++{0x654e, 0x00}, ++{0x654f, 0x04}, ++{0x6550, 0x05}, ++{0x6551, 0x00}, ++{0x6552, 0x05}, ++{0x6553, 0x08}, ++{0x6554, 0x03}, ++{0x6555, 0x96}, ++{0x6556, 0x05}, ++{0x6557, 0x06}, ++{0x6558, 0x05}, ++{0x6559, 0x04}, ++{0x655a, 0x00}, ++{0x655b, 0x04}, ++{0x655c, 0x05}, ++{0x655d, 0x00}, ++{0x655e, 0x05}, ++{0x655f, 0x08}, ++{0x6560, 0x03}, ++{0x6561, 0x95}, ++{0x6562, 0x05}, ++{0x6563, 0x06}, ++{0x6564, 0x05}, ++{0x6565, 0x04}, ++{0x6566, 0x00}, ++{0x6567, 0x04}, ++{0x6568, 0x05}, ++{0x6569, 0x00}, ++{0x656a, 0x05}, ++{0x656b, 0x08}, ++{0x656c, 0x03}, ++{0x656d, 0x94}, ++{0x656e, 0x05}, ++{0x656f, 0x06}, ++{0x6570, 0x00}, ++{0x6571, 0x00}, ++{0x6572, 0x05}, ++{0x6573, 0x04}, ++{0x6574, 0x00}, ++{0x6575, 0x04}, ++{0x6576, 0x05}, ++{0x6577, 0x00}, ++{0x6578, 0x05}, ++{0x6579, 0x08}, ++{0x657a, 0x03}, ++{0x657b, 0x93}, ++{0x657c, 0x05}, ++{0x657d, 0x06}, ++{0x657e, 0x00}, ++{0x657f, 0x00}, ++{0x6580, 0x05}, ++{0x6581, 0x04}, ++{0x6582, 0x00}, ++{0x6583, 0x04}, ++{0x6584, 0x05}, ++{0x6585, 0x00}, ++{0x6586, 0x05}, ++{0x6587, 0x08}, ++{0x6588, 0x03}, ++{0x6589, 0x92}, ++{0x658a, 0x05}, ++{0x658b, 0x06}, ++{0x658c, 0x05}, ++{0x658d, 0x04}, ++{0x658e, 0x00}, ++{0x658f, 0x04}, ++{0x6590, 0x05}, ++{0x6591, 0x00}, ++{0x6592, 0x05}, ++{0x6593, 0x08}, ++{0x6594, 0x03}, ++{0x6595, 0x91}, ++{0x6596, 0x05}, ++{0x6597, 0x06}, ++{0x6598, 0x05}, ++{0x6599, 0x04}, ++{0x659a, 0x00}, ++{0x659b, 0x04}, ++{0x659c, 0x05}, ++{0x659d, 0x00}, ++{0x659e, 0x05}, ++{0x659f, 0x08}, ++{0x65a0, 0x03}, ++{0x65a1, 0x90}, ++{0x65a2, 0x05}, ++{0x65a3, 0x06}, ++{0x65a4, 0x05}, ++{0x65a5, 0x04}, ++{0x65a6, 0x00}, ++{0x65a7, 0x04}, ++{0x65a8, 0x05}, ++{0x65a9, 0x00}, ++{0x65aa, 0x05}, ++{0x65ab, 0x08}, ++{0x65ac, 0x02}, ++{0x65ad, 0x90}, ++{0x65ae, 0x05}, ++{0x65af, 0x06}, ++{0x65b0, 0x00}, ++{0x65b1, 0xff}, ++{0x65b2, 0x04}, ++{0x65b3, 0x20}, ++{0x65b4, 0x05}, ++{0x65b5, 0x06}, ++{0x65b6, 0x08}, ++{0x65b7, 0x84}, ++{0x65b8, 0x04}, ++{0x65b9, 0x04}, ++{0x65ba, 0x00}, ++{0x65bb, 0xff}, ++{0x65bc, 0x08}, ++{0x65bd, 0x72}, ++{0x65be, 0x04}, ++{0x65bf, 0x0c}, ++{0x65c0, 0x04}, ++{0x65c1, 0x04}, ++{0x65c2, 0x00}, ++{0x65c3, 0xff}, ++{0x65c4, 0x04}, ++{0x65c5, 0x45}, ++{0x65c6, 0x04}, ++{0x65c7, 0x54}, ++{0x65c8, 0x08}, ++{0x65c9, 0x72}, ++{0x65ca, 0x00}, ++{0x65cb, 0xff}, ++{0x65cc, 0x04}, ++{0x65cd, 0x20}, ++{0x65ce, 0x05}, ++{0x65cf, 0x06}, ++{0x65d0, 0x08}, ++{0x65d1, 0x96}, ++{0x65d2, 0x08}, ++{0x65d3, 0x5e}, ++{0x65d4, 0x00}, ++{0x65d5, 0xff}, ++{0x65d6, 0x04}, ++{0x65d7, 0x20}, ++{0x65d8, 0x05}, ++{0x65d9, 0x06}, ++{0x65da, 0x08}, ++{0x65db, 0x96}, ++{0x65dc, 0x08}, ++{0x65dd, 0x5c}, ++{0x65de, 0x00}, ++{0x65df, 0xff}, ++{0x65e0, 0x04}, ++{0x65e1, 0x20}, ++{0x65e2, 0x05}, ++{0x65e3, 0x06}, ++{0x65e4, 0x08}, ++{0x65e5, 0x84}, ++{0x65e6, 0x08}, ++{0x65e7, 0x70}, ++{0x65e8, 0x00}, ++{0x65e9, 0xff}, ++{0x65ea, 0x00}, ++{0x65eb, 0xff}, ++{0x65ec, 0x00}, ++{0x65ed, 0xff}, ++{0x30eb, 0x04}, ++{0x30ed, 0x5a}, ++{0x30ee, 0x01}, ++{0x30ef, 0x80}, ++{0x30f1, 0x5a}, ++{0x303a, 0x04}, ++{0x303b, 0x7f}, ++{0x303c, 0xfe}, ++{0x303d, 0x19}, ++{0x303e, 0xd7}, ++{0x303f, 0x09}, ++{0x3040, 0x78}, ++{0x3042, 0x05}, ++{0x328a, 0x00}, ++{0x31bf, 0x9f}, ++{0x31c0, 0xff}, ++#if 0 ++{0x3012, 0x01}, ++{0x3012, 0x00}, ++{0x3119, 0x44}, ++//;{0x3132, 0x24}, ++//;{0x3128, 0xc0}, ++//;{0x328a, 0x02}, ++{0x3012, 0x01}, ++#else ++/* HFLIP=1, VFLIP=0 */ ++{0x3128, 0xc0 | 0x1}, ++{0x3291, 0x01 | 0x2}, ++{0x3090, 0x4}, ++/* change settings to 1280x1080 COMB12 30 fps, 96MHz */ ++{0x3012, 0x0}, ++{0x3000, 0x3}, ++{0x3001, 0x50}, ++{0x3002, 0x0a}, ++{0x3004, 0x3}, ++{0x3005, 0x48}, ++{0x3006, 0x7}, ++{0x308f, 0x10}, ++{0x3127, 0x63}, ++{0x3074, OV10640_X_START >> 8}, ++{0x3075, OV10640_X_START & 0xff}, ++{0x3076, OV10640_Y_START >> 8}, ++{0x3077, OV10640_Y_START & 0xff}, ++{0x3078, OV10640_X_END >> 8}, ++{0x3079, OV10640_X_END & 0xff}, ++{0x307a, OV10640_Y_END >> 8}, ++{0x307b, OV10640_Y_END & 0xff}, ++{0x307c, OV10640_MAX_WIDTH >> 8}, ++{0x307d, OV10640_MAX_WIDTH & 0xff}, ++{0x307e, OV10640_MAX_HEIGHT >> 8}, ++{0x307f, OV10640_MAX_HEIGHT & 0xff}, ++{0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS ++{0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff}, ++{0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS ++{0x3083, (OV10640_SENSOR_HEIGHT + 208) & 0xff}, ++{0x3084, 0x0}, ++{0x3085, 0x0}, ++{0x3086, 0x0}, ++{0x3087, 0x0}, ++{0x346d, 0x14}, ++{0x3444, 0x28}, ++{0x3091, 0x0}, ++{0x3119, 0x44}, // COMB12 ++{0x3012, 0x1}, ++#endif ++}; +diff --git a/drivers/media/i2c/soc_camera/ov10640_r1e.h b/drivers/media/i2c/soc_camera/ov10640_r1e.h +new file mode 100644 +index 0000000..eeff330 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ov10640_r1e.h +@@ -0,0 +1,1235 @@ ++/* ++ * OmniVision ov10640 sensor camera wizard 1280x1080@30/BGGR/BT601/12bit ++ * ++ * Copyright (C) 2015-2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++/* DVP_1280x1080_COMB12_raw 60fps */ ++static const struct ov10640_reg ov10640_regs_wizard_r1e[] = { ++//{0x3013, 0x01}, ++//{OV10640_DELAY, 10}, ++{0x328a, 0x11}, ++{0x313f, 0x80}, ++{0x3132, 0x24}, ++{0x3000, 0x03}, ++{0x3001, 0x62}, ++{0x3002, 0x07}, ++{0x3004, 0x03}, ++{0x3005, 0x62}, ++{0x3006, 0x07}, ++{0x3007, 0x01}, ++{0x3014, 0x03}, ++{0x3023, 0x05}, ++{0x3032, 0x35}, ++{0x3033, 0x04}, ++{0x3054, 0x00}, ++{0x3055, 0x08}, ++{0x3056, 0x01}, ++{0x3057, 0xff}, ++{0x3058, 0xaf}, ++{0x3059, 0x44}, ++{0x305a, 0x02}, ++{0x305b, 0x00}, ++{0x305c, 0x30}, ++{0x305d, 0x9e}, ++{0x305e, 0x19}, ++{0x305f, 0x18}, ++{0x3060, 0xf9}, ++{0x3061, 0xf0}, ++#ifdef OV10640_FSIN_ENABLE ++{0x308c, 0xb2}, ++#else ++{0x308c, 0x03}, ++#endif ++{0x308f, 0x10}, ++{0x3090, 0x00}, ++{0x3091, 0x00}, ++{0x30eb, 0x00}, ++{0x30a3, 0x08}, ++{0x30ad, 0x03}, ++{0x30ae, 0x80}, ++{0x30af, 0x80}, ++{0x30b0, 0xff}, ++{0x30b1, 0x3f}, ++{0x30b2, 0x22}, ++{0x30b9, 0x22}, ++{0x30bb, 0x00}, ++{0x30bc, 0x00}, ++{0x30bd, 0x00}, ++{0x30be, 0x00}, ++{0x30bf, 0x00}, ++{0x30c0, 0x00}, ++{0x30c1, 0x00}, ++{0x30c2, 0x00}, ++{0x30c3, 0x00}, ++{0x30c4, 0x80}, ++{0x30c5, 0x00}, ++{0x30c6, 0x80}, ++{0x30c7, 0x00}, ++{0x30c8, 0x80}, ++{0x3119, 0x45}, ++{0x311a, 0x01}, ++{0x311b, 0x4a}, ++{0x3074, 0x00}, ++{0x3075, 0x00}, ++{0x3076, 0x00}, ++{0x3077, 0x02}, ++{0x3078, 0x05}, ++{0x3079, 0x07}, ++{0x307a, 0x04}, ++{0x307b, 0x41}, ++{0x307c, 0x05}, ++{0x307d, 0x00}, ++{0x307e, 0x04}, ++{0x307f, 0x38}, ++{0x3080, 0x05}, ++{0x3081, 0xbe}, ++{0x3082, 0x04}, ++{0x3083, 0x57}, ++{0x3084, 0x00}, ++{0x3085, 0x04}, ++{0x3086, 0x00}, ++{0x3087, 0x04}, ++{0x3088, 0x00}, ++{0x3089, 0x40}, ++{0x308d, 0x92}, ++{0x3094, 0xa5}, ++{0x30e6, 0x04}, ++{0x30e7, 0x48}, ++{0x30e8, 0x04}, ++{0x30e9, 0x48}, ++{0x30e9, 0x05}, ++{0x30ec, 0x01}, ++{0x30fa, 0x06}, ++{0x3120, 0x00}, ++{0x3121, 0x01}, ++{0x3122, 0x00}, ++{0x3127, 0x63}, ++{0x3128, 0xc0}, ++#ifdef OV10640_DISPLAY_PATTERN ++{0x3129, 0x80}, ++#else ++{0x3129, 0x00}, ++#endif ++{0x31be, 0x00}, ++{0x30a5, 0x78}, ++{0x30a6, 0x40}, ++{0x30a7, 0x78}, ++{0x30a8, 0x80}, ++{0x30a9, 0x78}, ++{0x30aa, 0xe0}, ++{0x30ab, 0xf9}, ++{0x30ac, 0xc0}, ++{0x3440, 0x04}, ++{0x3444, 0x28}, ++{0x344e, 0x2c}, ++{0x3457, 0x33}, ++{0x345e, 0x38}, ++{0x3461, 0xa8}, ++{0x7002, 0xaa}, ++{0x7001, 0xdf}, ++{0x7048, 0x00}, ++{0x7049, 0x02}, ++{0x704a, 0x02}, ++{0x704b, 0x00}, ++{0x704c, 0x01}, ++{0x704d, 0x00}, ++{0x7043, 0x04}, ++{0x7040, 0x3c}, ++{0x7047, 0x00}, ++{0x7044, 0x01}, ++{0x7000, 0x1f}, ++{0x7084, 0x01}, ++{0x7085, 0x03}, ++{0x7086, 0x02}, ++{0x7087, 0x40}, ++{0x7088, 0x01}, ++{0x7089, 0x20}, ++{0x707f, 0x04}, ++{0x707c, 0x3c}, ++{0x7083, 0x00}, ++{0x7080, 0x01}, ++{0x7003, 0xdf}, ++{0x70c0, 0x00}, ++{0x70c1, 0x02}, ++{0x70c2, 0x02}, ++{0x70c3, 0x00}, ++{0x70c4, 0x01}, ++{0x70c5, 0x00}, ++{0x70b8, 0x03}, ++{0x70b9, 0x98}, ++{0x70bc, 0x00}, ++{0x70bd, 0x80}, ++{0x7004, 0x02}, ++{0x7005, 0x00}, ++{0x7006, 0x01}, ++{0x7007, 0x80}, ++{0x7008, 0x02}, ++{0x7009, 0x00}, ++{0x700a, 0x04}, ++{0x700b, 0x00}, ++{0x700e, 0x00}, ++{0x700f, 0x60}, ++{0x701a, 0x02}, ++{0x701b, 0x00}, ++{0x701c, 0x01}, ++{0x701d, 0x80}, ++{0x701e, 0x02}, ++{0x701f, 0x00}, ++{0x7020, 0x04}, ++{0x7021, 0x00}, ++{0x7024, 0x00}, ++{0x7025, 0x60}, ++{0x70e7, 0x00}, ++{0x70e4, 0x10}, ++{0x70e5, 0x00}, ++{0x70e6, 0x00}, ++{0x70eb, 0x00}, ++{0x70e8, 0x10}, ++{0x70e9, 0x00}, ++{0x70ea, 0x00}, ++{0x70ef, 0x00}, ++{0x70ec, 0xfd}, ++{0x70ed, 0x00}, ++{0x70ee, 0x00}, ++{0x70eb, 0x00}, ++{0x70f0, 0xfd}, ++{0x70f1, 0x00}, ++{0x70f2, 0x00}, ++{0x30fb, 0x06}, ++{0x30fc, 0x80}, ++{0x30fd, 0x02}, ++{0x30fe, 0x93}, ++{0x6000, 0xc1}, ++{0x6001, 0xb9}, ++{0x6002, 0xba}, ++{0x6003, 0xa4}, ++{0x6004, 0xb5}, ++{0x6005, 0xa0}, ++{0x6006, 0x82}, ++{0x6007, 0xa7}, ++{0x6008, 0xb7}, ++{0x6009, 0x5c}, ++{0x600a, 0x9e}, ++{0x600b, 0xc0}, ++{0x600c, 0xd2}, ++{0x600d, 0x33}, ++{0x600e, 0xcc}, ++{0x600f, 0xe2}, ++{0x6010, 0xc1}, ++{0x6011, 0xab}, ++{0x6012, 0xb7}, ++{0x6013, 0x00}, ++{0x6014, 0x00}, ++{0x6015, 0x00}, ++{0x6016, 0x00}, ++{0x6017, 0x00}, ++{0x6018, 0x00}, ++{0x6019, 0x00}, ++{0x601a, 0x00}, ++{0x601b, 0x00}, ++{0x601c, 0x00}, ++{0x601d, 0x00}, ++{0x601e, 0x9c}, ++{0x601f, 0x94}, ++{0x6020, 0x90}, ++{0x6021, 0xc5}, ++{0x6022, 0x01}, ++{0x6023, 0x54}, ++{0x6024, 0x2a}, ++{0x6025, 0x61}, ++{0x6026, 0xd2}, ++{0x6027, 0xcc}, ++{0x6028, 0x04}, ++{0x6029, 0x35}, ++{0x602a, 0xb1}, ++{0x602b, 0xb2}, ++{0x602c, 0xb3}, ++{0x602d, 0xd2}, ++{0x602e, 0xd3}, ++{0x602f, 0x12}, ++{0x6030, 0x31}, ++{0x6031, 0xcc}, ++{0x6032, 0x06}, ++{0x6033, 0xd2}, ++{0x6034, 0xc4}, ++{0x6035, 0xce}, ++{0x6036, 0x18}, ++{0x6037, 0xcf}, ++{0x6038, 0x1e}, ++{0x6039, 0xd0}, ++{0x603a, 0x24}, ++{0x603b, 0xc5}, ++{0x603c, 0xd2}, ++{0x603d, 0xbc}, ++{0x603e, 0xcc}, ++{0x603f, 0x52}, ++{0x6040, 0x2b}, ++{0x6041, 0xd2}, ++{0x6042, 0xd3}, ++{0x6043, 0x02}, ++{0x6044, 0xcc}, ++{0x6045, 0x0a}, ++{0x6046, 0xd2}, ++{0x6047, 0xd3}, ++{0x6048, 0x0f}, ++{0x6049, 0x1a}, ++{0x604a, 0x2a}, ++{0x604b, 0xd4}, ++{0x604c, 0xf6}, ++{0x604d, 0xba}, ++{0x604e, 0x56}, ++{0x604f, 0xd3}, ++{0x6050, 0x2e}, ++{0x6051, 0x54}, ++{0x6052, 0x26}, ++{0x6053, 0xd2}, ++{0x6054, 0xcc}, ++{0x6055, 0x60}, ++{0x6056, 0xd2}, ++{0x6057, 0xd3}, ++{0x6058, 0x27}, ++{0x6059, 0x27}, ++{0x605a, 0x08}, ++{0x605b, 0x1a}, ++{0x605c, 0xcc}, ++{0x605d, 0x88}, ++{0x605e, 0x00}, ++{0x605f, 0x12}, ++{0x6060, 0x2c}, ++{0x6061, 0x60}, ++{0x6062, 0xc2}, ++{0x6063, 0xb9}, ++{0x6064, 0xa5}, ++{0x6065, 0xb5}, ++{0x6066, 0xa0}, ++{0x6067, 0x82}, ++{0x6068, 0x5c}, ++{0x6069, 0xd4}, ++{0x606a, 0xbe}, ++{0x606b, 0xd4}, ++{0x606c, 0xbe}, ++{0x606d, 0xd3}, ++{0x606e, 0x01}, ++{0x606f, 0x7c}, ++{0x6070, 0x74}, ++{0x6071, 0x00}, ++{0x6072, 0x61}, ++{0x6073, 0x2a}, ++{0x6074, 0xd2}, ++{0x6075, 0xcc}, ++{0x6076, 0xdf}, ++{0x6077, 0xc6}, ++{0x6078, 0x35}, ++{0x6079, 0xd2}, ++{0x607a, 0xcc}, ++{0x607b, 0x06}, ++{0x607c, 0x31}, ++{0x607d, 0xd2}, ++{0x607e, 0xc5}, ++{0x607f, 0xbb}, ++{0x6080, 0xcc}, ++{0x6081, 0x18}, ++{0x6082, 0xc6}, ++{0x6083, 0xd2}, ++{0x6084, 0xbd}, ++{0x6085, 0xcc}, ++{0x6086, 0x52}, ++{0x6087, 0x2b}, ++{0x6088, 0xd2}, ++{0x6089, 0xd3}, ++{0x608a, 0x01}, ++{0x608b, 0xcc}, ++{0x608c, 0x0a}, ++{0x608d, 0xd2}, ++{0x608e, 0xd3}, ++{0x608f, 0x0f}, ++{0x6090, 0x1a}, ++{0x6091, 0x71}, ++{0x6092, 0x2a}, ++{0x6093, 0xd4}, ++{0x6094, 0xf6}, ++{0x6095, 0xd3}, ++{0x6096, 0x22}, ++{0x6097, 0x70}, ++{0x6098, 0xca}, ++{0x6099, 0x26}, ++{0x609a, 0xd2}, ++{0x609b, 0xcc}, ++{0x609c, 0x60}, ++{0x609d, 0xd2}, ++{0x609e, 0xd3}, ++{0x609f, 0x27}, ++{0x60a0, 0x27}, ++{0x60a1, 0x08}, ++{0x60a2, 0x1a}, ++{0x60a3, 0xcc}, ++{0x60a4, 0x88}, ++{0x60a5, 0x12}, ++{0x60a6, 0x2c}, ++{0x60a7, 0x60}, ++{0x60a8, 0x00}, ++{0x60a9, 0x00}, ++{0x60aa, 0xc0}, ++{0x60ab, 0xb9}, ++{0x60ac, 0xa3}, ++{0x60ad, 0xb5}, ++{0x60ae, 0x00}, ++{0x60af, 0xa0}, ++{0x60b0, 0x82}, ++{0x60b1, 0x5c}, ++{0x60b2, 0xd4}, ++{0x60b3, 0xa0}, ++{0x60b4, 0x9d}, ++{0x60b5, 0xd3}, ++{0x60b6, 0x26}, ++{0x60b7, 0xb0}, ++{0x60b8, 0xb7}, ++{0x60b9, 0x00}, ++{0x60ba, 0xd3}, ++{0x60bb, 0x0a}, ++{0x60bc, 0xd3}, ++{0x60bd, 0x10}, ++{0x60be, 0x9c}, ++{0x60bf, 0x94}, ++{0x60c0, 0x90}, ++{0x60c1, 0xc8}, ++{0x60c2, 0xba}, ++{0x60c3, 0x7c}, ++{0x60c4, 0x74}, ++{0x60c5, 0x00}, ++{0x60c6, 0x61}, ++{0x60c7, 0x2a}, ++{0x60c8, 0x00}, ++{0x60c9, 0xd2}, ++{0x60ca, 0xcc}, ++{0x60cb, 0xdf}, ++{0x60cc, 0xc4}, ++{0x60cd, 0x35}, ++{0x60ce, 0xd2}, ++{0x60cf, 0xcc}, ++{0x60d0, 0x06}, ++{0x60d1, 0x31}, ++{0x60d2, 0xd2}, ++{0x60d3, 0xcc}, ++{0x60d4, 0x15}, ++{0x60d5, 0xd2}, ++{0x60d6, 0xbb}, ++{0x60d7, 0xcc}, ++{0x60d8, 0x1a}, ++{0x60d9, 0xd2}, ++{0x60da, 0xbe}, ++{0x60db, 0xce}, ++{0x60dc, 0x52}, ++{0x60dd, 0xcf}, ++{0x60de, 0x56}, ++{0x60df, 0xd0}, ++{0x60e0, 0x5b}, ++{0x60e1, 0x2b}, ++{0x60e2, 0xd2}, ++{0x60e3, 0xd3}, ++{0x60e4, 0x01}, ++{0x60e5, 0xcc}, ++{0x60e6, 0x0a}, ++{0x60e7, 0xd2}, ++{0x60e8, 0xd3}, ++{0x60e9, 0x0f}, ++{0x60ea, 0xd9}, ++{0x60eb, 0xc7}, ++{0x60ec, 0xda}, ++{0x60ed, 0xce}, ++{0x60ee, 0x1a}, ++{0x60ef, 0xd4}, ++{0x60f0, 0xf6}, ++{0x60f1, 0xd4}, ++{0x60f2, 0xa9}, ++{0x60f3, 0x27}, ++{0x60f4, 0x00}, ++{0x60f5, 0xd2}, ++{0x60f6, 0xcc}, ++{0x60f7, 0x60}, ++{0x60f8, 0xd2}, ++{0x60f9, 0xd3}, ++{0x60fa, 0x2d}, ++{0x60fb, 0xd9}, ++{0x60fc, 0xdf}, ++{0x60fd, 0xda}, ++{0x60fe, 0xe5}, ++{0x60ff, 0x1a}, ++{0x6100, 0x12}, ++{0x6101, 0xcc}, ++{0x6102, 0x88}, ++{0x6103, 0xd6}, ++{0x6104, 0xb1}, ++{0x6105, 0xb9}, ++{0x6106, 0xba}, ++{0x6107, 0xaf}, ++{0x6108, 0xdc}, ++{0x6109, 0x00}, ++{0x610a, 0xcb}, ++{0x610b, 0xc3}, ++{0x610c, 0xb9}, ++{0x610d, 0xa4}, ++{0x610e, 0xb5}, ++{0x610f, 0x5c}, ++{0x6110, 0x12}, ++{0x6111, 0x2a}, ++{0x6112, 0x61}, ++{0x6113, 0xd2}, ++{0x6114, 0xcc}, ++{0x6115, 0xdf}, ++{0x6116, 0xc7}, ++{0x6117, 0x35}, ++{0x6118, 0xd2}, ++{0x6119, 0xcc}, ++{0x611a, 0x06}, ++{0x611b, 0x31}, ++{0x611c, 0xc6}, ++{0x611d, 0xbb}, ++{0x611e, 0xd2}, ++{0x611f, 0xcc}, ++{0x6120, 0x18}, ++{0x6121, 0xd2}, ++{0x6122, 0xbe}, ++{0x6123, 0xcc}, ++{0x6124, 0x52}, ++{0x6125, 0xc7}, ++{0x6126, 0xd2}, ++{0x6127, 0xcc}, ++{0x6128, 0x0a}, ++{0x6129, 0xb4}, ++{0x612a, 0xb7}, ++{0x612b, 0x94}, ++{0x612c, 0xd2}, ++{0x612d, 0x12}, ++{0x612e, 0x26}, ++{0x612f, 0x42}, ++{0x6130, 0x46}, ++{0x6131, 0x42}, ++{0x6132, 0xd3}, ++{0x6133, 0x20}, ++{0x6134, 0x27}, ++{0x6135, 0x00}, ++{0x6136, 0x1a}, ++{0x6137, 0xcc}, ++{0x6138, 0x88}, ++{0x6139, 0x60}, ++{0x613a, 0x2c}, ++{0x613b, 0x12}, ++{0x613c, 0x40}, ++{0x613d, 0xb8}, ++{0x613e, 0x90}, ++{0x613f, 0xd5}, ++{0x6140, 0xba}, ++{0x6141, 0x00}, ++{0x6142, 0x00}, ++{0x6143, 0x00}, ++{0x6144, 0x00}, ++{0x6145, 0x00}, ++{0x6146, 0x00}, ++{0x6147, 0xaa}, ++{0x6148, 0xb7}, ++{0x6149, 0x00}, ++{0x614a, 0x00}, ++{0x614b, 0x00}, ++{0x614c, 0x00}, ++{0x614d, 0xa6}, ++{0x614e, 0xb7}, ++{0x614f, 0x00}, ++{0x6150, 0xd5}, ++{0x6151, 0x00}, ++{0x6152, 0x71}, ++{0x6153, 0xd3}, ++{0x6154, 0x30}, ++{0x6155, 0xba}, ++{0x6156, 0x00}, ++{0x6157, 0x00}, ++{0x6158, 0x00}, ++{0x6159, 0x00}, ++{0x615a, 0xd3}, ++{0x615b, 0x10}, ++{0x615c, 0x70}, ++{0x615d, 0x00}, ++{0x615e, 0x00}, ++{0x615f, 0x00}, ++{0x6160, 0x00}, ++{0x6161, 0xd5}, ++{0x6162, 0xba}, ++{0x6163, 0xb0}, ++{0x6164, 0xb7}, ++{0x6165, 0x00}, ++{0x6166, 0x9d}, ++{0x6167, 0xd3}, ++{0x6168, 0x0a}, ++{0x6169, 0x9d}, ++{0x616a, 0x9d}, ++{0x616b, 0xd3}, ++{0x616c, 0x10}, ++{0x616d, 0x9c}, ++{0x616e, 0x94}, ++{0x616f, 0x90}, ++{0x6170, 0xc8}, ++{0x6171, 0xba}, ++{0x6172, 0xd2}, ++{0x6173, 0x60}, ++{0x6174, 0x2c}, ++{0x6175, 0x50}, ++{0x6176, 0x11}, ++{0x6177, 0xcc}, ++{0x6178, 0x00}, ++{0x6179, 0x30}, ++{0x617a, 0xd5}, ++{0x617b, 0x00}, ++{0x617c, 0xba}, ++{0x617d, 0xb0}, ++{0x617e, 0xb7}, ++{0x617f, 0x00}, ++{0x6180, 0x9d}, ++{0x6181, 0xd3}, ++{0x6182, 0x0a}, ++{0x6183, 0x9d}, ++{0x6184, 0x9d}, ++{0x6185, 0xd3}, ++{0x6186, 0x10}, ++{0x6187, 0x9c}, ++{0x6188, 0x94}, ++{0x6189, 0x90}, ++{0x618a, 0xc8}, ++{0x618b, 0xba}, ++{0x618c, 0xd5}, ++{0x618d, 0x00}, ++{0x618e, 0x01}, ++{0x618f, 0x1a}, ++{0x6190, 0xcc}, ++{0x6191, 0x12}, ++{0x6192, 0x12}, ++{0x6193, 0x00}, ++{0x6194, 0xcc}, ++{0x6195, 0x9c}, ++{0x6196, 0xd2}, ++{0x6197, 0xcc}, ++{0x6198, 0x60}, ++{0x6199, 0xd2}, ++{0x619a, 0x04}, ++{0x619b, 0xd5}, ++{0x619c, 0x1a}, ++{0x619d, 0xcc}, ++{0x619e, 0x12}, ++{0x619f, 0x00}, ++{0x61a0, 0x12}, ++{0x61a1, 0xcc}, ++{0x61a2, 0x9c}, ++{0x61a3, 0xd2}, ++{0x61a4, 0xcc}, ++{0x61a5, 0x60}, ++{0x61a6, 0xd2}, ++{0x61a7, 0x1a}, ++{0x61a8, 0xcc}, ++{0x61a9, 0x12}, ++{0x61aa, 0x00}, ++{0x61ab, 0x12}, ++{0x61ac, 0xcc}, ++{0x61ad, 0x9c}, ++{0x61ae, 0xd2}, ++{0x61af, 0xcc}, ++{0x61b0, 0x60}, ++{0x61b1, 0xd2}, ++{0x61b2, 0x1a}, ++{0x61b3, 0xcc}, ++{0x61b4, 0x12}, ++{0x61b5, 0x00}, ++{0x61b6, 0x12}, ++{0x61b7, 0xcc}, ++{0x61b8, 0x9c}, ++{0x61b9, 0xd2}, ++{0x61ba, 0xcc}, ++{0x61bb, 0x60}, ++{0x61bc, 0xd2}, ++{0x61bd, 0xd5}, ++{0x61be, 0x1a}, ++{0x61bf, 0xcc}, ++{0x61c0, 0x12}, ++{0x61c1, 0x12}, ++{0x61c2, 0x00}, ++{0x61c3, 0xcc}, ++{0x61c4, 0x8a}, ++{0x61c5, 0xd2}, ++{0x61c6, 0xcc}, ++{0x61c7, 0x74}, ++{0x61c8, 0xd2}, ++{0x61c9, 0xd5}, ++{0x61ca, 0x1a}, ++{0x61cb, 0xcc}, ++{0x61cc, 0x12}, ++{0x61cd, 0x00}, ++{0x61ce, 0x12}, ++{0x61cf, 0xcc}, ++{0x61d0, 0x8a}, ++{0x61d1, 0xd2}, ++{0x61d2, 0xcc}, ++{0x61d3, 0x74}, ++{0x61d4, 0xd2}, ++{0x61d5, 0x1a}, ++{0x61d6, 0xcc}, ++{0x61d7, 0x12}, ++{0x61d8, 0x00}, ++{0x61d9, 0x12}, ++{0x61da, 0xcc}, ++{0x61db, 0x8a}, ++{0x61dc, 0xd2}, ++{0x61dd, 0xcc}, ++{0x61de, 0x74}, ++{0x61df, 0xd2}, ++{0x61e0, 0x1a}, ++{0x61e1, 0xcc}, ++{0x61e2, 0x12}, ++{0x61e3, 0x00}, ++{0x61e4, 0x12}, ++{0x61e5, 0xcc}, ++{0x61e6, 0x8a}, ++{0x61e7, 0xd2}, ++{0x61e8, 0xcc}, ++{0x61e9, 0x74}, ++{0x61ea, 0xd2}, ++{0x61eb, 0xd5}, ++{0x61ec, 0xcc}, ++{0x61ed, 0x12}, ++{0x61ee, 0x00}, ++{0x61ef, 0x12}, ++{0x61f0, 0xcc}, ++{0x61f1, 0x9c}, ++{0x61f2, 0xd5}, ++{0x6400, 0x04}, ++{0x6401, 0x04}, ++{0x6402, 0x00}, ++{0x6403, 0xff}, ++{0x6404, 0x00}, ++{0x6405, 0x08}, ++{0x6406, 0x00}, ++{0x6407, 0xff}, ++{0x6408, 0x04}, ++{0x6409, 0x70}, ++{0x640a, 0x00}, ++{0x640b, 0xff}, ++{0x640c, 0x05}, ++{0x640d, 0x14}, ++{0x640e, 0x04}, ++{0x640f, 0x71}, ++{0x6410, 0x05}, ++{0x6411, 0x74}, ++{0x6412, 0x00}, ++{0x6413, 0xff}, ++{0x6414, 0x05}, ++{0x6415, 0x54}, ++{0x6416, 0x05}, ++{0x6417, 0x44}, ++{0x6418, 0x04}, ++{0x6419, 0x30}, ++{0x641a, 0x05}, ++{0x641b, 0x46}, ++{0x641c, 0x00}, ++{0x641d, 0xff}, ++{0x641e, 0x04}, ++{0x641f, 0x31}, ++{0x6420, 0x04}, ++{0x6421, 0x30}, ++{0x6422, 0x00}, ++{0x6423, 0xff}, ++{0x6424, 0x04}, ++{0x6425, 0x20}, ++{0x6426, 0x05}, ++{0x6427, 0x06}, ++{0x6428, 0x00}, ++{0x6429, 0xff}, ++{0x642a, 0x08}, ++{0x642b, 0x2a}, ++{0x642c, 0x08}, ++{0x642d, 0x31}, ++{0x642e, 0x00}, ++{0x642f, 0xff}, ++{0x6430, 0x08}, ++{0x6431, 0x2a}, ++{0x6432, 0x08}, ++{0x6433, 0x31}, ++{0x6434, 0x06}, ++{0x6435, 0x20}, ++{0x6436, 0x07}, ++{0x6437, 0x00}, ++{0x6438, 0x08}, ++{0x6439, 0x40}, ++{0x643a, 0x00}, ++{0x643b, 0xff}, ++{0x643c, 0x08}, ++{0x643d, 0x2a}, ++{0x643e, 0x08}, ++{0x643f, 0x36}, ++{0x6440, 0x06}, ++{0x6441, 0x10}, ++{0x6442, 0x07}, ++{0x6443, 0x00}, ++{0x6444, 0x08}, ++{0x6445, 0x40}, ++{0x6446, 0x00}, ++{0x6447, 0xff}, ++{0x6448, 0x08}, ++{0x6449, 0x2a}, ++{0x644a, 0x08}, ++{0x644b, 0x3b}, ++{0x644c, 0x06}, ++{0x644d, 0x00}, ++{0x644e, 0x07}, ++{0x644f, 0x00}, ++{0x6450, 0x08}, ++{0x6451, 0x40}, ++{0x6452, 0x00}, ++{0x6453, 0xff}, ++{0x6454, 0x06}, ++{0x6455, 0x00}, ++{0x6456, 0x07}, ++{0x6457, 0x05}, ++{0x6458, 0x01}, ++{0x6459, 0xaf}, ++{0x645a, 0x01}, ++{0x645b, 0x0f}, ++{0x645c, 0x01}, ++{0x645d, 0x90}, ++{0x645e, 0x01}, ++{0x645f, 0xc8}, ++{0x6460, 0x00}, ++{0x6461, 0xff}, ++{0x6462, 0x01}, ++{0x6463, 0xac}, ++{0x6464, 0x01}, ++{0x6465, 0x0c}, ++{0x6466, 0x01}, ++{0x6467, 0x90}, ++{0x6468, 0x01}, ++{0x6469, 0xe8}, ++{0x646a, 0x00}, ++{0x646b, 0xff}, ++{0x646c, 0x01}, ++{0x646d, 0xad}, ++{0x646e, 0x01}, ++{0x646f, 0x0d}, ++{0x6470, 0x01}, ++{0x6471, 0x90}, ++{0x6472, 0x01}, ++{0x6473, 0xe8}, ++{0x6474, 0x00}, ++{0x6475, 0xff}, ++{0x6476, 0x01}, ++{0x6477, 0xae}, ++{0x6478, 0x01}, ++{0x6479, 0x0e}, ++{0x647a, 0x01}, ++{0x647b, 0x90}, ++{0x647c, 0x01}, ++{0x647d, 0xe8}, ++{0x647e, 0x00}, ++{0x647f, 0xff}, ++{0x6480, 0x01}, ++{0x6481, 0xb0}, ++{0x6482, 0x01}, ++{0x6483, 0xb1}, ++{0x6484, 0x01}, ++{0x6485, 0xb2}, ++{0x6486, 0x01}, ++{0x6487, 0xb3}, ++{0x6488, 0x01}, ++{0x6489, 0xb4}, ++{0x648a, 0x01}, ++{0x648b, 0xb5}, ++{0x648c, 0x01}, ++{0x648d, 0xb6}, ++{0x648e, 0x01}, ++{0x648f, 0xb7}, ++{0x6490, 0x01}, ++{0x6491, 0xb8}, ++{0x6492, 0x01}, ++{0x6493, 0xb9}, ++{0x6494, 0x01}, ++{0x6495, 0xba}, ++{0x6496, 0x01}, ++{0x6497, 0xbb}, ++{0x6498, 0x01}, ++{0x6499, 0xbc}, ++{0x649a, 0x01}, ++{0x649b, 0xbd}, ++{0x649c, 0x01}, ++{0x649d, 0xbe}, ++{0x649e, 0x01}, ++{0x649f, 0xbf}, ++{0x64a0, 0x01}, ++{0x64a1, 0xc0}, ++{0x64a2, 0x00}, ++{0x64a3, 0xff}, ++{0x64a4, 0x06}, ++{0x64a5, 0x00}, ++{0x64a6, 0x01}, ++{0x64a7, 0xf6}, ++{0x64a8, 0x04}, ++{0x64a9, 0x30}, ++{0x64aa, 0x00}, ++{0x64ab, 0xff}, ++{0x64ac, 0x06}, ++{0x64ad, 0x10}, ++{0x64ae, 0x01}, ++{0x64af, 0xf6}, ++{0x64b0, 0x04}, ++{0x64b1, 0x30}, ++{0x64b2, 0x06}, ++{0x64b3, 0x00}, ++{0x64b4, 0x00}, ++{0x64b5, 0xff}, ++{0x64b6, 0x06}, ++{0x64b7, 0x20}, ++{0x64b8, 0x01}, ++{0x64b9, 0xf6}, ++{0x64ba, 0x04}, ++{0x64bb, 0x30}, ++{0x64bc, 0x06}, ++{0x64bd, 0x00}, ++{0x64be, 0x00}, ++{0x64bf, 0xff}, ++{0x64c0, 0x04}, ++{0x64c1, 0x31}, ++{0x64c2, 0x04}, ++{0x64c3, 0x30}, ++{0x64c4, 0x01}, ++{0x64c5, 0x20}, ++{0x64c6, 0x01}, ++{0x64c7, 0x31}, ++{0x64c8, 0x01}, ++{0x64c9, 0x32}, ++{0x64ca, 0x01}, ++{0x64cb, 0x33}, ++{0x64cc, 0x01}, ++{0x64cd, 0x34}, ++{0x64ce, 0x01}, ++{0x64cf, 0x35}, ++{0x64d0, 0x01}, ++{0x64d1, 0x36}, ++{0x64d2, 0x01}, ++{0x64d3, 0x37}, ++{0x64d4, 0x01}, ++{0x64d5, 0x38}, ++{0x64d6, 0x01}, ++{0x64d7, 0x39}, ++{0x64d8, 0x01}, ++{0x64d9, 0x3a}, ++{0x64da, 0x01}, ++{0x64db, 0x3b}, ++{0x64dc, 0x01}, ++{0x64dd, 0x3c}, ++{0x64de, 0x01}, ++{0x64df, 0x3d}, ++{0x64e0, 0x01}, ++{0x64e1, 0x3e}, ++{0x64e2, 0x01}, ++{0x64e3, 0x3f}, ++{0x64e4, 0x02}, ++{0x64e5, 0xa0}, ++{0x64e6, 0x00}, ++{0x64e7, 0xff}, ++{0x64e8, 0x04}, ++{0x64e9, 0x31}, ++{0x64ea, 0x04}, ++{0x64eb, 0x30}, ++{0x64ec, 0x01}, ++{0x64ed, 0x00}, ++{0x64ee, 0x01}, ++{0x64ef, 0x11}, ++{0x64f0, 0x01}, ++{0x64f1, 0x12}, ++{0x64f2, 0x01}, ++{0x64f3, 0x13}, ++{0x64f4, 0x01}, ++{0x64f5, 0x14}, ++{0x64f6, 0x01}, ++{0x64f7, 0x15}, ++{0x64f8, 0x01}, ++{0x64f9, 0x16}, ++{0x64fa, 0x01}, ++{0x64fb, 0x17}, ++{0x64fc, 0x01}, ++{0x64fd, 0x18}, ++{0x64fe, 0x01}, ++{0x64ff, 0x19}, ++{0x6500, 0x01}, ++{0x6501, 0x1a}, ++{0x6502, 0x01}, ++{0x6503, 0x1b}, ++{0x6504, 0x01}, ++{0x6505, 0x1c}, ++{0x6506, 0x01}, ++{0x6507, 0x1d}, ++{0x6508, 0x01}, ++{0x6509, 0x1e}, ++{0x650a, 0x01}, ++{0x650b, 0x1f}, ++{0x650c, 0x02}, ++{0x650d, 0xa0}, ++{0x650e, 0x00}, ++{0x650f, 0xff}, ++{0x6510, 0x04}, ++{0x6511, 0x20}, ++{0x6512, 0x05}, ++{0x6513, 0x86}, ++{0x6514, 0x03}, ++{0x6515, 0x0b}, ++{0x6516, 0x05}, ++{0x6517, 0x86}, ++{0x6518, 0x00}, ++{0x6519, 0x00}, ++{0x651a, 0x05}, ++{0x651b, 0x06}, ++{0x651c, 0x00}, ++{0x651d, 0x04}, ++{0x651e, 0x05}, ++{0x651f, 0x04}, ++{0x6520, 0x00}, ++{0x6521, 0x04}, ++{0x6522, 0x05}, ++{0x6523, 0x00}, ++{0x6524, 0x05}, ++{0x6525, 0x0a}, ++{0x6526, 0x03}, ++{0x6527, 0x9a}, ++{0x6528, 0x05}, ++{0x6529, 0x86}, ++{0x652a, 0x00}, ++{0x652b, 0x00}, ++{0x652c, 0x05}, ++{0x652d, 0x06}, ++{0x652e, 0x00}, ++{0x652f, 0x01}, ++{0x6530, 0x05}, ++{0x6531, 0x04}, ++{0x6532, 0x00}, ++{0x6533, 0x04}, ++{0x6534, 0x05}, ++{0x6535, 0x00}, ++{0x6536, 0x05}, ++{0x6537, 0x0a}, ++{0x6538, 0x03}, ++{0x6539, 0x99}, ++{0x653a, 0x05}, ++{0x653b, 0x06}, ++{0x653c, 0x00}, ++{0x653d, 0x00}, ++{0x653e, 0x05}, ++{0x653f, 0x04}, ++{0x6540, 0x00}, ++{0x6541, 0x04}, ++{0x6542, 0x05}, ++{0x6543, 0x00}, ++{0x6544, 0x05}, ++{0x6545, 0x0a}, ++{0x6546, 0x03}, ++{0x6547, 0x98}, ++{0x6548, 0x05}, ++{0x6549, 0x06}, ++{0x654a, 0x00}, ++{0x654b, 0x00}, ++{0x654c, 0x05}, ++{0x654d, 0x04}, ++{0x654e, 0x00}, ++{0x654f, 0x04}, ++{0x6550, 0x05}, ++{0x6551, 0x00}, ++{0x6552, 0x05}, ++{0x6553, 0x0a}, ++{0x6554, 0x03}, ++{0x6555, 0x97}, ++{0x6556, 0x05}, ++{0x6557, 0x06}, ++{0x6558, 0x05}, ++{0x6559, 0x04}, ++{0x655a, 0x00}, ++{0x655b, 0x04}, ++{0x655c, 0x05}, ++{0x655d, 0x00}, ++{0x655e, 0x05}, ++{0x655f, 0x0a}, ++{0x6560, 0x03}, ++{0x6561, 0x96}, ++{0x6562, 0x05}, ++{0x6563, 0x06}, ++{0x6564, 0x05}, ++{0x6565, 0x04}, ++{0x6566, 0x00}, ++{0x6567, 0x04}, ++{0x6568, 0x05}, ++{0x6569, 0x00}, ++{0x656a, 0x05}, ++{0x656b, 0x0a}, ++{0x656c, 0x03}, ++{0x656d, 0x95}, ++{0x656e, 0x05}, ++{0x656f, 0x06}, ++{0x6570, 0x05}, ++{0x6571, 0x04}, ++{0x6572, 0x00}, ++{0x6573, 0x04}, ++{0x6574, 0x05}, ++{0x6575, 0x00}, ++{0x6576, 0x05}, ++{0x6577, 0x0a}, ++{0x6578, 0x03}, ++{0x6579, 0x94}, ++{0x657a, 0x05}, ++{0x657b, 0x06}, ++{0x657c, 0x00}, ++{0x657d, 0x00}, ++{0x657e, 0x05}, ++{0x657f, 0x04}, ++{0x6580, 0x00}, ++{0x6581, 0x04}, ++{0x6582, 0x05}, ++{0x6583, 0x00}, ++{0x6584, 0x05}, ++{0x6585, 0x0a}, ++{0x6586, 0x03}, ++{0x6587, 0x93}, ++{0x6588, 0x05}, ++{0x6589, 0x06}, ++{0x658a, 0x00}, ++{0x658b, 0x00}, ++{0x658c, 0x05}, ++{0x658d, 0x04}, ++{0x658e, 0x00}, ++{0x658f, 0x04}, ++{0x6590, 0x05}, ++{0x6591, 0x00}, ++{0x6592, 0x05}, ++{0x6593, 0x0a}, ++{0x6594, 0x03}, ++{0x6595, 0x92}, ++{0x6596, 0x05}, ++{0x6597, 0x06}, ++{0x6598, 0x05}, ++{0x6599, 0x04}, ++{0x659a, 0x00}, ++{0x659b, 0x04}, ++{0x659c, 0x05}, ++{0x659d, 0x00}, ++{0x659e, 0x05}, ++{0x659f, 0x0a}, ++{0x65a0, 0x03}, ++{0x65a1, 0x91}, ++{0x65a2, 0x05}, ++{0x65a3, 0x06}, ++{0x65a4, 0x05}, ++{0x65a5, 0x04}, ++{0x65a6, 0x00}, ++{0x65a7, 0x04}, ++{0x65a8, 0x05}, ++{0x65a9, 0x00}, ++{0x65aa, 0x05}, ++{0x65ab, 0x0a}, ++{0x65ac, 0x03}, ++{0x65ad, 0x90}, ++{0x65ae, 0x05}, ++{0x65af, 0x06}, ++{0x65b0, 0x05}, ++{0x65b1, 0x04}, ++{0x65b2, 0x00}, ++{0x65b3, 0x04}, ++{0x65b4, 0x05}, ++{0x65b5, 0x00}, ++{0x65b6, 0x05}, ++{0x65b7, 0x0a}, ++{0x65b8, 0x02}, ++{0x65b9, 0x90}, ++{0x65ba, 0x05}, ++{0x65bb, 0x06}, ++{0x65bc, 0x00}, ++{0x65bd, 0xff}, ++{0x65be, 0x04}, ++{0x65bf, 0x70}, ++{0x65c0, 0x08}, ++{0x65c1, 0x76}, ++{0x65c2, 0x00}, ++{0x65c3, 0xff}, ++{0x65c4, 0x08}, ++{0x65c5, 0x76}, ++{0x65c6, 0x04}, ++{0x65c7, 0x0c}, ++{0x65c8, 0x05}, ++{0x65c9, 0x07}, ++{0x65ca, 0x04}, ++{0x65cb, 0x04}, ++{0x65cc, 0x00}, ++{0x65cd, 0xff}, ++{0x65ce, 0x00}, ++{0x65cf, 0xff}, ++{0x65d0, 0x00}, ++{0x65d1, 0xff}, ++{0x30eb, 0x04}, ++{0x30ed, 0x5a}, ++{0x30ee, 0x01}, ++{0x30ef, 0x80}, ++{0x30f1, 0x5a}, ++{0x303a, 0x04}, ++{0x303b, 0x7f}, ++{0x303c, 0xfe}, ++{0x303d, 0x19}, ++{0x303e, 0xd7}, ++{0x303f, 0x09}, ++{0x3040, 0x78}, ++{0x3042, 0x05}, ++{0x328a, 0x10}, ++#if 0 ++{0x3012, 0x01}, ++{0x3012, 0x00}, ++{0x3119, 0x44}, ++{0x328a, 0x10}, ++{0x3012, 0x01}, ++#else ++{0x328a, 0x10}, ++/* HFLIP=1, VFLIP=0 */ ++{0x3128, 0xc0 | 0x1}, ++{0x3291, 0x01 | 0x2}, ++{0x3090, 0x4}, ++/* change settings to 1280x1080 COMB12 30 fps, 96MHz */ ++{0x3012, 0x0}, ++{0x3000, 0x3}, ++{0x3001, 0x50}, ++{0x3002, 0x0a}, ++{0x3004, 0x3}, ++{0x3005, 0x48}, ++{0x3006, 0x7}, ++{0x308f, 0x10}, ++{0x3127, 0x63}, ++{0x3074, OV10640_X_START >> 8}, ++{0x3075, OV10640_X_START & 0xff}, ++{0x3076, OV10640_Y_START >> 8}, ++{0x3077, OV10640_Y_START & 0xff}, ++{0x3078, OV10640_X_END >> 8}, ++{0x3079, OV10640_X_END & 0xff}, ++{0x307a, OV10640_Y_END >> 8}, ++{0x307b, OV10640_Y_END & 0xff}, ++{0x307c, OV10640_MAX_WIDTH >> 8}, ++{0x307d, OV10640_MAX_WIDTH & 0xff}, ++{0x307e, OV10640_MAX_HEIGHT >> 8}, ++{0x307f, OV10640_MAX_HEIGHT & 0xff}, ++{0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS ++{0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff}, ++{0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS ++{0x3083, (OV10640_SENSOR_HEIGHT + 208) & 0xff}, ++{0x3084, 0x0}, ++{0x3085, 0x0}, ++{0x3086, 0x0}, ++{0x3087, 0x0}, ++{0x346d, 0x14}, ++{0x3444, 0x28}, ++{0x3091, 0x0}, ++{0x3119, 0x44}, // COMB12 ++{0x3012, 0x1}, ++#endif ++}; +diff --git a/drivers/media/i2c/soc_camera/ov10640_r1f.h b/drivers/media/i2c/soc_camera/ov10640_r1f.h +new file mode 100644 +index 0000000..ef866fa +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ov10640_r1f.h +@@ -0,0 +1,1198 @@ ++/* ++ * OmniVision ov10640 sensor camera wizard 1280x1080@30/BGGR/BT601/12bit ++ * ++ * Copyright (C) 2015-2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++/* DVP_1280x1080_COMB12_raw 60fps */ ++static const struct ov10640_reg ov10640_regs_wizard_r1f[] = { ++//{0x3013, 0x01}, ++//{OV10640_DELAY, 10}, ++{0x31be, 0x01}, ++{0x3133, 0xb7}, ++{0x3134, 0xca}, ++{0x3135, 0xcc}, ++{0x313f, 0x80}, ++{0x3132, 0x24}, ++{0x3000, 0x03}, ++{0x3001, 0x62}, ++{0x3002, 0x07}, ++{0x3004, 0x03}, ++{0x3005, 0x62}, ++{0x3006, 0x07}, ++{0x3007, 0x01}, ++{0x3023, 0x05}, ++{0x3032, 0x35}, ++{0x3033, 0x04}, ++{0x3054, 0x00}, ++{0x3055, 0x0f}, ++{0x3056, 0x01}, ++{0x3057, 0xff}, ++{0x3058, 0xaf}, ++{0x3059, 0x44}, ++{0x305a, 0x02}, ++{0x305b, 0x00}, ++{0x305c, 0x30}, ++{0x305d, 0x9e}, ++{0x305e, 0x19}, ++{0x305f, 0x18}, ++{0x3060, 0xf9}, ++{0x3061, 0xf0}, ++#ifdef OV10640_FSIN_ENABLE ++{0x308c, 0xb2}, ++#else ++{0x308c, 0x03}, ++#endif ++{0x308f, 0x10}, ++{0x3090, 0x00}, ++{0x3091, 0x00}, ++{0x30eb, 0x00}, ++{0x30a3, 0x08}, ++{0x30ad, 0x03}, ++{0x30ae, 0x80}, ++{0x30af, 0x80}, ++{0x30b0, 0xff}, ++{0x30b1, 0x3f}, ++{0x30b2, 0x22}, ++{0x30b9, 0x22}, ++{0x30bb, 0x00}, ++{0x30bc, 0x00}, ++{0x30bd, 0x00}, ++{0x30be, 0x00}, ++{0x30bf, 0x00}, ++{0x30c0, 0x00}, ++{0x30c1, 0x00}, ++{0x30c2, 0x00}, ++{0x30c3, 0x00}, ++{0x30c4, 0x80}, ++{0x30c5, 0x00}, ++{0x30c6, 0x80}, ++{0x30c7, 0x00}, ++{0x30c8, 0x80}, ++{0x3119, 0x44}, ++{0x311a, 0x01}, ++{0x311b, 0x4a}, ++{0x3074, 0x00}, ++{0x3075, 0x00}, ++{0x3076, 0x00}, ++{0x3077, 0x02}, ++{0x3078, 0x05}, ++{0x3079, 0x07}, ++{0x307a, 0x04}, ++{0x307b, 0x41}, ++{0x307c, 0x05}, ++{0x307d, 0x00}, ++{0x307e, 0x04}, ++{0x307f, 0x38}, ++{0x3080, 0x05}, ++{0x3081, 0xbe}, ++{0x3082, 0x04}, ++{0x3083, 0x57}, ++{0x3084, 0x00}, ++{0x3085, 0x04}, ++{0x3086, 0x00}, ++{0x3087, 0x04}, ++{0x3088, 0x00}, ++{0x3089, 0x40}, ++{0x308d, 0x92}, ++{0x3094, 0xa5}, ++{0x30e6, 0x04}, ++{0x30e7, 0x48}, ++{0x30e8, 0x04}, ++{0x30e9, 0x48}, ++{0x30ea, 0x11}, ++{0x30ec, 0x01}, ++{0x30fa, 0x06}, ++{0x3120, 0x00}, ++{0x3121, 0x01}, ++{0x3122, 0x00}, ++{0x3127, 0x63}, ++{0x3128, 0xc0}, ++#ifdef OV10640_DISPLAY_PATTERN ++{0x3129, 0x80}, ++#else ++{0x3129, 0x00}, ++#endif ++{0x31be, 0x01}, ++{0x30a5, 0x78}, ++{0x30a6, 0x40}, ++{0x30a7, 0x78}, ++{0x30a8, 0x80}, ++{0x30a9, 0x79}, ++{0x30aa, 0x00}, ++{0x30ab, 0x79}, ++{0x30ac, 0xf8}, ++{0x3440, 0x04}, ++{0x3444, 0x28}, ++{0x344e, 0x2c}, ++{0x3457, 0x33}, ++{0x345e, 0x38}, ++{0x3461, 0xa8}, ++{0x7002, 0xaa}, ++{0x7001, 0xdf}, ++{0x7048, 0x00}, ++{0x7049, 0x02}, ++{0x704a, 0x02}, ++{0x704b, 0x00}, ++{0x704c, 0x01}, ++{0x704d, 0x00}, ++{0x7043, 0x04}, ++{0x7040, 0x3c}, ++{0x7047, 0x00}, ++{0x7044, 0x01}, ++{0x7000, 0x1f}, ++{0x7084, 0x01}, ++{0x7085, 0x03}, ++{0x7086, 0x02}, ++{0x7087, 0x40}, ++{0x7088, 0x01}, ++{0x7089, 0x20}, ++{0x707f, 0x04}, ++{0x707c, 0x3c}, ++{0x7083, 0x00}, ++{0x7080, 0x01}, ++{0x7003, 0xdf}, ++{0x70c0, 0x00}, ++{0x70c1, 0x02}, ++{0x70c2, 0x02}, ++{0x70c3, 0x00}, ++{0x70c4, 0x01}, ++{0x70c5, 0x00}, ++{0x70b8, 0x03}, ++{0x70b9, 0x98}, ++{0x70bc, 0x00}, ++{0x70bd, 0x80}, ++{0x7004, 0x02}, ++{0x7005, 0x00}, ++{0x7006, 0x01}, ++{0x7007, 0x80}, ++{0x7008, 0x02}, ++{0x7009, 0x00}, ++{0x700a, 0x04}, ++{0x700b, 0x00}, ++{0x700e, 0x00}, ++{0x700f, 0x60}, ++{0x701a, 0x02}, ++{0x701b, 0x00}, ++{0x701c, 0x01}, ++{0x701d, 0x80}, ++{0x701e, 0x02}, ++{0x701f, 0x00}, ++{0x7020, 0x04}, ++{0x7021, 0x00}, ++{0x7024, 0x00}, ++{0x7025, 0x60}, ++{0x70e7, 0x00}, ++{0x70e4, 0x10}, ++{0x70e5, 0x00}, ++{0x70e6, 0x00}, ++{0x70eb, 0x00}, ++{0x70e8, 0x10}, ++{0x70e9, 0x00}, ++{0x70ea, 0x00}, ++{0x70ef, 0x00}, ++{0x70ec, 0xfd}, ++{0x70ed, 0x00}, ++{0x70ee, 0x00}, ++{0x70eb, 0x00}, ++{0x70f0, 0xfd}, ++{0x70f1, 0x00}, ++{0x70f2, 0x00}, ++{0x30fb, 0x06}, ++{0x30fc, 0x80}, ++{0x30fd, 0x02}, ++{0x30fe, 0x93}, ++{0x6000, 0xc1}, ++{0x6001, 0xb9}, ++{0x6002, 0xba}, ++{0x6003, 0xa4}, ++{0x6004, 0xa4}, ++{0x6005, 0xb5}, ++{0x6006, 0xa0}, ++{0x6007, 0x82}, ++{0x6008, 0xa7}, ++{0x6009, 0xa7}, ++{0x600a, 0xb7}, ++{0x600b, 0x5c}, ++{0x600c, 0x9e}, ++{0x600d, 0xc0}, ++{0x600e, 0xd2}, ++{0x600f, 0x33}, ++{0x6010, 0xcc}, ++{0x6011, 0xe2}, ++{0x6012, 0xc1}, ++{0x6013, 0xab}, ++{0x6014, 0xab}, ++{0x6015, 0xb7}, ++{0x6016, 0x00}, ++{0x6017, 0x00}, ++{0x6018, 0x00}, ++{0x6019, 0x00}, ++{0x601a, 0x00}, ++{0x601b, 0x00}, ++{0x601c, 0x00}, ++{0x601d, 0x00}, ++{0x601e, 0x00}, ++{0x601f, 0x00}, ++{0x6020, 0x00}, ++{0x6021, 0x00}, ++{0x6022, 0x00}, ++{0x6023, 0x9c}, ++{0x6024, 0x94}, ++{0x6025, 0x90}, ++{0x6026, 0xc5}, ++{0x6027, 0x00}, ++{0x6028, 0x54}, ++{0x6029, 0x2a}, ++{0x602a, 0x61}, ++{0x602b, 0xd2}, ++{0x602c, 0xcc}, ++{0x602d, 0x04}, ++{0x602e, 0x35}, ++{0x602f, 0xb1}, ++{0x6030, 0xb2}, ++{0x6031, 0xb3}, ++{0x6032, 0xd2}, ++{0x6033, 0xd3}, ++{0x6034, 0x11}, ++{0x6035, 0x31}, ++{0x6036, 0xcc}, ++{0x6037, 0x06}, ++{0x6038, 0xd2}, ++{0x6039, 0x00}, ++{0x603a, 0xce}, ++{0x603b, 0x18}, ++{0x603c, 0xcf}, ++{0x603d, 0x1e}, ++{0x603e, 0xd0}, ++{0x603f, 0x24}, ++{0x6040, 0xc5}, ++{0x6041, 0xd2}, ++{0x6042, 0xbc}, ++{0x6043, 0xcc}, ++{0x6044, 0x52}, ++{0x6045, 0x2b}, ++{0x6046, 0xd2}, ++{0x6047, 0xd3}, ++{0x6048, 0x01}, ++{0x6049, 0xcc}, ++{0x604a, 0x0a}, ++{0x604b, 0xd2}, ++{0x604c, 0xd3}, ++{0x604d, 0x0f}, ++{0x604e, 0x1a}, ++{0x604f, 0x2a}, ++{0x6050, 0xd4}, ++{0x6051, 0xe3}, ++{0x6052, 0xba}, ++{0x6053, 0x56}, ++{0x6054, 0xd3}, ++{0x6055, 0x2e}, ++{0x6056, 0x54}, ++{0x6057, 0x26}, ++{0x6058, 0xd2}, ++{0x6059, 0xcc}, ++{0x605a, 0x60}, ++{0x605b, 0xd2}, ++{0x605c, 0xd3}, ++{0x605d, 0x27}, ++{0x605e, 0x27}, ++{0x605f, 0x08}, ++{0x6060, 0x1a}, ++{0x6061, 0xcc}, ++{0x6062, 0x88}, ++{0x6063, 0x00}, ++{0x6064, 0x12}, ++{0x6065, 0x2c}, ++{0x6066, 0x60}, ++{0x6067, 0xc2}, ++{0x6068, 0xb9}, ++{0x6069, 0xa5}, ++{0x606a, 0xa5}, ++{0x606b, 0xb5}, ++{0x606c, 0xa0}, ++{0x606d, 0x82}, ++{0x606e, 0x5c}, ++{0x606f, 0xd4}, ++{0x6070, 0xab}, ++{0x6071, 0xd4}, ++{0x6072, 0xab}, ++{0x6073, 0xd3}, ++{0x6074, 0x01}, ++{0x6075, 0x7c}, ++{0x6076, 0x74}, ++{0x6077, 0x00}, ++{0x6078, 0x61}, ++{0x6079, 0x2a}, ++{0x607a, 0xd2}, ++{0x607b, 0xcc}, ++{0x607c, 0xdf}, ++{0x607d, 0xc6}, ++{0x607e, 0x35}, ++{0x607f, 0xd2}, ++{0x6080, 0xcc}, ++{0x6081, 0x06}, ++{0x6082, 0x31}, ++{0x6083, 0xd2}, ++{0x6084, 0x00}, ++{0x6085, 0xbb}, ++{0x6086, 0xcc}, ++{0x6087, 0x18}, ++{0x6088, 0xc6}, ++{0x6089, 0xd2}, ++{0x608a, 0xbd}, ++{0x608b, 0xcc}, ++{0x608c, 0x52}, ++{0x608d, 0x2b}, ++{0x608e, 0xd2}, ++{0x608f, 0xd3}, ++{0x6090, 0x01}, ++{0x6091, 0xcc}, ++{0x6092, 0x0a}, ++{0x6093, 0xd2}, ++{0x6094, 0xd3}, ++{0x6095, 0x0f}, ++{0x6096, 0x1a}, ++{0x6097, 0x71}, ++{0x6098, 0x2a}, ++{0x6099, 0xd4}, ++{0x609a, 0xe3}, ++{0x609b, 0xd3}, ++{0x609c, 0x22}, ++{0x609d, 0x70}, ++{0x609e, 0xca}, ++{0x609f, 0x26}, ++{0x60a0, 0xd2}, ++{0x60a1, 0xcc}, ++{0x60a2, 0x60}, ++{0x60a3, 0xd2}, ++{0x60a4, 0xd3}, ++{0x60a5, 0x27}, ++{0x60a6, 0x27}, ++{0x60a7, 0x08}, ++{0x60a8, 0x1a}, ++{0x60a9, 0xcc}, ++{0x60aa, 0x88}, ++{0x60ab, 0x00}, ++{0x60ac, 0x12}, ++{0x60ad, 0x2c}, ++{0x60ae, 0x60}, ++{0x60af, 0x00}, ++{0x60b0, 0x00}, ++{0x60b1, 0xc0}, ++{0x60b2, 0xb9}, ++{0x60b3, 0xa3}, ++{0x60b4, 0xa3}, ++{0x60b5, 0xb5}, ++{0x60b6, 0x00}, ++{0x60b7, 0xa0}, ++{0x60b8, 0x82}, ++{0x60b9, 0x5c}, ++{0x60ba, 0xd4}, ++{0x60bb, 0x8b}, ++{0x60bc, 0x9d}, ++{0x60bd, 0xd3}, ++{0x60be, 0x21}, ++{0x60bf, 0xb0}, ++{0x60c0, 0xb0}, ++{0x60c1, 0xb7}, ++{0x60c2, 0x05}, ++{0x60c3, 0xd3}, ++{0x60c4, 0x0a}, ++{0x60c5, 0xd3}, ++{0x60c6, 0x10}, ++{0x60c7, 0x9c}, ++{0x60c8, 0x94}, ++{0x60c9, 0x90}, ++{0x60ca, 0xc8}, ++{0x60cb, 0xba}, ++{0x60cc, 0x7c}, ++{0x60cd, 0x74}, ++{0x60ce, 0x00}, ++{0x60cf, 0x61}, ++{0x60d0, 0x2a}, ++{0x60d1, 0x00}, ++{0x60d2, 0xd2}, ++{0x60d3, 0xcc}, ++{0x60d4, 0xdf}, ++{0x60d5, 0xc4}, ++{0x60d6, 0x35}, ++{0x60d7, 0xd3}, ++{0x60d8, 0x13}, ++{0x60d9, 0xd2}, ++{0x60da, 0xcc}, ++{0x60db, 0x06}, ++{0x60dc, 0x31}, ++{0x60dd, 0xd2}, ++{0x60de, 0xcc}, ++{0x60df, 0x15}, ++{0x60e0, 0xd2}, ++{0x60e1, 0xbb}, ++{0x60e2, 0xcc}, ++{0x60e3, 0x1a}, ++{0x60e4, 0xd2}, ++{0x60e5, 0xbe}, ++{0x60e6, 0xce}, ++{0x60e7, 0x52}, ++{0x60e8, 0xcf}, ++{0x60e9, 0x56}, ++{0x60ea, 0xd0}, ++{0x60eb, 0x5b}, ++{0x60ec, 0x2b}, ++{0x60ed, 0xd2}, ++{0x60ee, 0xd3}, ++{0x60ef, 0x01}, ++{0x60f0, 0xcc}, ++{0x60f1, 0x0a}, ++{0x60f2, 0xd2}, ++{0x60f3, 0xd3}, ++{0x60f4, 0x0f}, ++{0x60f5, 0xd9}, ++{0x60f6, 0xb4}, ++{0x60f7, 0xda}, ++{0x60f8, 0xbb}, ++{0x60f9, 0x1a}, ++{0x60fa, 0xd4}, ++{0x60fb, 0xe3}, ++{0x60fc, 0xd4}, ++{0x60fd, 0x96}, ++{0x60fe, 0x27}, ++{0x60ff, 0x00}, ++{0x6100, 0xd2}, ++{0x6101, 0xcc}, ++{0x6102, 0x60}, ++{0x6103, 0xd2}, ++{0x6104, 0xd3}, ++{0x6105, 0x2d}, ++{0x6106, 0xd9}, ++{0x6107, 0xcc}, ++{0x6108, 0xda}, ++{0x6109, 0xd2}, ++{0x610a, 0x1a}, ++{0x610b, 0x12}, ++{0x610c, 0xcc}, ++{0x610d, 0x88}, ++{0x610e, 0xd6}, ++{0x610f, 0x9e}, ++{0x6110, 0xb9}, ++{0x6111, 0xba}, ++{0x6112, 0xaf}, ++{0x6113, 0xdc}, ++{0x6114, 0x00}, ++{0x6115, 0xd5}, ++{0x6116, 0xba}, ++{0x6117, 0x00}, ++{0x6118, 0x00}, ++{0x6119, 0x00}, ++{0x611a, 0x00}, ++{0x611b, 0x00}, ++{0x611c, 0x00}, ++{0x611d, 0x00}, ++{0x611e, 0x00}, ++{0x611f, 0xaa}, ++{0x6120, 0xaa}, ++{0x6121, 0xb7}, ++{0x6122, 0x00}, ++{0x6123, 0x00}, ++{0x6124, 0x00}, ++{0x6125, 0x00}, ++{0x6126, 0x00}, ++{0x6127, 0xa6}, ++{0x6128, 0xa6}, ++{0x6129, 0xb7}, ++{0x612a, 0x00}, ++{0x612b, 0xd5}, ++{0x612c, 0x71}, ++{0x612d, 0xd3}, ++{0x612e, 0x30}, ++{0x612f, 0xba}, ++{0x6130, 0x00}, ++{0x6131, 0x00}, ++{0x6132, 0x00}, ++{0x6133, 0x00}, ++{0x6134, 0xd3}, ++{0x6135, 0x10}, ++{0x6136, 0x70}, ++{0x6137, 0x00}, ++{0x6138, 0x00}, ++{0x6139, 0x00}, ++{0x613a, 0x00}, ++{0x613b, 0xd5}, ++{0x613c, 0xba}, ++{0x613d, 0xb0}, ++{0x613e, 0xb0}, ++{0x613f, 0xb7}, ++{0x6140, 0x9d}, ++{0x6141, 0x02}, ++{0x6142, 0xd3}, ++{0x6143, 0x0a}, ++{0x6144, 0x9d}, ++{0x6145, 0x9d}, ++{0x6146, 0xd3}, ++{0x6147, 0x10}, ++{0x6148, 0x9c}, ++{0x6149, 0x94}, ++{0x614a, 0x90}, ++{0x614b, 0xc8}, ++{0x614c, 0xba}, ++{0x614d, 0xd2}, ++{0x614e, 0x60}, ++{0x614f, 0x2c}, ++{0x6150, 0x50}, ++{0x6151, 0x11}, ++{0x6152, 0xcc}, ++{0x6153, 0x00}, ++{0x6154, 0x30}, ++{0x6155, 0xd5}, ++{0x6156, 0xba}, ++{0x6157, 0xb0}, ++{0x6158, 0xb0}, ++{0x6159, 0xb7}, ++{0x615a, 0x9d}, ++{0x615b, 0x02}, ++{0x615c, 0xd3}, ++{0x615d, 0x0a}, ++{0x615e, 0x9d}, ++{0x615f, 0x9d}, ++{0x6160, 0xd3}, ++{0x6161, 0x10}, ++{0x6162, 0x9c}, ++{0x6163, 0x94}, ++{0x6164, 0x90}, ++{0x6165, 0xc8}, ++{0x6166, 0xba}, ++{0x6167, 0xd5}, ++{0x6168, 0x01}, ++{0x6169, 0x1a}, ++{0x616a, 0xcc}, ++{0x616b, 0x12}, ++{0x616c, 0x12}, ++{0x616d, 0x00}, ++{0x616e, 0xcc}, ++{0x616f, 0x9c}, ++{0x6170, 0xd2}, ++{0x6171, 0xcc}, ++{0x6172, 0x60}, ++{0x6173, 0xd2}, ++{0x6174, 0x04}, ++{0x6175, 0xd5}, ++{0x6176, 0x1a}, ++{0x6177, 0xcc}, ++{0x6178, 0x12}, ++{0x6179, 0x00}, ++{0x617a, 0x12}, ++{0x617b, 0xcc}, ++{0x617c, 0x9c}, ++{0x617d, 0xd2}, ++{0x617e, 0xcc}, ++{0x617f, 0x60}, ++{0x6180, 0xd2}, ++{0x6181, 0x1a}, ++{0x6182, 0xcc}, ++{0x6183, 0x12}, ++{0x6184, 0x00}, ++{0x6185, 0x12}, ++{0x6186, 0xcc}, ++{0x6187, 0x9c}, ++{0x6188, 0xd2}, ++{0x6189, 0xcc}, ++{0x618a, 0x60}, ++{0x618b, 0xd2}, ++{0x618c, 0x1a}, ++{0x618d, 0xcc}, ++{0x618e, 0x12}, ++{0x618f, 0x00}, ++{0x6190, 0x12}, ++{0x6191, 0xcc}, ++{0x6192, 0x9c}, ++{0x6193, 0xd2}, ++{0x6194, 0xcc}, ++{0x6195, 0x60}, ++{0x6196, 0xd2}, ++{0x6197, 0xd5}, ++{0x6198, 0x1a}, ++{0x6199, 0xcc}, ++{0x619a, 0x12}, ++{0x619b, 0x12}, ++{0x619c, 0x00}, ++{0x619d, 0xcc}, ++{0x619e, 0x8a}, ++{0x619f, 0xd2}, ++{0x61a0, 0xcc}, ++{0x61a1, 0x74}, ++{0x61a2, 0xd2}, ++{0x61a3, 0xd5}, ++{0x61a4, 0x1a}, ++{0x61a5, 0xcc}, ++{0x61a6, 0x12}, ++{0x61a7, 0x00}, ++{0x61a8, 0x12}, ++{0x61a9, 0xcc}, ++{0x61aa, 0x8a}, ++{0x61ab, 0xd2}, ++{0x61ac, 0xcc}, ++{0x61ad, 0x74}, ++{0x61ae, 0xd2}, ++{0x61af, 0x1a}, ++{0x61b0, 0xcc}, ++{0x61b1, 0x12}, ++{0x61b2, 0x00}, ++{0x61b3, 0x12}, ++{0x61b4, 0xcc}, ++{0x61b5, 0x8a}, ++{0x61b6, 0xd2}, ++{0x61b7, 0xcc}, ++{0x61b8, 0x74}, ++{0x61b9, 0xd2}, ++{0x61ba, 0x1a}, ++{0x61bb, 0xcc}, ++{0x61bc, 0x12}, ++{0x61bd, 0x00}, ++{0x61be, 0x12}, ++{0x61bf, 0xcc}, ++{0x61c0, 0x8a}, ++{0x61c1, 0xd2}, ++{0x61c2, 0xcc}, ++{0x61c3, 0x74}, ++{0x61c4, 0xd2}, ++{0x61c5, 0xd5}, ++{0x61c6, 0xcc}, ++{0x61c7, 0x12}, ++{0x61c8, 0x00}, ++{0x61c9, 0x12}, ++{0x61ca, 0xcc}, ++{0x61cb, 0x9c}, ++{0x61cc, 0xd5}, ++{0x6400, 0x04}, ++{0x6401, 0x04}, ++{0x6402, 0x00}, ++{0x6403, 0xff}, ++{0x6404, 0x00}, ++{0x6405, 0x08}, ++{0x6406, 0x00}, ++{0x6407, 0xff}, ++{0x6408, 0x04}, ++{0x6409, 0x70}, ++{0x640a, 0x00}, ++{0x640b, 0xff}, ++{0x640c, 0x05}, ++{0x640d, 0x14}, ++{0x640e, 0x04}, ++{0x640f, 0x71}, ++{0x6410, 0x05}, ++{0x6411, 0x74}, ++{0x6412, 0x00}, ++{0x6413, 0xff}, ++{0x6414, 0x05}, ++{0x6415, 0x54}, ++{0x6416, 0x05}, ++{0x6417, 0x44}, ++{0x6418, 0x04}, ++{0x6419, 0x30}, ++{0x641a, 0x05}, ++{0x641b, 0x46}, ++{0x641c, 0x00}, ++{0x641d, 0xff}, ++{0x641e, 0x04}, ++{0x641f, 0x31}, ++{0x6420, 0x04}, ++{0x6421, 0x30}, ++{0x6422, 0x00}, ++{0x6423, 0xff}, ++{0x6424, 0x04}, ++{0x6425, 0x20}, ++{0x6426, 0x05}, ++{0x6427, 0x06}, ++{0x6428, 0x00}, ++{0x6429, 0xff}, ++{0x642a, 0x08}, ++{0x642b, 0x2a}, ++{0x642c, 0x08}, ++{0x642d, 0x31}, ++{0x642e, 0x00}, ++{0x642f, 0xff}, ++{0x6430, 0x08}, ++{0x6431, 0x2a}, ++{0x6432, 0x08}, ++{0x6433, 0x31}, ++{0x6434, 0x06}, ++{0x6435, 0x20}, ++{0x6436, 0x07}, ++{0x6437, 0x00}, ++{0x6438, 0x08}, ++{0x6439, 0x40}, ++{0x643a, 0x00}, ++{0x643b, 0xff}, ++{0x643c, 0x08}, ++{0x643d, 0x2a}, ++{0x643e, 0x08}, ++{0x643f, 0x36}, ++{0x6440, 0x06}, ++{0x6441, 0x10}, ++{0x6442, 0x07}, ++{0x6443, 0x00}, ++{0x6444, 0x08}, ++{0x6445, 0x40}, ++{0x6446, 0x00}, ++{0x6447, 0xff}, ++{0x6448, 0x08}, ++{0x6449, 0x2a}, ++{0x644a, 0x08}, ++{0x644b, 0x3b}, ++{0x644c, 0x06}, ++{0x644d, 0x00}, ++{0x644e, 0x07}, ++{0x644f, 0x00}, ++{0x6450, 0x08}, ++{0x6451, 0x40}, ++{0x6452, 0x00}, ++{0x6453, 0xff}, ++{0x6454, 0x06}, ++{0x6455, 0x00}, ++{0x6456, 0x07}, ++{0x6457, 0x05}, ++{0x6458, 0x01}, ++{0x6459, 0xaf}, ++{0x645a, 0x01}, ++{0x645b, 0x0f}, ++{0x645c, 0x01}, ++{0x645d, 0x90}, ++{0x645e, 0x01}, ++{0x645f, 0xc8}, ++{0x6460, 0x00}, ++{0x6461, 0xff}, ++{0x6462, 0x01}, ++{0x6463, 0xac}, ++{0x6464, 0x01}, ++{0x6465, 0x0c}, ++{0x6466, 0x01}, ++{0x6467, 0x90}, ++{0x6468, 0x01}, ++{0x6469, 0xe8}, ++{0x646a, 0x00}, ++{0x646b, 0xff}, ++{0x646c, 0x01}, ++{0x646d, 0xad}, ++{0x646e, 0x01}, ++{0x646f, 0x0d}, ++{0x6470, 0x01}, ++{0x6471, 0x90}, ++{0x6472, 0x01}, ++{0x6473, 0xe8}, ++{0x6474, 0x00}, ++{0x6475, 0xff}, ++{0x6476, 0x01}, ++{0x6477, 0xae}, ++{0x6478, 0x01}, ++{0x6479, 0x0e}, ++{0x647a, 0x01}, ++{0x647b, 0x90}, ++{0x647c, 0x01}, ++{0x647d, 0xe8}, ++{0x647e, 0x00}, ++{0x647f, 0xff}, ++{0x6480, 0x01}, ++{0x6481, 0xb0}, ++{0x6482, 0x01}, ++{0x6483, 0xb1}, ++{0x6484, 0x01}, ++{0x6485, 0xb2}, ++{0x6486, 0x01}, ++{0x6487, 0xb3}, ++{0x6488, 0x01}, ++{0x6489, 0xb4}, ++{0x648a, 0x01}, ++{0x648b, 0xb5}, ++{0x648c, 0x01}, ++{0x648d, 0xb6}, ++{0x648e, 0x01}, ++{0x648f, 0xb7}, ++{0x6490, 0x01}, ++{0x6491, 0xb8}, ++{0x6492, 0x01}, ++{0x6493, 0xb9}, ++{0x6494, 0x01}, ++{0x6495, 0xba}, ++{0x6496, 0x01}, ++{0x6497, 0xbb}, ++{0x6498, 0x01}, ++{0x6499, 0xbc}, ++{0x649a, 0x01}, ++{0x649b, 0xbd}, ++{0x649c, 0x01}, ++{0x649d, 0xbe}, ++{0x649e, 0x01}, ++{0x649f, 0xbf}, ++{0x64a0, 0x01}, ++{0x64a1, 0xc0}, ++{0x64a2, 0x00}, ++{0x64a3, 0xff}, ++{0x64a4, 0x06}, ++{0x64a5, 0x00}, ++{0x64a6, 0x01}, ++{0x64a7, 0xf6}, ++{0x64a8, 0x04}, ++{0x64a9, 0x30}, ++{0x64aa, 0x00}, ++{0x64ab, 0xff}, ++{0x64ac, 0x06}, ++{0x64ad, 0x10}, ++{0x64ae, 0x01}, ++{0x64af, 0xf6}, ++{0x64b0, 0x04}, ++{0x64b1, 0x30}, ++{0x64b2, 0x06}, ++{0x64b3, 0x00}, ++{0x64b4, 0x00}, ++{0x64b5, 0xff}, ++{0x64b6, 0x06}, ++{0x64b7, 0x20}, ++{0x64b8, 0x01}, ++{0x64b9, 0xf6}, ++{0x64ba, 0x04}, ++{0x64bb, 0x30}, ++{0x64bc, 0x06}, ++{0x64bd, 0x00}, ++{0x64be, 0x00}, ++{0x64bf, 0xff}, ++{0x64c0, 0x04}, ++{0x64c1, 0x31}, ++{0x64c2, 0x04}, ++{0x64c3, 0x30}, ++{0x64c4, 0x01}, ++{0x64c5, 0x20}, ++{0x64c6, 0x01}, ++{0x64c7, 0x31}, ++{0x64c8, 0x01}, ++{0x64c9, 0x32}, ++{0x64ca, 0x01}, ++{0x64cb, 0x33}, ++{0x64cc, 0x01}, ++{0x64cd, 0x34}, ++{0x64ce, 0x01}, ++{0x64cf, 0x35}, ++{0x64d0, 0x01}, ++{0x64d1, 0x36}, ++{0x64d2, 0x01}, ++{0x64d3, 0x37}, ++{0x64d4, 0x01}, ++{0x64d5, 0x38}, ++{0x64d6, 0x01}, ++{0x64d7, 0x39}, ++{0x64d8, 0x01}, ++{0x64d9, 0x3a}, ++{0x64da, 0x01}, ++{0x64db, 0x3b}, ++{0x64dc, 0x01}, ++{0x64dd, 0x3c}, ++{0x64de, 0x01}, ++{0x64df, 0x3d}, ++{0x64e0, 0x01}, ++{0x64e1, 0x3e}, ++{0x64e2, 0x01}, ++{0x64e3, 0x3f}, ++{0x64e4, 0x02}, ++{0x64e5, 0xa0}, ++{0x64e6, 0x00}, ++{0x64e7, 0xff}, ++{0x64e8, 0x04}, ++{0x64e9, 0x31}, ++{0x64ea, 0x04}, ++{0x64eb, 0x30}, ++{0x64ec, 0x01}, ++{0x64ed, 0x00}, ++{0x64ee, 0x01}, ++{0x64ef, 0x11}, ++{0x64f0, 0x01}, ++{0x64f1, 0x12}, ++{0x64f2, 0x01}, ++{0x64f3, 0x13}, ++{0x64f4, 0x01}, ++{0x64f5, 0x14}, ++{0x64f6, 0x01}, ++{0x64f7, 0x15}, ++{0x64f8, 0x01}, ++{0x64f9, 0x16}, ++{0x64fa, 0x01}, ++{0x64fb, 0x17}, ++{0x64fc, 0x01}, ++{0x64fd, 0x18}, ++{0x64fe, 0x01}, ++{0x64ff, 0x19}, ++{0x6500, 0x01}, ++{0x6501, 0x1a}, ++{0x6502, 0x01}, ++{0x6503, 0x1b}, ++{0x6504, 0x01}, ++{0x6505, 0x1c}, ++{0x6506, 0x01}, ++{0x6507, 0x1d}, ++{0x6508, 0x01}, ++{0x6509, 0x1e}, ++{0x650a, 0x01}, ++{0x650b, 0x1f}, ++{0x650c, 0x02}, ++{0x650d, 0xa0}, ++{0x650e, 0x00}, ++{0x650f, 0xff}, ++{0x6510, 0x04}, ++{0x6511, 0x20}, ++{0x6512, 0x05}, ++{0x6513, 0x86}, ++{0x6514, 0x03}, ++{0x6515, 0x0b}, ++{0x6516, 0x05}, ++{0x6517, 0x86}, ++{0x6518, 0x00}, ++{0x6519, 0x00}, ++{0x651a, 0x05}, ++{0x651b, 0x06}, ++{0x651c, 0x00}, ++{0x651d, 0x04}, ++{0x651e, 0x05}, ++{0x651f, 0x04}, ++{0x6520, 0x00}, ++{0x6521, 0x04}, ++{0x6522, 0x05}, ++{0x6523, 0x00}, ++{0x6524, 0x05}, ++{0x6525, 0x0a}, ++{0x6526, 0x03}, ++{0x6527, 0x9a}, ++{0x6528, 0x05}, ++{0x6529, 0x86}, ++{0x652a, 0x00}, ++{0x652b, 0x00}, ++{0x652c, 0x05}, ++{0x652d, 0x06}, ++{0x652e, 0x00}, ++{0x652f, 0x01}, ++{0x6530, 0x05}, ++{0x6531, 0x04}, ++{0x6532, 0x00}, ++{0x6533, 0x04}, ++{0x6534, 0x05}, ++{0x6535, 0x00}, ++{0x6536, 0x05}, ++{0x6537, 0x0a}, ++{0x6538, 0x03}, ++{0x6539, 0x99}, ++{0x653a, 0x05}, ++{0x653b, 0x06}, ++{0x653c, 0x00}, ++{0x653d, 0x00}, ++{0x653e, 0x05}, ++{0x653f, 0x04}, ++{0x6540, 0x00}, ++{0x6541, 0x04}, ++{0x6542, 0x05}, ++{0x6543, 0x00}, ++{0x6544, 0x05}, ++{0x6545, 0x0a}, ++{0x6546, 0x03}, ++{0x6547, 0x98}, ++{0x6548, 0x05}, ++{0x6549, 0x06}, ++{0x654a, 0x00}, ++{0x654b, 0x00}, ++{0x654c, 0x05}, ++{0x654d, 0x04}, ++{0x654e, 0x00}, ++{0x654f, 0x04}, ++{0x6550, 0x05}, ++{0x6551, 0x00}, ++{0x6552, 0x05}, ++{0x6553, 0x0a}, ++{0x6554, 0x03}, ++{0x6555, 0x97}, ++{0x6556, 0x05}, ++{0x6557, 0x06}, ++{0x6558, 0x05}, ++{0x6559, 0x04}, ++{0x655a, 0x00}, ++{0x655b, 0x04}, ++{0x655c, 0x05}, ++{0x655d, 0x00}, ++{0x655e, 0x05}, ++{0x655f, 0x0a}, ++{0x6560, 0x03}, ++{0x6561, 0x96}, ++{0x6562, 0x05}, ++{0x6563, 0x06}, ++{0x6564, 0x05}, ++{0x6565, 0x04}, ++{0x6566, 0x00}, ++{0x6567, 0x04}, ++{0x6568, 0x05}, ++{0x6569, 0x00}, ++{0x656a, 0x05}, ++{0x656b, 0x0a}, ++{0x656c, 0x03}, ++{0x656d, 0x95}, ++{0x656e, 0x05}, ++{0x656f, 0x06}, ++{0x6570, 0x05}, ++{0x6571, 0x04}, ++{0x6572, 0x00}, ++{0x6573, 0x04}, ++{0x6574, 0x05}, ++{0x6575, 0x00}, ++{0x6576, 0x05}, ++{0x6577, 0x0a}, ++{0x6578, 0x03}, ++{0x6579, 0x94}, ++{0x657a, 0x05}, ++{0x657b, 0x06}, ++{0x657c, 0x00}, ++{0x657d, 0x00}, ++{0x657e, 0x05}, ++{0x657f, 0x04}, ++{0x6580, 0x00}, ++{0x6581, 0x04}, ++{0x6582, 0x05}, ++{0x6583, 0x00}, ++{0x6584, 0x05}, ++{0x6585, 0x0a}, ++{0x6586, 0x03}, ++{0x6587, 0x93}, ++{0x6588, 0x05}, ++{0x6589, 0x06}, ++{0x658a, 0x00}, ++{0x658b, 0x00}, ++{0x658c, 0x05}, ++{0x658d, 0x04}, ++{0x658e, 0x00}, ++{0x658f, 0x04}, ++{0x6590, 0x05}, ++{0x6591, 0x00}, ++{0x6592, 0x05}, ++{0x6593, 0x0a}, ++{0x6594, 0x03}, ++{0x6595, 0x92}, ++{0x6596, 0x05}, ++{0x6597, 0x06}, ++{0x6598, 0x05}, ++{0x6599, 0x04}, ++{0x659a, 0x00}, ++{0x659b, 0x04}, ++{0x659c, 0x05}, ++{0x659d, 0x00}, ++{0x659e, 0x05}, ++{0x659f, 0x0a}, ++{0x65a0, 0x03}, ++{0x65a1, 0x91}, ++{0x65a2, 0x05}, ++{0x65a3, 0x06}, ++{0x65a4, 0x05}, ++{0x65a5, 0x04}, ++{0x65a6, 0x00}, ++{0x65a7, 0x04}, ++{0x65a8, 0x05}, ++{0x65a9, 0x00}, ++{0x65aa, 0x05}, ++{0x65ab, 0x0a}, ++{0x65ac, 0x03}, ++{0x65ad, 0x90}, ++{0x65ae, 0x05}, ++{0x65af, 0x06}, ++{0x65b0, 0x05}, ++{0x65b1, 0x04}, ++{0x65b2, 0x00}, ++{0x65b3, 0x04}, ++{0x65b4, 0x05}, ++{0x65b5, 0x00}, ++{0x65b6, 0x05}, ++{0x65b7, 0x0a}, ++{0x65b8, 0x02}, ++{0x65b9, 0x90}, ++{0x65ba, 0x05}, ++{0x65bb, 0x06}, ++{0x65bc, 0x00}, ++{0x65bd, 0xff}, ++{0x65be, 0x04}, ++{0x65bf, 0x70}, ++{0x65c0, 0x08}, ++{0x65c1, 0x76}, ++{0x65c2, 0x00}, ++{0x65c3, 0xff}, ++{0x65c4, 0x08}, ++{0x65c5, 0x76}, ++{0x65c6, 0x04}, ++{0x65c7, 0x0c}, ++{0x65c8, 0x05}, ++{0x65c9, 0x07}, ++{0x65ca, 0x04}, ++{0x65cb, 0x04}, ++{0x65cc, 0x00}, ++{0x65cd, 0xff}, ++{0x65ce, 0x00}, ++{0x65cf, 0xff}, ++{0x65d0, 0x00}, ++{0x65d1, 0xff}, ++{0x30eb, 0x04}, ++{0x30ed, 0x5a}, ++{0x30ee, 0x01}, ++{0x30ef, 0x80}, ++{0x30f1, 0x5a}, ++{0x303a, 0x04}, ++{0x303b, 0x7f}, ++{0x303c, 0xfe}, ++{0x303d, 0x19}, ++{0x303e, 0xd7}, ++{0x303f, 0x09}, ++{0x3040, 0x78}, ++{0x3042, 0x05}, ++#if 0 ++{0x3012, 0x01}, ++{0x3012, 0x00}, ++{0x3119, 0x44}, ++{0x328a, 0x10}, ++{0x3012, 0x01}, ++#else ++{0x328a, 0x10}, ++/* HFLIP=1, VFLIP=0 */ ++{0x3128, 0xc0 | 0x1}, ++{0x3291, 0x01 | 0x2}, ++{0x3090, 0x4}, ++/* change settings to 1280x1080 COMB12 30 fps, 96MHz */ ++{0x3012, 0x0}, ++{0x3000, 0x3}, ++{0x3001, 0x50}, ++{0x3002, 0x0a}, ++{0x3004, 0x3}, ++{0x3005, 0x48}, ++{0x3006, 0x7}, ++{0x308f, 0x10}, ++{0x3127, 0x63}, ++{0x3074, OV10640_X_START >> 8}, ++{0x3075, OV10640_X_START & 0xff}, ++{0x3076, OV10640_Y_START >> 8}, ++{0x3077, OV10640_Y_START & 0xff}, ++{0x3078, OV10640_X_END >> 8}, ++{0x3079, OV10640_X_END & 0xff}, ++{0x307a, OV10640_Y_END >> 8}, ++{0x307b, OV10640_Y_END & 0xff}, ++{0x307c, OV10640_MAX_WIDTH >> 8}, ++{0x307d, OV10640_MAX_WIDTH & 0xff}, ++{0x307e, OV10640_MAX_HEIGHT >> 8}, ++{0x307f, OV10640_MAX_HEIGHT & 0xff}, ++{0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS ++{0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff}, ++{0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS ++{0x3083, (OV10640_SENSOR_HEIGHT + 208) & 0xff}, ++{0x3084, 0x0}, ++{0x3085, 0x0}, ++{0x3086, 0x0}, ++{0x3087, 0x0}, ++{0x346d, 0x14}, ++{0x3444, 0x28}, ++{0x3091, 0x0}, ++{0x3119, 0x44}, // COMB12 ++{0x3012, 0x1}, ++#endif ++}; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0460-media-ar0xxx-add-embedded-line-into-frame.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0460-media-ar0xxx-add-embedded-line-into-frame.patch new file mode 100644 index 00000000..67dfa466 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0460-media-ar0xxx-add-embedded-line-into-frame.patch @@ -0,0 +1,534 @@ +From 093694680d2fc99df1dc5118b78f80f34a0e3f4b Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 30 Dec 2019 19:48:34 +0300 +Subject: [PATCH] media: ar0xxx: add embedded line into frame + +This adds embedded line into frame for further parsing in ISP + +Signed-off-by: Petr Nechaev <petr.nechaev@cogentembedded.com> +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ar0140.c | 49 +++++++++++++++++++++---- + drivers/media/i2c/soc_camera/ar0140.h | 21 ++++++----- + drivers/media/i2c/soc_camera/ar0143.c | 53 +++++++++++++++++++++++++--- + drivers/media/i2c/soc_camera/ar0143.h | 17 +++++---- + drivers/media/i2c/soc_camera/ar0143_custom.h | 6 +--- + drivers/media/i2c/soc_camera/ar0143_rev1.h | 8 +---- + drivers/media/i2c/soc_camera/ar0220.h | 12 ++++--- + drivers/media/i2c/soc_camera/ar0233.c | 31 ++++++++++------ + drivers/media/i2c/soc_camera/ar0233.h | 12 ++++--- + drivers/media/i2c/soc_camera/ar0233_rev1.h | 2 +- + drivers/media/i2c/soc_camera/ar0233_rev2.h | 2 +- + 11 files changed, 150 insertions(+), 63 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ar0140.c b/drivers/media/i2c/soc_camera/ar0140.c +index ec2b2e5..ceb2c31 100644 +--- a/drivers/media/i2c/soc_camera/ar0140.c ++++ b/drivers/media/i2c/soc_camera/ar0140.c +@@ -36,6 +36,7 @@ struct ar0140_priv { + struct v4l2_rect rect; + int init_complete; + u8 id[6]; ++ bool emb_enable; + /* serializers */ + int max9286_addr; + int max9271_addr; +@@ -115,7 +116,7 @@ static int ar0140_set_window(struct v4l2_subdev *sd) + reg16_write16(client, 0x3008, priv->rect.left + priv->rect.width - 1 + AR0140_X_START); + /* vert crop start */ + reg16_write16(client, 0x3002, priv->rect.top + AR0140_Y_START); +- /* vert crop end */ ++ /* limit window for embedded data/stats */ + reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR0140_Y_START); + + return 0; +@@ -235,12 +236,18 @@ static int ar0140_get_selection(struct v4l2_subdev *sd, + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; +- sel->r.width = AR0140_MAX_WIDTH; +- sel->r.height = AR0140_MAX_HEIGHT; ++ sel->r.width = AR0140_DEFAULT_WIDTH; ++ sel->r.height = AR0140_DEFAULT_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r = priv->rect; + return 0; ++ case V4L2_SEL_TGT_COMPOSE_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = AR0140_EMB_PADDED; ++ sel->r.width = priv->rect.width; ++ sel->r.height = priv->rect.height; ++ return 0; + default: + return -EINVAL; + } +@@ -402,7 +409,35 @@ static ssize_t ar0140_otp_id_show(struct device *dev, + priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + } + ++static ssize_t ar0140_emb_enable_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0140_priv *priv = to_ar0140(client); ++ u32 val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ priv->emb_enable = !!val; ++ ++ reg16_write16(client, 0x3064, priv->emb_enable ? 0x1982 : 0x1802); ++ ++ return count; ++} ++ ++static ssize_t ar0140_emb_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0140_priv *priv = to_ar0140(client); ++ ++ return snprintf(buf, 4, "%d\n", priv->emb_enable); ++} ++ + static DEVICE_ATTR(otp_id_ar0140, S_IRUGO, ar0140_otp_id_show, NULL); ++static DEVICE_ATTR(emb_enable_ar0140, S_IRUGO|S_IWUSR, ar0140_emb_enable_show, ar0140_emb_enable_store); + + static int ar0140_initialize(struct i2c_client *client) + { +@@ -589,14 +624,15 @@ static int ar0140_probe(struct i2c_client *client, + + priv->rect.left = 0; + priv->rect.top = 0; +- priv->rect.width = AR0140_MAX_WIDTH; +- priv->rect.height = AR0140_MAX_HEIGHT; ++ priv->rect.width = AR0140_DEFAULT_WIDTH; ++ priv->rect.height = AR0140_DEFAULT_HEIGHT; + + ret = v4l2_async_register_subdev(&priv->sd); + if (ret) + goto cleanup; + +- if (device_create_file(&client->dev, &dev_attr_otp_id_ar0140) != 0) { ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ar0140) != 0 || ++ device_create_file(&client->dev, &dev_attr_emb_enable_ar0140) != 0) { + dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); + goto cleanup; + } +@@ -620,6 +656,7 @@ static int ar0140_remove(struct i2c_client *client) + { + struct ar0140_priv *priv = i2c_get_clientdata(client); + ++ device_remove_file(&client->dev, &dev_attr_emb_enable_ar0140); + device_remove_file(&client->dev, &dev_attr_otp_id_ar0140); + v4l2_async_unregister_subdev(&priv->sd); + media_entity_cleanup(&priv->sd.entity); +diff --git a/drivers/media/i2c/soc_camera/ar0140.h b/drivers/media/i2c/soc_camera/ar0140.h +index 2993478..08ce1ca 100644 +--- a/drivers/media/i2c/soc_camera/ar0140.h ++++ b/drivers/media/i2c/soc_camera/ar0140.h +@@ -12,20 +12,23 @@ + //#define AR0140_DISPLAY_PATTERN_FIXED + //#define AR0140_DISPLAY_PATTERN_COLOR_BAR + +-//#define AR0140_EMBEDDED_LINE ++#define AR0140_DEFAULT_WIDTH 1280 ++#define AR0140_DEFAULT_HEIGHT 800 + +-#define AR0140_MAX_WIDTH 1280 +-#define AR0140_MAX_HEIGHT 800 ++#define AR0140_EMB_LINES 4 ++#define AR0140_EMB_PADDED (priv->emb_enable ? AR0140_EMB_LINES + 30 : 0) /* embedded data (SOF) and stats (EOF) + post padding */ + + #define AR0140_DELAY 0xffff + ++#define AR0140_MAX_WIDTH 1280 ++#define AR0140_MAX_HEIGHT 800 + #define AR0140_SENSOR_WIDTH 1280 + #define AR0140_SENSOR_HEIGHT 800 + +-#define AR0140_X_START ((AR0140_SENSOR_WIDTH - AR0140_MAX_WIDTH) / 2) +-#define AR0140_Y_START ((AR0140_SENSOR_HEIGHT - AR0140_MAX_HEIGHT) / 2) +-#define AR0140_X_END (AR0140_X_START + AR0140_MAX_WIDTH - 1) +-#define AR0140_Y_END (AR0140_Y_START + AR0140_MAX_HEIGHT + 1) /* must be +1 and not -1 or 2 lines missed - bug in imager? */ ++#define AR0140_X_START ((AR0140_SENSOR_WIDTH - AR0140_DEFAULT_WIDTH) / 2) ++#define AR0140_Y_START ((AR0140_SENSOR_HEIGHT - AR0140_DEFAULT_HEIGHT) / 2) ++#define AR0140_X_END (AR0140_X_START + AR0140_DEFAULT_WIDTH - 1) ++#define AR0140_Y_END (AR0140_Y_START + AR0140_DEFAULT_HEIGHT + 1) /* must be +1 and not -1 or 2 lines missed - bug in imager? */ + + struct ar0140_reg { + u16 reg; +@@ -395,11 +398,7 @@ static const struct ar0140_reg ar0140_regs_wizard[] = { + {0x3086, 0x2C2C}, + {0x3086, 0x2C00}, + /* End Sequencer */ +-#ifdef AR0140_EMBEDDED_LINE +-{0x3064, 0x1982}, // SMIA_TEST +-#else + {0x3064, 0x1802}, // SMIA_TEST +-#endif + /* PCLK=27Mhz/0x2 *0x30 /1/0x10 - TI serializers */ + {0x302A, 0x0010}, // vt_pix_clk_div + {0x302E, 0x0002}, // pre_pll_clk_div +diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c +index 0c4b970..bf8d717 100644 +--- a/drivers/media/i2c/soc_camera/ar0143.c ++++ b/drivers/media/i2c/soc_camera/ar0143.c +@@ -38,6 +38,7 @@ struct ar0143_priv { + int init_complete; + u8 id[6]; + int setup; ++ bool emb_enable; + /* serializers */ + int max9286_addr; + int max9271_addr; +@@ -265,12 +270,18 @@ static int ar0143_get_selection(struct v4l2_subdev *sd, + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; +- sel->r.width = AR0143_MAX_WIDTH; +- sel->r.height = AR0143_MAX_HEIGHT; ++ sel->r.width = AR0143_DEFAULT_WIDTH; ++ sel->r.height = AR0143_DEFAULT_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r = priv->rect; + return 0; ++ case V4L2_SEL_TGT_COMPOSE_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = AR0143_EMB_PADDED; ++ sel->r.width = priv->rect.width; ++ sel->r.height = priv->rect.height; ++ return 0; + default: + return -EINVAL; + } +@@ -436,7 +449,35 @@ static ssize_t ar0143_otp_id_show(struct device *dev, + priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + } + ++static ssize_t ar0143_emb_enable_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0143_priv *priv = to_ar0143(client); ++ u32 val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ priv->emb_enable = !!val; ++ ++ reg16_write16(client, 0x3064, priv->emb_enable ? 0x1982 : 0x1802); ++ ++ return count; ++} ++ ++static ssize_t ar0143_emb_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0143_priv *priv = to_ar0143(client); ++ ++ return snprintf(buf, 4, "%d\n", priv->emb_enable); ++} ++ + static DEVICE_ATTR(otp_id_ar0143, S_IRUGO, ar0143_otp_id_show, NULL); ++static DEVICE_ATTR(emb_enable_ar0143, S_IRUGO|S_IWUSR, ar0143_emb_enable_show, ar0143_emb_enable_store); + + static int ar0143_initialize(struct i2c_client *client) + { +@@ -632,14 +673,15 @@ static int ar0143_probe(struct i2c_client *client, + + priv->rect.left = 0; + priv->rect.top = 0; +- priv->rect.width = AR0143_MAX_WIDTH; +- priv->rect.height = AR0143_MAX_HEIGHT; ++ priv->rect.width = AR0143_DEFAULT_WIDTH; ++ priv->rect.height = AR0143_DEFAULT_HEIGHT; + + ret = v4l2_async_register_subdev(&priv->sd); + if (ret) + goto cleanup; + +- if (device_create_file(&client->dev, &dev_attr_otp_id_ar0143) != 0) { ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ar0143) != 0|| ++ device_create_file(&client->dev, &dev_attr_emb_enable_ar0143) != 0) { + dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); + goto cleanup; + } +@@ -664,6 +706,7 @@ static int ar0143_remove(struct i2c_client *client) + struct ar0143_priv *priv = i2c_get_clientdata(client); + + device_remove_file(&client->dev, &dev_attr_otp_id_ar0143); ++ device_remove_file(&client->dev, &dev_attr_emb_enable_ar0143); + v4l2_async_unregister_subdev(&priv->sd); + media_entity_cleanup(&priv->sd.entity); + v4l2_ctrl_handler_free(&priv->hdl); +diff --git a/drivers/media/i2c/soc_camera/ar0143.h b/drivers/media/i2c/soc_camera/ar0143.h +index 14d8175..d14ecae 100644 +--- a/drivers/media/i2c/soc_camera/ar0143.h ++++ b/drivers/media/i2c/soc_camera/ar0143.h +@@ -12,20 +12,23 @@ + //#define AR0143_DISPLAY_PATTERN_FIXED + //#define AR0143_DISPLAY_PATTERN_COLOR_BAR + +-//#define AR0143_EMBEDDED_LINE ++#define AR0143_DEFAULT_WIDTH 1280 ++#define AR0143_DEFAULT_HEIGHT 960 + +-#define AR0143_MAX_WIDTH 1344 +-#define AR0143_MAX_HEIGHT 968 ++#define AR0143_EMB_LINES 8 ++#define AR0143_EMB_PADDED (priv->emb_enable ? AR0143_EMB_LINES + 30 : 0) /* embedded data (SOF) and stats (EOF) + post padding */ + + #define AR0143_DELAY 0xffff + ++#define AR0143_MAX_WIDTH 1344 ++#define AR0143_MAX_HEIGHT 968 + #define AR0143_SENSOR_WIDTH 1344 + #define AR0143_SENSOR_HEIGHT 968 + +-#define AR0143_X_START ((AR0143_SENSOR_WIDTH - AR0143_MAX_WIDTH) / 2) +-#define AR0143_Y_START ((AR0143_SENSOR_HEIGHT - AR0143_MAX_HEIGHT) / 2) +-#define AR0143_X_END (AR0143_X_START + AR0143_MAX_WIDTH - 1) +-#define AR0143_Y_END (AR0143_Y_START + AR0143_MAX_HEIGHT + 1) /* must be +1 and not -1 or 2 lines missed - bug in imager? */ ++#define AR0143_X_START ((AR0143_SENSOR_WIDTH - AR0143_DEFAULT_WIDTH) / 2) ++#define AR0143_Y_START ((AR0143_SENSOR_HEIGHT - AR0143_DEFAULT_HEIGHT) / 2) ++#define AR0143_X_END (AR0143_X_START + AR0143_DEFAULT_WIDTH - 1) ++#define AR0143_Y_END (AR0143_Y_START + AR0143_DEFAULT_HEIGHT + 1) /* must be +1 and not -1 or 2 lines missed - bug in imager? */ + + struct ar0143_reg { + u16 reg; +diff --git a/drivers/media/i2c/soc_camera/ar0143_custom.h b/drivers/media/i2c/soc_camera/ar0143_custom.h +index e5bc37a..8e21416 100644 +--- a/drivers/media/i2c/soc_camera/ar0143_custom.h ++++ b/drivers/media/i2c/soc_camera/ar0143_custom.h +@@ -368,11 +368,7 @@ static const struct ar0143_reg ar0143_regs_wizard_custom[] = { + {0x3180, 0x0080}, // RESERVED_MFR_3180 + {0x33E4, 0x0080}, // RESERVED_MFR_33E4 + {0x33E0, 0x0880}, // TEST_ASIL_ROWS +-#ifdef AR0143_EMBEDDED_LINE +-{0x3064, 0x1982}, // SMIA_TEST +-#else + {0x3064, 0x1802}, // SMIA_TEST +-#endif + {0x3004, 0x0000}, // X_ADDR_START_ + {0x3008, 0x053F}, // X_ADDR_END_ + {0x3002, 0x0000}, // Y_ADDR_START_ +@@ -455,7 +451,7 @@ static const struct ar0143_reg ar0143_regs_wizard_custom[] = { + {0x31B8, 0x404B}, // RESERVED_MFR_31B8 + {0x31BA, 0x020A}, // RESERVED_MFR_31BA + {0x31BC, 0x0C08}, // RESERVED_MFR_31BC +-{0x3040, 0x0000}, // READ_MODE ++{0x3040, 0x0005}, // READ_MODE + {0x30BA, 0x01E2}, // DIGITAL_CTRL + {0x3082, 0x0008}, // OPERATION_MODE_CTRL + {0x3044, 0x0400}, // DARK_CONTROL +diff --git a/drivers/media/i2c/soc_camera/ar0143_rev1.h b/drivers/media/i2c/soc_camera/ar0143_rev1.h +index ec941d8..21cb4bf 100644 +--- a/drivers/media/i2c/soc_camera/ar0143_rev1.h ++++ b/drivers/media/i2c/soc_camera/ar0143_rev1.h +@@ -390,7 +390,7 @@ static const struct ar0143_reg ar0143_regs_wizard_rev1[] = { + #ifdef AR0143_Readout_Mode_Configuration + {0x30A2, 0x0001}, // X_ODD_INC_ + {0x30A6, 0x0001}, // Y_ODD_INC_ +-{0x3040, 0x0000}, // READ_MODE ++{0x3040, 0x0005}, // READ_MODE + {0x3082, 0x0008}, // OPERATION_MODE_CTRL: 3exp + {0x30BA, 0x01E2}, // DIGITAL_CTRL: 3exp max + {0x3044, 0x0400}, // DARK_CONTROL +@@ -400,12 +400,6 @@ static const struct ar0143_reg ar0143_regs_wizard_rev1[] = { + {0x33E4, 0x0080}, // RESERVED_MFR_33E4 + #endif /* AR0143_Readout_Mode_Configuration */ + +-#ifdef AR0143_HDR_Readout_Mode_Configuration +-#ifdef AR0143_EMBEDDED_LINE +-{0x3064, 0x1982}, // SMIA_TEST: enable emb data and stats +-#endif +-#endif /* AR0143_HDR_Readout_Mode_Configuration */ +- + #ifdef AR0143_Full_Res_FOV + {0x31B0, 0x0006}, // FRAME_PREAMBLE + {0x31B2, 0x0045}, // LINE_PREAMBLE +diff --git a/drivers/media/i2c/soc_camera/ar0220.h b/drivers/media/i2c/soc_camera/ar0220.h +index 59a949e..f90deae 100644 +--- a/drivers/media/i2c/soc_camera/ar0220.h ++++ b/drivers/media/i2c/soc_camera/ar0220.h +@@ -12,16 +12,18 @@ + //#define AR0220_DISPLAY_PATTERN_FIXED + //#define AR0220_DISPLAY_PATTERN_COLOR_BAR + ++#define AR0220_DEFAULT_WIDTH 1792 ++#define AR0220_DEFAULT_HEIGHT 944 ++ + #define AR0220_MAX_WIDTH 1828 + #define AR0220_MAX_HEIGHT 948 +- + #define AR0220_SENSOR_WIDTH 1828 + #define AR0220_SENSOR_HEIGHT 948 + +-#define AR0220_X_START ((AR0220_SENSOR_WIDTH - AR0220_MAX_WIDTH) / 2) +-#define AR0220_Y_START ((AR0220_SENSOR_HEIGHT - AR0220_MAX_HEIGHT) / 2) +-#define AR0220_X_END (AR0220_X_START + AR0220_MAX_WIDTH - 1) +-#define AR0220_Y_END (AR0220_Y_START + AR0220_MAX_HEIGHT - 1) ++#define AR0220_X_START ((AR0220_SENSOR_WIDTH - AR0220_DEFAULT_WIDTH) / 2) ++#define AR0220_Y_START ((AR0220_SENSOR_HEIGHT - AR0220_DEFAULT_HEIGHT) / 2) ++#define AR0220_X_END (AR0220_X_START + AR0220_DEFAULT_WIDTH - 1) ++#define AR0220_Y_END (AR0220_Y_START + AR0220_DEFAULT_HEIGHT - 1) + + #include "ar0220_rev2.h" + #include "ar0220_rev3.h" +diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c +index b62fb77..cdd2d8a 100644 +--- a/drivers/media/i2c/soc_camera/ar0233.c ++++ b/drivers/media/i2c/soc_camera/ar0233.c +@@ -21,9 +21,10 @@ + #include <media/v4l2-ctrls.h> + + #define AR_DELAY 0xffff +-static int AR_MAX_WIDTH; +-static int AR_MAX_HEIGHT; +-#define AR_MAX_HEIGHT_EMB (AR_MAX_HEIGHT + priv->emb_enable * 4) /* embedded data (SOF) and stats (EOF) */ ++static int AR_MAX_WIDTH, AR_DEFAULT_WIDTH; ++static int AR_MAX_HEIGHT, AR_DEFAULT_HEIGHT; ++#define AR_EMB_LINES 8 ++#define AR_EMB_PADDED (priv->emb_enable ? AR_EMB_LINES : 0) /* embedded data (SOF) and stats (EOF) */ + static int AR_X_START; + static int AR_Y_START; + static int AR_X_END; +@@ -124,7 +125,7 @@ static int ar0233_set_window(struct v4l2_subdev *sd) + reg16_write16(client, 0x3002, priv->rect.top + AR_Y_START); + /* vert crop end */ + /* limit window for embedded data/stats */ +- reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START - priv->emb_enable * 4); ++ reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START); + + return 0; + }; +@@ -210,7 +211,7 @@ static int ar0233_set_selection(struct v4l2_subdev *sd, + rect->height = ALIGN(rect->height, 2); + + if ((rect->left + rect->width > AR_MAX_WIDTH) || +- (rect->top + rect->height > AR_MAX_HEIGHT_EMB)) ++ (rect->top + rect->height > AR_MAX_HEIGHT)) + *rect = priv->rect; + + priv->rect.left = rect->left; +@@ -238,17 +239,23 @@ static int ar0233_get_selection(struct v4l2_subdev *sd, + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = AR_MAX_WIDTH; +- sel->r.height = AR_MAX_HEIGHT_EMB; ++ sel->r.height = AR_MAX_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; +- sel->r.width = AR_MAX_WIDTH; +- sel->r.height = AR_MAX_HEIGHT_EMB; ++ sel->r.width = AR_DEFAULT_WIDTH; ++ sel->r.height = AR_DEFAULT_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r = priv->rect; + return 0; ++ case V4L2_SEL_TGT_COMPOSE_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = AR_EMB_PADDED; ++ sel->r.width = priv->rect.width; ++ sel->r.height = priv->rect.height; ++ return 0; + default: + return -EINVAL; + } +@@ -496,6 +503,8 @@ static int ar0233_initialize(struct i2c_client *client) + strncpy(chip_name, "AR0220", 10); + AR_MAX_WIDTH = AR0220_MAX_WIDTH; + AR_MAX_HEIGHT = AR0220_MAX_HEIGHT; ++ AR_DEFAULT_WIDTH = AR0220_DEFAULT_WIDTH; ++ AR_DEFAULT_HEIGHT = AR0220_DEFAULT_HEIGHT; + AR_X_START = AR0220_X_START; + AR_Y_START = AR0220_Y_START; + AR_X_END = AR0220_X_END; +@@ -532,6 +541,8 @@ static int ar0233_initialize(struct i2c_client *client) + strncpy(chip_name, "AR0233", 10); + AR_MAX_WIDTH = AR0233_MAX_WIDTH; + AR_MAX_HEIGHT = AR0233_MAX_HEIGHT; ++ AR_DEFAULT_WIDTH = AR0233_DEFAULT_WIDTH; ++ AR_DEFAULT_HEIGHT = AR0233_DEFAULT_HEIGHT; + AR_X_START = AR0233_X_START; + AR_Y_START = AR0233_Y_START; + AR_X_END = AR0233_X_END; +@@ -693,8 +704,8 @@ static int ar0233_probe(struct i2c_client *client, + + priv->rect.left = 0; + priv->rect.top = 0; +- priv->rect.width = AR_MAX_WIDTH; +- priv->rect.height = AR_MAX_HEIGHT; ++ priv->rect.width = AR_DEFAULT_WIDTH; ++ priv->rect.height = AR_DEFAULT_HEIGHT; + + ret = v4l2_async_register_subdev(&priv->sd); + if (ret) +diff --git a/drivers/media/i2c/soc_camera/ar0233.h b/drivers/media/i2c/soc_camera/ar0233.h +index 33b661a..cb79421 100644 +--- a/drivers/media/i2c/soc_camera/ar0233.h ++++ b/drivers/media/i2c/soc_camera/ar0233.h +@@ -12,16 +12,18 @@ + //#define AR0233_DISPLAY_PATTERN_FIXED + //#define AR0233_DISPLAY_PATTERN_COLOR_BAR + ++#define AR0233_DEFAULT_WIDTH 2048 ++#define AR0233_DEFAULT_HEIGHT 1280 ++ + #define AR0233_MAX_WIDTH 2048 + #define AR0233_MAX_HEIGHT 1280 +- + #define AR0233_SENSOR_WIDTH 2072 + #define AR0233_SENSOR_HEIGHT 1296 + +-#define AR0233_X_START ((AR0233_SENSOR_WIDTH - AR0233_MAX_WIDTH) / 2) +-#define AR0233_Y_START ((AR0233_SENSOR_HEIGHT - AR0233_MAX_HEIGHT) / 2) +-#define AR0233_X_END (AR0233_X_START + AR0233_MAX_WIDTH - 1) +-#define AR0233_Y_END (AR0233_Y_START + AR0233_MAX_HEIGHT - 1) ++#define AR0233_X_START ((AR0233_SENSOR_WIDTH - AR0233_DEFAULT_WIDTH) / 2) ++#define AR0233_Y_START ((AR0233_SENSOR_HEIGHT - AR0233_DEFAULT_HEIGHT) / 2) ++#define AR0233_X_END (AR0233_X_START + AR0233_DEFAULT_WIDTH - 1) ++#define AR0233_Y_END (AR0233_Y_START + AR0233_DEFAULT_HEIGHT - 1) + + #include "ar0233_rev1.h" + #include "ar0233_rev2.h" +diff --git a/drivers/media/i2c/soc_camera/ar0233_rev1.h b/drivers/media/i2c/soc_camera/ar0233_rev1.h +index 3ff944f..8b9638b 100644 +--- a/drivers/media/i2c/soc_camera/ar0233_rev1.h ++++ b/drivers/media/i2c/soc_camera/ar0233_rev1.h +@@ -1156,7 +1156,7 @@ static const struct ar0xxx_reg ar0233_rev1_Full_resolution[] = { + }; /* Full_resolution */ + + static const struct ar0xxx_reg ar0233_rev1_disable_embed_data_stat[] = { +-{0x3040, 0xC000}, //Embedded stat2 and data2 rows, hflip/vflip=1 ++{0x3040, 0xC005}, //Embedded stat4 and data4 rows, hflip/vflip=1 + #ifdef AR0233_EMBEDDED_LINE + {0x3064, 0x0180}, //Enable embedded data and stat + #else +diff --git a/drivers/media/i2c/soc_camera/ar0233_rev2.h b/drivers/media/i2c/soc_camera/ar0233_rev2.h +index 80572ff..bd508f0 100644 +--- a/drivers/media/i2c/soc_camera/ar0233_rev2.h ++++ b/drivers/media/i2c/soc_camera/ar0233_rev2.h +@@ -2265,7 +2265,7 @@ static const struct ar0xxx_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[ + }; /* O1_Recommended_Defaults_SE_T1_LIN_T2 */ + + static const struct ar0xxx_reg ar0233_rev2_disable_embed_data_stat[] = { +-{0x3040, 0xC000}, //Embedded stat2 and data2 rows, hflip/vflip=1 ++{0x3040, 0xC005}, //Embedded stat4 and data4 rows, hflip/vflip=1 + {0x350e, 0x2089}, // bit0 must be set for vflip=1 + #ifdef AR0233_EMBEDDED_LINE + {0x3064, 0x0180}, // SMIA_TEST: enable emb data and stats +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0461-v3hsk-Add-separate-dts-for-dummy-camera-1920x1080.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0461-v3hsk-Add-separate-dts-for-dummy-camera-1920x1080.patch new file mode 100644 index 00000000..a34231f6 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0461-v3hsk-Add-separate-dts-for-dummy-camera-1920x1080.patch @@ -0,0 +1,132 @@ +From 193b183e75deb047c60196e987b3112e134abe17 Mon Sep 17 00:00:00 2001 +From: Petr Nechaev <petr.nechaev@cogentembedded.com> +Date: Thu, 13 Jun 2019 21:20:25 -0400 +Subject: [PATCH] v3hsk: Add separate dts for dummy camera 1920x1080 + +To be used as LVDS -> HDMI converter. +--- + arch/arm64/boot/dts/renesas/Makefile | 1 + + .../renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts | 46 +++++++++++++++++++ + .../renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts | 46 +++++++++++++++++++ + 3 files changed, 93 insertions(+) + create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts + create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts + +diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile +index 4b2f4fb73bed..89da50cbfbdb 100644 +--- a/arch/arm64/boot/dts/renesas/Makefile ++++ b/arch/arm64/boot/dts/renesas/Makefile +@@ -42,5 +42,6 @@ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v2.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-8ch.dtb r8a77980-v3hsk-vb-4ch.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl-8ch.dtb ++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-4ch-hdmi.dtb r8a77980-v3hsk-vb-8ch-hdmi.dtb + + always := $(dtb-y) +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts +new file mode 100644 +index 000000000000..f5931c5d3ef6 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts +@@ -0,0 +1,46 @@ ++/* ++ * Device Tree Source for the V3HSK VideoBox 4-channel board on r8a7798 with dummy LVDS input ++ * ++ * Copyright (C) 2018 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "r8a77980-v3hsk-vb-4ch.dts" ++ ++&i2cswitch1 { ++ i2c@2 { ++ /delete-node/ ov106xx@0; ++ ++ dummy-camera@0 { ++ compatible = "dummy-camera"; ++ reg = <0x60>; ++ ++ dummy,width = <1920>; ++ dummy,height = <1080>; ++ ++ port@0 { ++ dummy_camera_in0: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin0ep0>; ++ }; ++ }; ++ port@1 { ++ dummy_camera_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&ti9x4_des0ep0 { ++ remote-endpoint = <&dummy_camera_in0>; ++}; ++ ++&vin0ep0 { ++ remote-endpoint = <&dummy_camera_in0>; ++}; +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts +new file mode 100644 +index 000000000000..5aecc0e80cde +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts +@@ -0,0 +1,46 @@ ++/* ++ * Device Tree Source for the V3HSK VideoBox 8-channel board on r8a7798 with dummy LVDS input ++ * ++ * Copyright (C) 2018 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "r8a77980-v3hsk-vb-8ch.dts" ++ ++&i2cswitch1 { ++ i2c@2 { ++ /delete-node/ ov106xx@0; ++ ++ dummy-camera@0 { ++ compatible = "dummy-camera"; ++ reg = <0x60>; ++ ++ dummy,width = <1920>; ++ dummy,height = <1080>; ++ ++ port@0 { ++ dummy_camera_in0: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin0ep0>; ++ }; ++ }; ++ port@1 { ++ dummy_camera_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&ti9x4_des0ep0 { ++ remote-endpoint = <&dummy_camera_in0>; ++}; ++ ++&vin0ep0 { ++ remote-endpoint = <&dummy_camera_in0>; ++}; +-- +2.20.1 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0462-media-i2c-ov10640-add-embedded-data-fix-crop.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0462-media-i2c-ov10640-add-embedded-data-fix-crop.patch new file mode 100644 index 00000000..683ee130 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0462-media-i2c-ov10640-add-embedded-data-fix-crop.patch @@ -0,0 +1,289 @@ +From 0f0c2244b6ed65807d40b8cf730d297e1218600e Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 13 Jan 2020 19:01:29 +0300 +Subject: [PATCH] media: i2c: ov10640: add embedded data, fix crop + +This addes embedded line and stats for furhter parsing inside ISP +This also fixes the crop. + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov10640.c | 79 ++++++++++++++++++++++++------ + drivers/media/i2c/soc_camera/ov10640.h | 17 ++++--- + drivers/media/i2c/soc_camera/ov10640_r1d.h | 10 ++-- + drivers/media/i2c/soc_camera/ov10640_r1e.h | 10 ++-- + drivers/media/i2c/soc_camera/ov10640_r1f.h | 10 ++-- + 5 files changed, 89 insertions(+), 37 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c +index 40058b7..fab2c0d 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.c ++++ b/drivers/media/i2c/soc_camera/ov10640.c +@@ -42,6 +42,7 @@ struct ov10640_priv { + int init_complete; + u8 id[6]; + int dvp_order; ++ bool emb_enable; + /* serializers */ + int max9286_addr; + int max9271_addr; +@@ -113,23 +114,23 @@ static int ov10640_set_window(struct v4l2_subdev *sd) + dev_dbg(&client->dev, "L=%d T=%d %dx%d\n", priv->rect.left, priv->rect.top, priv->rect.width, priv->rect.height); + + /* horiz crop start (reverse) */ +- reg16_write(client, 0x3074, (OV10640_MAX_WIDTH - priv->rect.width - priv->rect.left) >> 8); +- reg16_write(client, 0x3075, (OV10640_MAX_WIDTH - priv->rect.width - priv->rect.left) & 0xff); ++ reg16_write(client, 0x3074, (OV10640_X_END - priv->rect.left - priv->rect.width + 1) >> 8); ++ reg16_write(client, 0x3075, (OV10640_X_END - priv->rect.left - priv->rect.width + 1) & 0xff); + /* horiz crop end (reverse) */ +- reg16_write(client, 0x3078, (OV10640_MAX_WIDTH - priv->rect.left - 1) >> 8); +- reg16_write(client, 0x3079, (OV10640_MAX_WIDTH - priv->rect.left - 1) & 0xff); ++ reg16_write(client, 0x3078, (OV10640_X_END - priv->rect.left) >> 8); ++ reg16_write(client, 0x3079, (OV10640_X_END - priv->rect.left) & 0xff); + /* vert crop start */ +- reg16_write(client, 0x3076, priv->rect.top >> 8); +- reg16_write(client, 0x3077, priv->rect.top & 0xff); ++ reg16_write(client, 0x3076, (priv->rect.top + OV10640_Y_START - OV10640_EMB_PADDED / 2) >> 8); ++ reg16_write(client, 0x3077, (priv->rect.top + OV10640_Y_START - OV10640_EMB_PADDED / 2) & 0xff); + /* vert crop end */ +- reg16_write(client, 0x307a, (priv->rect.top + priv->rect.height + 1) >> 8); +- reg16_write(client, 0x307b, (priv->rect.top + priv->rect.height + 1) & 0xff); ++ reg16_write(client, 0x307a, (priv->rect.top + priv->rect.height + OV10640_Y_START - 1 + OV10640_EMB_PADDED / 2) >> 8); ++ reg16_write(client, 0x307b, (priv->rect.top + priv->rect.height + OV10640_Y_START - 1 + OV10640_EMB_PADDED / 2) & 0xff); + /* horiz output */ + reg16_write(client, 0x307c, priv->rect.width >> 8); + reg16_write(client, 0x307d, priv->rect.width & 0xff); + /* vert output */ +- reg16_write(client, 0x307e, priv->rect.height >> 8); +- reg16_write(client, 0x307f, priv->rect.height & 0xff); ++ reg16_write(client, 0x307e, (priv->rect.height + OV10640_EMB_PADDED) >> 8); ++ reg16_write(client, 0x307f, (priv->rect.height + OV10640_EMB_PADDED) & 0xff); + + return 0; + }; +@@ -248,12 +249,18 @@ static int ov10640_get_selection(struct v4l2_subdev *sd, + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; +- sel->r.width = OV10640_MAX_WIDTH; +- sel->r.height = OV10640_MAX_HEIGHT; ++ sel->r.width = OV10640_DEFAULT_WIDTH; ++ sel->r.height = OV10640_DEFAULT_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r = priv->rect; + return 0; ++ case V4L2_SEL_TGT_COMPOSE_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = OV10640_EMB_PADDED / 2; ++ sel->r.width = priv->rect.width; ++ sel->r.height = priv->rect.height; ++ return 0; + default: + return -EINVAL; + } +@@ -464,7 +471,45 @@ static ssize_t ov10640_otp_id_show(struct device *dev, + priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + } + ++static ssize_t ov10640_emb_enable_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10640_priv *priv = to_ov10640(client); ++ u32 val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ priv->emb_enable = !!val; ++ ++ /* vert crop start */ ++ reg16_write(client, 0x3076, (priv->rect.top + OV10640_Y_START - OV10640_EMB_PADDED / 2) >> 8); ++ reg16_write(client, 0x3077, (priv->rect.top + OV10640_Y_START - OV10640_EMB_PADDED / 2) & 0xff); ++ /* vert crop end */ ++ reg16_write(client, 0x307a, (priv->rect.top + priv->rect.height - 1 + OV10640_Y_START + OV10640_EMB_PADDED / 2) >> 8); ++ reg16_write(client, 0x307b, (priv->rect.top + priv->rect.height - 1 + OV10640_Y_START + OV10640_EMB_PADDED / 2) & 0xff); ++ /* vert output */ ++ reg16_write(client, 0x307e, (priv->rect.height + OV10640_EMB_PADDED) >> 8); ++ reg16_write(client, 0x307f, (priv->rect.height + OV10640_EMB_PADDED) & 0xff); ++ ++ reg16_write(client, 0x3091, priv->emb_enable ? 0x0C : 0x00); ++ ++ return count; ++} ++ ++static ssize_t ov10640_emb_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10640_priv *priv = to_ov10640(client); ++ ++ return snprintf(buf, 4, "%d\n", priv->emb_enable); ++} ++ + static DEVICE_ATTR(otp_id_ov10640, S_IRUGO, ov10640_otp_id_show, NULL); ++static DEVICE_ATTR(emb_enable_ov10640, S_IRUGO|S_IWUSR, ov10640_emb_enable_show, ov10640_emb_enable_store); + + static int ov10640_initialize(struct i2c_client *client) + { +@@ -510,7 +555,7 @@ static int ov10640_initialize(struct i2c_client *client) + reg16_write(client, 0x3124, priv->dvp_order << 4); + + dev_info(&client->dev, "ov10640 PID %x (r%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", +- pid, rev, OV10640_MAX_WIDTH, OV10640_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ pid, rev, OV10640_DEFAULT_WIDTH, OV10640_DEFAULT_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + out: + ov10640_s_port(client, 0); + +@@ -596,8 +641,8 @@ static int ov10640_probe(struct i2c_client *client, + priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + priv->rect.left = 0; + priv->rect.top = 0; +- priv->rect.width = OV10640_MAX_WIDTH; +- priv->rect.height = OV10640_MAX_HEIGHT; ++ priv->rect.width = OV10640_DEFAULT_WIDTH; ++ priv->rect.height = OV10640_DEFAULT_HEIGHT; + priv->fps_denominator = 30; + + v4l2_ctrl_handler_init(&priv->hdl, 4); +@@ -653,7 +698,8 @@ static int ov10640_probe(struct i2c_client *client, + if (ret) + goto cleanup; + +- if (device_create_file(&client->dev, &dev_attr_otp_id_ov10640) != 0) { ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov10640) != 0|| ++ device_create_file(&client->dev, &dev_attr_emb_enable_ov10640) != 0) { + dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); + goto cleanup; + } +@@ -678,6 +724,7 @@ static int ov10640_remove(struct i2c_client *client) + struct ov10640_priv *priv = i2c_get_clientdata(client); + + device_remove_file(&client->dev, &dev_attr_otp_id_ov10640); ++ device_remove_file(&client->dev, &dev_attr_emb_enable_ov10640); + v4l2_async_unregister_subdev(&priv->sd); + media_entity_cleanup(&priv->sd.entity); + v4l2_ctrl_handler_free(&priv->hdl); +diff --git a/drivers/media/i2c/soc_camera/ov10640.h b/drivers/media/i2c/soc_camera/ov10640.h +index 3d2de3d..04ff326 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.h ++++ b/drivers/media/i2c/soc_camera/ov10640.h +@@ -12,18 +12,23 @@ + //#define OV10640_DISPLAY_PATTERN + #define OV10640_FSIN_ENABLE + +-#define OV10640_MAX_WIDTH 1280 +-#define OV10640_MAX_HEIGHT 1080 ++#define OV10640_DEFAULT_WIDTH 1280 ++#define OV10640_DEFAULT_HEIGHT 1080 ++ ++#define OV10640_EMB_LINES 4 /* 2 emb lines at top and 2 stat lines at bottom */ ++#define OV10640_EMB_PADDED (priv->emb_enable ? OV10640_EMB_LINES : 0) /* embedded data (SOF) and stats (EOF) */ + + #define OV10640_DELAY 0xffff + ++#define OV10640_MAX_WIDTH 1280 ++#define OV10640_MAX_HEIGHT 1080 + #define OV10640_SENSOR_WIDTH 1292 + #define OV10640_SENSOR_HEIGHT 1092 + +-#define OV10640_X_START ((OV10640_SENSOR_WIDTH - OV10640_MAX_WIDTH) / 2) +-#define OV10640_Y_START ((OV10640_SENSOR_HEIGHT - OV10640_MAX_HEIGHT) / 2) +-#define OV10640_X_END (OV10640_X_START + OV10640_MAX_WIDTH - 1) +-#define OV10640_Y_END (OV10640_Y_START + OV10640_MAX_HEIGHT - 1) ++#define OV10640_X_START ((OV10640_SENSOR_WIDTH - OV10640_DEFAULT_WIDTH) / 2) ++#define OV10640_Y_START ((OV10640_SENSOR_HEIGHT - OV10640_DEFAULT_HEIGHT) / 2) ++#define OV10640_X_END (OV10640_X_START + OV10640_DEFAULT_WIDTH - 1) ++#define OV10640_Y_END (OV10640_Y_START + OV10640_DEFAULT_HEIGHT - 1) + + struct ov10640_reg { + u16 reg; +diff --git a/drivers/media/i2c/soc_camera/ov10640_r1d.h b/drivers/media/i2c/soc_camera/ov10640_r1d.h +index 374b6d1..6f29b01 100644 +--- a/drivers/media/i2c/soc_camera/ov10640_r1d.h ++++ b/drivers/media/i2c/soc_camera/ov10640_r1d.h +@@ -1219,10 +1219,10 @@ static const struct ov10640_reg ov10640_regs_wizard_r1d[] = { + {0x3079, OV10640_X_END & 0xff}, + {0x307a, OV10640_Y_END >> 8}, + {0x307b, OV10640_Y_END & 0xff}, +-{0x307c, OV10640_MAX_WIDTH >> 8}, +-{0x307d, OV10640_MAX_WIDTH & 0xff}, +-{0x307e, OV10640_MAX_HEIGHT >> 8}, +-{0x307f, OV10640_MAX_HEIGHT & 0xff}, ++{0x307c, OV10640_DEFAULT_WIDTH >> 8}, ++{0x307d, OV10640_DEFAULT_WIDTH & 0xff}, ++{0x307e, OV10640_DEFAULT_HEIGHT >> 8}, ++{0x307f, OV10640_DEFAULT_HEIGHT & 0xff}, + {0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS + {0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff}, + {0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS +@@ -1233,7 +1233,7 @@ static const struct ov10640_reg ov10640_regs_wizard_r1d[] = { + {0x3087, 0x0}, + {0x346d, 0x14}, + {0x3444, 0x28}, +-{0x3091, 0x0}, ++{0x3091, 0x00}, // embedded data, embedded stats + {0x3119, 0x44}, // COMB12 + {0x3012, 0x1}, + #endif +diff --git a/drivers/media/i2c/soc_camera/ov10640_r1e.h b/drivers/media/i2c/soc_camera/ov10640_r1e.h +index eeff330..ba3c636 100644 +--- a/drivers/media/i2c/soc_camera/ov10640_r1e.h ++++ b/drivers/media/i2c/soc_camera/ov10640_r1e.h +@@ -1214,10 +1214,10 @@ static const struct ov10640_reg ov10640_regs_wizard_r1e[] = { + {0x3079, OV10640_X_END & 0xff}, + {0x307a, OV10640_Y_END >> 8}, + {0x307b, OV10640_Y_END & 0xff}, +-{0x307c, OV10640_MAX_WIDTH >> 8}, +-{0x307d, OV10640_MAX_WIDTH & 0xff}, +-{0x307e, OV10640_MAX_HEIGHT >> 8}, +-{0x307f, OV10640_MAX_HEIGHT & 0xff}, ++{0x307c, OV10640_DEFAULT_WIDTH >> 8}, ++{0x307d, OV10640_DEFAULT_WIDTH & 0xff}, ++{0x307e, OV10640_DEFAULT_HEIGHT >> 8}, ++{0x307f, OV10640_DEFAULT_HEIGHT & 0xff}, + {0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS + {0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff}, + {0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS +@@ -1228,7 +1228,7 @@ static const struct ov10640_reg ov10640_regs_wizard_r1e[] = { + {0x3087, 0x0}, + {0x346d, 0x14}, + {0x3444, 0x28}, +-{0x3091, 0x0}, ++{0x3091, 0x00}, // embedded data, embedded stats + {0x3119, 0x44}, // COMB12 + {0x3012, 0x1}, + #endif +diff --git a/drivers/media/i2c/soc_camera/ov10640_r1f.h b/drivers/media/i2c/soc_camera/ov10640_r1f.h +index ef866fa..3f9b3f5 100644 +--- a/drivers/media/i2c/soc_camera/ov10640_r1f.h ++++ b/drivers/media/i2c/soc_camera/ov10640_r1f.h +@@ -1177,10 +1177,10 @@ static const struct ov10640_reg ov10640_regs_wizard_r1f[] = { + {0x3079, OV10640_X_END & 0xff}, + {0x307a, OV10640_Y_END >> 8}, + {0x307b, OV10640_Y_END & 0xff}, +-{0x307c, OV10640_MAX_WIDTH >> 8}, +-{0x307d, OV10640_MAX_WIDTH & 0xff}, +-{0x307e, OV10640_MAX_HEIGHT >> 8}, +-{0x307f, OV10640_MAX_HEIGHT & 0xff}, ++{0x307c, OV10640_DEFAULT_WIDTH >> 8}, ++{0x307d, OV10640_DEFAULT_WIDTH & 0xff}, ++{0x307e, OV10640_DEFAULT_HEIGHT >> 8}, ++{0x307f, OV10640_DEFAULT_HEIGHT & 0xff}, + {0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS + {0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff}, + {0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS +@@ -1191,7 +1191,7 @@ static const struct ov10640_reg ov10640_regs_wizard_r1f[] = { + {0x3087, 0x0}, + {0x346d, 0x14}, + {0x3444, 0x28}, +-{0x3091, 0x0}, ++{0x3091, 0x00}, // embedded data, embedded stats + {0x3119, 0x44}, // COMB12 + {0x3012, 0x1}, + #endif +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0463-net-can-rcar_can-fix-possible-IRQ-storm-on-high-load.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0463-net-can-rcar_can-fix-possible-IRQ-storm-on-high-load.patch new file mode 100644 index 00000000..8fffdc42 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0463-net-can-rcar_can-fix-possible-IRQ-storm-on-high-load.patch @@ -0,0 +1,62 @@ +From f64aaea45c16fd3f34e4130b62a14389fb174b13 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Jan 2020 13:17:42 +0300 +Subject: [PATCH] net: can: rcar_can: fix possible IRQ storm on high load + +We have observed rcar_canfd driver entering IRQ storm under high load, +with following scenario: +- rcar_canfd_global_interrupt() in entered due to Rx available, +- napi_schedule_prep() is called, and sets NAPIF_STATE_SCHED in state +- Rx fifo interrupts are masked, +- rcar_canfd_global_interrupt() is entered again, this time due to + error interrupt (e.g. due to overflow), +- since scheduled napi poller has not yet executed, condition for calling + napi_schedule_prep() from rcar_canfd_global_interrupt() remains true, + thus napi_schedule_prep() gets called and sets NAPIF_STATE_MISSED flag + in state, +- later, napi poller function rcar_canfd_rx_poll() gets executed, and + calls napi_complete_done(), +- due to NAPIF_STATE_MISSED flag in state, this call does not clear + NAPIF_STATE_SCHED flag from state, +- on return from napi_complete_done(), rcar_canfd_rx_poll() unmasks Rx + interrutps, +- Rx interrupt happens, rcar_canfd_global_interrupt() gets called + and calls napi_schedule_prep(), +- since NAPIF_STATE_SCHED is set in state at this time, this call + returns false, +- due to that false return, rcar_canfd_global_interrupt() returns + without masking Rx interrupt +- and this results into IRQ storm: unmasked Rx interrupt happens again + and again is misprocessed in the same way. + +This patch fixes that scenario by unmasking Rx interrupts only when +napi_complete_done() returns true, which means it has cleared +NAPIF_STATE_SCHED in state. + +Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com> +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/net/can/rcar/rcar_can.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c +index 8d2c709..b06bfc2 100644 +--- a/drivers/net/can/rcar/rcar_can.c ++++ b/drivers/net/can/rcar/rcar_can.c +@@ -705,9 +705,10 @@ static int rcar_can_rx_poll(struct napi_struct *napi, int quota) + } + /* All packets processed */ + if (num_pkts < quota) { +- napi_complete_done(napi, num_pkts); +- priv->ier |= RCAR_CAN_IER_RXFIE; +- writeb(priv->ier, &priv->regs->ier); ++ if (napi_complete_done(napi, num_pkts)) { ++ priv->ier |= RCAR_CAN_IER_RXFIE; ++ writeb(priv->ier, &priv->regs->ier); ++ } + } + return num_pkts; + } +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0464-arm64-dts-renesas-ulcb-v2-use-CANFD-instead-CAN.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0464-arm64-dts-renesas-ulcb-v2-use-CANFD-instead-CAN.patch new file mode 100644 index 00000000..5d8b49e0 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0464-arm64-dts-renesas-ulcb-v2-use-CANFD-instead-CAN.patch @@ -0,0 +1,48 @@ +From 233ca8eeba0564b0754a31afd4535f35362479cf Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Jan 2020 16:28:12 +0300 +Subject: [PATCH] arm64: dts: renesas: ulcb-v2: use CANFD instead CAN + +Replace replace CAN with CANFD + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi +index 89bc8c1..1b4e6c3 100644 +--- a/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi ++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi +@@ -1584,25 +1584,19 @@ + &can0 { + pinctrl-0 = <&can0_pins>; + pinctrl-names = "default"; +- status = "okay"; +- +- renesas,can-clock-select = <0x0>; ++ status = "disabled"; + }; + + &can1 { + pinctrl-0 = <&can1_pins>; + pinctrl-names = "default"; +- status = "okay"; +- +- renesas,can-clock-select = <0x0>; ++ status = "disabled"; + }; + + &canfd { + pinctrl-0 = <&canfd0_pins &canfd1_pins>; + pinctrl-names = "default"; +- status = "disabled"; +- +- renesas,can-clock-select = <0x0>; ++ status = "okay"; + + channel0 { + status = "okay"; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0465-arm64-dts-renesas-add-cn12-support-on-VB2-1.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0465-arm64-dts-renesas-add-cn12-support-on-VB2-1.patch new file mode 100644 index 00000000..12d71ec1 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0465-arm64-dts-renesas-add-cn12-support-on-VB2-1.patch @@ -0,0 +1,481 @@ +From 13310cdf96f0f4cf63c2b374267fce6794573500 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Tue, 28 Jan 2020 21:13:56 +0300 +Subject: [PATCH] arm64: dts: renesas: add cn12 support on VB2.1 + +This adds CN12 (SLOT C) on VB2.1 + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi | 459 +++++++++++++++++++++++++ + 1 file changed, 459 insertions(+) + create mode 100644 arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi + +diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi +new file mode 100644 +index 0000000..7ce48d90 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi +@@ -0,0 +1,459 @@ ++/* ++ * Device Tree Source for the H3ULCB Videobox board V2: ++ * this adding conflicting resource on VIN4/VIN5/VIN6/VIN7 for CN12 ++ * ++ * Copyright (C) 2020 Renesas Electronics Corp. ++ * Copyright (C) 2020 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++&i2cswitch2 { ++ i2c@7 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <7>; ++ /* Slot C (CN12) */ ++ ++ ov106xx@8 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x68>; ++ ++ port@0 { ++ ov106xx_in8: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ remote-endpoint = <&vin4ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des2ep0: endpoint@0 { ++ remote-endpoint = <&max9286_des2ep0>; ++ }; ++ ov106xx_ti9x4_des2ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep0>; ++ }; ++ }; ++ }; ++ ++ ov106xx@9 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x69>; ++ ++ port@0 { ++ ov106xx_in9: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ remote-endpoint = <&vin5ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des2ep1: endpoint@0 { ++ remote-endpoint = <&max9286_des2ep1>; ++ }; ++ ov106xx_ti9x4_des2ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep1>; ++ }; ++ }; ++ }; ++ ++ ov106xx@10 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x6a>; ++ ++ port@0 { ++ ov106xx_in10: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ remote-endpoint = <&vin6ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des2ep2: endpoint@0 { ++ remote-endpoint = <&max9286_des2ep2>; ++ }; ++ ov106xx_ti9x4_des2ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep2>; ++ }; ++ }; ++ }; ++ ++ ov106xx@11 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x6b>; ++ ++ port@0 { ++ ov106xx_in11: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ remote-endpoint = <&vin7ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_max9286_des2ep3: endpoint@0 { ++ remote-endpoint = <&max9286_des2ep3>; ++ }; ++ ov106xx_ti9x4_des2ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep3>; ++ }; ++ }; ++ }; ++ ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@2 { ++ compatible = "ti,ti9x4"; ++ reg = <0x3a>; ++ ti,sensor_delay = <350>; ++ ti,links = <4>; ++ ti,lanes = <2>; ++ ti,forwarding-mode = "round-robin"; ++ ti,cable-mode = "coax"; ++ ++ POC0-gpios = <&gpio_exp_c_5c 8 GPIO_ACTIVE_HIGH>; ++ POC1-gpios = <&gpio_exp_c_5c 9 GPIO_ACTIVE_HIGH>; ++ POC2-gpios = <&gpio_exp_c_5c 10 GPIO_ACTIVE_HIGH>; ++ POC3-gpios = <&gpio_exp_c_5c 11 GPIO_ACTIVE_HIGH>; ++ ++ port@0 { ++ ti9x4_des2ep0: endpoint@0 { ++ ti9x3-addr = <0x0c>; ++ dvp-order = <0>; ++ remote-endpoint = <&ov106xx_in8>; ++ }; ++ ti9x4_des2ep1: endpoint@1 { ++ ti9x3-addr = <0x0d>; ++ dvp-order = <0>; ++ remote-endpoint = <&ov106xx_in9>; ++ }; ++ ti9x4_des2ep2: endpoint@2 { ++ ti9x3-addr = <0x0e>; ++ dvp-order = <0>; ++ remote-endpoint = <&ov106xx_in10>; ++ }; ++ ti9x4_des2ep3: endpoint@3 { ++ ti9x3-addr = <0x0f>; ++ dvp-order = <0>; ++ remote-endpoint = <&ov106xx_in11>; ++ }; ++ }; ++ port@1 { ++ ti9x4_csi1ep0: endpoint { ++ csi-rate = <1450>; ++ remote-endpoint = <&csi20_ep>; ++ }; ++ }; ++ }; ++ ++ /* MAX9286 @ 0x2c */ ++ max9286@2 { ++ compatible = "maxim,max9286"; ++ reg = <0x2c>; ++ maxim,sensor_delay = <350>; ++ maxim,links = <4>; ++ maxim,lanes = <2>; ++ maxim,resetb-gpio = <1>; ++ maxim,fsync-mode = "automatic"; ++ maxim,timeout = <100>; ++ ++ POC0-gpios = <&gpio_exp_c_5c 9 GPIO_ACTIVE_HIGH>; ++ POC1-gpios = <&gpio_exp_c_5c 8 GPIO_ACTIVE_HIGH>; ++ POC2-gpios = <&gpio_exp_c_5c 11 GPIO_ACTIVE_HIGH>; ++ POC3-gpios = <&gpio_exp_c_5c 10 GPIO_ACTIVE_HIGH>; ++ ++ port@0 { ++ max9286_des2ep0: endpoint@0 { ++ max9271-addr = <0x50>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in8>; ++ }; ++ max9286_des2ep1: endpoint@1 { ++ max9271-addr = <0x51>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in9>; ++ }; ++ max9286_des2ep2: endpoint@2 { ++ max9271-addr = <0x52>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in10>; ++ }; ++ max9286_des2ep3: endpoint@3 { ++ max9271-addr = <0x53>; ++ dvp-order = <1>; ++ remote-endpoint = <&ov106xx_in11>; ++ }; ++ }; ++ port@1 { ++ max9286_csi1ep0: endpoint { ++ csi-rate = <700>; ++ remote-endpoint = <&csi20_ep>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@5 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <5>; ++ /* Slot C (CN12) */ ++ ++ /* PCA9535 is a redundand/deprecated card */ ++ gpio_exp_c_27: gpio@27 { ++ compatible = "nxp,pca9535"; ++ reg = <0x26>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ video_c_des_cfg1 { ++ gpio-hog; ++ gpios = <5 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-C cfg1"; ++ }; ++ video_c_des_cfg0 { ++ gpio-hog; ++ gpios = <6 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-C cfg0"; ++ }; ++ video_c_pwr_shdn { ++ gpio-hog; ++ gpios = <3 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C PWR_SHDN"; ++ }; ++ video_c_cam_pwr0 { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C PWR0"; ++ }; ++ video_c_cam_pwr1 { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C PWR1"; ++ }; ++ video_c_cam_pwr2 { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C PWR2"; ++ }; ++ video_c_cam_pwr3 { ++ gpio-hog; ++ gpios = <15 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C PWR3"; ++ }; ++ video_c_des_shdn { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C DES_SHDN"; ++ }; ++ video_c_des_led { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "Video-C led"; ++ }; ++ }; ++ ++ gpio_exp_c_5c: gpio@5c { ++ compatible = "maxim,max7325"; ++ reg = <0x5c>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ video_c_des_cfg2 { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-C cfg2"; ++ }; ++ video_c_des_cfg1 { ++ gpio-hog; ++ gpios = <6 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-C cfg1"; ++ }; ++ video_c_des_cfg0 { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-C cfg0"; ++ }; ++ video_c_pwr_shdn { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C PWR_SHDN"; ++ }; ++ video_c_des_shdn { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C DES_SHDN"; ++ }; ++ video_c_led { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "Video-C LED"; ++ }; ++ }; ++ }; ++}; ++ ++&vin4 { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin4ep0: endpoint { ++ csi,select = "csi20"; ++ virtual,channel = <0>; ++ remote-endpoint = <&ov106xx_in8>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ port@1 { ++ csi2ep0: endpoint { ++ remote-endpoint = <&csi20_ep>; ++ }; ++ }; ++ port@2 { ++ vin4_max9286_des2ep0: endpoint@0 { ++ remote-endpoint = <&max9286_des2ep0>; ++ }; ++ vin4_ti9x4_des2ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin5 { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin5ep0: endpoint@0 { ++ csi,select = "csi20"; ++ virtual,channel = <1>; ++ remote-endpoint = <&ov106xx_in9>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ port@1 { ++ csi2ep1: endpoint { ++ remote-endpoint = <&csi20_ep>; ++ }; ++ }; ++ port@2 { ++ vin5_max9286_des2ep1: endpoint@0 { ++ remote-endpoint = <&max9286_des2ep1>; ++ }; ++ vin5_ti9x4_des2ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep1>; ++ }; ++ }; ++ }; ++}; ++ ++&vin6 { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin6ep0: endpoint@0 { ++ csi,select = "csi20"; ++ virtual,channel = <2>; ++ remote-endpoint = <&ov106xx_in10>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ port@1 { ++ csi2ep2: endpoint { ++ remote-endpoint = <&csi20_ep>; ++ }; ++ }; ++ port@2 { ++ vin6_max9286_des2ep2: endpoint@0 { ++ remote-endpoint = <&max9286_des2ep2>; ++ }; ++ vin6_ti9x4_des2ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep2>; ++ }; ++ }; ++ }; ++}; ++ ++&vin7 { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin7ep0: endpoint@0 { ++ csi,select = "csi20"; ++ virtual,channel = <3>; ++ remote-endpoint = <&ov106xx_in11>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ port@1 { ++ csi2ep3: endpoint { ++ remote-endpoint = <&csi20_ep>; ++ }; ++ }; ++ port@2 { ++ vin7_max9286_des2ep3: endpoint@0 { ++ remote-endpoint = <&max9286_des2ep3>; ++ }; ++ vin7_ti9x4_des2ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep3>; ++ }; ++ }; ++ }; ++}; ++ ++&csi20 { ++ status = "okay"; ++ ++ virtual,channel { ++ csi2_vc0 { ++ data,type = "ycbcr422"; ++ receive,vc = <0>; ++ }; ++ csi2_vc1 { ++ data,type = "ycbcr422"; ++ receive,vc = <1>; ++ }; ++ csi2_vc2 { ++ data,type = "ycbcr422"; ++ receive,vc = <2>; ++ }; ++ csi2_vc3 { ++ data,type = "ycbcr422"; ++ receive,vc = <3>; ++ }; ++ }; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi20_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ csi-rate = <300>; ++ }; ++ }; ++}; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0466-media-i2c-max9286-parse-crossbar-from-dt.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0466-media-i2c-max9286-parse-crossbar-from-dt.patch new file mode 100644 index 00000000..f96696d6 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0466-media-i2c-max9286-parse-crossbar-from-dt.patch @@ -0,0 +1,58 @@ +From 0220ffebe645d66242aca68d7a374140dea9e6a3 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Jan 2020 16:38:19 +0300 +Subject: [PATCH] media: i2c: max9286: parse crossbar from dt + +This allows to parse crossbar from device tree + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/max9286.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c +index f6c6b0a..0a1732a 100644 +--- a/drivers/media/i2c/soc_camera/max9286.c ++++ b/drivers/media/i2c/soc_camera/max9286.c +@@ -56,6 +56,7 @@ struct max9286_priv { + int dbl; + int dt; + int hsgen; ++ u64 crossbar; + char cb[16]; + int hts; + int vts; +@@ -141,8 +142,8 @@ static int switchin = 0; + module_param(switchin, int, 0644); + MODULE_PARM_DESC(switchin, " COAX SWITCH IN+ and IN- (default: 0 - not switched)"); + +-static long crossbar = 0xba9876543210; +-module_param(crossbar, long, 0644); ++static unsigned long crossbar = 0xba9876543210; ++module_param(crossbar, ulong, 0644); + MODULE_PARM_DESC(crossbar, " Crossbar setup (default: ba9876543210 - reversed)"); + + enum { +@@ -738,6 +739,8 @@ static int max9286_parse_dt(struct i2c_client *client) + priv->pclk = pclk; + if (of_property_read_u32(np, "maxim,switchin", &priv->switchin)) + priv->switchin = 0; ++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar)) ++ priv->crossbar = crossbar; + + /* module params override dts */ + if (him) +@@ -773,8 +776,8 @@ static int max9286_parse_dt(struct i2c_client *client) + + /* parse crossbar setup */ + for (i = 0; i < 16; i++) { +- priv->cb[i] = crossbar % 16; +- crossbar /= 16; ++ priv->cb[i] = priv->crossbar % 16; ++ priv->crossbar /= 16; + } + + for (i = 0; i < priv->links; i++) { +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0467-media-i2c-isx016-add-fixed-sensor.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0467-media-i2c-isx016-add-fixed-sensor.patch new file mode 100644 index 00000000..359e1903 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0467-media-i2c-isx016-add-fixed-sensor.patch @@ -0,0 +1,94 @@ +From 43b01937acf76c4d057fd6681ff66f945634f5c4 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Jan 2020 16:41:59 +0300 +Subject: [PATCH] media: i2c: isx016: add fixed sensor + +This add possibility to enable camera if the imager is not +accessible in i2c line for ID detection + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/isx016.c | 41 +++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/drivers/media/i2c/soc_camera/isx016.c b/drivers/media/i2c/soc_camera/isx016.c +index 9465c8f..a9f137c 100644 +--- a/drivers/media/i2c/soc_camera/isx016.c ++++ b/drivers/media/i2c/soc_camera/isx016.c +@@ -51,8 +51,21 @@ struct isx016_priv { + int port; + int gpio_resetb; + int gpio_fsin; ++ int fixed_sensor; + }; + ++static int isx016_fixed = 0; ++module_param(isx016_fixed, int, 0644); ++MODULE_PARM_DESC(isx016_fixed, " isx016 fixed detect (0 - imager disabled)"); ++ ++static int isx016_width = ISX016_MAX_WIDTH; ++module_param(isx016_width, int, 0644); ++MODULE_PARM_DESC(isx016_width, " isx016 fixed width"); ++ ++static int isx016_height = ISX016_MAX_HEIGHT; ++module_param(isx016_height, int, 0644); ++MODULE_PARM_DESC(isx016_height, " isx016 fixed height"); ++ + static inline struct isx016_priv *to_isx016(const struct i2c_client *client) + { + return container_of(i2c_get_clientdata(client), struct isx016_priv, sd); +@@ -371,9 +384,27 @@ static int isx016_initialize(struct i2c_client *client) + int ret = 0; + int tmp_addr; + int i; ++ u8 ser_pid = 0; + + isx016_s_port(client, 1); + ++ if (priv->fixed_sensor) { ++ tmp_addr = client->addr; ++ if (priv->max9286_addr) { ++ client->addr = priv->max9271_addr; ++ /* check serizlizer ID */ ++ reg8_read(client, 0x1e, &ser_pid); ++ } ++ client->addr = tmp_addr; ++ ++ if (ser_pid != MAX9271_ID && ser_pid != MAX96705_ID && ser_pid != MAX96707_ID) { ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ goto out; ++ } ++ + for (i = 0; i < ARRAY_SIZE(isx016_i2c_addr); i++) { + tmp_addr = client->addr; + if (priv->max9286_addr) { +@@ -409,6 +440,7 @@ static int isx016_initialize(struct i2c_client *client) + /* Program wizard registers */ + isx016_set_regs(client, isx016_regs_wizard, ARRAY_SIZE(isx016_regs_wizard)); + ++out: + dev_info(&client->dev, "isx016 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", + pid, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + err: +@@ -471,6 +503,15 @@ static int isx016_parse_dt(struct device_node *np, struct isx016_priv *priv) + } + client->addr = tmp_addr; + ++ if (of_property_read_u32(np, "isx016,fixed", &priv->fixed_sensor)) ++ priv->fixed_sensor = isx016_fixed; ++ if (priv->fixed_sensor) { ++ if (of_property_read_u32(np, "width", &priv->max_width)) ++ priv->max_width = ISX016_MAX_WIDTH; ++ if (of_property_read_u32(np, "height", &priv->max_height)) ++ priv->max_height = ISX016_MAX_HEIGHT; ++ } ++ + return 0; + } + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0468-imx390-Read-1-byte-registers-by-default.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0468-imx390-Read-1-byte-registers-by-default.patch new file mode 100644 index 00000000..50658706 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0468-imx390-Read-1-byte-registers-by-default.patch @@ -0,0 +1,37 @@ +From 0dc45a01a271f56aedeb7cfc72f8550243d0b3b0 Mon Sep 17 00:00:00 2001 +From: Petr Nechaev <petr.nechaev@cogentembedded.com> +Date: Fri, 27 Dec 2019 22:07:20 +0300 +Subject: [PATCH] imx390: Read 1 byte registers by default + +This patch switches to 1-byte default register size for imx390 image sensor. + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imx390.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imx390.c b/drivers/media/i2c/soc_camera/imx390.c +index c1e568055e54..9d970b16697d 100644 +--- a/drivers/media/i2c/soc_camera/imx390.c ++++ b/drivers/media/i2c/soc_camera/imx390.c +@@ -217,7 +217,7 @@ static int imx390_g_register(struct v4l2_subdev *sd, + int ret; + + if (!s) +- s = 4; ++ s = 1; + if (s > sizeof(reg->val)) + s = sizeof(reg->val); + +@@ -235,7 +235,7 @@ static int imx390_s_register(struct v4l2_subdev *sd, + u32 s = reg->size; + + if (!s) +- s = 4; ++ s = 1; + if (s > sizeof(reg->val)) + s = sizeof(reg->val); + +-- +2.20.1 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0469-rcar_canfd-fix-one-more-interrupt-storm-window.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0469-rcar_canfd-fix-one-more-interrupt-storm-window.patch new file mode 100644 index 00000000..506ff276 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0469-rcar_canfd-fix-one-more-interrupt-storm-window.patch @@ -0,0 +1,67 @@ +From bfdc3bf828002a0550b8183a67879fc3a9246795 Mon Sep 17 00:00:00 2001 +From: Nikita Yushchenko <nikita.yoush@cogentembedded.com> +Date: Thu, 6 Feb 2020 23:13:19 +0300 +Subject: [PATCH] rcar_canfd: fix one more interrupt storm window + +When more than one rcar_canfd channel works simultaneously, same irq and +same irq handler, rcar_canfd_global_interrupt(), is shared between them +all. Entry into this handler while Rx interrupt for one channel is masked +per NAPI, becomes a very frequent event. + +Code makes an attempt to alter interrupt mask only when NAPI suggests to +do so. However that code is racy, and with frequent call to handler with +masked interrupt, this race actually happens. + +The race window is: +- after code in napi_complete_done() clears NAPIF_STATE_SCHED flag inside + NAPI state, but before napi_complete_done() returns true, side-called + interrupt handler detects pending (although masked) Rx, calls + napi_schedule_prep(), and NAPIF_STATE_SCHED flag is re-set, +- then napi_complete_done() returns true and Rx interrupt gets unmasked, +- then unmasked interrupt fires, but this time NAPIF_STATE_SCHED flag + is already set, so napi_schedule_prep() returns false, +- which causes return from interrupt handler without touching interrupt, + and IRQ storm is entered. + +To fix it, active Rx interrupt must be UNCONDITIONALLY masked inside the +handler. Failing to mask active interrupt immediately results into IRQ +storm, regardless of NAPI state or whatever other conditions. + +Once napi_schedule_prep() is called after this unconditional masking, future +call to NAPI poller and evential interrupt unmask is guaranteed. + +Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com> +--- + drivers/net/can/rcar/rcar_canfd.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c +index 0017ab9..056a5f6 100644 +--- a/drivers/net/can/rcar/rcar_canfd.c ++++ b/drivers/net/can/rcar/rcar_canfd.c +@@ -1101,13 +1101,16 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id) + /* Handle Rx interrupts */ + sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(ridx)); + if (likely(sts & RCANFD_RFSTS_RFIF)) { +- if (napi_schedule_prep(&priv->napi)) { +- /* Disable Rx FIFO interrupts */ +- rcar_canfd_clear_bit(priv->base, +- RCANFD_RFCC(ridx), +- RCANFD_RFCC_RFIE); ++ /* If Rx FIFO interrupt is there, it must be masked ++ * UNCONDITIONALLY, otherwise IRQ storm will start */ ++ rcar_canfd_clear_bit(priv->base, ++ RCANFD_RFCC(ridx), ++ RCANFD_RFCC_RFIE); ++ /* The above calls ensure that napi polling will be ++ * called sometime AFTER the above call, which ++ * eventually ensures interrupt re-enable */ ++ if (napi_schedule_prep(&priv->napi)) + __napi_schedule(&priv->napi); +- } + } + } + return IRQ_HANDLED; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0470-media-i2c-add-fps-setup.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0470-media-i2c-add-fps-setup.patch new file mode 100644 index 00000000..70fac592 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0470-media-i2c-add-fps-setup.patch @@ -0,0 +1,429 @@ +From 07c0308d3c5991ff67c32329d56f14e375e3e981 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 10 Feb 2020 18:46:46 +0300 +Subject: [PATCH] media: i2c: add fps setup + +This adds FPS setup for max9286/ti9x4 with ar0143/147 imagers + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ar0143.c | 66 ++++++++++++++++++++++++++++++++-- + drivers/media/i2c/soc_camera/ar0147.c | 64 +++++++++++++++++++++++++++++++-- + drivers/media/i2c/soc_camera/max9286.c | 42 ++++++++++++++++++++++ + drivers/media/i2c/soc_camera/ti9x4.c | 54 ++++++++++++++++++++++++---- + 4 files changed, 215 insertions(+), 11 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c +index d81871b..de4ca3c 100644 +--- a/drivers/media/i2c/soc_camera/ar0143.c ++++ b/drivers/media/i2c/soc_camera/ar0143.c +@@ -35,6 +35,8 @@ struct ar0143_priv { + struct v4l2_ctrl_handler hdl; + struct media_pad pad; + struct v4l2_rect rect; ++ int fps_numerator; ++ int fps_denominator; + int init_complete; + u8 id[6]; + int setup; +@@ -297,6 +299,61 @@ static int ar0143_g_mbus_config(struct v4l2_subdev *sd, + return 0; + } + ++static int ar0143_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0143_priv *priv = to_ar0143(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ memset(cp, 0, sizeof(struct v4l2_captureparm)); ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = priv->fps_numerator; ++ cp->timeperframe.denominator = priv->fps_denominator; ++ ++ return 0; ++} ++ ++static int ar0143_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0143_priv *priv = to_ar0143(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ int ret = 0; ++ int tmp_addr; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ if (priv->ti9x4_addr) ++ priv->vts = (AR0143_SENSOR_HEIGHT + 157) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ else ++ priv->vts = (AR0143_SENSOR_HEIGHT + 142) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ ++ ret = reg16_write16(client, 0x300A, priv->vts); /* FRAME_LENGTH_LINES_ */ ++ ++ tmp_addr = client->addr; ++ if (priv->max9271_addr) { ++ client->addr = priv->max9271_addr; /* Serializer I2C address */ ++ reg8_write(client, 0x58, priv->vts >> 8); /* HS count */ ++ reg8_write(client, 0x59, priv->vts & 0xff); ++ } ++ client->addr = tmp_addr; ++ ++ priv->fps_denominator = cp->timeperframe.numerator; ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++out: ++ return ret; ++} ++ ++ + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0143_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +@@ -361,7 +418,8 @@ static int ar0143_s_ctrl(struct v4l2_ctrl *ctrl) + break; + case V4L2_CID_EXPOSURE: + /* T1 exposure */ +- ret = reg16_write16(client, 0x3012, ctrl->val); ++ if (ctrl->val < 0x400 * 30 * priv->fps_numerator / priv->fps_denominator) ++ ret = reg16_write16(client, 0x3012, ctrl->val); + break; + case V4L2_CID_HFLIP: + ret = reg16_read16(client, 0x3040, &val); +@@ -394,6 +452,8 @@ static const struct v4l2_ctrl_ops ar0143_ctrl_ops = { + static struct v4l2_subdev_video_ops ar0143_video_ops = { + .s_stream = ar0143_s_stream, + .g_mbus_config = ar0143_g_mbus_config, ++ .g_parm = ar0143_g_parm, ++ .s_parm = ar0143_s_parm, + }; + + static const struct v4l2_subdev_pad_ops ar0143_subdev_pad_ops = { +@@ -617,6 +677,8 @@ static int ar0143_probe(struct i2c_client *client, + + v4l2_i2c_subdev_init(&priv->sd, client, &ar0143_subdev_ops); + priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ priv->fps_numerator = 1; ++ priv->fps_denominator = 30; + + v4l2_ctrl_handler_init(&priv->hdl, 4); + v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops, +@@ -638,7 +700,7 @@ static int ar0143_probe(struct i2c_client *client, + v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0x7); + v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops, +- V4L2_CID_EXPOSURE, 1, 0x400, 1, 0x300); ++ V4L2_CID_EXPOSURE, 1, 0x400 * 30, 1, 0x300); + v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops, +diff --git a/drivers/media/i2c/soc_camera/ar0147.c b/drivers/media/i2c/soc_camera/ar0147.c +index fc2a09e..e3ecec2 100644 +--- a/drivers/media/i2c/soc_camera/ar0147.c ++++ b/drivers/media/i2c/soc_camera/ar0147.c +@@ -36,6 +36,8 @@ struct ar0147_priv { + struct v4l2_ctrl_handler hdl; + struct media_pad pad; + struct v4l2_rect rect; ++ int fps_denominator; ++ int fps_numerator; + int init_complete; + u8 id[6]; + /* serializers */ +@@ -146,7 +148,7 @@ static int ar0147_set_regs(struct i2c_client *client, const struct ar0147_reg ** + reg16_write16(client, regs[i].reg, 1); // OP_SYS_CLK_DIV + continue; + case 0x300A: +- reg16_write16(client, regs[i].reg, AR0147_SENSOR_HEIGHT + 142); // FRAME_LENGTH_LINES_ ++ reg16_write16(client, regs[i].reg, AR0147_SENSOR_HEIGHT + 226); // FRAME_LENGTH_LINES_ + continue; + } + } +@@ -317,6 +319,57 @@ static int ar0147_g_mbus_config(struct v4l2_subdev *sd, + return 0; + } + ++static int ar0147_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0147_priv *priv = to_ar0147(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ memset(cp, 0, sizeof(struct v4l2_captureparm)); ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = priv->fps_numerator; ++ cp->timeperframe.denominator = priv->fps_denominator; ++ ++ return 0; ++} ++ ++static int ar0147_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0147_priv *priv = to_ar0147(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ int ret = 0; ++ int tmp_addr; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ priv->vts = (AR0147_SENSOR_HEIGHT + 226) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ ++ ret = reg16_write16(client, 0x300A, priv->vts); /* FRAME_LENGTH_LINES_ */ ++ ++ tmp_addr = client->addr; ++ if (priv->max9271_addr) { ++ client->addr = priv->max9271_addr; /* Serializer I2C address */ ++ reg8_write(client, 0x58, priv->vts >> 8); /* HS count */ ++ reg8_write(client, 0x59, priv->vts & 0xff); ++ } ++ client->addr = tmp_addr; ++ ++ priv->fps_numerator = cp->timeperframe.numerator; ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++out: ++ return ret; ++} ++ + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0147_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +@@ -381,7 +434,8 @@ static int ar0147_s_ctrl(struct v4l2_ctrl *ctrl) + break; + case V4L2_CID_EXPOSURE: + /* T1 exposure */ +- ret = reg16_write16(client, 0x3012, ctrl->val); ++ if (ctrl->val < 0x400 * 30 * priv->fps_numerator / priv->fps_denominator) ++ ret = reg16_write16(client, 0x3012, ctrl->val); + break; + case V4L2_CID_HFLIP: + ret = reg16_read16(client, 0x3040, &val); +@@ -414,6 +468,8 @@ static const struct v4l2_ctrl_ops ar0147_ctrl_ops = { + static struct v4l2_subdev_video_ops ar0147_video_ops = { + .s_stream = ar0147_s_stream, + .g_mbus_config = ar0147_g_mbus_config, ++ .g_parm = ar0147_g_parm, ++ .s_parm = ar0147_s_parm, + }; + + static const struct v4l2_subdev_pad_ops ar0147_subdev_pad_ops = { +@@ -648,6 +704,8 @@ static int ar0147_probe(struct i2c_client *client, + + v4l2_i2c_subdev_init(&priv->sd, client, &ar0147_subdev_ops); + priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ priv->fps_numerator = 1; ++ priv->fps_denominator = 30; + + v4l2_ctrl_handler_init(&priv->hdl, 4); + v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops, +@@ -669,7 +727,7 @@ static int ar0147_probe(struct i2c_client *client, + v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0x7); + v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops, +- V4L2_CID_EXPOSURE, 1, 0x400, 1, 0x300); ++ V4L2_CID_EXPOSURE, 1, 0x400 * 30, 1, 0x300); + v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops, +diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c +index 0a1732a..343b8ab 100644 +--- a/drivers/media/i2c/soc_camera/max9286.c ++++ b/drivers/media/i2c/soc_camera/max9286.c +@@ -43,6 +43,8 @@ struct max9286_priv { + int csi_rate; + const char *fsync_mode; + int fsync_period; ++ int fps_numerator; ++ int fps_denominator; + int pclk; + char pclk_rising_edge; + int gpio_resetb; +@@ -650,8 +652,46 @@ static struct v4l2_subdev_core_ops max9286_subdev_core_ops = { + .registered_async = max9286_registered_async, + }; + ++static int max9286_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ return 0; ++} ++ ++static int max9286_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ int f_period; ++ ++ f_period = priv->fsync_period * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ reg8_write(client, 0x06, f_period & 0xff); ++ reg8_write(client, 0x07, (f_period >> 8) & 0xff); ++ reg8_write(client, 0x08, f_period >> 16); ++ ++ priv->fps_numerator = cp->timeperframe.numerator; ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++ ++ return 0; ++} ++ ++static struct v4l2_subdev_video_ops max9286_video_ops = { ++ .g_parm = max9286_g_parm, ++ .s_parm = max9286_s_parm, ++}; ++ + static struct v4l2_subdev_ops max9286_subdev_ops = { + .core = &max9286_subdev_core_ops, ++ .video = &max9286_video_ops, + }; + + static int max9286_parse_dt(struct i2c_client *client) +@@ -926,6 +966,8 @@ static int max9286_probe(struct i2c_client *client, + priv->client = client; + atomic_set(&priv->use_count, 0); + priv->csi2_outord = 0xff; ++ priv->fps_numerator = 1; ++ priv->fps_denominator = 30; + + err = max9286_parse_dt(client); + if (err) +diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c +index aa85d92..b671736 100644 +--- a/drivers/media/i2c/soc_camera/ti9x4.c ++++ b/drivers/media/i2c/soc_camera/ti9x4.c +@@ -32,6 +32,9 @@ struct ti9x4_priv { + int lanes; + int csi_rate; + const char *forwarding_mode; ++ int fs_time; ++ int fps_numerator; ++ int fps_denominator; + int is_coax; + int dvp_bus; + int dvp_lsb; +@@ -139,7 +142,6 @@ static void ti9x4_read_chipid(struct i2c_client *client) + static void ti9x4_initial_setup(struct i2c_client *client) + { + struct ti9x4_priv *priv = i2c_get_clientdata(client); +- int fs_time = 0; + + /* Initial setup */ + client->addr = priv->des_addr; /* TI9x4 I2C */ +@@ -175,20 +177,21 @@ static void ti9x4_initial_setup(struct i2c_client *client) + case 800: + case 400: + /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/FPS/12mks=1/30/12e-6=2777 -> HI=2, LO=2775 */ +- fs_time = 2790; ++ priv->fs_time = 2790; + break; + case 1500: + /* FrameSync setup for REFCLK=23MHz, FPS=30: period_counts=1/FPS/13.043mks=1/30/13.043e-6=2556 -> HI=2, LO=2554 */ +- fs_time = 2570; ++ priv->fs_time = 2570; + break; + case 1450: + case 1100: + case 700: + case 350: + /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/FPS/13.333mks=1/30/13.333e-6=2500 -> HI=2, LO=2498 */ +- fs_time = 2513; ++ priv->fs_time = 2513; + break; + default: ++ priv->fs_time = 0; + dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate); + } + +@@ -213,8 +216,8 @@ static void ti9x4_initial_setup(struct i2c_client *client) + #else + reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */ + reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */ +- reg8_write(client, 0x1b, fs_time >> 8); /* FrameSync low time MSB */ +- reg8_write(client, 0x1c, fs_time & 0xff); /* FrameSync low time LSB */ ++ reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */ ++ reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */ + reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */ + // reg8_write(client, 0x18, 0x80); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */ + #endif +@@ -425,8 +428,45 @@ static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = { + .registered_async = ti9x4_registered_async, + }; + ++static int ti9x4_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ return 0; ++} ++ ++static int ti9x4_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ int f_time; ++ ++ f_time = priv->fs_time * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ reg8_write(client, 0x1b, f_time >> 8); /* FrameSync low time MSB */ ++ reg8_write(client, 0x1c, f_time & 0xff); /* FrameSync low time LSB */ ++ ++ priv->fps_denominator = cp->timeperframe.denominator; ++ priv->fps_numerator = cp->timeperframe.numerator; ++ } ++ ++ return 0; ++} ++ ++static struct v4l2_subdev_video_ops ti9x4_video_ops = { ++ .g_parm = ti9x4_g_parm, ++ .s_parm = ti9x4_s_parm, ++}; ++ + static struct v4l2_subdev_ops ti9x4_subdev_ops = { + .core = &ti9x4_subdev_core_ops, ++ .video = &ti9x4_video_ops, + }; + + static int ti9x4_parse_dt(struct i2c_client *client) +@@ -607,6 +647,8 @@ static int ti9x4_probe(struct i2c_client *client, + priv->des_addr = client->addr; + priv->client = client; + atomic_set(&priv->use_count, 0); ++ priv->fps_numerator = 1; ++ priv->fps_denominator = 30; + + err = ti9x4_parse_dt(client); + if (err) +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0471-media-i2c-ov10640-add-fps-setup.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0471-media-i2c-ov10640-add-fps-setup.patch new file mode 100644 index 00000000..cf009e51 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0471-media-i2c-ov10640-add-fps-setup.patch @@ -0,0 +1,104 @@ +From 969dff5e0dbd9ad6b289073410dbd3013ccd5e31 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 10 Feb 2020 21:09:29 +0300 +Subject: [PATCH] media: i2c: ov10640: add fps setup + +This adds framerate change support for OV10640 imager + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov10640.c | 50 ++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c +index fab2c0d..0af091e 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.c ++++ b/drivers/media/i2c/soc_camera/ov10640.c +@@ -38,6 +38,7 @@ struct ov10640_priv { + struct media_pad pad; + struct v4l2_rect rect; + int subsampling; ++ int fps_numerator; + int fps_denominator; + int init_complete; + u8 id[6]; +@@ -51,6 +52,7 @@ struct ov10640_priv { + int port; + int gpio_resetb; + int gpio_fsin; ++ int vts; + }; + + static inline struct ov10640_priv *to_ov10640(const struct i2c_client *client) +@@ -276,6 +278,51 @@ static int ov10640_g_mbus_config(struct v4l2_subdev *sd, + return 0; + } + ++static int ov10640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10640_priv *priv = to_ov10640(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ memset(cp, 0, sizeof(struct v4l2_captureparm)); ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = priv->fps_numerator; ++ cp->timeperframe.denominator = priv->fps_denominator; ++ ++ return 0; ++} ++ ++static int ov10640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10640_priv *priv = to_ov10640(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ int ret = 0; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ priv->vts = (OV10640_SENSOR_HEIGHT + 208) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ ++ reg16_write(client, 0x3012, 0); ++ reg16_write(client, 0x3082, priv->vts >> 8); ++ reg16_write(client, 0x3083, priv->vts & 0xff); ++ ret = reg16_write(client, 0x3012, 1); ++ ++ priv->fps_denominator = cp->timeperframe.numerator; ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++ ++ return ret; ++} ++ + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ov10640_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +@@ -417,6 +464,8 @@ static const struct v4l2_ctrl_ops ov10640_ctrl_ops = { + static struct v4l2_subdev_video_ops ov10640_video_ops = { + .s_stream = ov10640_s_stream, + .g_mbus_config = ov10640_g_mbus_config, ++ .g_parm = ov10640_g_parm, ++ .s_parm = ov10640_s_parm, + }; + + static const struct v4l2_subdev_pad_ops ov10640_subdev_pad_ops = { +@@ -643,6 +692,7 @@ static int ov10640_probe(struct i2c_client *client, + priv->rect.top = 0; + priv->rect.width = OV10640_DEFAULT_WIDTH; + priv->rect.height = OV10640_DEFAULT_HEIGHT; ++ priv->fps_numerator = 1; + priv->fps_denominator = 30; + + v4l2_ctrl_handler_init(&priv->hdl, 4); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0472-media-i2c-soc_camera-fix-compilation-warnings.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0472-media-i2c-soc_camera-fix-compilation-warnings.patch new file mode 100644 index 00000000..396c78f8 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0472-media-i2c-soc_camera-fix-compilation-warnings.patch @@ -0,0 +1,70 @@ +From 088954dd3b295ef6401f58e694456c782e57ef39 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 10 Feb 2020 21:10:06 +0300 +Subject: [PATCH] media: i2c: soc_camera: fix compilation warnings + +Fix compilation warnings + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ar0143.c | 2 +- + drivers/media/i2c/soc_camera/ar0147.c | 2 +- + drivers/media/i2c/soc_camera/ov106xx.c | 3 +++ + drivers/media/i2c/soc_camera/ox01d10.c | 1 - + 4 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c +index de4ca3c..7d55afb 100644 +--- a/drivers/media/i2c/soc_camera/ar0143.c ++++ b/drivers/media/i2c/soc_camera/ar0143.c +@@ -349,7 +349,7 @@ static int ar0143_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) + priv->fps_denominator = cp->timeperframe.numerator; + priv->fps_denominator = cp->timeperframe.denominator; + } +-out: ++ + return ret; + } + +diff --git a/drivers/media/i2c/soc_camera/ar0147.c b/drivers/media/i2c/soc_camera/ar0147.c +index e3ecec2..a444700 100644 +--- a/drivers/media/i2c/soc_camera/ar0147.c ++++ b/drivers/media/i2c/soc_camera/ar0147.c +@@ -366,7 +366,7 @@ static int ar0147_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) + priv->fps_numerator = cp->timeperframe.numerator; + priv->fps_denominator = cp->timeperframe.denominator; + } +-out: ++ + return ret; + } + +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c +index 841861c..cf97f28 100644 +--- a/drivers/media/i2c/soc_camera/ov106xx.c ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -243,6 +243,9 @@ static int ov106xx_remove(struct i2c_client *client) + case ID_IMX390: + imx390_remove(client); + break; ++ case ID_OX01D10: ++ ox01d10_remove(client); ++ break; + case ID_OX03A: + ox03a_remove(client); + break; +diff --git a/drivers/media/i2c/soc_camera/ox01d10.c b/drivers/media/i2c/soc_camera/ox01d10.c +index 3ea3fef..082e88c 100644 +--- a/drivers/media/i2c/soc_camera/ox01d10.c ++++ b/drivers/media/i2c/soc_camera/ox01d10.c +@@ -388,7 +388,6 @@ static DEVICE_ATTR(otp_id_ox01d10, S_IRUGO, ox01d10_otp_id_show, NULL); + static int ox01d10_initialize(struct i2c_client *client) + { + struct ox01d10_priv *priv = to_ox01d10(client); +- char chip_name[10] = "unknown"; + u8 val = 0; + u16 pid; + int ret = 0; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0473-media-i2c-ov10640-add-different-imager-addresses.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0473-media-i2c-ov10640-add-different-imager-addresses.patch new file mode 100644 index 00000000..c00fef19 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0473-media-i2c-ov10640-add-different-imager-addresses.patch @@ -0,0 +1,96 @@ +From 304be73e907a8c63d774f32358a7087a8b76657a Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 10 Feb 2020 23:41:22 +0300 +Subject: [PATCH] media: i2c: ov10640: add different imager addresses + +This adds different i2c imager addresses + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov10640.c | 39 ++++++++++++++++++++++++---------- + 1 file changed, 28 insertions(+), 11 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c +index 0af091e..f5f0fdd 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.c ++++ b/drivers/media/i2c/soc_camera/ov10640.c +@@ -23,7 +23,7 @@ + #include "max9286.h" + #include "ov10640.h" + +-#define OV10640_I2C_ADDR 0x30 ++static const int ov10640_i2c_addr[] = {0x30, 0x34, 0x36}; + + #define OV10640_PIDA_REG 0x300a + #define OV10640_PIDB_REG 0x300b +@@ -566,16 +566,33 @@ static int ov10640_initialize(struct i2c_client *client) + u16 pid; + u8 val = 0, rev; + int ret = 0; ++ int tmp_addr, i; + + ov10640_s_port(client, 1); + +- /* check and show product ID and manufacturer ID */ +- reg16_read(client, OV10640_PIDA_REG, &val); +- pid = val; +- reg16_read(client, OV10640_PIDB_REG, &val); +- pid = (pid << 8) | val; +- reg16_read(client, OV10640_REV_REG, &val); +- rev = 0x10 | ((val & 0xf) + 0xa); ++ for (i = 0; i < ARRAY_SIZE(ov10640_i2c_addr); i++) { ++ tmp_addr = client->addr; ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; ++ reg8_write(client, 0x5d, ov10640_i2c_addr[i] << 1); /* Sensor native I2C address */ ++ usleep_range(2000, 2500); ++ } ++ if (priv->max9286_addr) { ++ client->addr = priv->max9271_addr; ++ reg8_write(client, 0x0a, ov10640_i2c_addr[i] << 1); /* Sensor native I2C address */ ++ usleep_range(2000, 2500); ++ }; ++ client->addr = tmp_addr; ++ ++ /* check product ID */ ++ reg16_read(client, OV10640_PIDA_REG, &val); ++ pid = val; ++ reg16_read(client, OV10640_PIDB_REG, &val); ++ pid = (pid << 8) | val; ++ ++ if (pid == OV10640_PID) ++ break; ++ } + + if (pid != OV10640_PID) { + dev_dbg(&client->dev, "Product ID error %x\n", pid); +@@ -583,6 +600,9 @@ static int ov10640_initialize(struct i2c_client *client) + goto out; + } + ++ /* check revision */ ++ reg16_read(client, OV10640_REV_REG, &val); ++ rev = 0x10 | ((val & 0xf) + 0xa); + /* Read OTP IDs */ + ov10640_otp_id_read(client); + /* Program wizard registers */ +@@ -655,16 +675,13 @@ static int ov10640_parse_dt(struct device_node *np, struct ov10640_priv *priv) + if (priv->max9286_addr) { + client->addr = priv->max9271_addr; /* Serializer I2C address */ + reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */ +- reg8_write(client, 0x0A, OV10640_I2C_ADDR << 1); /* Sensor native I2C address */ + usleep_range(2000, 2500); /* wait 2ms */ + }; +- + if (priv->ti9x4_addr) { + client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ + reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ + usleep_range(2000, 2500); /* wait 2ms */ + reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ +- reg8_write(client, 0x5d, OV10640_I2C_ADDR << 1); /* Sensor native I2C address */ + } + client->addr = tmp_addr; + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0474-media-i2c-soc_camera-add-V4L2_CID_MIN_BUFFERS_FOR_CA.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0474-media-i2c-soc_camera-add-V4L2_CID_MIN_BUFFERS_FOR_CA.patch new file mode 100644 index 00000000..c15a1f8a --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0474-media-i2c-soc_camera-add-V4L2_CID_MIN_BUFFERS_FOR_CA.patch @@ -0,0 +1,82 @@ +From 6c0c041b3bbfec436e96fe09fdbf5072688b7ad2 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 12 Feb 2020 01:24:14 +0300 +Subject: [PATCH] media: i2c: soc_camera: add V4L2_CID_MIN_BUFFERS_FOR_CAPTURE + +Add V4L2_CID_MIN_BUFFERS_FOR_CAPTURE for isx016 and ap0101 + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ap0101_ar014x.c | 8 ++++++++ + drivers/media/i2c/soc_camera/isx016.c | 8 ++++++++ + 2 files changed, 16 insertions(+) + +diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/ap0101_ar014x.c +index 4df5793..c458044 100644 +--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.c ++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.c +@@ -347,6 +347,9 @@ static int ap0101_s_ctrl(struct v4l2_ctrl *ctrl) + reg16_write16(client, 0xfc00, 0x2800); + ret = reg16_write16(client, 0x0040, 0x8100); + break; ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ret = 0; ++ break; + } + + return ret; +@@ -552,6 +555,7 @@ static int ap0101_probe(struct i2c_client *client, + const struct i2c_device_id *did) + { + struct ap0101_priv *priv; ++ struct v4l2_ctrl *ctrl; + int ret; + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); +@@ -587,6 +591,10 @@ static int ap0101_probe(struct i2c_client *client, + V4L2_CID_HFLIP, 0, 1, 1, 1); + v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 1); ++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); ++ if (ctrl) ++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; + priv->sd.ctrl_handler = &priv->hdl; + + ret = priv->hdl.error; +diff --git a/drivers/media/i2c/soc_camera/isx016.c b/drivers/media/i2c/soc_camera/isx016.c +index a9f137c..3001df9 100644 +--- a/drivers/media/i2c/soc_camera/isx016.c ++++ b/drivers/media/i2c/soc_camera/isx016.c +@@ -319,6 +319,9 @@ static int isx016_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + break; ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ret = 0; ++ break; + } + + return ret; +@@ -519,6 +522,7 @@ static int isx016_probe(struct i2c_client *client, + const struct i2c_device_id *did) + { + struct isx016_priv *priv; ++ struct v4l2_ctrl *ctrl; + int ret; + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); +@@ -554,6 +558,10 @@ static int isx016_probe(struct i2c_client *client, + V4L2_CID_HFLIP, 0, 1, 1, 1); + v4l2_ctrl_new_std(&priv->hdl, &isx016_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); ++ if (ctrl) ++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; + priv->sd.ctrl_handler = &priv->hdl; + + ret = priv->hdl.error; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0475-media-i2c-ar0233-add-fps-setup.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0475-media-i2c-ar0233-add-fps-setup.patch new file mode 100644 index 00000000..de7ca72a --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0475-media-i2c-ar0233-add-fps-setup.patch @@ -0,0 +1,127 @@ +From ec6c2c03f8c59cada4f8b0409b51534c54da282a Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 13 Feb 2020 10:02:20 +0300 +Subject: [PATCH] media: i2c: ar0233: add fps setup + +This add FPS setup for AR0233/AR0220 + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ar0233.c | 59 +++++++++++++++++++++++++++++++++-- + 1 file changed, 57 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c +index cdd2d8a..fbff49b 100644 +--- a/drivers/media/i2c/soc_camera/ar0233.c ++++ b/drivers/media/i2c/soc_camera/ar0233.c +@@ -55,6 +55,8 @@ struct ar0233_priv { + struct v4l2_ctrl_handler hdl; + struct media_pad pad; + struct v4l2_rect rect; ++ int fps_denominator; ++ int fps_numerator; + int init_complete; + u8 id[6]; + bool emb_enable; +@@ -63,6 +65,7 @@ struct ar0233_priv { + int ti9x3_addr; + int port; + int trigger; ++ int vts; + }; + + static int extclk = 23; +@@ -271,6 +274,53 @@ static int ar0233_g_mbus_config(struct v4l2_subdev *sd, + return 0; + } + ++static int ar0233_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0233_priv *priv = to_ar0233(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ memset(cp, 0, sizeof(struct v4l2_captureparm)); ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = priv->fps_numerator; ++ cp->timeperframe.denominator = priv->fps_denominator; ++ ++ return 0; ++} ++ ++static int ar0233_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0233_priv *priv = to_ar0233(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ int ret = 0; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ switch (chipid) { ++ case AR0220_PID: ++ priv->vts = (AR0233_SENSOR_HEIGHT + 794) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; break; ++ case AR0233_PID: ++ priv->vts = (AR0233_SENSOR_HEIGHT + 100) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; break; ++ }; ++ ++ ret = reg16_write16(client, 0x300A, priv->vts); /* FRAME_LENGTH_LINES_ */ ++ ++ priv->fps_numerator = cp->timeperframe.numerator; ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++ ++ return ret; ++} ++ + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0233_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +@@ -335,7 +385,8 @@ static int ar0233_s_ctrl(struct v4l2_ctrl *ctrl) + break; + case V4L2_CID_EXPOSURE: + /* T1 exposure */ +- ret = reg16_write16(client, 0x3012, ctrl->val); ++ if (ctrl->val < 0x600 * 30 * priv->fps_numerator / priv->fps_denominator) ++ ret = reg16_write16(client, 0x3012, ctrl->val); + break; + case V4L2_CID_HFLIP: + ret = reg16_read16(client, 0x3040, &val); +@@ -374,6 +425,8 @@ static const struct v4l2_ctrl_ops ar0233_ctrl_ops = { + static struct v4l2_subdev_video_ops ar0233_video_ops = { + .s_stream = ar0233_s_stream, + .g_mbus_config = ar0233_g_mbus_config, ++ .g_parm = ar0233_g_parm, ++ .s_parm = ar0233_s_parm, + }; + + static const struct v4l2_subdev_pad_ops ar0233_subdev_pad_ops = { +@@ -654,6 +707,8 @@ static int ar0233_probe(struct i2c_client *client, + + v4l2_i2c_subdev_init(&priv->sd, client, &ar0233_subdev_ops); + priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ priv->fps_numerator = 1; ++ priv->fps_denominator = 30; + + v4l2_ctrl_handler_init(&priv->hdl, 4); + v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops, +@@ -675,7 +730,7 @@ static int ar0233_probe(struct i2c_client *client, + v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa); + v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops, +- V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144); ++ V4L2_CID_EXPOSURE, 1, 0x600 * 30, 1, 0x144); + v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 1); + v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops, +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0476-media-i2c-imx390-add-fps-setup.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0476-media-i2c-imx390-add-fps-setup.patch new file mode 100644 index 00000000..792ddbdc --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0476-media-i2c-imx390-add-fps-setup.patch @@ -0,0 +1,158 @@ +From a58b6fe91b46f2e06ad59e80768d5bf548d0b539 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 13 Feb 2020 16:47:36 +0300 +Subject: [PATCH] media: i2c: imx390: add fps setup + +This adds FPS setup support on IMX390 imager + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imx390.c | 69 +++++++++++++++++++++++++++++++++-- + drivers/media/i2c/soc_camera/imx390.h | 9 +++-- + 2 files changed, 72 insertions(+), 6 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imx390.c b/drivers/media/i2c/soc_camera/imx390.c +index 9d970b1..4f3d730 100644 +--- a/drivers/media/i2c/soc_camera/imx390.c ++++ b/drivers/media/i2c/soc_camera/imx390.c +@@ -35,6 +35,8 @@ struct imx390_priv { + struct v4l2_ctrl_handler hdl; + struct media_pad pad; + struct v4l2_rect rect; ++ int fps_denominator; ++ int fps_numerator; + int init_complete; + u8 id[6]; + int exposure; +@@ -46,6 +48,7 @@ struct imx390_priv { + int port; + int gpio_resetb; + int gpio_fsin; ++ int vts; + }; + + static inline struct imx390_priv *to_imx390(const struct i2c_client *client) +@@ -208,6 +211,62 @@ static int imx390_g_mbus_config(struct v4l2_subdev *sd, + return 0; + } + ++static int imx390_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ memset(cp, 0, sizeof(struct v4l2_captureparm)); ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = priv->fps_numerator; ++ cp->timeperframe.denominator = priv->fps_denominator; ++ ++ return 0; ++} ++ ++static int imx390_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ int ret = 0, timeout; ++ u8 val; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ priv->vts = (IMX390_SENSOR_HEIGHT + 29) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ ++ reg16_write(client, 0x0, 1); ++ for (timeout = 100; timeout > 0; timeout--) { ++ reg16_read(client, 0x5001, &val); ++ if (val == 1) ++ break; ++ mdelay(1); ++ } ++ if (!timeout) ++ dev_err(&client->dev, "timeout enter standby\n"); ++ ++ reg16_write(client, 0x2008, priv->vts & 0xff); ++ reg16_write(client, 0x2009, (priv->vts >> 8) & 0xff); ++ reg16_write(client, 0x200A, priv->vts >> 16); ++ ret = reg16_write(client, 0x0, 0); ++ ++ priv->fps_numerator = cp->timeperframe.numerator; ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++ ++ return ret; ++} ++ + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int imx390_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +@@ -299,9 +358,9 @@ static int imx390_s_ctrl(struct v4l2_ctrl *ctrl) + break; + case V4L2_CID_EXPOSURE: + val = 0xfff - ctrl->val; +- ret = reg16_write(client, 0x0c, val); /* LSB */ +- ret |= reg16_write(client, 0x0d, val >> 8); +-// ret |= reg16_write(client, 0x0e, ctrl->val >> 16); /* MSB */ ++ reg16_write(client, 0x0c, val); /* LSB */ ++ reg16_write(client, 0x0d, val >> 8); ++ ret = reg16_write(client, 0x0e, val >> 16); /* MSB */ + break; + case V4L2_CID_HFLIP: + /* hflip */ +@@ -349,6 +408,8 @@ static const struct v4l2_ctrl_ops imx390_ctrl_ops = { + static struct v4l2_subdev_video_ops imx390_video_ops = { + .s_stream = imx390_s_stream, + .g_mbus_config = imx390_g_mbus_config, ++ .g_parm = imx390_g_parm, ++ .s_parm = imx390_s_parm, + }; + + static const struct v4l2_subdev_pad_ops imx390_subdev_pad_ops = { +@@ -509,6 +570,8 @@ static int imx390_probe(struct i2c_client *client, + + v4l2_i2c_subdev_init(&priv->sd, client, &imx390_subdev_ops); + priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ priv->fps_numerator = 1; ++ priv->fps_denominator = 30; + + priv->exposure = 0x100; + priv->gain = 0; +diff --git a/drivers/media/i2c/soc_camera/imx390.h b/drivers/media/i2c/soc_camera/imx390.h +index efd75a7..e9d9808 100644 +--- a/drivers/media/i2c/soc_camera/imx390.h ++++ b/drivers/media/i2c/soc_camera/imx390.h +@@ -14,6 +14,9 @@ + #define IMX390_MAX_WIDTH 1920 + #define IMX390_MAX_HEIGHT 1080 + ++#define IMX390_SENSOR_WIDTH 1936 ++#define IMX390_SENSOR_HEIGHT 1096 ++ + #define IMX390_DELAY 0xffff + #define IMX390_DT 0x2c /* MIPI Data Type RAW12 */ + +@@ -244,9 +247,9 @@ static const struct imx390_reg imx390_regs_wizard[] = { + {0x2002, 0x55}, + {0x2003, 0x05}, + {0x2004, 0x02}, +-{0x2008, 0x65}, +-{0x2009, 0x04}, +-{0x200A, 0x00}, ++{0x2008, (IMX390_SENSOR_HEIGHT + 29) & 0xff}, ++{0x2009, ((IMX390_SENSOR_HEIGHT + 29) >> 8) & 0xff}, ++{0x200A, (IMX390_SENSOR_HEIGHT + 29) >> 16}, + {0x200C, 0x30}, + {0x200D, 0x11}, + {0x2010, 0x04}, +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0477-media-i2c-ar0231-fix-FSIN-pin-input.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0477-media-i2c-ar0231-fix-FSIN-pin-input.patch new file mode 100644 index 00000000..c6096a94 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0477-media-i2c-ar0231-fix-FSIN-pin-input.patch @@ -0,0 +1,54 @@ +From 466e494ad2496bc1ec16a56425efef8023d5520d Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Fri, 14 Feb 2020 18:28:21 +0300 +Subject: [PATCH] media: i2c: ar0231: fix FSIN pin input + +This fixes lost FSIN gpio pin enablement on AR0231. +Also explicitly enable gpi pins on ar0143/140 + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ar0140.c | 1 + + drivers/media/i2c/soc_camera/ar0143.c | 1 + + drivers/media/i2c/soc_camera/ar0231.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/soc_camera/ar0140.c b/drivers/media/i2c/soc_camera/ar0140.c +index ceb2c31..bb7a3ce 100644 +--- a/drivers/media/i2c/soc_camera/ar0140.c ++++ b/drivers/media/i2c/soc_camera/ar0140.c +@@ -495,6 +495,7 @@ static int ar0140_initialize(struct i2c_client *client) + ar0140_set_regs(client, ar0140_regs_wizard, ARRAY_SIZE(ar0140_regs_wizard)); + /* Enable stream */ + reg16_read16(client, 0x301a, &val); // read inital reset_register value ++ val |= (1 << 8); /* GPI pins enable */ + val |= (1 << 2); // Set streamOn bit + reg16_write16(client, 0x301a, val); // Start Streaming + +diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c +index 7d55afb..07cc445 100644 +--- a/drivers/media/i2c/soc_camera/ar0143.c ++++ b/drivers/media/i2c/soc_camera/ar0143.c +@@ -584,6 +584,7 @@ static int ar0143_initialize(struct i2c_client *client) + + /* Enable stream */ + reg16_read16(client, 0x301a, &val); ++ val |= (1 << 8); /* GPI pins enable */ + val |= (1 << 2); + reg16_write16(client, 0x301a, val); + +diff --git a/drivers/media/i2c/soc_camera/ar0231.c b/drivers/media/i2c/soc_camera/ar0231.c +index c51ae9ad..6c450f7 100644 +--- a/drivers/media/i2c/soc_camera/ar0231.c ++++ b/drivers/media/i2c/soc_camera/ar0231.c +@@ -455,6 +455,7 @@ static int ar0231_initialize(struct i2c_client *client) + + /* Enable stream */ + reg16_read16(client, 0x301a, &val); ++ val |= (1 << 8); /* GPI pins enable */ + val |= (1 << 2); + reg16_write16(client, 0x301a, val); + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0478-media-i2c-ti9x4-fix-framesync.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0478-media-i2c-ti9x4-fix-framesync.patch new file mode 100644 index 00000000..3e7b9dd4 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0478-media-i2c-ti9x4-fix-framesync.patch @@ -0,0 +1,40 @@ +From 08a1910dd33fa0b5628d641854db8fb3200272f6 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 19 Feb 2020 01:49:42 +0300 +Subject: [PATCH] media: i2c: ti9x4: fix framesync + +This fixes frames syncronization. +Cameras must start (fsinc start) simultaneously, hence enable +framesync when all cameras are set up + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ti9x4.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c +index b671736..9004bb1 100644 +--- a/drivers/media/i2c/soc_camera/ti9x4.c ++++ b/drivers/media/i2c/soc_camera/ti9x4.c +@@ -218,8 +218,7 @@ static void ti9x4_initial_setup(struct i2c_client *client) + reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */ + reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */ + reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */ +- reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */ +-// reg8_write(client, 0x18, 0x80); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */ ++ reg8_write(client, 0x18, 0x00); /* Disable FrameSync - must be enabled after all cameras are set up */ + #endif + } + +@@ -415,6 +414,8 @@ static int ti9x4_registered_async(struct v4l2_subdev *sd) + struct i2c_client *client = priv->client; + + reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4 | 0x1); /* enable CSI output, set CSI lane count, non-continuous CSI mode */ ++ reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */ ++// reg8_write(client, 0x18, 0x80); /* Enable FrameSync, Frame clock is external */ + + return 0; + } +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0479-media-soc_camera-rcar_csi2-add-interrupts.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0479-media-soc_camera-rcar_csi2-add-interrupts.patch new file mode 100644 index 00000000..960da094 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0479-media-soc_camera-rcar_csi2-add-interrupts.patch @@ -0,0 +1,150 @@ +From 0812102bc301699c607229cb86b2bc8d385aef2f Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 19 Feb 2020 02:26:11 +0300 +Subject: [PATCH] media: soc_camera: rcar_csi2: add interrupts + +This enables interrupts from RCAR CSI2 and grab timestamp +of received frames (EOF) + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/platform/soc_camera/rcar_csi2.c | 58 ++++++++++++++++++++++++++- + 1 file changed, 57 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/soc_camera/rcar_csi2.c b/drivers/media/platform/soc_camera/rcar_csi2.c +index ffb28c7..ca47ba3 100644 +--- a/drivers/media/platform/soc_camera/rcar_csi2.c ++++ b/drivers/media/platform/soc_camera/rcar_csi2.c +@@ -200,6 +200,7 @@ struct rcar_csi2_link_config { + unsigned long vcdt; + unsigned long vcdt2; + unsigned int csi_rate; ++ unsigned int use_interrupts; + }; + + #define INIT_RCAR_CSI2_LINK_CONFIG(m) \ +@@ -228,6 +229,8 @@ struct rcar_csi2 { + unsigned int csi_rate; + spinlock_t lock; + atomic_t use_count; ++ unsigned int use_interrupts; ++ u64 timestamp[4]; + }; + + static int dump = 0; +@@ -434,6 +437,7 @@ static irqreturn_t rcar_csi2_irq(int irq, void *data) + struct rcar_csi2 *priv = data; + u32 int_status; + unsigned int handled = 0; ++ u64 ts; + + spin_lock(&priv->lock); + +@@ -441,6 +445,26 @@ static irqreturn_t rcar_csi2_irq(int irq, void *data) + if (!int_status) + goto done; + ++ /* update timestamp on EOF for remote */ ++ ts = ktime_get_ns(); ++ ++ if (int_status & RCAR_CSI2_INTSTATE_VD4_END) { ++ priv->timestamp[3] = ts; ++ //printk("eof vc3\n"); ++ } ++ if (int_status & RCAR_CSI2_INTSTATE_VD3_END) { ++ priv->timestamp[2] = ts; ++ //printk("eof vc2\n"); ++ } ++ if (int_status & RCAR_CSI2_INTSTATE_VD2_END) { ++ priv->timestamp[1] = ts; ++ //printk("eof vc1\n"); ++ } ++ if (int_status & RCAR_CSI2_INTSTATE_VD1_END) { ++ priv->timestamp[0] = ts; ++ //printk("eof vc0\n"); ++ } ++ + /* ack interrupts */ + iowrite32(int_status, priv->base + RCAR_CSI2_INTSTATE); + handled = 1; +@@ -456,6 +480,10 @@ static void rcar_csi2_hwdeinit(struct rcar_csi2 *priv) + { + iowrite32(0, priv->base + RCAR_CSI2_PHYCNT); + ++ /* mask interrupts */ ++ iowrite32(~0U, priv->base + RCAR_CSI2_INTCLOSE); ++ /* ack interrupts */ ++ iowrite32(~0U, priv->base + RCAR_CSI2_INTSTATE); + /* reset CSI2 hardware */ + iowrite32(0x00000001, priv->base + RCAR_CSI2_SRST); + udelay(5); +@@ -550,6 +578,18 @@ static int rcar_csi2_hwinit(struct rcar_csi2 *priv) + dev_dbg(&priv->pdev->dev, "CSI2 VCDT2: 0x%x\n", + ioread32(priv->base + RCAR_CSI2_VCDT2)); + ++ if (priv->use_interrupts) { ++ /* EOF only interrupts */ ++ tmp = RCAR_CSI2_INTSTATE_VD1_END | RCAR_CSI2_INTSTATE_VD2_END | ++ RCAR_CSI2_INTSTATE_VD3_END | RCAR_CSI2_INTSTATE_VD4_END; ++ /* unmask interrupts */ ++ iowrite32(~tmp, priv->base + RCAR_CSI2_INTCLOSE); ++ /* ack all interrupts */ ++ iowrite32(~0U, priv->base + RCAR_CSI2_INTSTATE); ++ /* enable interrupts */ ++ iowrite32(tmp, priv->base + RCAR_CSI2_INTEN); ++ } ++ + /* wait until video decoder power off */ + msleep(10); + { +@@ -608,8 +648,21 @@ static int rcar_csi2_s_power(struct v4l2_subdev *sd, int on) + return ret; + } + ++static long rcar_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) ++{ ++ struct rcar_csi2 *priv = v4l2_get_subdevdata(sd); ++ ++ if (cmd > 4 || !priv->use_interrupts) ++ return -EINVAL; ++ ++ *(u64 *)arg = priv->timestamp[cmd]; ++ ++ return 0; ++} ++ + static struct v4l2_subdev_core_ops rcar_csi2_subdev_core_ops = { + .s_power = rcar_csi2_s_power, ++ .ioctl = rcar_csi2_ioctl, + }; + + static struct v4l2_subdev_ops rcar_csi2_subdev_ops = { +@@ -660,6 +713,9 @@ static int rcar_csi2_parse_dt(struct device_node *np, + printk(KERN_ERR "csi-rate not set\n"); + return ret; + } ++ config->use_interrupts = 0; ++ if (of_property_read_bool(endpoint, "use-interrupts")) ++ config->use_interrupts = 1; + of_node_put(endpoint); + + config->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; +@@ -730,7 +786,6 @@ static int rcar_csi2_probe(struct platform_device *pdev) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- /* Interrupt unused so far */ + irq = platform_get_irq(pdev, 0); + + if (!res || (int)irq <= 0) { +@@ -754,6 +809,7 @@ static int rcar_csi2_probe(struct platform_device *pdev) + priv->vcdt = link_config.vcdt; + priv->vcdt2 = link_config.vcdt2; + priv->csi_rate = link_config.csi_rate; ++ priv->use_interrupts = link_config.use_interrupts; + atomic_set(&priv->use_count, 0); + + platform_set_drvdata(pdev, priv); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0480-media-i2c-soc_camera-ov10640-fix-emb-lines-number.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0480-media-i2c-soc_camera-ov10640-fix-emb-lines-number.patch new file mode 100644 index 00000000..121bab5a --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0480-media-i2c-soc_camera-ov10640-fix-emb-lines-number.patch @@ -0,0 +1,29 @@ +From b000da3023f944bb078c7bc284279b91854b0882 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Fri, 28 Feb 2020 11:51:12 +0300 +Subject: [PATCH] media: i2c: soc_camera: ov10640: fix emb lines number + +The number of emb lines are documnted as 2+2, but really +we see 4+4 + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov10640.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/soc_camera/ov10640.h b/drivers/media/i2c/soc_camera/ov10640.h +index 04ff326..de89b19 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.h ++++ b/drivers/media/i2c/soc_camera/ov10640.h +@@ -15,7 +15,7 @@ + #define OV10640_DEFAULT_WIDTH 1280 + #define OV10640_DEFAULT_HEIGHT 1080 + +-#define OV10640_EMB_LINES 4 /* 2 emb lines at top and 2 stat lines at bottom */ ++#define OV10640_EMB_LINES 8 /* 2+2 emb lines at top and 2+2 stat lines at bottom */ + #define OV10640_EMB_PADDED (priv->emb_enable ? OV10640_EMB_LINES : 0) /* embedded data (SOF) and stats (EOF) */ + + #define OV10640_DELAY 0xffff +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0481-r8a779-78-sysc-don-t-poweroff-Cortex-R7-core.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0481-r8a779-78-sysc-don-t-poweroff-Cortex-R7-core.patch new file mode 100644 index 00000000..d681e07a --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0481-r8a779-78-sysc-don-t-poweroff-Cortex-R7-core.patch @@ -0,0 +1,42 @@ +From 7ffd543f70c5455bc0a801036658c03a41cd3589 Mon Sep 17 00:00:00 2001 +From: Nikita Yushchenko <nikita.yoush@cogentembedded.com> +Date: Mon, 4 Jun 2018 11:12:25 +0300 +Subject: [PATCH] r8a779[78]-sysc: don't poweroff Cortex R7 core + +In V3M/V3H systems, Cortex R7 code normally executes code not anyhow +related to Linux. Linux should not touch R7's power domain. + +Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com> +--- + drivers/soc/renesas/r8a77970-sysc.c | 2 +- + drivers/soc/renesas/r8a77980-sysc.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/soc/renesas/r8a77970-sysc.c b/drivers/soc/renesas/r8a77970-sysc.c +index 5725ad09e4da..6d08a3c81262 100644 +--- a/drivers/soc/renesas/r8a77970-sysc.c ++++ b/drivers/soc/renesas/r8a77970-sysc.c +@@ -23,6 +23,7 @@ static const struct rcar_sysc_area r8a77970_areas[] __initconst = { + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A77970_PD_CA53_CPU1, R8A77970_PD_CA53_SCU, + PD_CPU_NOCR }, ++// { "cr7", 0x240, 0, R8A77970_PD_CR7, R8A77970_PD_ALWAYS_ON, PD_CPU }, + { "a3ir", 0x180, 0, R8A77970_PD_A3IR, R8A77970_PD_ALWAYS_ON }, + { "a2ir0", 0x400, 0, R8A77970_PD_A2IR0, R8A77970_PD_A3IR }, + { "a2ir1", 0x400, 1, R8A77970_PD_A2IR1, R8A77970_PD_A3IR }, +diff --git a/drivers/soc/renesas/r8a77980-sysc.c b/drivers/soc/renesas/r8a77980-sysc.c +index 2affaa27a6f8..ba73ce20d6ba 100644 +--- a/drivers/soc/renesas/r8a77980-sysc.c ++++ b/drivers/soc/renesas/r8a77980-sysc.c +@@ -28,7 +28,7 @@ static const struct rcar_sysc_area r8a77980_areas[] __initconst = { + PD_CPU_NOCR }, + { "ca53-cpu3", 0x200, 3, R8A77980_PD_CA53_CPU3, R8A77980_PD_CA53_SCU, + PD_CPU_NOCR }, +- { "cr7", 0x240, 0, R8A77980_PD_CR7, R8A77980_PD_ALWAYS_ON }, ++ { "cr7", 0x240, 0, R8A77980_PD_CR7, R8A77980_PD_ALWAYS_ON, PD_CPU }, + { "a3ir", 0x180, 0, R8A77980_PD_A3IR, R8A77980_PD_ALWAYS_ON }, + { "a2ir0", 0x400, 0, R8A77980_PD_A2IR0, R8A77980_PD_A3IR }, + { "a2ir1", 0x400, 1, R8A77980_PD_A2IR1, R8A77980_PD_A3IR }, +-- +2.11.0 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0482-media-i2c-max9286-ti9x4-power-down-POCs-on-reboot.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0482-media-i2c-max9286-ti9x4-power-down-POCs-on-reboot.patch new file mode 100644 index 00000000..ab493586 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0482-media-i2c-max9286-ti9x4-power-down-POCs-on-reboot.patch @@ -0,0 +1,139 @@ +From cc34c21f572727e49f69e10b761bc44d3addf520 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 4 Mar 2020 17:32:44 +0300 +Subject: [PATCH] media: i2c: max9286,ti9x4: power down POCs on reboot + +Power down all POCs on reboot/shutdown/halt + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/max9286.c | 23 +++++++++++++++++++++++ + drivers/media/i2c/soc_camera/ti9x4.c | 22 ++++++++++++++++++++++ + 2 files changed, 45 insertions(+) + +diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c +index 343b8ab..05247ff 100644 +--- a/drivers/media/i2c/soc_camera/max9286.c ++++ b/drivers/media/i2c/soc_camera/max9286.c +@@ -15,6 +15,7 @@ + #include <linux/notifier.h> + #include <linux/of_gpio.h> + #include <linux/of_graph.h> ++#include <linux/reboot.h> + #include <linux/videodev2.h> + + #include <media/v4l2-common.h> +@@ -71,6 +72,7 @@ struct max9286_priv { + int max9271_addr_map[4]; + int ser_id; + struct gpio_desc *poc_gpio[4]; /* PoC power supply */ ++ struct notifier_block reboot_notifier; + + /* link statistic */ + int prbserr[4]; +@@ -643,6 +645,19 @@ static int max9286_registered_async(struct v4l2_subdev *sd) + return 0; + } + ++static int max9286_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ struct max9286_priv *priv = container_of(nb, struct max9286_priv, reboot_notifier); ++ int idx; ++ ++ for (idx = 0; idx < priv->links; idx++) { ++ if (!IS_ERR(priv->poc_gpio[idx])) ++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ ++ } ++ ++ return NOTIFY_OK; ++} ++ + static struct v4l2_subdev_core_ops max9286_subdev_core_ops = { + #ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = max9286_g_register, +@@ -996,6 +1011,13 @@ static int max9286_probe(struct i2c_client *client, + goto out; + } + ++ priv->reboot_notifier.notifier_call = max9286_reboot_notifier; ++ err = register_reboot_notifier(&priv->reboot_notifier); ++ if (err) { ++ dev_err(&client->dev, "failed to register reboot notifier\n"); ++ goto out; ++ } ++ + err = sysfs_create_group(&client->dev.kobj, + &max9286_group); + if (err < 0) +@@ -1010,6 +1032,7 @@ static int max9286_remove(struct i2c_client *client) + int i; + + sysfs_remove_group(&client->dev.kobj, &max9286_group); ++ unregister_reboot_notifier(&priv->reboot_notifier); + + for (i = 0; i < 4; i++) { + v4l2_async_unregister_subdev(&priv->sd[i]); +diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c +index 9004bb1..627612a 100644 +--- a/drivers/media/i2c/soc_camera/ti9x4.c ++++ b/drivers/media/i2c/soc_camera/ti9x4.c +@@ -15,6 +15,7 @@ + #include <linux/notifier.h> + #include <linux/of_gpio.h> + #include <linux/of_graph.h> ++#include <linux/reboot.h> + #include <linux/videodev2.h> + + #include <media/v4l2-common.h> +@@ -52,6 +53,7 @@ struct ti9x4_priv { + struct gpio_desc *pwen; /* chip power en */ + struct gpio_desc *poc_gpio[4]; /* PoC power supply */ + struct v4l2_clk *ref_clk; /* ref clock */ ++ struct notifier_block reboot_notifier; + }; + + static int ser_id; +@@ -420,6 +422,19 @@ static int ti9x4_registered_async(struct v4l2_subdev *sd) + return 0; + } + ++static int ti9x4_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ struct ti9x4_priv *priv = container_of(nb, struct ti9x4_priv, reboot_notifier); ++ int idx; ++ ++ for (idx = 0; idx < priv->links; idx++) { ++ if (!IS_ERR(priv->poc_gpio[idx])) ++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ ++ } ++ ++ return NOTIFY_OK; ++} ++ + static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = { + #ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ti9x4_g_register, +@@ -676,6 +691,11 @@ static int ti9x4_probe(struct i2c_client *client, + goto out; + } + ++ priv->reboot_notifier.notifier_call = ti9x4_reboot_notifier; ++ err = register_reboot_notifier(&priv->reboot_notifier); ++ if (err) ++ dev_err(&client->dev, "failed to register reboot notifier\n"); ++ + out: + return err; + } +@@ -685,6 +705,8 @@ static int ti9x4_remove(struct i2c_client *client) + struct ti9x4_priv *priv = i2c_get_clientdata(client); + int i; + ++ unregister_reboot_notifier(&priv->reboot_notifier); ++ + for (i = 0; i < priv->links; i++) { + v4l2_async_unregister_subdev(&priv->sd[i]); + v4l2_device_unregister_subdev(&priv->sd[i]); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0484-media-platform-soc_camera-disable-mutex-locking-for-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0484-media-platform-soc_camera-disable-mutex-locking-for-.patch new file mode 100644 index 00000000..f654b012 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0484-media-platform-soc_camera-disable-mutex-locking-for-.patch @@ -0,0 +1,34 @@ +From fdfb65e3d12080ab862a1847f7d2127a9fd3c6b4 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 9 Mar 2020 23:15:28 +0300 +Subject: [PATCH] media: platform: soc_camera: disable mutex locking for + ADV_DEBUG + +This disabled v4l2_ioctl locking for G/S_REGISTER. +Hence the this allows to use G/S_REGISTER and Q/DQBUG under +stress load. + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com> +--- + drivers/media/platform/soc_camera/soc_camera.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c +index 8084683..654b0df 100644 +--- a/drivers/media/platform/soc_camera/soc_camera.c ++++ b/drivers/media/platform/soc_camera/soc_camera.c +@@ -2153,6 +2153,10 @@ static int soc_camera_video_start(struct soc_camera_device *icd) + v4l2_disable_ioctl(icd->vdev, VIDIOC_S_STD); + v4l2_disable_ioctl(icd->vdev, VIDIOC_ENUMSTD); + } ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ v4l2_disable_ioctl_locking(icd->vdev, VIDIOC_DBG_G_REGISTER); ++ v4l2_disable_ioctl_locking(icd->vdev, VIDIOC_DBG_S_REGISTER); ++#endif + ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + dev_err(icd->pdev, "video_register_device failed: %d\n", ret); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0485-media-i2c-ov10640-compensate-disabled-mutex.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0485-media-i2c-ov10640-compensate-disabled-mutex.patch new file mode 100644 index 00000000..1ddc7f9e --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0485-media-i2c-ov10640-compensate-disabled-mutex.patch @@ -0,0 +1,85 @@ +From 955d8c3c39605a389f10c96b2cf43b975476f272 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Tue, 10 Mar 2020 11:34:03 +0300 +Subject: [PATCH] media: i2c: ov10640: compensate disabled mutex + +Compensate ADV_DEBUG mutex after disabling in v4l2_ioctl + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ov10640.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c +index f5f0fdd..d52a0a2 100644 +--- a/drivers/media/i2c/soc_camera/ov10640.c ++++ b/drivers/media/i2c/soc_camera/ov10640.c +@@ -37,6 +37,7 @@ struct ov10640_priv { + struct v4l2_ctrl_handler hdl; + struct media_pad pad; + struct v4l2_rect rect; ++ struct mutex lock; + int subsampling; + int fps_numerator; + int fps_denominator; +@@ -328,6 +329,7 @@ static int ov10640_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10640_priv *priv = to_ov10640(client); + int ret; + __be64 be_val; + +@@ -336,10 +338,14 @@ static int ov10640_g_register(struct v4l2_subdev *sd, + if (reg->size > sizeof(reg->val)) + reg->size = sizeof(reg->val); + ++ mutex_lock(&priv->lock); ++ + ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); + be_val = be_val << ((sizeof(be_val) - reg->size) * 8); + reg->val = be64_to_cpu(be_val); + ++ mutex_unlock(&priv->lock); ++ + return ret; + } + +@@ -347,7 +353,9 @@ static int ov10640_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10640_priv *priv = to_ov10640(client); + u32 size = reg->size; ++ int ret; + __be64 be_val; + + if (!size) +@@ -355,10 +363,15 @@ static int ov10640_s_register(struct v4l2_subdev *sd, + if (size > sizeof(reg->val)) + size = sizeof(reg->val); + ++ mutex_lock(&priv->lock); ++ + be_val = cpu_to_be64(reg->val); + be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); + +- return reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ mutex_unlock(&priv->lock); ++ ++ return ret; + } + #endif + +@@ -711,6 +724,7 @@ static int ov10640_probe(struct i2c_client *client, + priv->rect.height = OV10640_DEFAULT_HEIGHT; + priv->fps_numerator = 1; + priv->fps_denominator = 30; ++ mutex_init(&priv->lock); + + v4l2_ctrl_handler_init(&priv->hdl, 4); + v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops, +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0487-i2c-busses-i2c-rcar-block-pm_runtime.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0487-i2c-busses-i2c-rcar-block-pm_runtime.patch new file mode 100644 index 00000000..24ec8902 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0487-i2c-busses-i2c-rcar-block-pm_runtime.patch @@ -0,0 +1,80 @@ +From 7fc6b55fbd279e287a350b85f45885d51c4de5c4 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 25 Mar 2020 15:07:48 +0300 +Subject: [PATCH] i2c: busses i2c-rcar: block pm_runtime + +This allows blocking of i2c clock runtime control by existing dts +pataremeter multi-master. +This speeds up i2c transaction during stress use case. + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/i2c/busses/i2c-rcar.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c +index ddd3b39..4a3ea72 100644 +--- a/drivers/i2c/busses/i2c-rcar.c ++++ b/drivers/i2c/busses/i2c-rcar.c +@@ -786,7 +786,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, + if (priv->suspended) + return -EBUSY; + +- pm_runtime_get_sync(dev); ++ if (!(priv->flags & ID_P_PM_BLOCKED)) ++ pm_runtime_get_sync(dev); + + /* Check bus state before init otherwise bus busy info will be lost */ + ret = rcar_i2c_bus_barrier(priv); +@@ -826,7 +827,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, + ret = num - priv->msgs_left; /* The number of transfer */ + } + out: +- pm_runtime_put(dev); ++ if (!(priv->flags & ID_P_PM_BLOCKED)) ++ pm_runtime_put(dev); + + if (ret < 0 && ret != -ENXIO) + dev_err(dev, "error %d : %x\n", ret, priv->flags); +@@ -845,7 +847,8 @@ static int rcar_reg_slave(struct i2c_client *slave) + return -EAFNOSUPPORT; + + /* Keep device active for slave address detection logic */ +- pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv)); ++ if (!(priv->flags & ID_P_PM_BLOCKED)) ++ pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv)); + + priv->slave = slave; + rcar_i2c_write(priv, ICSAR, slave->addr); +@@ -867,7 +870,8 @@ static int rcar_unreg_slave(struct i2c_client *slave) + + priv->slave = NULL; + +- pm_runtime_put(rcar_i2c_priv_to_dev(priv)); ++ if (!(priv->flags & ID_P_PM_BLOCKED)) ++ pm_runtime_put(rcar_i2c_priv_to_dev(priv)); + + return 0; + } +@@ -1026,6 +1030,8 @@ static int rcar_i2c_suspend(struct device *dev) + struct platform_device *pdev = to_platform_device(dev); + struct rcar_i2c_priv *priv = platform_get_drvdata(pdev); + ++ if (priv->flags & ID_P_PM_BLOCKED) ++ pm_runtime_put(dev); + priv->suspended = 1; + + return 0; +@@ -1045,7 +1051,8 @@ static int rcar_i2c_resume(struct device *dev) + dev_err(dev, "Could not calculate clock\n"); + + rcar_i2c_init(priv); +- pm_runtime_put(dev); ++ if (!(priv->flags & ID_P_PM_BLOCKED)) ++ pm_runtime_put(dev); + + priv->suspended = 0; + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0488-arm64-dts-renesas-block-i2c-pm-runtime.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0488-arm64-dts-renesas-block-i2c-pm-runtime.patch new file mode 100644 index 00000000..ef606653 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0488-arm64-dts-renesas-block-i2c-pm-runtime.patch @@ -0,0 +1,68 @@ +From 7d99fda5fcfea599b9611f4af562b5ee327e8745 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 25 Mar 2020 15:12:47 +0300 +Subject: [PATCH] arm64: dts: renesas: block i2c pm runtime + +Block i2c pm runtime on video boxes. +This speed up i2c under stress cases: imagers control over +FPDLINK or GMSL + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts | 1 + + arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts | 2 +- + arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts | 1 + + arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts | 1 + + 4 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts b/arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts +index 7ab71c8..4eb160c 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts +@@ -75,6 +75,7 @@ + status = "okay"; + + clock-frequency = <400000>; ++ multi-master; + + i2cswitch1: i2c-switch@74 { + compatible = "nxp,pca9548"; +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts +index 4ca62c6..7c84657 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts +@@ -143,6 +143,7 @@ + status = "okay"; + + clock-frequency = <400000>; ++ multi-master; + + i2cswitch1: i2c-switch@74 { + compatible = "nxp,pca9548"; +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts +index b635132..47f4408 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts +@@ -143,6 +143,7 @@ + status = "okay"; + + clock-frequency = <400000>; ++ multi-master; + + i2cswitch1: i2c-switch@74 { + compatible = "nxp,pca9548"; +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts +index f90951d..dc7938b 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts +@@ -137,6 +137,7 @@ + status = "okay"; + + clock-frequency = <400000>; ++ multi-master; + + i2cswitch1: i2c-switch@74 { + compatible = "nxp,pca9548"; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0489-media-i2c-max9286-increase-i2c-freq-inside-GMSL-cahn.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0489-media-i2c-max9286-increase-i2c-freq-inside-GMSL-cahn.patch new file mode 100644 index 00000000..7d10e4ce --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0489-media-i2c-max9286-increase-i2c-freq-inside-GMSL-cahn.patch @@ -0,0 +1,36 @@ +From 07aec3b12f833316963d45681f2dcbf688973621 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 25 Mar 2020 14:34:14 +0300 +Subject: [PATCH] media: i2c: max9286: increase i2c freq inside GMSL cahnnel + +This slightly (10%) increases the i2c transaction speed over GMSL. + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/max9286.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c +index 05247ff..28bd3c3 100644 +--- a/drivers/media/i2c/soc_camera/max9286.c ++++ b/drivers/media/i2c/soc_camera/max9286.c +@@ -31,7 +31,7 @@ + #define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ + #define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ + #define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ +-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ ++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_837KHZ + + struct max9286_priv { + struct v4l2_subdev sd[4]; +@@ -270,6 +270,7 @@ static void max9286_postinit(struct i2c_client *client, int addr) + reg8_write(client, 0x0b, priv->csi2_outord); /* CSI2 output order */ + reg8_write(client, 0x15, 0x9b); /* enable CSI output, VC is set accordingly to Link number, BIT7 magic must be set */ + reg8_write(client, 0x1b, priv->switchin | priv->links_mask); /* coax polarity, enable equalizer for CAMs */ ++ reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ + usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */ + + if (strcmp(priv->fsync_mode, "manual") == 0) { +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0490-media-i2c-ti9x4-increase-i2c-freq-on-master-bus.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0490-media-i2c-ti9x4-increase-i2c-freq-on-master-bus.patch new file mode 100644 index 00000000..adf70f4b --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0490-media-i2c-ti9x4-increase-i2c-freq-on-master-bus.patch @@ -0,0 +1,48 @@ +From 16082df9fc35be0488ddd3b4280187a9a361b511 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 25 Mar 2020 14:29:31 +0300 +Subject: [PATCH] media: i2c: ti9x4: increase i2c freq on master bus + +This increase the serializer (remote) i2c frequency on master bus. +This speed up imager access since deafult timings are 100Khz + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ti9x4.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c +index 627612a..ca86f1fc 100644 +--- a/drivers/media/i2c/soc_camera/ti9x4.c ++++ b/drivers/media/i2c/soc_camera/ti9x4.c +@@ -147,9 +147,6 @@ static void ti9x4_initial_setup(struct i2c_client *client) + + /* Initial setup */ + client->addr = priv->des_addr; /* TI9x4 I2C */ +- reg8_write(client, 0x08, 0x1c); /* I2C glitch filter depth */ +- reg8_write(client, 0x0a, 0x79); /* I2C high pulse width */ +- reg8_write(client, 0x0b, 0x79); /* I2C low pulse width */ + reg8_write(client, 0x0d, 0xb9); /* VDDIO 3.3V */ + switch (priv->csi_rate) { + case 1600: /* REFCLK = 25MHZ */ +@@ -340,6 +337,8 @@ static int ti9x4_initialize(struct i2c_client *client) + switch (priv->ser_id) { + case TI913_ID: + reg8_write(client, 0x0d, 0x55); /* Enable remote GPIO0/1 */ ++ reg8_write(client, 0x11, 0x10); /* I2C high pulse width */ ++ reg8_write(client, 0x12, 0x10); /* I2C low pulse width */ + break; + case TI953_ID: + reg8_write(client, 0x0d, (priv->gpio[0] & 0x1) << 0 | +@@ -354,6 +353,8 @@ static int ti9x4_initialize(struct i2c_client *client) + (!!priv->gpio[1] << 5) | + (!!priv->gpio[2] << 6) | + (!!priv->gpio[3] << 7)); /* Enable serializer GPIOs only for output */ ++ reg8_write(client, 0x0b, 0x10); /* I2C high pulse width */ ++ reg8_write(client, 0x0c, 0x10); /* I2C low pulse width */ + break; + } + client->addr = priv->des_addr; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0491-media-i2c-soc_camera-switch-to-u64-adv_debug-access.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0491-media-i2c-soc_camera-switch-to-u64-adv_debug-access.patch new file mode 100644 index 00000000..05274af5 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0491-media-i2c-soc_camera-switch-to-u64-adv_debug-access.patch @@ -0,0 +1,690 @@ +From 479f56c0ec0ce981e9333e7c1628c4850f3c8043 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 25 Mar 2020 17:27:04 +0300 +Subject: [PATCH] media: i2c: soc_camera: switch to u64 adv_debug access + +This allows up to 8 bytes block writes/reads using ADV_DEBUG +interface. + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ap0101_ar014x.c | 34 +++++++++++++++++++-------- + drivers/media/i2c/soc_camera/ar0132.c | 34 +++++++++++++++++++-------- + drivers/media/i2c/soc_camera/ar0140.c | 34 +++++++++++++++++++-------- + drivers/media/i2c/soc_camera/ar0143.c | 35 +++++++++++++++++++--------- + drivers/media/i2c/soc_camera/ar0147.c | 34 +++++++++++++++++++-------- + drivers/media/i2c/soc_camera/ar0231.c | 34 +++++++++++++++++++-------- + drivers/media/i2c/soc_camera/ar0233.c | 34 +++++++++++++++++++-------- + drivers/media/i2c/soc_camera/ar0323.c | 34 +++++++++++++++++++-------- + drivers/media/i2c/soc_camera/ov10635.c | 30 +++++++++++++++++------- + drivers/media/i2c/soc_camera/ov2311.c | 30 +++++++++++++++++------- + drivers/media/i2c/soc_camera/ox01d10.c | 30 +++++++++++++++++------- + drivers/media/i2c/soc_camera/ox03a.c | 30 +++++++++++++++++------- + 12 files changed, 280 insertions(+), 113 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/ap0101_ar014x.c +index c458044..8a2d2a6 100644 +--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.c ++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.c +@@ -273,28 +273,42 @@ static int ap0101_g_mbus_config(struct v4l2_subdev *sd, + + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ap0101_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) ++ struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u16 val = 0; ++ __be64 be_val; + +- ret = reg16_read16(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ap0101_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) ++ const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write16(client, (u16)reg->reg, (u16)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ar0132.c b/drivers/media/i2c/soc_camera/ar0132.c +index 30e9517..9f55364 100644 +--- a/drivers/media/i2c/soc_camera/ar0132.c ++++ b/drivers/media/i2c/soc_camera/ar0132.c +@@ -232,28 +232,42 @@ static int ar0132_g_mbus_config(struct v4l2_subdev *sd, + + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0132_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) ++ struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u16 val = 0; ++ __be64 be_val; + +- ret = reg16_read16(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ar0132_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) ++ const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write16(client, (u16)reg->reg, (u16)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ar0140.c b/drivers/media/i2c/soc_camera/ar0140.c +index bb7a3ce..4d3893bf 100644 +--- a/drivers/media/i2c/soc_camera/ar0140.c ++++ b/drivers/media/i2c/soc_camera/ar0140.c +@@ -265,28 +265,42 @@ static int ar0140_g_mbus_config(struct v4l2_subdev *sd, + + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0140_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) ++ struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u16 val = 0; ++ __be64 be_val; + +- ret = reg16_read16(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ar0140_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) ++ const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write16(client, (u16)reg->reg, (u16)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c +index 083b7ec..e60e2ec 100644 +--- a/drivers/media/i2c/soc_camera/ar0143.c ++++ b/drivers/media/i2c/soc_camera/ar0143.c +@@ -356,31 +356,44 @@ static int ar0143_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) + return ret; + } + +- + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0143_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) ++ struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u16 val = 0; ++ __be64 be_val; + +- ret = reg16_read16(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ar0143_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) ++ const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write16(client, (u16)reg->reg, (u16)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ar0147.c b/drivers/media/i2c/soc_camera/ar0147.c +index a444700..d7e3f83 100644 +--- a/drivers/media/i2c/soc_camera/ar0147.c ++++ b/drivers/media/i2c/soc_camera/ar0147.c +@@ -372,28 +372,42 @@ static int ar0147_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) + + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0147_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) ++ struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u16 val = 0; ++ __be64 be_val; + +- ret = reg16_read16(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ar0147_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) ++ const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write16(client, (u16)reg->reg, (u16)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ar0231.c b/drivers/media/i2c/soc_camera/ar0231.c +index 6c450f7..922c078 100644 +--- a/drivers/media/i2c/soc_camera/ar0231.c ++++ b/drivers/media/i2c/soc_camera/ar0231.c +@@ -253,28 +253,42 @@ static int ar0231_g_mbus_config(struct v4l2_subdev *sd, + + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0231_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) ++ struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u16 val = 0; ++ __be64 be_val; + +- ret = reg16_read16(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ar0231_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) ++ const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write16(client, (u16)reg->reg, (u16)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c +index fbff49b..2bf260b 100644 +--- a/drivers/media/i2c/soc_camera/ar0233.c ++++ b/drivers/media/i2c/soc_camera/ar0233.c +@@ -323,28 +323,42 @@ static int ar0233_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) + + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0233_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) ++ struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u16 val = 0; ++ __be64 be_val; + +- ret = reg16_read16(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ar0233_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) ++ const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write16(client, (u16)reg->reg, (u16)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ar0323.c b/drivers/media/i2c/soc_camera/ar0323.c +index 2104d6a..1f20fef 100644 +--- a/drivers/media/i2c/soc_camera/ar0323.c ++++ b/drivers/media/i2c/soc_camera/ar0323.c +@@ -207,28 +207,42 @@ static int ar0323_g_mbus_config(struct v4l2_subdev *sd, + + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int ar0323_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) ++ struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u16 val = 0; ++ __be64 be_val; + +- ret = reg16_read16(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ar0323_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) ++ const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write16(client, (u16)reg->reg, (u16)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ov10635.c b/drivers/media/i2c/soc_camera/ov10635.c +index 14bb339..e9e0cdf 100644 +--- a/drivers/media/i2c/soc_camera/ov10635.c ++++ b/drivers/media/i2c/soc_camera/ov10635.c +@@ -357,24 +357,38 @@ static int ov10635_g_register(struct v4l2_subdev *sd, + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u8 val = 0; ++ __be64 be_val; + +- ret = reg16_read(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u8); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ov10635_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u8); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write(client, (u16)reg->reg, (u8)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ov2311.c b/drivers/media/i2c/soc_camera/ov2311.c +index c61059d..f8099c7 100644 +--- a/drivers/media/i2c/soc_camera/ov2311.c ++++ b/drivers/media/i2c/soc_camera/ov2311.c +@@ -268,24 +268,38 @@ static int ov2311_g_register(struct v4l2_subdev *sd, + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u8 val = 0; ++ __be64 be_val; + +- ret = reg16_read(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u8); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u16); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ov2311_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u8); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write(client, (u16)reg->reg, (u8)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ox01d10.c b/drivers/media/i2c/soc_camera/ox01d10.c +index 082e88c..cac267a 100644 +--- a/drivers/media/i2c/soc_camera/ox01d10.c ++++ b/drivers/media/i2c/soc_camera/ox01d10.c +@@ -215,24 +215,38 @@ static int ox01d10_g_register(struct v4l2_subdev *sd, + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u8 val = 0; ++ __be64 be_val; + +- ret = reg16_read(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u8); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u8); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ox01d10_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u8); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write(client, (u16)reg->reg, (u8)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +diff --git a/drivers/media/i2c/soc_camera/ox03a.c b/drivers/media/i2c/soc_camera/ox03a.c +index 162c75b..3b4ae27 100644 +--- a/drivers/media/i2c/soc_camera/ox03a.c ++++ b/drivers/media/i2c/soc_camera/ox03a.c +@@ -214,24 +214,38 @@ static int ox03a_g_register(struct v4l2_subdev *sd, + { + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; +- u8 val = 0; ++ __be64 be_val; + +- ret = reg16_read(client, (u16)reg->reg, &val); +- if (ret < 0) +- return ret; ++ if (!reg->size) ++ reg->size = sizeof(u8); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); + +- reg->val = val; +- reg->size = sizeof(u8); ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); + +- return 0; ++ return ret; + } + + static int ox03a_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u8); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); + +- return reg16_write(client, (u16)reg->reg, (u8)reg->val); ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; + } + #endif + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0492-media-i2c-move-gmsl-fpdlink-drivers-to-separate-fold.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0492-media-i2c-move-gmsl-fpdlink-drivers-to-separate-fold.patch new file mode 100644 index 00000000..a4851c0d --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0492-media-i2c-move-gmsl-fpdlink-drivers-to-separate-fold.patch @@ -0,0 +1,6794 @@ +From 40f71bc01fcacef975e9fd507ec212a08aeeade9 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 10:47:53 +0300 +Subject: [PATCH] media: i2c: move gmsl/fpdlink drivers to separate + folder + +Move GMSL/FPDLINK driver to separate folder + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/Kconfig | 28 +- + drivers/media/i2c/soc_camera/Makefile | 7 +- + drivers/media/i2c/soc_camera/dummy.c | 491 ----------- + drivers/media/i2c/soc_camera/fpdlink/Kconfig | 5 + + drivers/media/i2c/soc_camera/fpdlink/Makefile | 2 + + drivers/media/i2c/soc_camera/fpdlink/ti9x4.c | 745 +++++++++++++++++ + drivers/media/i2c/soc_camera/fpdlink/ti9x4.h | 204 +++++ + drivers/media/i2c/soc_camera/gmsl/Kconfig | 11 + + drivers/media/i2c/soc_camera/gmsl/Makefile | 3 + + drivers/media/i2c/soc_camera/gmsl/max9286.c | 1072 +++++++++++++++++++++++++ + drivers/media/i2c/soc_camera/gmsl/max9288.c | 768 ++++++++++++++++++ + drivers/media/i2c/soc_camera/imagers/Kconfig | 5 + + drivers/media/i2c/soc_camera/imagers/Makefile | 2 + + drivers/media/i2c/soc_camera/imagers/dummy.c | 491 +++++++++++ + drivers/media/i2c/soc_camera/max9286.c | 1072 ------------------------- + drivers/media/i2c/soc_camera/max9288.c | 768 ------------------ + drivers/media/i2c/soc_camera/ti9x4.c | 745 ----------------- + drivers/media/i2c/soc_camera/ti9x4.h | 204 ----- + 18 files changed, 3315 insertions(+), 3308 deletions(-) + delete mode 100644 drivers/media/i2c/soc_camera/dummy.c + create mode 100644 drivers/media/i2c/soc_camera/fpdlink/Kconfig + create mode 100644 drivers/media/i2c/soc_camera/fpdlink/Makefile + create mode 100644 drivers/media/i2c/soc_camera/fpdlink/ti9x4.c + create mode 100644 drivers/media/i2c/soc_camera/fpdlink/ti9x4.h + create mode 100644 drivers/media/i2c/soc_camera/gmsl/Kconfig + create mode 100644 drivers/media/i2c/soc_camera/gmsl/Makefile + create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9286.c + create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9288.c + create mode 100644 drivers/media/i2c/soc_camera/imagers/Kconfig + create mode 100644 drivers/media/i2c/soc_camera/imagers/Makefile + create mode 100644 drivers/media/i2c/soc_camera/imagers/dummy.c + delete mode 100644 drivers/media/i2c/soc_camera/max9286.c + delete mode 100644 drivers/media/i2c/soc_camera/max9288.c + delete mode 100644 drivers/media/i2c/soc_camera/ti9x4.c + delete mode 100644 drivers/media/i2c/soc_camera/ti9x4.h + +diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig +index 729b5af..6792522 100644 +--- a/drivers/media/i2c/soc_camera/Kconfig ++++ b/drivers/media/i2c/soc_camera/Kconfig +@@ -83,30 +83,6 @@ config SOC_CAMERA_TW9910 + help + This is a tw9910 video driver + +-config SOC_CAMERA_MAX9286 +- tristate "max9286 GMSL support" +- depends on SOC_CAMERA && I2C +- help +- This is a MAXIM max9286 GMSL driver +- +-config SOC_CAMERA_MAX9288 +- tristate "max9288 GMSL support" +- depends on SOC_CAMERA && I2C +- help +- This is a MAXIM max9288 GMSL driver +- +-config SOC_CAMERA_TI9X4 +- tristate "ti9x4 FPDLink3 support" +- depends on SOC_CAMERA && I2C +- help +- This is an Texas Instruments ti9X4 FPDLink3 driver +- +-config SOC_CAMERA_OV106XX +- tristate "ov106xx camera support" +- depends on SOC_CAMERA && I2C +- help +- This is a runtime detected GMSL/FPDLink3 sensors driver +- + config SOC_CAMERA_IMX219 + tristate "imx219 camera support" + depends on SOC_CAMERA && I2C +@@ -118,3 +94,7 @@ config SOC_CAMERA_AR0147 + depends on SOC_CAMERA && I2C + help + This is an AR0147 imager glue ++ ++source "drivers/media/i2c/soc_camera/gmsl/Kconfig" ++source "drivers/media/i2c/soc_camera/fpdlink/Kconfig" ++source "drivers/media/i2c/soc_camera/imagers/Kconfig" +diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile +index d916bba..5e08254 100644 +--- a/drivers/media/i2c/soc_camera/Makefile ++++ b/drivers/media/i2c/soc_camera/Makefile +@@ -11,11 +11,10 @@ obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o + obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o + obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o + obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o +-obj-$(CONFIG_SOC_CAMERA_MAX9286) += max9286.o +-obj-$(CONFIG_SOC_CAMERA_MAX9288) += max9288.o +-obj-$(CONFIG_SOC_CAMERA_TI9X4) += ti9x4.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov106xx.o + obj-$(CONFIG_SOC_CAMERA_IMX219) += imx219.o +-obj-y += dummy.o + + obj-$(CONFIG_SOC_CAMERA_AR0147) += ar0147.o ++obj-y += imagers/ ++obj-y += gmsl/ ++obj-y += fpdlink/ +diff --git a/drivers/media/i2c/soc_camera/dummy.c b/drivers/media/i2c/soc_camera/dummy.c +deleted file mode 100644 +index d213fff..0000000 +--- a/drivers/media/i2c/soc_camera/dummy.c ++++ /dev/null +@@ -1,491 +0,0 @@ +-/* +- * Dummy sensor camera driver +- * +- * Copyright (C) 2019 Cogent Embedded, Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- */ +- +-#include <linux/delay.h> +-#include <linux/init.h> +-#include <linux/i2c.h> +-#include <linux/module.h> +-#include <linux/of_graph.h> +-#include <linux/videodev2.h> +- +-#include <media/soc_camera.h> +-#include <media/v4l2-common.h> +-#include <media/v4l2-ctrls.h> +- +-struct dummy_priv { +- struct v4l2_subdev sd; +- struct v4l2_ctrl_handler hdl; +- struct media_pad pad; +- struct v4l2_rect rect; +- u8 id[6]; +- int max_width; +- int max_height; +- const char * media_bus_format; +- int mbus_format; +-}; +- +-static int width = 1920; +-module_param(width, int, 0644); +-MODULE_PARM_DESC(width, " width (default: 1920)"); +- +-static int height = 1080; +-module_param(height, int, 0644); +-MODULE_PARM_DESC(height, " height (default: 1080)"); +- +-static char *mbus = "yuyv"; +-module_param(mbus, charp, 0644); +-MODULE_PARM_DESC(mbus, " MEDIA_BUS_FORMAT (default: YUYV)"); +- +-static inline struct dummy_priv *to_dummy(const struct i2c_client *client) +-{ +- return container_of(i2c_get_clientdata(client), struct dummy_priv, sd); +-} +- +-static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +-{ +- return &container_of(ctrl->handler, struct dummy_priv, hdl)->sd; +-} +- +-static int dummy_s_stream(struct v4l2_subdev *sd, int enable) +-{ +- return 0; +-} +- +-static int dummy_get_fmt(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_format *format) +-{ +- struct v4l2_mbus_framefmt *mf = &format->format; +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct dummy_priv *priv = to_dummy(client); +- +- if (format->pad) +- return -EINVAL; +- +- mf->width = priv->rect.width; +- mf->height = priv->rect.height; +- mf->code = priv->mbus_format; +- mf->colorspace = V4L2_COLORSPACE_SMPTE170M; +- mf->field = V4L2_FIELD_NONE; +- +- return 0; +-} +- +-static int dummy_set_fmt(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_format *format) +-{ +- struct v4l2_mbus_framefmt *mf = &format->format; +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct dummy_priv *priv = to_dummy(client); +- +- mf->code = priv->mbus_format; +- mf->colorspace = V4L2_COLORSPACE_SMPTE170M; +- mf->field = V4L2_FIELD_NONE; +- +- if (format->which == V4L2_SUBDEV_FORMAT_TRY) +- cfg->try_fmt = *mf; +- +- return 0; +-} +- +-static int dummy_enum_mbus_code(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_mbus_code_enum *code) +-{ +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct dummy_priv *priv = to_dummy(client); +- +- if (code->pad || code->index > 0) +- return -EINVAL; +- +- code->code = priv->mbus_format; +- +- return 0; +-} +- +-static int dummy_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +-{ +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct dummy_priv *priv = to_dummy(client); +- +- memcpy(edid->edid, priv->id, 6); +- +- edid->edid[6] = 0xff; +- edid->edid[7] = client->addr; +- edid->edid[8] = 'D' >> 8; +- edid->edid[9] = 'Y' & 0xff; +- +- return 0; +-} +- +-static int dummy_set_selection(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_selection *sel) +-{ +- struct v4l2_rect *rect = &sel->r; +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct dummy_priv *priv = to_dummy(client); +- +- if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || +- sel->target != V4L2_SEL_TGT_CROP) +- return -EINVAL; +- +- rect->left = ALIGN(rect->left, 2); +- rect->top = ALIGN(rect->top, 2); +- rect->width = ALIGN(rect->width, 2); +- rect->height = ALIGN(rect->height, 2); +- +- if ((rect->left + rect->width > priv->max_width) || +- (rect->top + rect->height > priv->max_height)) +- *rect = priv->rect; +- +- priv->rect.left = rect->left; +- priv->rect.top = rect->top; +- priv->rect.width = rect->width; +- priv->rect.height = rect->height; +- +- return 0; +-} +- +-static int dummy_get_selection(struct v4l2_subdev *sd, +- struct v4l2_subdev_pad_config *cfg, +- struct v4l2_subdev_selection *sel) +-{ +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct dummy_priv *priv = to_dummy(client); +- +- if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) +- return -EINVAL; +- +- switch (sel->target) { +- case V4L2_SEL_TGT_CROP_BOUNDS: +- sel->r.left = 0; +- sel->r.top = 0; +- sel->r.width = priv->max_width; +- sel->r.height = priv->max_height; +- return 0; +- case V4L2_SEL_TGT_CROP_DEFAULT: +- sel->r.left = 0; +- sel->r.top = 0; +- sel->r.width = priv->max_width; +- sel->r.height = priv->max_height; +- return 0; +- case V4L2_SEL_TGT_CROP: +- sel->r = priv->rect; +- return 0; +- default: +- return -EINVAL; +- } +-} +- +-static int dummy_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) +-{ +- cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | +- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; +- cfg->type = V4L2_MBUS_CSI2; +- +- return 0; +-} +- +-#ifdef CONFIG_VIDEO_ADV_DEBUG +-static int dummy_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) +-{ +- reg->val = 0; +- reg->size = sizeof(u16); +- +- return 0; +-} +- +-static int dummy_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) +-{ +- return 0; +-} +-#endif +- +-static struct v4l2_subdev_core_ops dummy_core_ops = { +-#ifdef CONFIG_VIDEO_ADV_DEBUG +- .g_register = dummy_g_register, +- .s_register = dummy_s_register, +-#endif +-}; +- +-static int dummy_s_ctrl(struct v4l2_ctrl *ctrl) +-{ +- switch (ctrl->id) { +- case V4L2_CID_BRIGHTNESS: +- case V4L2_CID_CONTRAST: +- case V4L2_CID_SATURATION: +- case V4L2_CID_HUE: +- case V4L2_CID_GAMMA: +- case V4L2_CID_SHARPNESS: +- case V4L2_CID_AUTOGAIN: +- case V4L2_CID_GAIN: +- case V4L2_CID_ANALOGUE_GAIN: +- case V4L2_CID_EXPOSURE: +- case V4L2_CID_HFLIP: +- case V4L2_CID_VFLIP: +- case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: +- break; +- } +- +- return 0; +-} +- +-static const struct v4l2_ctrl_ops dummy_ctrl_ops = { +- .s_ctrl = dummy_s_ctrl, +-}; +- +-static struct v4l2_subdev_video_ops dummy_video_ops = { +- .s_stream = dummy_s_stream, +- .g_mbus_config = dummy_g_mbus_config, +-}; +- +-static const struct v4l2_subdev_pad_ops dummy_subdev_pad_ops = { +- .get_edid = dummy_get_edid, +- .enum_mbus_code = dummy_enum_mbus_code, +- .get_selection = dummy_get_selection, +- .set_selection = dummy_set_selection, +- .get_fmt = dummy_get_fmt, +- .set_fmt = dummy_set_fmt, +-}; +- +-static struct v4l2_subdev_ops dummy_subdev_ops = { +- .core = &dummy_core_ops, +- .video = &dummy_video_ops, +- .pad = &dummy_subdev_pad_ops, +-}; +- +-static void dummy_otp_id_read(struct i2c_client *client) +-{ +- struct dummy_priv *priv = to_dummy(client); +- +- /* dummy camera id */ +- priv->id[0] = 'd'; +- priv->id[1] = 'u'; +- priv->id[2] = 'm'; +- priv->id[3] = 'm'; +- priv->id[4] = 'y'; +- priv->id[5] = '.'; +-} +- +-static ssize_t dummy_otp_id_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); +- struct i2c_client *client = v4l2_get_subdevdata(sd); +- struct dummy_priv *priv = to_dummy(client); +- +- dummy_otp_id_read(client); +- +- return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", +- priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +-} +- +-static DEVICE_ATTR(otp_id_dummy, S_IRUGO, dummy_otp_id_show, NULL); +- +-static int dummy_initialize(struct i2c_client *client) +-{ +- struct dummy_priv *priv = to_dummy(client); +- +- if (strcmp(priv->media_bus_format, "yuyv") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_YUYV8_2X8; +- else if (strcmp(priv->media_bus_format, "uyvy") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_UYVY8_2X8; +- else if (strcmp(priv->media_bus_format, "grey") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_Y8_1X8; +- else if (strcmp(priv->media_bus_format, "rggb8") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SRGGB8_1X8; +- else if (strcmp(priv->media_bus_format, "bggr8") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SBGGR8_1X8; +- else if (strcmp(priv->media_bus_format, "grbg8") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SGRBG8_1X8; +- else if (strcmp(priv->media_bus_format, "rggb12") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SRGGB12_1X12; +- else if (strcmp(priv->media_bus_format, "bggr12") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SBGGR12_1X12; +- else if (strcmp(priv->media_bus_format, "grbg12") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SGRBG12_1X12; +- else if (strcmp(priv->media_bus_format, "rggb14") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SRGGB14_1X14; +- else if (strcmp(priv->media_bus_format, "bggr14") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SBGGR14_1X14; +- else if (strcmp(priv->media_bus_format, "grbg14") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SGRBG14_1X14; +- else if (strcmp(priv->media_bus_format, "rggb16") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SRGGB16_1X16; +- else if (strcmp(priv->media_bus_format, "bggr16") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SBGGR16_1X16; +- else if (strcmp(priv->media_bus_format, "grbg16") == 0) +- priv->mbus_format = MEDIA_BUS_FMT_SGRBG16_1X16; +- else { +- v4l_err(client, "failed to parse mbus format (%s)\n", priv->media_bus_format); +- return -EINVAL; +- } +- +- /* Read OTP IDs */ +- dummy_otp_id_read(client); +- +- dev_info(&client->dev, "Dummy camera sensor, res %dx%d, mbus %s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", +- priv->max_width, priv->max_height, priv->media_bus_format, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +- +- return 0; +-} +- +-static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv) +-{ +- if (of_property_read_u32(np, "dummy,width", &priv->max_width)) +- priv->max_width = width; +- +- if (of_property_read_u32(np, "dummy,height", &priv->max_height)) +- priv->max_height = height; +- +- if (of_property_read_string(np, "dummy,mbus", &priv->media_bus_format)) +- priv->media_bus_format = mbus; +- +- /* module params override dts */ +- if (strcmp(mbus, "yuyv")) +- priv->media_bus_format = mbus; +- if (width != 1920) +- priv->max_width = width; +- if (height != 1080) +- priv->max_height = height; +- +- return 0; +-} +- +-static int dummy_probe(struct i2c_client *client, +- const struct i2c_device_id *did) +-{ +- struct dummy_priv *priv; +- int ret; +- +- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- v4l2_i2c_subdev_init(&priv->sd, client, &dummy_subdev_ops); +- priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; +- +- v4l2_ctrl_handler_init(&priv->hdl, 4); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_CONTRAST, 0, 16, 1, 7); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_SATURATION, 0, 7, 1, 2); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_HUE, 0, 23, 1, 12); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_GAMMA, -128, 128, 1, 0); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_SHARPNESS, 0, 10, 1, 3); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_AUTOGAIN, 0, 1, 1, 0); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_GAIN, 1, 0x7ff, 1, 0x200); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_HFLIP, 0, 1, 1, 0); +- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, +- V4L2_CID_VFLIP, 0, 1, 1, 0); +- priv->sd.ctrl_handler = &priv->hdl; +- +- ret = priv->hdl.error; +- if (ret) +- goto cleanup; +- +- v4l2_ctrl_handler_setup(&priv->hdl); +- +- priv->pad.flags = MEDIA_PAD_FL_SOURCE; +- priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; +- ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); +- if (ret < 0) +- goto cleanup; +- +- ret = dummy_parse_dt(client->dev.of_node, priv); +- if (ret) +- goto cleanup; +- +- ret = dummy_initialize(client); +- if (ret < 0) +- goto cleanup; +- +- priv->rect.left = 0; +- priv->rect.top = 0; +- priv->rect.width = priv->max_width; +- priv->rect.height = priv->max_height; +- +- ret = v4l2_async_register_subdev(&priv->sd); +- if (ret) +- goto cleanup; +- +- if (device_create_file(&client->dev, &dev_attr_otp_id_dummy) != 0) { +- dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); +- goto cleanup; +- } +- +- return 0; +- +-cleanup: +- media_entity_cleanup(&priv->sd.entity); +- v4l2_ctrl_handler_free(&priv->hdl); +- v4l2_device_unregister_subdev(&priv->sd); +- v4l_err(client, "failed to probe @ 0x%02x (%s)\n", +- client->addr, client->adapter->name); +- return ret; +-} +- +-static int dummy_remove(struct i2c_client *client) +-{ +- struct dummy_priv *priv = i2c_get_clientdata(client); +- +- device_remove_file(&client->dev, &dev_attr_otp_id_dummy); +- v4l2_async_unregister_subdev(&priv->sd); +- media_entity_cleanup(&priv->sd.entity); +- v4l2_ctrl_handler_free(&priv->hdl); +- v4l2_device_unregister_subdev(&priv->sd); +- +- return 0; +-} +- +-static const struct i2c_device_id dummy_id[] = { +- { "dummy-camera", 0 }, +- { } +-}; +-MODULE_DEVICE_TABLE(i2c, dummy_id); +- +-static const struct of_device_id dummy_of_ids[] = { +- { .compatible = "dummy-camera", }, +- { } +-}; +-MODULE_DEVICE_TABLE(of, dummy_of_ids); +- +-static struct i2c_driver dummy_i2c_driver = { +- .driver = { +- .name = "dummy-camera", +- .of_match_table = dummy_of_ids, +- }, +- .probe = dummy_probe, +- .remove = dummy_remove, +- .id_table = dummy_id, +-}; +-module_i2c_driver(dummy_i2c_driver); +- +-MODULE_DESCRIPTION("Dummy SoC camera driver"); +-MODULE_AUTHOR("Vladimir Barinov"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/fpdlink/Kconfig b/drivers/media/i2c/soc_camera/fpdlink/Kconfig +new file mode 100644 +index 0000000..9550563 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/fpdlink/Kconfig +@@ -0,0 +1,5 @@ ++config SOC_CAMERA_TI9X4 ++ tristate "ti9x4 FPDLink3 support" ++ depends on I2C ++ help ++ This is an Texas Instruments ti9X4 FPDLink3 driver +diff --git a/drivers/media/i2c/soc_camera/fpdlink/Makefile b/drivers/media/i2c/soc_camera/fpdlink/Makefile +new file mode 100644 +index 0000000..29f4a59 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/fpdlink/Makefile +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_SOC_CAMERA_TI9X4) += ti9x4.o +diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c +new file mode 100644 +index 0000000..340e61e +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c +@@ -0,0 +1,745 @@ ++ /* ++ * TI DS90UB954/960/964 FPDLinkIII driver ++ * ++ * Copyright (C) 2017-2018 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/notifier.h> ++#include <linux/of_gpio.h> ++#include <linux/of_graph.h> ++#include <linux/reboot.h> ++#include <linux/videodev2.h> ++ ++#include <media/v4l2-common.h> ++#include <media/v4l2-clk.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-subdev.h> ++ ++#include "ti9x4.h" ++ ++struct ti9x4_priv { ++ struct v4l2_subdev sd[4]; ++ struct fwnode_handle *sd_fwnode[4]; ++ int des_addr; ++ int links; ++ int lanes; ++ int csi_rate; ++ const char *forwarding_mode; ++ int fs_time; ++ int fps_numerator; ++ int fps_denominator; ++ int is_coax; ++ int dvp_bus; ++ int dvp_lsb; ++ int hsync; ++ int vsync; ++ int poc_delay; ++ atomic_t use_count; ++ struct i2c_client *client; ++ int ti9x3_addr_map[4]; ++ char chip_id[6]; ++ int ser_id; ++ int vc_map; ++ int csi_map; ++ int gpio[4]; ++ struct gpio_desc *pwen; /* chip power en */ ++ struct gpio_desc *poc_gpio[4]; /* PoC power supply */ ++ struct v4l2_clk *ref_clk; /* ref clock */ ++ struct notifier_block reboot_notifier; ++}; ++ ++static int ser_id; ++module_param(ser_id, int, 0644); ++MODULE_PARM_DESC(ser_id, " Serializer ID (default: TI913)"); ++ ++static int is_stp; ++module_param(is_stp, int, 0644); ++MODULE_PARM_DESC(is_stp, " STP cable (default: Coax cable)"); ++ ++static int dvp_bus = 8; ++module_param(dvp_bus, int, 0644); ++MODULE_PARM_DESC(dvp_bus, " DVP/CSI over FPDLink (default: DVP 8-bit)"); ++ ++static int dvp_lsb = 0; ++module_param(dvp_lsb, int, 0644); ++MODULE_PARM_DESC(dvp_lsb, " DVP 8-bit LSB/MSB selection (default: DVP 8-bit MSB)"); ++ ++static int hsync; ++module_param(hsync, int, 0644); ++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); ++ ++static int vsync = 1; ++module_param(vsync, int, 0644); ++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); ++ ++static int poc_delay; ++module_param(poc_delay, int, 0644); ++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms)"); ++ ++static int vc_map = 0x3210; ++module_param(vc_map, int, 0644); ++MODULE_PARM_DESC(vc_map, " CSI VC MAP (default: 0xe4 - linear map VCx=LINKx)"); ++ ++static int csi_map = 0; ++module_param(csi_map, int, 0644); ++MODULE_PARM_DESC(csi_map, " CSI TX MAP (default: 0 - forwarding of all links to CSI0)"); ++ ++static int gpio0 = 0, gpio1 = 0, gpio2 = 0, gpio3 = 0; ++module_param(gpio0, int, 0644); ++MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 low level)"); ++module_param(gpio1, int, 0644); ++MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 low level)"); ++module_param(gpio2, int, 0644); ++MODULE_PARM_DESC(gpio2, " GPIO2 function select (default: GPIO2 low level)"); ++module_param(gpio3, int, 0644); ++MODULE_PARM_DESC(gpio3, " GPIO3 function select (default: GPIO3 low level)"); ++ ++#ifdef TI954_SILICON_ERRATA ++static int indirect_write(struct i2c_client *client, unsigned int page, u8 reg, u8 val) ++{ ++ if (page > 7) ++ return -EINVAL; ++ ++ reg8_write(client, 0xb0, page << 2); ++ reg8_write(client, 0xb1, reg); ++ reg8_write(client, 0xb2, val); ++ ++ return 0; ++} ++ ++static int indirect_read(struct i2c_client *client, unsigned int page, u8 reg, u8 *val) ++{ ++ if (page > 7) ++ return -EINVAL; ++ ++ reg8_write(client, 0xb0, page << 2); ++ reg8_write(client, 0xb1, reg); ++ reg8_read(client, 0xb2, val); ++ ++ return 0; ++} ++#endif ++ ++static void ti9x4_read_chipid(struct i2c_client *client) ++{ ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); ++ ++ /* Chip ID */ ++ reg8_read(client, 0xf1, &priv->chip_id[0]); ++ reg8_read(client, 0xf2, &priv->chip_id[1]); ++ reg8_read(client, 0xf3, &priv->chip_id[2]); ++ reg8_read(client, 0xf4, &priv->chip_id[3]); ++ reg8_read(client, 0xf5, &priv->chip_id[4]); ++ priv->chip_id[5] = '\0'; ++} ++ ++static void ti9x4_initial_setup(struct i2c_client *client) ++{ ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); ++ ++ /* Initial setup */ ++ client->addr = priv->des_addr; /* TI9x4 I2C */ ++ reg8_write(client, 0x0d, 0xb9); /* VDDIO 3.3V */ ++ switch (priv->csi_rate) { ++ case 1600: /* REFCLK = 25MHZ */ ++ case 1500: /* REFCLK = 23MHZ */ ++ case 1450: /* REFCLK = 22.5MHZ */ ++ reg8_write(client, 0x1f, 0x00); /* CSI rate 1.5/1.6Gbps */ ++ break; ++ case 1200: /* REFCLK = 25MHZ */ ++ case 1100: /* REFCLK = 22.5MHZ */ ++ reg8_write(client, 0x1f, 0x01); /* CSI rate 1.1/1.2Gbps */ ++ break; ++ case 800: /* REFCLK = 25MHZ */ ++ case 700: /* REFCLK = 22.5MHZ */ ++ reg8_write(client, 0x1f, 0x02); /* CSI rate 700/800Mbps */ ++ break; ++ case 400: /* REFCLK = 25MHZ */ ++ case 350: /* REFCLK = 22.5MHZ */ ++ reg8_write(client, 0x1f, 0x03); /* CSI rate 350/400Mbps */ ++ break; ++ default: ++ dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate); ++ } ++ ++ switch (priv->csi_rate) { ++ case 1600: ++ case 1200: ++ case 800: ++ case 400: ++ /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/FPS/12mks=1/30/12e-6=2777 -> HI=2, LO=2775 */ ++ priv->fs_time = 2790; ++ break; ++ case 1500: ++ /* FrameSync setup for REFCLK=23MHz, FPS=30: period_counts=1/FPS/13.043mks=1/30/13.043e-6=2556 -> HI=2, LO=2554 */ ++ priv->fs_time = 2570; ++ break; ++ case 1450: ++ case 1100: ++ case 700: ++ case 350: ++ /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/FPS/13.333mks=1/30/13.333e-6=2500 -> HI=2, LO=2498 */ ++ priv->fs_time = 2513; ++ break; ++ default: ++ priv->fs_time = 0; ++ dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate); ++ } ++ ++ if (strcmp(priv->forwarding_mode, "round-robin") == 0) { ++ reg8_write(client, 0x21, 0x03); /* Round Robin forwarding enable for CSI0/CSI1 */ ++ } else if (strcmp(priv->forwarding_mode, "synchronized") == 0) { ++ reg8_write(client, 0x21, 0x54); /* Basic Syncronized forwarding enable (FrameSync must be enabled!!) for CSI0/CSI1 */ ++ } ++ ++ reg8_write(client, 0x32, 0x03); /* Select TX for CSI0/CSI1, RX for CSI0 */ ++ reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4); /* disable CSI output, set CSI lane count, non-continuous CSI mode */ ++ reg8_write(client, 0x20, 0xf0 | priv->csi_map); /* disable port forwarding */ ++#if 0 ++ /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/2/FPS*25MHz =1/2/30*25Mhz =416666 -> FS_TIME=416666 */ ++ /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/2/FPS*22.5Mhz=1/2/30*22.5Mhz=375000 -> FS_TIME=375000 */ ++// #define FS_TIME (priv->csi_rate == 1450 ? 376000 : 417666) ++ #define FS_TIME (priv->csi_rate == 1450 ? 385000 : 428000) // FPS=29.2 (new vendor's firmware AWB restriction?) ++ reg8_write(client, 0x1a, FS_TIME >> 16); /* FrameSync time 24bit */ ++ reg8_write(client, 0x1b, (FS_TIME >> 8) & 0xff); ++ reg8_write(client, 0x1c, FS_TIME & 0xff); ++ reg8_write(client, 0x18, 0x43); /* Enable FrameSync, 50/50 mode, Frame clock from 25MHz */ ++#else ++ reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */ ++ reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */ ++ reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */ ++ reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */ ++ reg8_write(client, 0x18, 0x00); /* Disable FrameSync - must be enabled after all cameras are set up */ ++#endif ++} ++ ++static void ti9x4_fpdlink3_setup(struct i2c_client *client, int idx) ++{ ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); ++ u8 port_config = 0x78; ++ u8 port_config2 = 0; ++ ++ /* FPDLinkIII setup */ ++ client->addr = priv->des_addr; /* TI9x4 I2C */ ++ reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ ++ switch (priv->ser_id) { ++ case TI913_ID: ++ reg8_write(client, 0x58, 0x58); /* Back channel: Freq=2.5Mbps */ ++ break; ++ case TI953_ID: ++ reg8_write(client, 0x58, 0x5e); /* Back channel: Freq=50Mbps */ ++ break; ++ default: ++ break; ++ } ++ ++ reg8_write(client, 0x5c, priv->ti9x3_addr_map[idx] << 1); /* TI9X3 I2C addr */ ++// reg8_write(client, 0x5d, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */ ++// reg8_write(client, 0x65, (0x60 + idx) << 1); /* SENSOR I2C translated - must be set by sensor driver */ ++ ++ if (priv->is_coax) ++ port_config |= 0x04; /* Coax */ ++ else ++ port_config |= 0x00; /* STP */ ++ ++ switch (priv->dvp_bus) { ++ case 8: ++ port_config2 |= (priv->dvp_lsb ? 0xC0 : 0x80); /* RAW10 as 8-bit prosessing using LSB/MSB bits */ ++ /* fall through */ ++ case 10: ++ port_config |= 0x03; /* DVP over FPDLink (TI913 compatible) RAW10/RAW8 */ ++ break; ++ case 12: ++ port_config |= 0x02; /* DVP over FPDLink (TI913 compatible) RAW12 */ ++ break; ++ default: ++ port_config |= 0x00; /* CSI over FPDLink (TI953 compatible) */ ++ } ++ ++ if (priv->vsync) ++ port_config2 |= 0x01; /* VSYNC acive low */ ++ if (priv->hsync) ++ port_config2 |= 0x02; /* HSYNC acive low */ ++ ++ reg8_write(client, 0x6d, port_config); ++ reg8_write(client, 0x7c, port_config2); ++ reg8_write(client, 0x70, ((priv->vc_map >> (idx * 4)) << 6) | 0x1e); /* CSI data type: yuv422 8-bit, assign VC */ ++ reg8_write(client, 0x71, ((priv->vc_map >> (idx * 4)) << 6) | 0x2c); /* CSI data type: RAW12, assign VC */ ++ reg8_write(client, 0xbc, 0x00); /* Setup minimal time between FV and LV to 3 PCLKs */ ++ reg8_write(client, 0x72, priv->vc_map >> (idx * 4)); /* CSI VC MAP */ ++} ++ ++static int ti9x4_initialize(struct i2c_client *client) ++{ ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); ++ int idx, timeout; ++ u8 port_sts1[4] = {0, 0, 0, 0}, port_sts2[4] = {0, 0, 0, 0}; ++ ++ dev_info(&client->dev, "LINKs=%d, LANES=%d, FORWARDING=%s, CABLE=%s, ID=%s\n", ++ priv->links, priv->lanes, priv->forwarding_mode, priv->is_coax ? "coax" : "stp", priv->chip_id); ++ ++ ti9x4_initial_setup(client); ++ ++ for (idx = 0; idx < priv->links; idx++) { ++ if (!IS_ERR(priv->poc_gpio[idx])) { ++ gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */ ++ mdelay(priv->poc_delay); ++ } ++ ++ ti9x4_fpdlink3_setup(client, idx); ++ } ++ ++ client->addr = priv->des_addr; ++ ++ /* check lock status */ ++ for (timeout = 500 / priv->links; timeout > 0; timeout--) { ++ for (idx = 0; idx < priv->links; idx++) { ++ if ((port_sts1[idx] & 0x1) && (port_sts2[idx] & 0x4)) ++ continue; ++ ++ reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */ ++ usleep_range(1000, 1500); /* wait 1ms */ ++ reg8_read(client, 0x4d, &port_sts1[idx]); /* Lock status */ ++ reg8_read(client, 0x4e, &port_sts2[idx]); /* Freq stable */ ++ } ++ } ++ ++ if (!timeout) ++ dev_info(&client->dev, "Receiver lock status [%d,%d,%d,%d]\n", ++ (port_sts1[0] & 0x1) && (port_sts2[0] & 0x4), ++ (port_sts1[1] & 0x1) && (port_sts2[1] & 0x4), ++ (port_sts1[2] & 0x1) && (port_sts2[2] & 0x4), ++ (port_sts1[3] & 0x1) && (port_sts2[3] & 0x4)); ++ ++ if (priv->poc_delay) ++ mdelay(100); ++ ++ for (idx = 0; idx < priv->links; idx++) { ++ reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */ ++ usleep_range(1000, 1500); /* wait 1ms */ ++ ++ /* ++ * Enable only FSIN for remote gpio, all permanent states (0 or 1) setup on serializer side: ++ * this avoids intermittent remote gpio noise (f.e. reset or spuriouse fsin) caused by ++ * unstable/bad link, hence unstable backchannel ++ */ ++ client->addr = priv->ti9x3_addr_map[idx]; /* TI9X3 I2C addr */ ++ switch (priv->ser_id) { ++ case TI913_ID: ++ reg8_write(client, 0x0d, 0x55); /* Enable remote GPIO0/1 */ ++ reg8_write(client, 0x11, 0x10); /* I2C high pulse width */ ++ reg8_write(client, 0x12, 0x10); /* I2C low pulse width */ ++ break; ++ case TI953_ID: ++ reg8_write(client, 0x0d, (priv->gpio[0] & 0x1) << 0 | ++ (priv->gpio[1] & 0x1) << 1 | ++ (priv->gpio[2] & 0x1) << 2 | ++ (priv->gpio[3] & 0x1) << 3 | ++ (priv->gpio[0] & 0x2) << 3 | ++ (priv->gpio[1] & 0x2) << 4 | ++ (priv->gpio[2] & 0x2) << 5 | ++ (priv->gpio[3] & 0x2) << 6); /* Enable FSIN remote GPIOs and set local constant gpios */ ++ reg8_write(client, 0x0e, (!!priv->gpio[0] << 4) | ++ (!!priv->gpio[1] << 5) | ++ (!!priv->gpio[2] << 6) | ++ (!!priv->gpio[3] << 7)); /* Enable serializer GPIOs only for output */ ++ reg8_write(client, 0x0b, 0x10); /* I2C high pulse width */ ++ reg8_write(client, 0x0c, 0x10); /* I2C low pulse width */ ++ break; ++ } ++ client->addr = priv->des_addr; ++ ++ reg8_write(client, 0x6e, 0x88 | (priv->gpio[1] << 4) | priv->gpio[0]); /* Remote GPIO1/GPIO0 setup */ ++ reg8_write(client, 0x6f, 0x88 | (priv->gpio[3] << 4) | priv->gpio[2]); /* Remote GPIO3/GPIO2 setup */ ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ti9x4_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ int ret; ++ u8 val = 0; ++ ++ ret = reg8_read(client, (u8)reg->reg, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = sizeof(u8); ++ ++ return 0; ++} ++ ++static int ti9x4_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ return reg8_write(client, (u8)reg->reg, (u8)reg->val); ++} ++#endif ++ ++static int ti9x4_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ if (on) { ++ if (atomic_inc_return(&priv->use_count) == 1) ++ reg8_write(client, 0x20, 0x00 | priv->csi_map); /* enable port forwarding to CSI */ ++ } else { ++ if (atomic_dec_return(&priv->use_count) == 0) ++ reg8_write(client, 0x20, 0xf0 | priv->csi_map); /* disable port forwarding to CSI */ ++ } ++ ++ return 0; ++} ++ ++static int ti9x4_registered_async(struct v4l2_subdev *sd) ++{ ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4 | 0x1); /* enable CSI output, set CSI lane count, non-continuous CSI mode */ ++ reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */ ++// reg8_write(client, 0x18, 0x80); /* Enable FrameSync, Frame clock is external */ ++ ++ return 0; ++} ++ ++static int ti9x4_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ struct ti9x4_priv *priv = container_of(nb, struct ti9x4_priv, reboot_notifier); ++ int idx; ++ ++ for (idx = 0; idx < priv->links; idx++) { ++ if (!IS_ERR(priv->poc_gpio[idx])) ++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ti9x4_g_register, ++ .s_register = ti9x4_s_register, ++#endif ++ .s_power = ti9x4_s_power, ++ .registered_async = ti9x4_registered_async, ++}; ++ ++static int ti9x4_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ return 0; ++} ++ ++static int ti9x4_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ int f_time; ++ ++ f_time = priv->fs_time * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ reg8_write(client, 0x1b, f_time >> 8); /* FrameSync low time MSB */ ++ reg8_write(client, 0x1c, f_time & 0xff); /* FrameSync low time LSB */ ++ ++ priv->fps_denominator = cp->timeperframe.denominator; ++ priv->fps_numerator = cp->timeperframe.numerator; ++ } ++ ++ return 0; ++} ++ ++static struct v4l2_subdev_video_ops ti9x4_video_ops = { ++ .g_parm = ti9x4_g_parm, ++ .s_parm = ti9x4_s_parm, ++}; ++ ++static struct v4l2_subdev_ops ti9x4_subdev_ops = { ++ .core = &ti9x4_subdev_core_ops, ++ .video = &ti9x4_video_ops, ++}; ++ ++static int ti9x4_parse_dt(struct i2c_client *client) ++{ ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); ++ struct device_node *np = client->dev.of_node; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ struct property *prop; ++ int i; ++ int sensor_delay; ++ char forwarding_mode_default[20] = "round-robin"; /* round-robin, synchronized */ ++ struct property *csi_rate_prop, *dvp_order_prop; ++ u8 val = 0; ++ char name[10]; ++ ++ if (of_property_read_u32(np, "ti,links", &priv->links)) ++ priv->links = 4; ++ ++ if (of_property_read_u32(np, "ti,lanes", &priv->lanes)) ++ priv->lanes = 4; ++ ++ priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk"); ++ if (!IS_ERR(priv->ref_clk)) { ++ dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000); ++ v4l2_clk_enable(priv->ref_clk); ++ } ++ ++ priv->pwen = devm_gpiod_get(&client->dev, NULL, GPIOF_OUT_INIT_HIGH); ++ if (!IS_ERR(priv->pwen)) { ++ mdelay(5); ++ gpiod_direction_output(priv->pwen, 0); ++ mdelay(5); ++ } ++ ++ for (i = 0; i < 4; i++) { ++ sprintf(name, "POC%d", i); ++ priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(name, GFP_KERNEL), 0); ++ } ++ ++ reg8_read(client, 0x00, &val); /* read TI9x4 I2C address */ ++ if (val != (priv->des_addr << 1)) { ++ prop = of_find_property(np, "reg", NULL); ++ if (prop) ++ of_remove_property(np, prop); ++ return -ENODEV; ++ } ++ ++ ti9x4_read_chipid(client); ++ ++#ifdef TI954_SILICON_ERRATA ++ indirect_write(client, 7, 0x15, 0x30); ++ if (pwen > 0) ++ gpio_set_value(pwen, 1); ++ usleep_range(5000, 5500); /* wait 5ms */ ++ indirect_write(client, 7, 0x15, 0); ++#endif ++ if (!of_property_read_u32(np, "ti,sensor_delay", &sensor_delay)) ++ mdelay(sensor_delay); ++ if (of_property_read_string(np, "ti,forwarding-mode", &priv->forwarding_mode)) ++ priv->forwarding_mode = forwarding_mode_default; ++ if (of_property_read_bool(np, "ti,stp")) ++ priv->is_coax = 0; ++ else ++ priv->is_coax = 1; ++ if (of_property_read_u32(np, "ti,dvp_bus", &priv->dvp_bus)) ++ priv->dvp_bus = 8; ++ if (of_property_read_bool(np, "ti,dvp_lsb")) ++ priv->dvp_lsb = 1; ++ else ++ priv->dvp_lsb = 0; ++ if (of_property_read_u32(np, "ti,hsync", &priv->hsync)) ++ priv->hsync = 0; ++ if (of_property_read_u32(np, "ti,vsync", &priv->vsync)) ++ priv->vsync = 1; ++ if (of_property_read_u32(np, "ti,ser_id", &priv->ser_id)) ++ priv->ser_id = TI913_ID; ++ if (of_property_read_u32(np, "ti,poc-delay", &priv->poc_delay)) ++ priv->poc_delay = 10; ++ if (of_property_read_u32(np, "ti,vc-map", &priv->vc_map)) ++ priv->vc_map = 0x3210; ++ for (i = 0; i < 4; i++) { ++ sprintf(name, "ti,gpio%d", i); ++ if (of_property_read_u32(np, name, &priv->gpio[i])) ++ priv->gpio[i] = 0; ++ } ++ ++ /* ++ * CSI forwarding of all links is to CSI0 by default. ++ * Decide if any link will be forwarded to CSI1 instead CSI0 ++ */ ++ prop = of_find_property(np, "ti,csi1-links", NULL); ++ if (prop) { ++ const __be32 *link = NULL; ++ u32 v; ++ ++ for (i = 0; i < 4; i++) { ++ link = of_prop_next_u32(prop, link, &v); ++ if (!link) ++ break; ++ priv->csi_map |= BIT(v); ++ } ++ } else { ++ priv->csi_map = 0; ++ } ++ ++ /* module params override dts */ ++ if (is_stp) ++ priv->is_coax = 0; ++ if (dvp_bus != 8) ++ priv->dvp_bus = dvp_bus; ++ if (dvp_lsb) ++ priv->dvp_lsb = dvp_lsb; ++ if (hsync) ++ priv->hsync = hsync; ++ if (!vsync) ++ priv->vsync = vsync; ++ if (ser_id) ++ priv->ser_id = ser_id; ++ if (poc_delay) ++ priv->poc_delay = poc_delay; ++ if (vc_map != 0x3210) ++ priv->vc_map = vc_map; ++ if (csi_map) ++ priv->csi_map = csi_map; ++ if (gpio0) ++ priv->gpio[0] = gpio0; ++ if (gpio1) ++ priv->gpio[1] = gpio1; ++ if (gpio2) ++ priv->gpio[2] = gpio2; ++ if (gpio3) ++ priv->gpio[3] = gpio3; ++ ++ for (i = 0; ; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; ++ ++ if (i < priv->links) { ++ if (of_property_read_u32(endpoint, "ti9x3-addr", &priv->ti9x3_addr_map[i])) { ++ of_node_put(endpoint); ++ dev_err(&client->dev, "ti9x3-addr not set\n"); ++ return -EINVAL; ++ } ++ priv->sd_fwnode[i] = of_fwnode_handle(endpoint); ++ } ++ ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; ++ ++ csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL); ++ if (csi_rate_prop) { ++ of_property_read_u32(endpoint, "csi-rate", &priv->csi_rate); ++ of_update_property(rendpoint, csi_rate_prop); ++ } ++ ++ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL); ++ if (dvp_order_prop) ++ of_update_property(rendpoint, dvp_order_prop); ++ } ++ ++ of_node_put(endpoint); ++ return 0; ++} ++ ++static int ti9x4_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ti9x4_priv *priv; ++ int err, i; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ i2c_set_clientdata(client, priv); ++ priv->des_addr = client->addr; ++ priv->client = client; ++ atomic_set(&priv->use_count, 0); ++ priv->fps_numerator = 1; ++ priv->fps_denominator = 30; ++ ++ err = ti9x4_parse_dt(client); ++ if (err) ++ goto out; ++ ++ err = ti9x4_initialize(client); ++ if (err < 0) ++ goto out; ++ ++ for (i = 0; i < priv->links; i++) { ++ v4l2_subdev_init(&priv->sd[i], &ti9x4_subdev_ops); ++ priv->sd[i].owner = client->dev.driver->owner; ++ priv->sd[i].dev = &client->dev; ++ priv->sd[i].grp_id = i; ++ v4l2_set_subdevdata(&priv->sd[i], priv); ++ priv->sd[i].fwnode = priv->sd_fwnode[i]; ++ ++ snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x", ++ client->dev.driver->name, i2c_adapter_id(client->adapter), ++ client->addr); ++ ++ err = v4l2_async_register_subdev(&priv->sd[i]); ++ if (err < 0) ++ goto out; ++ } ++ ++ priv->reboot_notifier.notifier_call = ti9x4_reboot_notifier; ++ err = register_reboot_notifier(&priv->reboot_notifier); ++ if (err) ++ dev_err(&client->dev, "failed to register reboot notifier\n"); ++ ++out: ++ return err; ++} ++ ++static int ti9x4_remove(struct i2c_client *client) ++{ ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); ++ int i; ++ ++ unregister_reboot_notifier(&priv->reboot_notifier); ++ ++ for (i = 0; i < priv->links; i++) { ++ v4l2_async_unregister_subdev(&priv->sd[i]); ++ v4l2_device_unregister_subdev(&priv->sd[i]); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id ti9x4_dt_ids[] = { ++ { .compatible = "ti,ti9x4" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ti9x4_dt_ids); ++ ++static const struct i2c_device_id ti9x4_id[] = { ++ { "ti9x4", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ti9x4_id); ++ ++static struct i2c_driver ti9x4_i2c_driver = { ++ .driver = { ++ .name = "ti9x4", ++ .of_match_table = of_match_ptr(ti9x4_dt_ids), ++ }, ++ .probe = ti9x4_probe, ++ .remove = ti9x4_remove, ++ .id_table = ti9x4_id, ++}; ++ ++module_i2c_driver(ti9x4_i2c_driver); ++ ++MODULE_DESCRIPTION("FPDLinkIII driver for DS90UB9x4"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h +new file mode 100644 +index 0000000..6825f8a +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h +@@ -0,0 +1,204 @@ ++/* ++ * TI FPDLinkIII driver include file ++ * ++ * Copyright (C) 2017 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#ifndef _TI9X4_H ++#define _TI9X4_H ++ ++//#define DEBUG ++#ifdef DEBUG ++#undef dev_dbg ++#define dev_dbg dev_info ++#endif ++ ++#define MAXIM_NUM_RETRIES 1 /* number of read/write retries */ ++#define TI913_ID 0x58 ++#define TI953_ID 0x30 /* or starapped to 0x32 */ ++#define TI9X4_ID 0x00 /* strapped */ ++#define BROADCAST 0x6f ++ ++static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val) ++{ ++ int ret, retries; ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_smbus_read_byte_data(client, reg); ++ if (!(ret < 0)) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++ *val = ret; ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg8_write(struct i2c_client *client, u8 reg, u8 val) ++{ ++ int ret, retries; ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_smbus_write_byte_data(client, reg, val); ++ if (!(ret < 0)) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_read(struct i2c_client *client, u16 reg, u8 *val) ++{ ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, buf, 1); ++ if (ret == 1) ++ break; ++ } ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++ *val = buf[0]; ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val) ++{ ++ int ret, retries; ++ u8 buf[3] = {reg >> 8, reg & 0xff, val}; ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 3); ++ if (ret == 3) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n) ++{ ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, val, n); ++ if (ret == n) ++ break; ++ } ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x registers 0x%x-0x%x: %d\n", ++ client->addr, reg, reg + n, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n) ++{ ++ int ret, retries; ++ u8 buf[2 + n]; ++ ++ buf[0] = reg >> 8; ++ buf[1] = reg & 0xff; ++ memcpy(&buf[2], val, n); ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2 + n); ++ if (ret == 2 + n) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x-0x%x: %d\n", ++ client->addr, reg, reg + n, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val) ++{ ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, buf, 2); ++ if (ret == 2) ++ break; ++ } ++ } ++ ++ if (ret < 0) { ++ dev_err(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++ *val = ((u16)buf[0] << 8) | buf[1]; ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val) ++{ ++ int ret, retries; ++ u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff}; ++ ++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 4); ++ if (ret == 4) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_err(&client->dev, ++ "write fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++#endif /* _TI9X4_H */ ++ +diff --git a/drivers/media/i2c/soc_camera/gmsl/Kconfig b/drivers/media/i2c/soc_camera/gmsl/Kconfig +new file mode 100644 +index 0000000..c7a33bf +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/Kconfig +@@ -0,0 +1,11 @@ ++config SOC_CAMERA_MAX9286 ++ tristate "max9286 GMSL support" ++ depends on I2C ++ help ++ This is a MAXIM max9286 GMSL driver ++ ++config SOC_CAMERA_MAX9288 ++ tristate "max9288 GMSL support" ++ depends on I2C ++ help ++ This is a MAXIM max9288 GMSL driver +diff --git a/drivers/media/i2c/soc_camera/gmsl/Makefile b/drivers/media/i2c/soc_camera/gmsl/Makefile +new file mode 100644 +index 0000000..9925314 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_SOC_CAMERA_MAX9286) += max9286.o ++obj-$(CONFIG_SOC_CAMERA_MAX9288) += max9288.o +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9286.c b/drivers/media/i2c/soc_camera/gmsl/max9286.c +new file mode 100644 +index 0000000..2d56b41 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/max9286.c +@@ -0,0 +1,1072 @@ ++/* ++ * MAXIM max9286 GMSL driver ++ * ++ * Copyright (C) 2015-2018 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/notifier.h> ++#include <linux/of_gpio.h> ++#include <linux/of_graph.h> ++#include <linux/reboot.h> ++#include <linux/videodev2.h> ++ ++#include <media/v4l2-common.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-subdev.h> ++ ++#include "../max9286.h" ++ ++#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */ ++#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */ ++#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */ ++#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */ ++#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ ++#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ ++#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ ++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ ++ ++struct max9286_priv { ++ struct v4l2_subdev sd[4]; ++ struct fwnode_handle *sd_fwnode[4]; ++ int des_addr; ++ int des_quirk_addr; /* second MAX9286 on the same I2C bus */ ++ int links; ++ int links_mask; ++ int lanes; ++ int csi_rate; ++ const char *fsync_mode; ++ int fsync_period; ++ int fps_numerator; ++ int fps_denominator; ++ int pclk; ++ char pclk_rising_edge; ++ int gpio_resetb; ++ int active_low_resetb; ++ int him; ++ int hsync; ++ int vsync; ++ int timeout; ++ int poc_delay; ++ int bws; ++ int dbl; ++ int dt; ++ int hsgen; ++ u64 crossbar; ++ char cb[16]; ++ int hts; ++ int vts; ++ int hts_delay; ++ int imager_width; ++ atomic_t use_count; ++ u32 csi2_outord; ++ u32 switchin; ++ struct i2c_client *client; ++ int max9271_addr_map[4]; ++ int ser_id; ++ struct gpio_desc *poc_gpio[4]; /* PoC power supply */ ++ struct notifier_block reboot_notifier; ++ ++ /* link statistic */ ++ int prbserr[4]; ++ int deterr[4]; ++ int correrr[4]; ++}; ++ ++static char fsync_mode_default[20] = "manual"; /* manual, automatic, semi-automatic, external */ ++ ++static int conf_link; ++module_param(conf_link, int, 0644); ++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); ++ ++static int poc_trig; ++module_param(poc_trig, int, 0644); ++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock"); ++ ++static int him; ++module_param(him, int, 0644); ++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)"); ++ ++static int fsync_period; ++module_param(fsync_period, int, 0644); ++MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)"); ++ ++static int hsync; ++module_param(hsync, int, 0644); ++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); ++ ++static int vsync = 1; ++module_param(vsync, int, 0644); ++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); ++ ++static int gpio_resetb; ++module_param(gpio_resetb, int, 0644); ++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)"); ++ ++static int active_low_resetb; ++module_param(active_low_resetb, int, 0644); ++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)"); ++ ++static int timeout_n = 100; ++module_param(timeout_n, int, 0644); ++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)"); ++ ++static int poc_delay = 50; ++module_param(poc_delay, int, 0644); ++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)"); ++ ++static int bws; ++module_param(bws, int, 0644); ++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)"); ++ ++static int dbl = 1; ++module_param(dbl, int, 0644); ++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)"); ++ ++static int dt = 3; ++module_param(dt, int, 0644); ++MODULE_PARM_DESC(dt, " DataType (default: 3 - YUV8), 0 - RGB888, 5 - RAW8, 6 - RAW10, 7 - RAW12, 8 - RAW14"); ++ ++static int hsgen; ++module_param(hsgen, int, 0644); ++MODULE_PARM_DESC(hsgen, " Enable HS embedded generator (default: 0 - disabled)"); ++ ++static int pclk = 100; ++module_param(pclk, int, 0644); ++MODULE_PARM_DESC(pclk, " PCLK rate (default: 100MHz)"); ++ ++static int switchin = 0; ++module_param(switchin, int, 0644); ++MODULE_PARM_DESC(switchin, " COAX SWITCH IN+ and IN- (default: 0 - not switched)"); ++ ++static unsigned long crossbar = 0xba9876543210; ++module_param(crossbar, ulong, 0644); ++MODULE_PARM_DESC(crossbar, " Crossbar setup (default: ba9876543210 - reversed)"); ++ ++enum { ++ RGB888_DT = 0, ++ RGB565_DT, ++ RGB666_DT, ++ YUV8_DT, /* default */ ++ YUV10_DT, ++ RAW8_DT, ++ RAW10_DT, ++ RAW12_DT, ++ RAW14_DT, ++}; ++ ++static int dt2bpp [9] = { ++ 24, /* RGB888 */ ++ 16, /* RGB565 */ ++ 18, /* RGB666 */ ++ 8, /* YUV8 - default */ ++ 10, /* YUV10 */ ++ 8, /* RAW8/RAW16 */ ++ 10, /* RAW10 */ ++ 12, /* RAW12 */ ++ 14, /* RAW14 */ ++}; ++ ++static char* ser_name(int id) ++{ ++ switch (id) { ++ case MAX9271_ID: ++ return "MAX9271"; ++ case MAX96705_ID: ++ return "MAX96705"; ++ case MAX96707_ID: ++ return "MAX96707"; ++ default: ++ return "unknown"; ++ } ++} ++ ++static void max9286_write_remote_verify(struct i2c_client *client, int idx, u8 reg, u8 val) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ int timeout; ++ ++ for (timeout = 0; timeout < 10; timeout++) { ++ int tmp_addr; ++ u8 sts = 0; ++ u8 val2 = 0; ++ ++ reg8_write(client, reg, val); ++ ++ tmp_addr = client->addr; ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_read(client, 0x70, &sts); ++ client->addr = tmp_addr; ++ if (sts & BIT(idx)) /* if ACKed */ { ++ reg8_read(client, reg, &val2); ++ if (val2 == val) ++ break; ++ } ++ ++ usleep_range(1000, 1500); ++ } ++ ++ if (timeout >= 10) ++ dev_err(&client->dev, "timeout remote write acked\n"); ++} ++ ++static void max9286_preinit(struct i2c_client *client, int addr) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ ++ client->addr = addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */ ++ reg8_write(client, 0x00, 0x00); /* disable all GMSL links [0:3] */ ++// usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x1b, priv->switchin); /* coax polarity (default - normal) */ ++ reg8_write(client, 0x1c, (priv->him ? 0xf0 : 0x00) | ++ (priv->bws ? 0x05 : 0x04)); /* high-immunity/legacy mode, BWS 24bit */ ++} ++ ++static void max9286_sensor_reset(struct i2c_client *client, int addr, int reset_on) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ ++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) ++ return; ++ ++ if (priv->active_low_resetb) ++ reset_on = !reset_on; ++ ++ /* sensor reset/unreset using serializer gpio */ ++ client->addr = addr; ++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | (reset_on ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value */ ++ reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ ++} ++ ++static void max9286_postinit(struct i2c_client *client, int addr) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ int idx; ++ ++ for (idx = 0; idx < priv->links; idx++) { ++ if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) ++ continue; ++ ++ client->addr = priv->des_addr; /* MAX9286 I2C */ ++ reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */ ++ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */ ++ usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */ ++ ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */ ++ max9286_sensor_reset(client, client->addr, 0); /* sensor unreset using gpios. TODO: should be in imager driver */ ++ } ++ ++ client->addr = addr; /* MAX9286 I2C */ ++ reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */ ++ reg8_write(client, 0x00, 0xe0 | priv->links_mask); /* enable GMSL link for CAMs */ ++ reg8_write(client, 0x0b, priv->csi2_outord); /* CSI2 output order */ ++ reg8_write(client, 0x15, 0x9b); /* enable CSI output, VC is set accordingly to Link number, BIT7 magic must be set */ ++ reg8_write(client, 0x1b, priv->switchin | priv->links_mask); /* coax polarity, enable equalizer for CAMs */ ++ reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ ++ usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */ ++ ++ if (strcmp(priv->fsync_mode, "manual") == 0) { ++ reg8_write(client, 0x01, 0x00); /* manual: FRAMESYNC set manually via [0x06:0x08] regs */ ++ } else if (strcmp(priv->fsync_mode, "automatic") == 0) { ++ reg8_write(client, 0x01, 0x02); /* automatic: FRAMESYNC taken from the slowest Link */ ++ } else if (strcmp(priv->fsync_mode, "semi-automatic") == 0) { ++ reg8_write(client, 0x01, 0x01); /* semi-automatic: FRAMESYNC taken from the slowest Link */ ++ } else if (strcmp(priv->fsync_mode, "external") == 0) { ++ reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */ ++ } ++} ++ ++static int max9286_reverse_channel_setup(struct i2c_client *client, int idx) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ u8 val = 0, lock_sts = 0, link_sts = 0; ++ int timeout = priv->timeout; ++ char timeout_str[40]; ++ int ret = 0; ++ ++ /* Reverse channel enable */ ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x34, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */ ++ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse control for CAMx */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ ++ for (;;) { ++ if (priv->him) { ++ /* HIM mode setup */ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x4d, 0xc0); ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ if (priv->bws) { ++ reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) | ++ (priv->dbl ? 0x80 : 0) | ++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ } ++ } else { ++ /* Legacy mode setup */ ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x3f, 0x4f); /* enable custom reverse channel & first pulse length */ ++ reg8_write(client, 0x3b, 0x1e); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */ ++ reg8_write(client, 0x97, 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ if (priv->bws) { ++ reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) | ++ (priv->dbl ? 0x80 : 0) | ++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ } ++ ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x3b, 0x19); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ } ++ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_read(client, 0x1e, &val); /* read max9271 ID */ ++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID || --timeout == 0) { ++ priv->ser_id = val; ++ break; ++ } ++ ++ /* Check if already initialized (after reboot/reset ?) */ ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */ ++ reg8_read(client, 0x1e, &val); /* read max9271 ID */ ++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) { ++ priv->ser_id = val; ++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ ret = -EADDRINUSE; ++ break; ++ } ++ ++ if (poc_trig) { ++ if (!IS_ERR(priv->poc_gpio[idx]) && (timeout % poc_trig == 0)) { ++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ ++ mdelay(200); ++ gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */ ++ mdelay(priv->poc_delay); ++ } ++ } ++ } ++ ++ max9286_sensor_reset(client, client->addr, 1); /* sensor reset */ ++ ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_read(client, 0x27, &lock_sts); /* LOCK status */ ++ reg8_read(client, 0x49, &link_sts); /* LINK status */ ++ ++ if (!timeout) { ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++ priv->links_mask |= BIT(idx); ++ priv->csi2_outord &= ~(0x3 << (idx * 2)); ++ priv->csi2_outord |= ((hweight8(priv->links_mask) - 1) << (idx * 2)); ++ ++out: ++ sprintf(timeout_str, "retries=%d lock_sts=%d link_sts=0x%x", priv->timeout - timeout, !!(lock_sts & 0x80), link_sts & (0x11 << idx)); ++ dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, ser_name(priv->ser_id), ++ ret == -EADDRINUSE ? "already " : "", priv->max9271_addr_map[idx], ++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", ++ priv->timeout - timeout ? timeout_str : ""); ++ ++ return ret; ++} ++ ++static void max9286_initial_setup(struct i2c_client *client) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ ++ /* Initial setup */ ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x15, 0x13); /* disable CSI output, VC is set accordingly to Link number */ ++ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ ++ reg8_write(client, 0x12, ((priv->lanes - 1) << 6) | ++ (priv->dbl ? 0x30 : 0) | ++ (priv->dt & 0xf)); /* setup lanes, DBL mode, DataType */ ++ ++ /* Start GMSL initialization with FSYNC disabled. This is required for some odd LVDS cameras */ ++ reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */ ++ reg8_write(client, 0x06, priv->fsync_period & 0xff); ++ reg8_write(client, 0x07, (priv->fsync_period >> 8) & 0xff); ++ reg8_write(client, 0x08, priv->fsync_period >> 16); ++ ++ reg8_write(client, 0x63, 0); /* disable overlap window */ ++ reg8_write(client, 0x64, 0); ++ reg8_write(client, 0x0c, 0x91 | (priv->vsync ? BIT(3) : 0) | (priv->hsync ? BIT(2) : 0)); /* enable HS/VS encoding, use D14/15 for HS/VS, invert HS/VS */ ++ reg8_write(client, 0x19, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */ ++} ++ ++static void max9286_gmsl_link_setup(struct i2c_client *client, int idx) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ ++ /* GMSL setup */ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ ++ reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) | ++ (priv->dbl ? 0x80 : 0) | ++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ ++ if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) { ++ switch (priv->dt) { ++ case YUV8_DT: ++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */ ++ reg8_write(client, 0x20, priv->cb[7]); ++ reg8_write(client, 0x21, priv->cb[6]); ++ reg8_write(client, 0x22, priv->cb[5]); ++ reg8_write(client, 0x23, priv->cb[4]); ++ reg8_write(client, 0x24, priv->cb[3]); ++ reg8_write(client, 0x25, priv->cb[2]); ++ reg8_write(client, 0x26, priv->cb[1]); ++ reg8_write(client, 0x27, priv->cb[0]); ++ ++ /* this is second byte if DBL=1 */ ++ reg8_write(client, 0x30, priv->cb[7] + 16); ++ reg8_write(client, 0x31, priv->cb[6] + 16); ++ reg8_write(client, 0x32, priv->cb[5] + 16); ++ reg8_write(client, 0x33, priv->cb[4] + 16); ++ reg8_write(client, 0x34, priv->cb[3] + 16); ++ reg8_write(client, 0x35, priv->cb[2] + 16); ++ reg8_write(client, 0x36, priv->cb[1] + 16); ++ reg8_write(client, 0x37, priv->cb[0] + 16); ++ break; ++ case RAW12_DT: ++ /* setup crossbar for RAW12: reverse DVP bus */ ++ reg8_write(client, 0x20, priv->cb[11]); ++ reg8_write(client, 0x21, priv->cb[10]); ++ reg8_write(client, 0x22, priv->cb[9]); ++ reg8_write(client, 0x23, priv->cb[8]); ++ reg8_write(client, 0x24, priv->cb[7]); ++ reg8_write(client, 0x25, priv->cb[6]); ++ reg8_write(client, 0x26, priv->cb[5]); ++ reg8_write(client, 0x27, priv->cb[4]); ++ reg8_write(client, 0x28, priv->cb[3]); ++ reg8_write(client, 0x29, priv->cb[2]); ++ reg8_write(client, 0x2a, priv->cb[1]); ++ reg8_write(client, 0x2b, priv->cb[0]); ++ ++ /* this is second byte if DBL=1 */ ++ reg8_write(client, 0x30, priv->cb[11] + 16); ++ reg8_write(client, 0x31, priv->cb[10] + 16); ++ reg8_write(client, 0x32, priv->cb[9] + 16); ++ reg8_write(client, 0x33, priv->cb[8] + 16); ++ reg8_write(client, 0x34, priv->cb[7] + 16); ++ reg8_write(client, 0x35, priv->cb[6] + 16); ++ reg8_write(client, 0x36, priv->cb[5] + 16); ++ reg8_write(client, 0x37, priv->cb[4] + 16); ++ reg8_write(client, 0x38, priv->cb[3] + 16); ++ reg8_write(client, 0x39, priv->cb[2] + 16); ++ reg8_write(client, 0x3a, priv->cb[1] + 16); ++ reg8_write(client, 0x3b, priv->cb[0] + 16); ++ ++ if (!priv->bws && priv->dbl) ++ dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n"); ++ ++ break; ++ } ++ ++ if (priv->hsgen) { ++ /* HS/VS pins map */ ++ reg8_write(client, 0x3f, 0x10); /* HS (NC) */ ++ reg8_write(client, 0x41, 0x10); /* DE (NC) */ ++ if (priv->ser_id == MAX96705_ID) ++ reg8_write(client, 0x40, 15); /* VS (DIN13) */ ++ if (priv->ser_id == MAX96707_ID) ++ reg8_write(client, 0x40, 13); /* VS (DIN13) */ ++#if 0 ++ /* following must come from imager */ ++#define SENSOR_WIDTH (1280*2) ++#define HTS (1288*2) ++#define VTS 960 ++#define HTS_DELAY 0x9 ++ reg8_write(client, 0x4e, HTS_DELAY >> 16); /* HS delay */ ++ reg8_write(client, 0x4f, (HTS_DELAY >> 8) & 0xff); ++ reg8_write(client, 0x50, HTS_DELAY & 0xff); ++ reg8_write(client, 0x54, SENSOR_WIDTH >> 8); /* HS high period */ ++ reg8_write(client, 0x55, SENSOR_WIDTH & 0xff); ++ reg8_write(client, 0x56, (HTS - SENSOR_WIDTH) >> 8); /* HS low period */ ++ reg8_write(client, 0x57, (HTS - SENSOR_WIDTH) & 0xff); ++ reg8_write(client, 0x58, VTS >> 8); /* HS count */ ++ reg8_write(client, 0x59, VTS & 0xff ); ++#endif ++ reg8_write(client, 0x43, 0x15); /* enable HS generator */ ++ } ++ } ++ ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ ++ /* I2C translator setup */ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */ ++// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */ ++ reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */ ++ reg8_write(client, 0x0C, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAMx I2C new */ ++ /* I2C addresse change */ ++ reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9286 I2C */ ++ reg8_write(client, 0x00, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAM0 I2C new */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ /* put MAX9271 in configuration link state */ ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */ ++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++#ifdef MAXIM_DUMP ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ maxim_max927x_dump_regs(client); ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */ ++ maxim_max927x_dump_regs(client); ++#endif ++} ++ ++static int max9286_initialize(struct i2c_client *client) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ int idx, ret; ++ ++ dev_info(&client->dev, "LINKs=%d, LANES=%d, FSYNC mode=%s, FSYNC period=%d, PCLK edge=%s\n", ++ priv->links, priv->lanes, priv->fsync_mode, priv->fsync_period, ++ priv->pclk_rising_edge ? "rising" : "falling"); ++ ++ if (priv->des_quirk_addr) ++ max9286_preinit(client, priv->des_quirk_addr); ++ ++ max9286_preinit(client, priv->des_addr); ++ max9286_initial_setup(client); ++ ++ for (idx = 0; idx < priv->links; idx++) { ++ if (!IS_ERR(priv->poc_gpio[idx])) { ++ gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */ ++ mdelay(priv->poc_delay); ++ } ++ ++ ret = max9286_reverse_channel_setup(client, idx); ++ if (ret) ++ continue; ++ max9286_gmsl_link_setup(client, idx); ++ } ++ ++ max9286_postinit(client, priv->des_addr); ++ ++ client->addr = priv->des_addr; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int max9286_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ int ret; ++ u8 val = 0; ++ ++ ret = reg8_read(client, (u8)reg->reg, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = sizeof(u8); ++ ++ return 0; ++} ++ ++static int max9286_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ return reg8_write(client, (u8)reg->reg, (u8)reg->val); ++} ++#endif ++ ++static int max9286_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ if (on) { ++ if (atomic_inc_return(&priv->use_count) == 1) ++ reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */ ++ } else { ++ if (atomic_dec_return(&priv->use_count) == 0) ++ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ ++ } ++ ++ return 0; ++} ++ ++static int max9286_registered_async(struct v4l2_subdev *sd) ++{ ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ int idx, tmp_addr; ++ ++ /* switch to GMSL serial_link for streaming video */ ++ tmp_addr = client->addr; ++ idx = sd->grp_id; ++ ++ client->addr = priv->des_addr; /* MAX9286 I2C */ ++ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */ ++ ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx */ ++ max9286_write_remote_verify(client, idx, 0x04, conf_link ? 0x43 : 0x83); ++// usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */ ++ ++ client->addr = priv->des_addr; /* MAX9286 I2C */ ++ reg8_write(client, 0x0a, (priv->links_mask << 4) | priv->links_mask); /* enable reverse/forward control for all CAMs */ ++ ++ client->addr = tmp_addr; ++ ++ return 0; ++} ++ ++static int max9286_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ struct max9286_priv *priv = container_of(nb, struct max9286_priv, reboot_notifier); ++ int idx; ++ ++ for (idx = 0; idx < priv->links; idx++) { ++ if (!IS_ERR(priv->poc_gpio[idx])) ++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static struct v4l2_subdev_core_ops max9286_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = max9286_g_register, ++ .s_register = max9286_s_register, ++#endif ++ .s_power = max9286_s_power, ++ .registered_async = max9286_registered_async, ++}; ++ ++static int max9286_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ return 0; ++} ++ ++static int max9286_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ int f_period; ++ ++ f_period = priv->fsync_period * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ reg8_write(client, 0x06, f_period & 0xff); ++ reg8_write(client, 0x07, (f_period >> 8) & 0xff); ++ reg8_write(client, 0x08, f_period >> 16); ++ ++ priv->fps_numerator = cp->timeperframe.numerator; ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++ ++ return 0; ++} ++ ++static struct v4l2_subdev_video_ops max9286_video_ops = { ++ .g_parm = max9286_g_parm, ++ .s_parm = max9286_s_parm, ++}; ++ ++static struct v4l2_subdev_ops max9286_subdev_ops = { ++ .core = &max9286_subdev_core_ops, ++ .video = &max9286_video_ops, ++}; ++ ++static int max9286_parse_dt(struct i2c_client *client) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ struct device_node *np = client->dev.of_node; ++ struct device_node *endpoint = NULL; ++ struct property *prop; ++ int err, pwen, i; ++ int sensor_delay, gpio0 = 1, gpio1 = 1; ++ u8 val = 0; ++ char poc_name[10]; ++ ++ if (of_property_read_u32(np, "maxim,links", &priv->links)) ++ priv->links = 4; ++ ++ if (of_property_read_u32(np, "maxim,lanes", &priv->lanes)) ++ priv->lanes = 4; ++ ++ pwen = of_get_gpio(np, 0); ++ if (pwen > 0) { ++ err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev)); ++ if (err) ++ dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err); ++ } ++ ++ mdelay(250); ++ ++ for (i = 0; i < 4; i++) { ++ sprintf(poc_name, "POC%d", i); ++ priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(poc_name, GFP_KERNEL), 0); ++ } ++ ++ reg8_read(client, 0x1e, &val); /* read max9286 ID */ ++ if (val != MAX9286_ID) { ++ prop = of_find_property(np, "reg", NULL); ++ if (prop) ++ of_remove_property(np, prop); ++ return -ENODEV; ++ } ++ ++ if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) || ++ !of_property_read_u32(np, "maxim,gpio1", &gpio1)) ++ reg8_write(client, 0x0f, 0x08 | (gpio1 << 1) | gpio0); ++ ++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) { ++ priv->gpio_resetb = -1; ++ } else { ++ if (of_property_read_bool(np, "maxim,resetb-active-high")) ++ priv->active_low_resetb = 0; ++ else ++ priv->active_low_resetb = 1; ++ } ++ ++ if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay)) ++ mdelay(sensor_delay); ++ if (of_property_read_string(np, "maxim,fsync-mode", &priv->fsync_mode)) ++ priv->fsync_mode = fsync_mode_default; ++ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period)) ++ priv->fsync_period = 3200000; /* 96MHz/30fps */ ++ priv->pclk_rising_edge = true; ++ if (of_property_read_bool(np, "maxim,pclk-falling-edge")) ++ priv->pclk_rising_edge = false; ++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout)) ++ priv->timeout = 100; ++ if (of_property_read_u32(np, "maxim,i2c-quirk", &priv->des_quirk_addr)) ++ priv->des_quirk_addr = 0; ++ if (of_property_read_u32(np, "maxim,him", &priv->him)) ++ priv->him = 0; ++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync)) ++ priv->hsync = 0; ++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync)) ++ priv->vsync = 1; ++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay)) ++ priv->poc_delay = 50; ++ if (of_property_read_u32(np, "maxim,bws", &priv->bws)) ++ priv->bws = 0; ++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl)) ++ priv->dbl = 1; ++ if (of_property_read_u32(np, "maxim,dt", &priv->dt)) ++ priv->dt = 3; ++ if (of_property_read_u32(np, "maxim,hsgen", &priv->hsgen)) ++ priv->hsgen = 0; ++ if (of_property_read_u32(np, "maxim,pclk", &priv->pclk)) ++ priv->pclk = pclk; ++ if (of_property_read_u32(np, "maxim,switchin", &priv->switchin)) ++ priv->switchin = 0; ++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar)) ++ priv->crossbar = crossbar; ++ ++ /* module params override dts */ ++ if (him) ++ priv->him = him; ++ if (fsync_period) { ++ priv->fsync_period = fsync_period; ++ priv->fsync_mode = fsync_mode_default; ++ } ++ if (hsync) ++ priv->hsync = hsync; ++ if (!vsync) ++ priv->vsync = vsync; ++ if (gpio_resetb) ++ priv->gpio_resetb = gpio_resetb; ++ if (active_low_resetb) ++ priv->active_low_resetb = active_low_resetb; ++ if (timeout_n) ++ priv->timeout = timeout_n; ++ if (poc_delay) ++ priv->poc_delay = poc_delay; ++ if (bws) ++ priv->bws = bws; ++ if (!dbl) ++ priv->dbl = dbl; ++ if (dt != 3) ++ priv->dt = dt; ++ if (hsgen) ++ priv->hsgen = hsgen; ++ if (pclk != 100) ++ priv->pclk = pclk; ++ if (switchin) ++ priv->switchin = switchin; ++ ++ /* parse crossbar setup */ ++ for (i = 0; i < 16; i++) { ++ priv->cb[i] = priv->crossbar % 16; ++ priv->crossbar /= 16; ++ } ++ ++ for (i = 0; i < priv->links; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; ++ ++ if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr_map[i])) { ++ of_node_put(endpoint); ++ dev_err(&client->dev, "max9271-addr not set\n"); ++ return -EINVAL; ++ } ++ ++ priv->sd_fwnode[i] = of_fwnode_handle(endpoint); ++ } ++ ++ of_node_put(endpoint); ++ return 0; ++} ++ ++static void max9286_setup_remote_endpoint(struct i2c_client *client) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ struct device_node *np = client->dev.of_node; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ int i; ++ struct property *csi_rate_prop, *dvp_order_prop; ++ ++ for (i = 0; ; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; ++ ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; ++ ++ csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL); ++ if (csi_rate_prop) { ++ /* CSI2_RATE = PCLK*bpp*links/lanes */ ++ priv->csi_rate = cpu_to_be32(priv->pclk * dt2bpp[priv->dt] * hweight8(priv->links_mask) / priv->lanes); ++ csi_rate_prop->value = &priv->csi_rate; ++ of_update_property(rendpoint, csi_rate_prop); ++ } ++ ++ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL); ++ if (dvp_order_prop) ++ of_update_property(rendpoint, dvp_order_prop); ++ } ++ ++ of_node_put(endpoint); ++} ++ ++static const char *line_status[] = ++{ ++ "BAT", ++ "GND", ++ "NORMAL", ++ "OPEN" ++}; ++ ++static ssize_t max9286_link_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int i = -1; ++ u8 val = 0; ++ bool lenghterr, linebuffof, hlocked, prbsok, vsyncdet, configdet, videodet; ++ int lf; ++ u8 prbserr = 0, deterr = 0, correrr = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ ++ if (!sscanf(attr->attr.name, "link_%d", &i)) ++ return -EINVAL; ++ ++ if ((i < 0) || (i > 3)) ++ return -EINVAL; ++ ++ reg8_read(client, 0x20, &val); ++ lf = (val >> (2 * i)) & 0x03; ++ ++ reg8_read(client, 0x21, &val); ++ hlocked = !!(val & (1 << i)); ++ prbsok = !!(val & (1 << (i + 4))); ++ ++ reg8_read(client, 0x22, &val); ++ lenghterr = !!(val & (1 << i)); ++ linebuffof = !!(val & (1 << (i + 4))); ++ ++ reg8_read(client, 0x23 + i, &prbserr); ++ priv->prbserr[i] += prbserr; ++ ++ reg8_read(client, 0x27, &val); ++ vsyncdet = !!(val & (1 << i)); ++ ++ reg8_read(client, 0x28 + i, &deterr); ++ priv->deterr[i] += deterr; ++ ++ reg8_read(client, 0x2c + i, &correrr); ++ priv->correrr[i] += correrr; ++ ++ reg8_read(client, 0x49, &val); ++ configdet = !!(val & (1 << i)); ++ videodet = !!(val & (1 << (i + 4))); ++ ++ return sprintf(buf, "LINK:%d LF:%s HLOCKED:%d PRBSOK:%d LINBUFFOF:%d" ++ " LENGHTERR:%d VSYNCDET:%d CONFIGDET:%d VIDEODET:%d" ++ " PRBSERR:%d(%d) DETEERR:%d(%d) CORRERR:%d(%d)\n", ++ i, line_status[lf], hlocked, prbsok, lenghterr, ++ linebuffof, vsyncdet, configdet, videodet, ++ priv->prbserr[i], prbserr, ++ priv->deterr[i], deterr, ++ priv->correrr[i], correrr); ++ return 0; ++} ++ ++static DEVICE_ATTR(link_0, S_IRUGO, max9286_link_show, NULL); ++static DEVICE_ATTR(link_1, S_IRUGO, max9286_link_show, NULL); ++static DEVICE_ATTR(link_2, S_IRUGO, max9286_link_show, NULL); ++static DEVICE_ATTR(link_3, S_IRUGO, max9286_link_show, NULL); ++ ++static struct attribute *max9286_attributes_links[] = { ++ &dev_attr_link_0.attr, ++ &dev_attr_link_1.attr, ++ &dev_attr_link_2.attr, ++ &dev_attr_link_3.attr, ++ NULL ++}; ++ ++static const struct attribute_group max9286_group = { ++ .attrs = max9286_attributes_links, ++}; ++ ++static int max9286_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct max9286_priv *priv; ++ int err, i; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ i2c_set_clientdata(client, priv); ++ priv->des_addr = client->addr; ++ priv->client = client; ++ atomic_set(&priv->use_count, 0); ++ priv->csi2_outord = 0xff; ++ priv->fps_numerator = 1; ++ priv->fps_denominator = 30; ++ ++ err = max9286_parse_dt(client); ++ if (err) ++ goto out; ++ ++ err = max9286_initialize(client); ++ if (err < 0) ++ goto out; ++ ++ max9286_setup_remote_endpoint(client); ++ ++ for (i = 0; i < 4; i++) { ++ v4l2_subdev_init(&priv->sd[i], &max9286_subdev_ops); ++ priv->sd[i].owner = client->dev.driver->owner; ++ priv->sd[i].dev = &client->dev; ++ priv->sd[i].grp_id = i; ++ v4l2_set_subdevdata(&priv->sd[i], priv); ++ priv->sd[i].fwnode = priv->sd_fwnode[i]; ++ ++ snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x", ++ client->dev.driver->name, i, i2c_adapter_id(client->adapter), ++ client->addr); ++ ++ err = v4l2_async_register_subdev(&priv->sd[i]); ++ if (err < 0) ++ goto out; ++ } ++ ++ priv->reboot_notifier.notifier_call = max9286_reboot_notifier; ++ err = register_reboot_notifier(&priv->reboot_notifier); ++ if (err) { ++ dev_err(&client->dev, "failed to register reboot notifier\n"); ++ goto out; ++ } ++ ++ err = sysfs_create_group(&client->dev.kobj, ++ &max9286_group); ++ if (err < 0) ++ dev_err(&client->dev, "Sysfs registration failed\n"); ++out: ++ return err; ++} ++ ++static int max9286_remove(struct i2c_client *client) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ int i; ++ ++ sysfs_remove_group(&client->dev.kobj, &max9286_group); ++ unregister_reboot_notifier(&priv->reboot_notifier); ++ ++ for (i = 0; i < 4; i++) { ++ v4l2_async_unregister_subdev(&priv->sd[i]); ++ v4l2_device_unregister_subdev(&priv->sd[i]); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id max9286_dt_ids[] = { ++ { .compatible = "maxim,max9286" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, max9286_dt_ids); ++ ++static const struct i2c_device_id max9286_id[] = { ++ { "max9286", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max9286_id); ++ ++static struct i2c_driver max9286_i2c_driver = { ++ .driver = { ++ .name = "max9286", ++ .of_match_table = of_match_ptr(max9286_dt_ids), ++ }, ++ .probe = max9286_probe, ++ .remove = max9286_remove, ++ .id_table = max9286_id, ++}; ++ ++module_i2c_driver(max9286_i2c_driver); ++ ++MODULE_DESCRIPTION("GMSL driver for MAX9286"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9288.c b/drivers/media/i2c/soc_camera/gmsl/max9288.c +new file mode 100644 +index 0000000..7de1f9e +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/max9288.c +@@ -0,0 +1,768 @@ ++/* ++ * MAXIM max9288 GMSL driver ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/notifier.h> ++#include <linux/of_gpio.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/v4l2-common.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-subdev.h> ++ ++#include "../max9286.h" ++ ++#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */ ++#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */ ++#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */ ++#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */ ++#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ ++#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ ++#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ ++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ ++ ++struct max9288_priv { ++ struct v4l2_subdev sd; ++ struct fwnode_handle *sd_fwnode; ++ int des_addr; ++ int lanes; ++ int csi_rate; ++ int pclk; ++ char pclk_rising_edge; ++ int gpio_resetb; ++ int active_low_resetb; ++ int him; ++ int hsync; ++ int vsync; ++ int timeout; ++ int poc_delay; ++ int bws; ++ int dbl; ++ int dt; ++ int hsgen; ++ int hts; ++ int vts; ++ int hts_delay; ++ struct i2c_client *client; ++ int max9271_addr; ++ int ser_id; ++ struct gpio_desc *poc_gpio; /* PoC power supply */ ++}; ++ ++static int conf_link; ++module_param(conf_link, int, 0644); ++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); ++ ++static int poc_trig; ++module_param(poc_trig, int, 0644); ++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock"); ++ ++static int him = 0; ++module_param(him, int, 0644); ++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)"); ++ ++static int hsync; ++module_param(hsync, int, 0644); ++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); ++ ++static int vsync = 1; ++module_param(vsync, int, 0644); ++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); ++ ++static int gpio_resetb; ++module_param(gpio_resetb, int, 0644); ++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)"); ++ ++static int active_low_resetb; ++module_param(active_low_resetb, int, 0644); ++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)"); ++ ++static int timeout_n = 100; ++module_param(timeout_n, int, 0644); ++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)"); ++ ++static int poc_delay = 50; ++module_param(poc_delay, int, 0644); ++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)"); ++ ++static int bws = 0; ++module_param(bws, int, 0644); ++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)"); ++ ++static int dbl = 1; ++module_param(dbl, int, 0644); ++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)"); ++ ++static int dt = 3; ++module_param(dt, int, 0644); ++MODULE_PARM_DESC(dt, " DataType (default: 3 - YUV8), 0 - RGB888, 5 - RAW8, 6 - RAW10, 7 - RAW12, 8 - RAW14"); ++ ++static int hsgen; ++module_param(hsgen, int, 0644); ++MODULE_PARM_DESC(hsgen, " Enable HS embedded generator (default: 0 - disabled)"); ++ ++static int pclk = 100; ++module_param(pclk, int, 0644); ++MODULE_PARM_DESC(pclk, " PCLK rate (default: 100MHz)"); ++ ++enum { ++ RGB888_DT = 0, ++ RGB565_DT, ++ RGB666_DT, ++ YUV8_DT, /* default */ ++ YUV10_DT, ++ RAW8_DT, ++ RAW10_DT, ++ RAW12_DT, ++ RAW14_DT, ++}; ++ ++static int dt2bpp [9] = { ++ 24, /* RGB888 */ ++ 16, /* RGB565 */ ++ 18, /* RGB666 */ ++ 8, /* YUV8 - default */ ++ 10, /* YUV10 */ ++ 8, /* RAW8/RAW16 */ ++ 10, /* RAW10 */ ++ 12, /* RAW12 */ ++ 14, /* RAW14 */ ++}; ++ ++static char* ser_name(int id) ++{ ++ switch (id) { ++ case MAX9271_ID: ++ return "MAX9271"; ++ case MAX96705_ID: ++ return "MAX96705"; ++ case MAX96707_ID: ++ return "MAX96707"; ++ default: ++ return "unknown"; ++ } ++} ++ ++static void max9288_write_remote_verify(struct i2c_client *client, u8 reg, u8 val) ++{ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ int timeout; ++ ++ for (timeout = 0; timeout < 10; timeout++) { ++ u8 val2 = 0; ++ ++ reg8_write(client, reg, val); ++ reg8_read(client, reg, &val2); ++ if (val2 == val) ++ break; ++ ++ usleep_range(1000, 1500); ++ } ++ ++ if (timeout >= 10) ++ dev_err(&client->dev, "timeout remote write acked\n"); ++} ++ ++ ++static void max9288_preinit(struct i2c_client *client, int addr) ++{ ++ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ ++ client->addr = addr; /* MAX9288-CAMx I2C */ ++ reg8_write(client, 0x04, 0x00); /* disable reverse control */ ++ reg8_write(client, 0x16, (priv->him ? 0x80 : 0x00) | ++ 0x5a); /* high-immunity/legacy mode */ ++} ++ ++static void max9288_sensor_reset(struct i2c_client *client, int addr, int reset_on) ++{ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ ++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) ++ return; ++ ++ /* sensor reset/unreset */ ++ client->addr = addr; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */ ++ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on)); ++ reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ ++} ++ ++static int max9288_reverse_channel_setup(struct i2c_client *client) ++{ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ u8 val = 0, lock_sts = 0; ++ int timeout = priv->timeout; ++ char timeout_str[40]; ++ int ret = 0; ++ ++ /* Reverse channel enable */ ++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ ++ reg8_write(client, 0x1c, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x04, 0x03); /* enable reverse control */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ ++ for (;;) { ++ if (priv->him) { ++ /* HIM mode setup */ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x4d, 0xc0); ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ if (priv->bws) { ++ reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) | ++ (priv->dbl ? 0x80 : 0) | ++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS disabled enabled, DBL mode, BWS 24/32-bit */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ } ++ } else { ++ /* Legacy mode setup */ ++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ ++ reg8_write(client, 0x13, 0x00); ++ reg8_write(client, 0x11, 0x42); /* enable custom reverse channel & first pulse length */ ++ reg8_write(client, 0x0a, 0x0f); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ if (priv->bws) { ++ reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) | ++ (priv->dbl ? 0x80 : 0) | ++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding disabled, DBL mode, BWS 24/32-bit */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ } ++ reg8_write(client, 0x97, 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ ++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ ++ reg8_write(client, 0x0a, 0x0c); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */ ++ reg8_write(client, 0x13, 0x20); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ } ++ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_read(client, 0x1e, &val); /* read max9271 ID */ ++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID || --timeout == 0) { ++ priv->ser_id = val; ++ break; ++ } ++ ++ /* Check if already initialized (after reboot/reset ?) */ ++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C */ ++ reg8_read(client, 0x1e, &val); /* read max9271 ID */ ++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) { ++ priv->ser_id = val; ++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ ret = -EADDRINUSE; ++ break; ++ } ++ ++ if (poc_trig) { ++ if (!IS_ERR(priv->poc_gpio) && (timeout % poc_trig == 0)) { ++ gpiod_direction_output(priv->poc_gpio, 0); /* POC power off */ ++ mdelay(200); ++ gpiod_direction_output(priv->poc_gpio, 1); /* POC power on */ ++ mdelay(priv->poc_delay); ++ } ++ } ++ } ++ ++ max9288_sensor_reset(client, client->addr, 1); /* sensor reset */ ++ ++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ ++ reg8_read(client, 0x04, &lock_sts); /* LOCK status */ ++ ++ if (!timeout) { ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++out: ++ sprintf(timeout_str, "retries=%d lock_sts=%d", priv->timeout - timeout, !!(lock_sts & 0x80)); ++ dev_info(&client->dev, "link %s %sat 0x%x %s %s\n", ser_name(priv->ser_id), ++ ret == -EADDRINUSE ? "already " : "", priv->max9271_addr, ++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", ++ priv->timeout - timeout ? timeout_str : ""); ++ ++ return ret; ++} ++ ++static void max9288_initial_setup(struct i2c_client *client) ++{ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ ++ /* Initial setup */ ++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ ++ reg8_write(client, 0x09, 0x40); /* Automatic pixel count enable */ ++ reg8_write(client, 0x15, 0x70); /* Enable HV and DE tracking by register 0x69 */ ++ reg8_write(client, 0x60, (priv->dbl ? 0x20 : 0) | ++ (priv->dt & 0xf)); /* VC=0, DBL mode, DataType */ ++ reg8_write(client, 0x65, 0x47 | ((priv->lanes - 1) << 4)); /* setup CSI lanes, DE input is HS */ ++ ++ reg8_write(client, 0x08, 0x20); /* use D18/19 for HS/VS */ ++ reg8_write(client, 0x14, (priv->vsync ? 0x80 : 0) | (priv->hsync ? 0x40 : 0)); /* setup HS/VS inversion */ ++ reg8_write(client, 0x64, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */ ++} ++ ++static void max9288_gmsl_link_setup(struct i2c_client *client) ++{ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ ++ /* GMSL setup */ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ ++ reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) | ++ (priv->dbl ? 0x80 : 0) | ++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding disabled, DBL mode, BWS 24/32-bit */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ ++ if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) { ++ switch (priv->dt) { ++ case YUV8_DT: ++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */ ++ reg8_write(client, 0x20, 3); ++ reg8_write(client, 0x21, 4); ++ reg8_write(client, 0x22, 5); ++ reg8_write(client, 0x23, 6); ++ reg8_write(client, 0x24, 7); ++ reg8_write(client, 0x25, 0x40); ++ reg8_write(client, 0x26, 0x40); ++ if (priv->ser_id == MAX96705_ID) { ++ reg8_write(client, 0x27, 14); /* HS: D14->D18 */ ++ reg8_write(client, 0x28, 15); /* VS: D15->D19 */ ++ } ++ if (priv->ser_id == MAX96707_ID) { ++ reg8_write(client, 0x27, 14); /* HS: D14->D18, this is a virtual NC pin, hence it is D14 at HS */ ++ reg8_write(client, 0x28, 13); /* VS: D13->D19 */ ++ } ++ reg8_write(client, 0x29, 0x40); ++ reg8_write(client, 0x2A, 0x40); ++ ++ /* this is second byte if DBL=1 */ ++ reg8_write(client, 0x30, 0x10 + 0); ++ reg8_write(client, 0x31, 0x10 + 1); ++ reg8_write(client, 0x32, 0x10 + 2); ++ reg8_write(client, 0x33, 0x10 + 3); ++ reg8_write(client, 0x34, 0x10 + 4); ++ reg8_write(client, 0x35, 0x10 + 5); ++ reg8_write(client, 0x36, 0x10 + 6); ++ reg8_write(client, 0x37, 0x10 + 7); ++ reg8_write(client, 0x38, 0); ++ reg8_write(client, 0x39, 1); ++ reg8_write(client, 0x3A, 2); ++ ++ reg8_write(client, 0x67, 0xC4); /* DBL_ALIGN_TO = 100b */ ++ ++ break; ++ case RAW12_DT: ++#if 0 /* Not supported yet */ ++ /* setup crossbar for RAW12: reverse DVP bus */ ++ reg8_write(client, 0x20, 11); ++ reg8_write(client, 0x21, 10); ++ reg8_write(client, 0x22, 9); ++ reg8_write(client, 0x23, 8); ++ reg8_write(client, 0x24, 7); ++ reg8_write(client, 0x25, 6); ++ reg8_write(client, 0x26, 5); ++ reg8_write(client, 0x27, 4); ++ reg8_write(client, 0x28, 3); ++ reg8_write(client, 0x29, 2); ++ reg8_write(client, 0x2a, 1); ++ reg8_write(client, 0x2b, 0); ++ ++ /* this is second byte if DBL=1 */ ++ reg8_write(client, 0x30, 27); ++ reg8_write(client, 0x31, 26); ++ reg8_write(client, 0x32, 25); ++ reg8_write(client, 0x33, 24); ++ reg8_write(client, 0x34, 23); ++ reg8_write(client, 0x35, 22); ++ reg8_write(client, 0x36, 21); ++ reg8_write(client, 0x37, 20); ++ reg8_write(client, 0x38, 19); ++ reg8_write(client, 0x39, 18); ++ reg8_write(client, 0x3a, 17); ++ reg8_write(client, 0x3b, 16); ++ ++ if (!priv->bws && priv->dbl) ++ dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n"); ++#endif ++ break; ++ } ++ ++ if (priv->hsgen) { ++ /* HS/VS pins map */ ++ reg8_write(client, 0x3f, 0x10); /* HS (NC) */ ++ reg8_write(client, 0x41, 0x10); /* DE (NC) */ ++ if (priv->ser_id == MAX96705_ID) ++ reg8_write(client, 0x40, 15); /* VS (DIN13) */ ++ if (priv->ser_id == MAX96707_ID) ++ reg8_write(client, 0x40, 13); /* VS (DIN13) */ ++#if 0 ++ /* following must come from imager */ ++#define SENSOR_WIDTH (1280*2) ++#define HTS (1288*2) ++#define VTS 960 ++#define HTS_DELAY 0x9 ++ reg8_write(client, 0x4e, HTS_DELAY >> 16); /* HS delay */ ++ reg8_write(client, 0x4f, (HTS_DELAY >> 8) & 0xff); ++ reg8_write(client, 0x50, HTS_DELAY & 0xff); ++ reg8_write(client, 0x54, SENSOR_WIDTH >> 8); /* HS high period */ ++ reg8_write(client, 0x55, SENSOR_WIDTH & 0xff); ++ reg8_write(client, 0x56, (HTS - SENSOR_WIDTH) >> 8); /* HS low period */ ++ reg8_write(client, 0x57, (HTS - SENSOR_WIDTH) & 0xff); ++ reg8_write(client, 0x58, VTS >> 8); /* HS count */ ++ reg8_write(client, 0x59, VTS & 0xff ); ++#endif ++ reg8_write(client, 0x43, 0x15); /* enable HS generator */ ++ } ++ } ++ ++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ ++ reg8_write(client, 0x1c, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ ++ /* I2C translator setup */ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */ ++// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */ ++ reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */ ++ reg8_write(client, 0x0C, priv->max9271_addr << 1); /* MAX9271-CAMx I2C new */ ++ /* I2C addresse change */ ++ reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9288 I2C */ ++ reg8_write(client, 0x00, priv->max9271_addr << 1); /* MAX9271-CAM0 I2C new */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ /* put MAX9271 in configuration link state */ ++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */ ++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++#ifdef MAXIM_DUMP ++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ ++ maxim_max927x_dump_regs(client); ++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */ ++ maxim_max927x_dump_regs(client); ++#endif ++} ++ ++static int max9288_initialize(struct i2c_client *client) ++{ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ ++ dev_info(&client->dev, "LANES=%d, PCLK edge=%s\n", ++ priv->lanes, priv->pclk_rising_edge ? "rising" : "falling"); ++ ++ max9288_preinit(client, priv->des_addr); ++ max9288_initial_setup(client); ++ ++ if (!IS_ERR(priv->poc_gpio)) { ++ gpiod_direction_output(priv->poc_gpio, 1); /* POC power on */ ++ mdelay(priv->poc_delay); ++ } ++ ++ max9288_reverse_channel_setup(client); ++ max9288_gmsl_link_setup(client); ++ ++ client->addr = priv->des_addr; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int max9288_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct max9288_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ int ret; ++ u8 val = 0; ++ ++ ret = reg8_read(client, (u8)reg->reg, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = sizeof(u8); ++ ++ return 0; ++} ++ ++static int max9288_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct max9288_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ return reg8_write(client, (u8)reg->reg, (u8)reg->val); ++} ++#endif ++ ++static int max9288_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct max9288_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */ ++ max9288_write_remote_verify(client, 0x04, on ? (conf_link ? 0x43 : 0x83) : 0x43); /* enable serial_link or conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */ ++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ ++ ++ return 0; ++} ++ ++static struct v4l2_subdev_core_ops max9288_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = max9288_g_register, ++ .s_register = max9288_s_register, ++#endif ++ .s_power = max9288_s_power, ++}; ++ ++static struct v4l2_subdev_ops max9288_subdev_ops = { ++ .core = &max9288_subdev_core_ops, ++}; ++ ++static int max9288_parse_dt(struct i2c_client *client) ++{ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ struct device_node *np = client->dev.of_node; ++ struct device_node *endpoint = NULL; ++ struct property *prop; ++ int err, pwen; ++ int sensor_delay, gpio0 = 1, gpio1 = 1; ++ u8 val = 0; ++ char poc_name[10]; ++ ++ if (of_property_read_u32(np, "maxim,lanes", &priv->lanes)) ++ priv->lanes = 4; ++ ++ pwen = of_get_gpio(np, 0); ++ if (pwen > 0) { ++ err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev)); ++ if (err) ++ dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err); ++ } ++ ++ mdelay(250); ++ ++ sprintf(poc_name, "POC%d", 0); ++ priv->poc_gpio = devm_gpiod_get_optional(&client->dev, kstrdup(poc_name, GFP_KERNEL), 0); ++ ++ reg8_read(client, 0x1e, &val); /* read max9288 ID */ ++ if (val != MAX9288_ID) { ++ prop = of_find_property(np, "reg", NULL); ++ if (prop) ++ of_remove_property(np, prop); ++ return -ENODEV; ++ } ++ ++ if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) || ++ !of_property_read_u32(np, "maxim,gpio1", &gpio1)) ++ reg8_write(client, 0x06, (gpio1 << 3) | (gpio0 << 1)); ++ ++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) { ++ priv->gpio_resetb = -1; ++ } else { ++ if (of_property_read_bool(np, "maxim,resetb-active-high")) ++ priv->active_low_resetb = 0; ++ else ++ priv->active_low_resetb = 1; ++ } ++ ++ if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay)) ++ mdelay(sensor_delay); ++ priv->pclk_rising_edge = true; ++ if (of_property_read_bool(np, "maxim,pclk-falling-edge")) ++ priv->pclk_rising_edge = false; ++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout)) ++ priv->timeout = 100; ++ if (of_property_read_u32(np, "maxim,him", &priv->him)) ++ priv->him = 0; ++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync)) ++ priv->hsync = 0; ++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync)) ++ priv->vsync = 1; ++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay)) ++ priv->poc_delay = 50; ++ if (of_property_read_u32(np, "maxim,bws", &priv->bws)) ++ priv->bws = 0; ++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl)) ++ priv->dbl = 1; ++ if (of_property_read_u32(np, "maxim,dt", &priv->dt)) ++ priv->dt = 3; ++ if (of_property_read_u32(np, "maxim,hsgen", &priv->hsgen)) ++ priv->hsgen = 0; ++ if (of_property_read_u32(np, "maxim,pclk", &priv->pclk)) ++ priv->pclk = pclk; ++ ++ /* module params override dts */ ++ if (him) ++ priv->him = him; ++ if (hsync) ++ priv->hsync = hsync; ++ if (!vsync) ++ priv->vsync = vsync; ++ if (gpio_resetb) ++ priv->gpio_resetb = gpio_resetb; ++ if (active_low_resetb) ++ priv->active_low_resetb = active_low_resetb; ++ if (timeout_n) ++ priv->timeout = timeout_n; ++ if (poc_delay) ++ priv->poc_delay = poc_delay; ++ if (bws) ++ priv->bws = bws; ++ if (!dbl) ++ priv->dbl = dbl; ++ if (dt != 3) ++ priv->dt = dt; ++ if (hsgen) ++ priv->hsgen = hsgen; ++ if (pclk != 100) ++ priv->pclk = pclk; ++ ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (endpoint) { ++ if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr)) { ++ of_node_put(endpoint); ++ dev_err(&client->dev, "max9271-addr not set\n"); ++ return -EINVAL; ++ } ++ ++ priv->sd_fwnode = of_fwnode_handle(endpoint); ++ } ++ ++ of_node_put(endpoint); ++ return 0; ++} ++ ++static void max9288_setup_remote_endpoint(struct i2c_client *client) ++{ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ struct device_node *np = client->dev.of_node; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ int i; ++ struct property *csi_rate_prop, *dvp_order_prop; ++ ++ for (i = 0; ; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; ++ ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; ++ ++ csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL); ++ if (csi_rate_prop) { ++ /* CSI2_RATE = PCLK*bpp/lanes */ ++ priv->csi_rate = cpu_to_be32(priv->pclk * dt2bpp[priv->dt] / priv->lanes); ++ csi_rate_prop->value = &priv->csi_rate; ++ of_update_property(rendpoint, csi_rate_prop); ++ } ++ ++ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL); ++ if (dvp_order_prop) ++ of_update_property(rendpoint, dvp_order_prop); ++ } ++ ++ of_node_put(endpoint); ++} ++ ++static int max9288_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct max9288_priv *priv; ++ int err; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ i2c_set_clientdata(client, priv); ++ priv->des_addr = client->addr; ++ priv->client = client; ++ ++ err = max9288_parse_dt(client); ++ if (err) ++ goto out; ++ ++ err = max9288_initialize(client); ++ if (err < 0) ++ goto out; ++ ++ max9288_setup_remote_endpoint(client); ++ ++ v4l2_subdev_init(&priv->sd, &max9288_subdev_ops); ++ priv->sd.owner = client->dev.driver->owner; ++ priv->sd.dev = &client->dev; ++ v4l2_set_subdevdata(&priv->sd, priv); ++ priv->sd.fwnode = priv->sd_fwnode; ++ ++ snprintf(priv->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x", ++ client->dev.driver->name, i2c_adapter_id(client->adapter), ++ client->addr); ++ ++ err = v4l2_async_register_subdev(&priv->sd); ++ if (err < 0) ++ goto out; ++out: ++ return err; ++} ++ ++static int max9288_remove(struct i2c_client *client) ++{ ++ struct max9288_priv *priv = i2c_get_clientdata(client); ++ ++ v4l2_async_unregister_subdev(&priv->sd); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++static const struct of_device_id max9288_dt_ids[] = { ++ { .compatible = "maxim,max9288" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, max9288_dt_ids); ++ ++static const struct i2c_device_id max9288_id[] = { ++ { "max9288", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max9288_id); ++ ++static struct i2c_driver max9288_i2c_driver = { ++ .driver = { ++ .name = "max9288", ++ .of_match_table = of_match_ptr(max9288_dt_ids), ++ }, ++ .probe = max9288_probe, ++ .remove = max9288_remove, ++ .id_table = max9288_id, ++}; ++ ++module_i2c_driver(max9288_i2c_driver); ++ ++MODULE_DESCRIPTION("GMSL driver for MAX9288"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/imagers/Kconfig b/drivers/media/i2c/soc_camera/imagers/Kconfig +new file mode 100644 +index 0000000..a6ccf62 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/Kconfig +@@ -0,0 +1,5 @@ ++config SOC_CAMERA_OV106XX ++ tristate "ov106xx camera support" ++ depends on I2C ++ help ++ This is a runtime detected GMSL1/GMSL2/FPDLink3 sensors driver +diff --git a/drivers/media/i2c/soc_camera/imagers/Makefile b/drivers/media/i2c/soc_camera/imagers/Makefile +new file mode 100644 +index 0000000..ca10bbc +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/Makefile +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += dummy.o +diff --git a/drivers/media/i2c/soc_camera/imagers/dummy.c b/drivers/media/i2c/soc_camera/imagers/dummy.c +new file mode 100644 +index 0000000..d213fff +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/dummy.c +@@ -0,0 +1,491 @@ ++/* ++ * Dummy sensor camera driver ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++struct dummy_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ u8 id[6]; ++ int max_width; ++ int max_height; ++ const char * media_bus_format; ++ int mbus_format; ++}; ++ ++static int width = 1920; ++module_param(width, int, 0644); ++MODULE_PARM_DESC(width, " width (default: 1920)"); ++ ++static int height = 1080; ++module_param(height, int, 0644); ++MODULE_PARM_DESC(height, " height (default: 1080)"); ++ ++static char *mbus = "yuyv"; ++module_param(mbus, charp, 0644); ++MODULE_PARM_DESC(mbus, " MEDIA_BUS_FORMAT (default: YUYV)"); ++ ++static inline struct dummy_priv *to_dummy(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct dummy_priv, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct dummy_priv, hdl)->sd; ++} ++ ++static int dummy_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int dummy_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = priv->mbus_format; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int dummy_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ mf->code = priv->mbus_format; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int dummy_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = priv->mbus_format; ++ ++ return 0; ++} ++ ++static int dummy_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = 'D' >> 8; ++ edid->edid[9] = 'Y' & 0xff; ++ ++ return 0; ++} ++ ++static int dummy_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > priv->max_width) || ++ (rect->top + rect->height > priv->max_height)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ return 0; ++} ++ ++static int dummy_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int dummy_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int dummy_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ reg->val = 0; ++ reg->size = sizeof(u16); ++ ++ return 0; ++} ++ ++static int dummy_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ return 0; ++} ++#endif ++ ++static struct v4l2_subdev_core_ops dummy_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = dummy_g_register, ++ .s_register = dummy_s_register, ++#endif ++}; ++ ++static int dummy_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ case V4L2_CID_SHARPNESS: ++ case V4L2_CID_AUTOGAIN: ++ case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: ++ case V4L2_CID_EXPOSURE: ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ break; ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops dummy_ctrl_ops = { ++ .s_ctrl = dummy_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops dummy_video_ops = { ++ .s_stream = dummy_s_stream, ++ .g_mbus_config = dummy_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops dummy_subdev_pad_ops = { ++ .get_edid = dummy_get_edid, ++ .enum_mbus_code = dummy_enum_mbus_code, ++ .get_selection = dummy_get_selection, ++ .set_selection = dummy_set_selection, ++ .get_fmt = dummy_get_fmt, ++ .set_fmt = dummy_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops dummy_subdev_ops = { ++ .core = &dummy_core_ops, ++ .video = &dummy_video_ops, ++ .pad = &dummy_subdev_pad_ops, ++}; ++ ++static void dummy_otp_id_read(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = to_dummy(client); ++ ++ /* dummy camera id */ ++ priv->id[0] = 'd'; ++ priv->id[1] = 'u'; ++ priv->id[2] = 'm'; ++ priv->id[3] = 'm'; ++ priv->id[4] = 'y'; ++ priv->id[5] = '.'; ++} ++ ++static ssize_t dummy_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ dummy_otp_id_read(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_dummy, S_IRUGO, dummy_otp_id_show, NULL); ++ ++static int dummy_initialize(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (strcmp(priv->media_bus_format, "yuyv") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_YUYV8_2X8; ++ else if (strcmp(priv->media_bus_format, "uyvy") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_UYVY8_2X8; ++ else if (strcmp(priv->media_bus_format, "grey") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_Y8_1X8; ++ else if (strcmp(priv->media_bus_format, "rggb8") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB8_1X8; ++ else if (strcmp(priv->media_bus_format, "bggr8") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR8_1X8; ++ else if (strcmp(priv->media_bus_format, "grbg8") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG8_1X8; ++ else if (strcmp(priv->media_bus_format, "rggb12") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB12_1X12; ++ else if (strcmp(priv->media_bus_format, "bggr12") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR12_1X12; ++ else if (strcmp(priv->media_bus_format, "grbg12") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG12_1X12; ++ else if (strcmp(priv->media_bus_format, "rggb14") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB14_1X14; ++ else if (strcmp(priv->media_bus_format, "bggr14") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR14_1X14; ++ else if (strcmp(priv->media_bus_format, "grbg14") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG14_1X14; ++ else if (strcmp(priv->media_bus_format, "rggb16") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB16_1X16; ++ else if (strcmp(priv->media_bus_format, "bggr16") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR16_1X16; ++ else if (strcmp(priv->media_bus_format, "grbg16") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG16_1X16; ++ else { ++ v4l_err(client, "failed to parse mbus format (%s)\n", priv->media_bus_format); ++ return -EINVAL; ++ } ++ ++ /* Read OTP IDs */ ++ dummy_otp_id_read(client); ++ ++ dev_info(&client->dev, "Dummy camera sensor, res %dx%d, mbus %s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->max_width, priv->max_height, priv->media_bus_format, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ ++ return 0; ++} ++ ++static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv) ++{ ++ if (of_property_read_u32(np, "dummy,width", &priv->max_width)) ++ priv->max_width = width; ++ ++ if (of_property_read_u32(np, "dummy,height", &priv->max_height)) ++ priv->max_height = height; ++ ++ if (of_property_read_string(np, "dummy,mbus", &priv->media_bus_format)) ++ priv->media_bus_format = mbus; ++ ++ /* module params override dts */ ++ if (strcmp(mbus, "yuyv")) ++ priv->media_bus_format = mbus; ++ if (width != 1920) ++ priv->max_width = width; ++ if (height != 1080) ++ priv->max_height = height; ++ ++ return 0; ++} ++ ++static int dummy_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct dummy_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &dummy_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_GAIN, 1, 0x7ff, 1, 0x200); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = dummy_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = dummy_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = priv->max_width; ++ priv->rect.height = priv->max_height; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_dummy) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", ++ client->addr, client->adapter->name); ++ return ret; ++} ++ ++static int dummy_remove(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_dummy); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id dummy_id[] = { ++ { "dummy-camera", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, dummy_id); ++ ++static const struct of_device_id dummy_of_ids[] = { ++ { .compatible = "dummy-camera", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, dummy_of_ids); ++ ++static struct i2c_driver dummy_i2c_driver = { ++ .driver = { ++ .name = "dummy-camera", ++ .of_match_table = dummy_of_ids, ++ }, ++ .probe = dummy_probe, ++ .remove = dummy_remove, ++ .id_table = dummy_id, ++}; ++module_i2c_driver(dummy_i2c_driver); ++ ++MODULE_DESCRIPTION("Dummy SoC camera driver"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c +deleted file mode 100644 +index 28bd3c3..0000000 +--- a/drivers/media/i2c/soc_camera/max9286.c ++++ /dev/null +@@ -1,1071 +0,0 @@ +-/* +- * MAXIM max9286 GMSL driver +- * +- * Copyright (C) 2015-2018 Cogent Embedded, Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- */ +- +-#include <linux/delay.h> +-#include <linux/i2c.h> +-#include <linux/module.h> +-#include <linux/notifier.h> +-#include <linux/of_gpio.h> +-#include <linux/of_graph.h> +-#include <linux/reboot.h> +-#include <linux/videodev2.h> +- +-#include <media/v4l2-common.h> +-#include <media/v4l2-device.h> +-#include <media/v4l2-subdev.h> +- +-#include "max9286.h" +- +-#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */ +-#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */ +-#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */ +-#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */ +-#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ +-#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ +-#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ +-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ +- +-struct max9286_priv { +- struct v4l2_subdev sd[4]; +- struct fwnode_handle *sd_fwnode[4]; +- int des_addr; +- int des_quirk_addr; /* second MAX9286 on the same I2C bus */ +- int links; +- int links_mask; +- int lanes; +- int csi_rate; +- const char *fsync_mode; +- int fsync_period; +- int fps_numerator; +- int fps_denominator; +- int pclk; +- char pclk_rising_edge; +- int gpio_resetb; +- int active_low_resetb; +- int him; +- int hsync; +- int vsync; +- int timeout; +- int poc_delay; +- int bws; +- int dbl; +- int dt; +- int hsgen; +- u64 crossbar; +- char cb[16]; +- int hts; +- int vts; +- int hts_delay; +- int imager_width; +- atomic_t use_count; +- u32 csi2_outord; +- u32 switchin; +- struct i2c_client *client; +- int max9271_addr_map[4]; +- int ser_id; +- struct gpio_desc *poc_gpio[4]; /* PoC power supply */ +- struct notifier_block reboot_notifier; +- +- /* link statistic */ +- int prbserr[4]; +- int deterr[4]; +- int correrr[4]; +-}; +- +-static char fsync_mode_default[20] = "manual"; /* manual, automatic, semi-automatic, external */ +- +-static int conf_link; +-module_param(conf_link, int, 0644); +-MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); +- +-static int poc_trig; +-module_param(poc_trig, int, 0644); +-MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock"); +- +-static int him; +-module_param(him, int, 0644); +-MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)"); +- +-static int fsync_period; +-module_param(fsync_period, int, 0644); +-MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)"); +- +-static int hsync; +-module_param(hsync, int, 0644); +-MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); +- +-static int vsync = 1; +-module_param(vsync, int, 0644); +-MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); +- +-static int gpio_resetb; +-module_param(gpio_resetb, int, 0644); +-MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)"); +- +-static int active_low_resetb; +-module_param(active_low_resetb, int, 0644); +-MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)"); +- +-static int timeout_n = 100; +-module_param(timeout_n, int, 0644); +-MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)"); +- +-static int poc_delay = 50; +-module_param(poc_delay, int, 0644); +-MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)"); +- +-static int bws; +-module_param(bws, int, 0644); +-MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)"); +- +-static int dbl = 1; +-module_param(dbl, int, 0644); +-MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)"); +- +-static int dt = 3; +-module_param(dt, int, 0644); +-MODULE_PARM_DESC(dt, " DataType (default: 3 - YUV8), 0 - RGB888, 5 - RAW8, 6 - RAW10, 7 - RAW12, 8 - RAW14"); +- +-static int hsgen; +-module_param(hsgen, int, 0644); +-MODULE_PARM_DESC(hsgen, " Enable HS embedded generator (default: 0 - disabled)"); +- +-static int pclk = 100; +-module_param(pclk, int, 0644); +-MODULE_PARM_DESC(pclk, " PCLK rate (default: 100MHz)"); +- +-static int switchin = 0; +-module_param(switchin, int, 0644); +-MODULE_PARM_DESC(switchin, " COAX SWITCH IN+ and IN- (default: 0 - not switched)"); +- +-static unsigned long crossbar = 0xba9876543210; +-module_param(crossbar, ulong, 0644); +-MODULE_PARM_DESC(crossbar, " Crossbar setup (default: ba9876543210 - reversed)"); +- +-enum { +- RGB888_DT = 0, +- RGB565_DT, +- RGB666_DT, +- YUV8_DT, /* default */ +- YUV10_DT, +- RAW8_DT, +- RAW10_DT, +- RAW12_DT, +- RAW14_DT, +-}; +- +-static int dt2bpp [9] = { +- 24, /* RGB888 */ +- 16, /* RGB565 */ +- 18, /* RGB666 */ +- 8, /* YUV8 - default */ +- 10, /* YUV10 */ +- 8, /* RAW8/RAW16 */ +- 10, /* RAW10 */ +- 12, /* RAW12 */ +- 14, /* RAW14 */ +-}; +- +-static char* ser_name(int id) +-{ +- switch (id) { +- case MAX9271_ID: +- return "MAX9271"; +- case MAX96705_ID: +- return "MAX96705"; +- case MAX96707_ID: +- return "MAX96707"; +- default: +- return "unknown"; +- } +-} +- +-static void max9286_write_remote_verify(struct i2c_client *client, int idx, u8 reg, u8 val) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- int timeout; +- +- for (timeout = 0; timeout < 10; timeout++) { +- int tmp_addr; +- u8 sts = 0; +- u8 val2 = 0; +- +- reg8_write(client, reg, val); +- +- tmp_addr = client->addr; +- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ +- reg8_read(client, 0x70, &sts); +- client->addr = tmp_addr; +- if (sts & BIT(idx)) /* if ACKed */ { +- reg8_read(client, reg, &val2); +- if (val2 == val) +- break; +- } +- +- usleep_range(1000, 1500); +- } +- +- if (timeout >= 10) +- dev_err(&client->dev, "timeout remote write acked\n"); +-} +- +-static void max9286_preinit(struct i2c_client *client, int addr) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- +- client->addr = addr; /* MAX9286-CAMx I2C */ +- reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */ +- reg8_write(client, 0x00, 0x00); /* disable all GMSL links [0:3] */ +-// usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- reg8_write(client, 0x1b, priv->switchin); /* coax polarity (default - normal) */ +- reg8_write(client, 0x1c, (priv->him ? 0xf0 : 0x00) | +- (priv->bws ? 0x05 : 0x04)); /* high-immunity/legacy mode, BWS 24bit */ +-} +- +-static void max9286_sensor_reset(struct i2c_client *client, int addr, int reset_on) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- +- if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) +- return; +- +- if (priv->active_low_resetb) +- reset_on = !reset_on; +- +- /* sensor reset/unreset using serializer gpio */ +- client->addr = addr; +- reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | (reset_on ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value */ +- reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ +-} +- +-static void max9286_postinit(struct i2c_client *client, int addr) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- int idx; +- +- for (idx = 0; idx < priv->links; idx++) { +- if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) +- continue; +- +- client->addr = priv->des_addr; /* MAX9286 I2C */ +- reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */ +- reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */ +- usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */ +- +- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */ +- max9286_sensor_reset(client, client->addr, 0); /* sensor unreset using gpios. TODO: should be in imager driver */ +- } +- +- client->addr = addr; /* MAX9286 I2C */ +- reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */ +- reg8_write(client, 0x00, 0xe0 | priv->links_mask); /* enable GMSL link for CAMs */ +- reg8_write(client, 0x0b, priv->csi2_outord); /* CSI2 output order */ +- reg8_write(client, 0x15, 0x9b); /* enable CSI output, VC is set accordingly to Link number, BIT7 magic must be set */ +- reg8_write(client, 0x1b, priv->switchin | priv->links_mask); /* coax polarity, enable equalizer for CAMs */ +- usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */ +- +- if (strcmp(priv->fsync_mode, "manual") == 0) { +- reg8_write(client, 0x01, 0x00); /* manual: FRAMESYNC set manually via [0x06:0x08] regs */ +- } else if (strcmp(priv->fsync_mode, "automatic") == 0) { +- reg8_write(client, 0x01, 0x02); /* automatic: FRAMESYNC taken from the slowest Link */ +- } else if (strcmp(priv->fsync_mode, "semi-automatic") == 0) { +- reg8_write(client, 0x01, 0x01); /* semi-automatic: FRAMESYNC taken from the slowest Link */ +- } else if (strcmp(priv->fsync_mode, "external") == 0) { +- reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */ +- } +-} +- +-static int max9286_reverse_channel_setup(struct i2c_client *client, int idx) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- u8 val = 0, lock_sts = 0, link_sts = 0; +- int timeout = priv->timeout; +- char timeout_str[40]; +- int ret = 0; +- +- /* Reverse channel enable */ +- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ +- reg8_write(client, 0x34, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */ +- reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse control for CAMx */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- +- for (;;) { +- if (priv->him) { +- /* HIM mode setup */ +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +- reg8_write(client, 0x4d, 0xc0); +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- if (priv->bws) { +- reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) | +- (priv->dbl ? 0x80 : 0) | +- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- } +- } else { +- /* Legacy mode setup */ +- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ +- reg8_write(client, 0x3f, 0x4f); /* enable custom reverse channel & first pulse length */ +- reg8_write(client, 0x3b, 0x1e); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +- reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */ +- reg8_write(client, 0x97, 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- if (priv->bws) { +- reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) | +- (priv->dbl ? 0x80 : 0) | +- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- } +- +- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ +- reg8_write(client, 0x3b, 0x19); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- } +- +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +- reg8_read(client, 0x1e, &val); /* read max9271 ID */ +- if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID || --timeout == 0) { +- priv->ser_id = val; +- break; +- } +- +- /* Check if already initialized (after reboot/reset ?) */ +- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */ +- reg8_read(client, 0x1e, &val); /* read max9271 ID */ +- if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) { +- priv->ser_id = val; +- reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- ret = -EADDRINUSE; +- break; +- } +- +- if (poc_trig) { +- if (!IS_ERR(priv->poc_gpio[idx]) && (timeout % poc_trig == 0)) { +- gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ +- mdelay(200); +- gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */ +- mdelay(priv->poc_delay); +- } +- } +- } +- +- max9286_sensor_reset(client, client->addr, 1); /* sensor reset */ +- +- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ +- reg8_read(client, 0x27, &lock_sts); /* LOCK status */ +- reg8_read(client, 0x49, &link_sts); /* LINK status */ +- +- if (!timeout) { +- ret = -ETIMEDOUT; +- goto out; +- } +- +- priv->links_mask |= BIT(idx); +- priv->csi2_outord &= ~(0x3 << (idx * 2)); +- priv->csi2_outord |= ((hweight8(priv->links_mask) - 1) << (idx * 2)); +- +-out: +- sprintf(timeout_str, "retries=%d lock_sts=%d link_sts=0x%x", priv->timeout - timeout, !!(lock_sts & 0x80), link_sts & (0x11 << idx)); +- dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, ser_name(priv->ser_id), +- ret == -EADDRINUSE ? "already " : "", priv->max9271_addr_map[idx], +- ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", +- priv->timeout - timeout ? timeout_str : ""); +- +- return ret; +-} +- +-static void max9286_initial_setup(struct i2c_client *client) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- +- /* Initial setup */ +- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ +- reg8_write(client, 0x15, 0x13); /* disable CSI output, VC is set accordingly to Link number */ +- reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ +- reg8_write(client, 0x12, ((priv->lanes - 1) << 6) | +- (priv->dbl ? 0x30 : 0) | +- (priv->dt & 0xf)); /* setup lanes, DBL mode, DataType */ +- +- /* Start GMSL initialization with FSYNC disabled. This is required for some odd LVDS cameras */ +- reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */ +- reg8_write(client, 0x06, priv->fsync_period & 0xff); +- reg8_write(client, 0x07, (priv->fsync_period >> 8) & 0xff); +- reg8_write(client, 0x08, priv->fsync_period >> 16); +- +- reg8_write(client, 0x63, 0); /* disable overlap window */ +- reg8_write(client, 0x64, 0); +- reg8_write(client, 0x0c, 0x91 | (priv->vsync ? BIT(3) : 0) | (priv->hsync ? BIT(2) : 0)); /* enable HS/VS encoding, use D14/15 for HS/VS, invert HS/VS */ +- reg8_write(client, 0x19, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */ +-} +- +-static void max9286_gmsl_link_setup(struct i2c_client *client, int idx) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- +- /* GMSL setup */ +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +- reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ +- reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) | +- (priv->dbl ? 0x80 : 0) | +- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */ +- usleep_range(2000, 2500); /* wait 2ms */ +- reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */ +- usleep_range(2000, 2500); /* wait 2ms */ +- +- if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) { +- switch (priv->dt) { +- case YUV8_DT: +- /* setup crossbar for YUV8/RAW8: reverse DVP bus */ +- reg8_write(client, 0x20, priv->cb[7]); +- reg8_write(client, 0x21, priv->cb[6]); +- reg8_write(client, 0x22, priv->cb[5]); +- reg8_write(client, 0x23, priv->cb[4]); +- reg8_write(client, 0x24, priv->cb[3]); +- reg8_write(client, 0x25, priv->cb[2]); +- reg8_write(client, 0x26, priv->cb[1]); +- reg8_write(client, 0x27, priv->cb[0]); +- +- /* this is second byte if DBL=1 */ +- reg8_write(client, 0x30, priv->cb[7] + 16); +- reg8_write(client, 0x31, priv->cb[6] + 16); +- reg8_write(client, 0x32, priv->cb[5] + 16); +- reg8_write(client, 0x33, priv->cb[4] + 16); +- reg8_write(client, 0x34, priv->cb[3] + 16); +- reg8_write(client, 0x35, priv->cb[2] + 16); +- reg8_write(client, 0x36, priv->cb[1] + 16); +- reg8_write(client, 0x37, priv->cb[0] + 16); +- break; +- case RAW12_DT: +- /* setup crossbar for RAW12: reverse DVP bus */ +- reg8_write(client, 0x20, priv->cb[11]); +- reg8_write(client, 0x21, priv->cb[10]); +- reg8_write(client, 0x22, priv->cb[9]); +- reg8_write(client, 0x23, priv->cb[8]); +- reg8_write(client, 0x24, priv->cb[7]); +- reg8_write(client, 0x25, priv->cb[6]); +- reg8_write(client, 0x26, priv->cb[5]); +- reg8_write(client, 0x27, priv->cb[4]); +- reg8_write(client, 0x28, priv->cb[3]); +- reg8_write(client, 0x29, priv->cb[2]); +- reg8_write(client, 0x2a, priv->cb[1]); +- reg8_write(client, 0x2b, priv->cb[0]); +- +- /* this is second byte if DBL=1 */ +- reg8_write(client, 0x30, priv->cb[11] + 16); +- reg8_write(client, 0x31, priv->cb[10] + 16); +- reg8_write(client, 0x32, priv->cb[9] + 16); +- reg8_write(client, 0x33, priv->cb[8] + 16); +- reg8_write(client, 0x34, priv->cb[7] + 16); +- reg8_write(client, 0x35, priv->cb[6] + 16); +- reg8_write(client, 0x36, priv->cb[5] + 16); +- reg8_write(client, 0x37, priv->cb[4] + 16); +- reg8_write(client, 0x38, priv->cb[3] + 16); +- reg8_write(client, 0x39, priv->cb[2] + 16); +- reg8_write(client, 0x3a, priv->cb[1] + 16); +- reg8_write(client, 0x3b, priv->cb[0] + 16); +- +- if (!priv->bws && priv->dbl) +- dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n"); +- +- break; +- } +- +- if (priv->hsgen) { +- /* HS/VS pins map */ +- reg8_write(client, 0x3f, 0x10); /* HS (NC) */ +- reg8_write(client, 0x41, 0x10); /* DE (NC) */ +- if (priv->ser_id == MAX96705_ID) +- reg8_write(client, 0x40, 15); /* VS (DIN13) */ +- if (priv->ser_id == MAX96707_ID) +- reg8_write(client, 0x40, 13); /* VS (DIN13) */ +-#if 0 +- /* following must come from imager */ +-#define SENSOR_WIDTH (1280*2) +-#define HTS (1288*2) +-#define VTS 960 +-#define HTS_DELAY 0x9 +- reg8_write(client, 0x4e, HTS_DELAY >> 16); /* HS delay */ +- reg8_write(client, 0x4f, (HTS_DELAY >> 8) & 0xff); +- reg8_write(client, 0x50, HTS_DELAY & 0xff); +- reg8_write(client, 0x54, SENSOR_WIDTH >> 8); /* HS high period */ +- reg8_write(client, 0x55, SENSOR_WIDTH & 0xff); +- reg8_write(client, 0x56, (HTS - SENSOR_WIDTH) >> 8); /* HS low period */ +- reg8_write(client, 0x57, (HTS - SENSOR_WIDTH) & 0xff); +- reg8_write(client, 0x58, VTS >> 8); /* HS count */ +- reg8_write(client, 0x59, VTS & 0xff ); +-#endif +- reg8_write(client, 0x43, 0x15); /* enable HS generator */ +- } +- } +- +- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ +- reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ +- usleep_range(2000, 2500); /* wait 2ms */ +- +- /* I2C translator setup */ +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +-// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */ +-// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */ +- reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */ +- reg8_write(client, 0x0C, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAMx I2C new */ +- /* I2C addresse change */ +- reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9286 I2C */ +- reg8_write(client, 0x00, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAM0 I2C new */ +- usleep_range(2000, 2500); /* wait 2ms */ +- /* put MAX9271 in configuration link state */ +- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */ +- reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ +- usleep_range(2000, 2500); /* wait 2ms */ +-#ifdef MAXIM_DUMP +- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ +- maxim_max927x_dump_regs(client); +- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */ +- maxim_max927x_dump_regs(client); +-#endif +-} +- +-static int max9286_initialize(struct i2c_client *client) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- int idx, ret; +- +- dev_info(&client->dev, "LINKs=%d, LANES=%d, FSYNC mode=%s, FSYNC period=%d, PCLK edge=%s\n", +- priv->links, priv->lanes, priv->fsync_mode, priv->fsync_period, +- priv->pclk_rising_edge ? "rising" : "falling"); +- +- if (priv->des_quirk_addr) +- max9286_preinit(client, priv->des_quirk_addr); +- +- max9286_preinit(client, priv->des_addr); +- max9286_initial_setup(client); +- +- for (idx = 0; idx < priv->links; idx++) { +- if (!IS_ERR(priv->poc_gpio[idx])) { +- gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */ +- mdelay(priv->poc_delay); +- } +- +- ret = max9286_reverse_channel_setup(client, idx); +- if (ret) +- continue; +- max9286_gmsl_link_setup(client, idx); +- } +- +- max9286_postinit(client, priv->des_addr); +- +- client->addr = priv->des_addr; +- +- return 0; +-} +- +-#ifdef CONFIG_VIDEO_ADV_DEBUG +-static int max9286_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) +-{ +- struct max9286_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- int ret; +- u8 val = 0; +- +- ret = reg8_read(client, (u8)reg->reg, &val); +- if (ret < 0) +- return ret; +- +- reg->val = val; +- reg->size = sizeof(u8); +- +- return 0; +-} +- +-static int max9286_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) +-{ +- struct max9286_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- +- return reg8_write(client, (u8)reg->reg, (u8)reg->val); +-} +-#endif +- +-static int max9286_s_power(struct v4l2_subdev *sd, int on) +-{ +- struct max9286_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- +- if (on) { +- if (atomic_inc_return(&priv->use_count) == 1) +- reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */ +- } else { +- if (atomic_dec_return(&priv->use_count) == 0) +- reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ +- } +- +- return 0; +-} +- +-static int max9286_registered_async(struct v4l2_subdev *sd) +-{ +- struct max9286_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- int idx, tmp_addr; +- +- /* switch to GMSL serial_link for streaming video */ +- tmp_addr = client->addr; +- idx = sd->grp_id; +- +- client->addr = priv->des_addr; /* MAX9286 I2C */ +- reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */ +- +- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx */ +- max9286_write_remote_verify(client, idx, 0x04, conf_link ? 0x43 : 0x83); +-// usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */ +- +- client->addr = priv->des_addr; /* MAX9286 I2C */ +- reg8_write(client, 0x0a, (priv->links_mask << 4) | priv->links_mask); /* enable reverse/forward control for all CAMs */ +- +- client->addr = tmp_addr; +- +- return 0; +-} +- +-static int max9286_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf) +-{ +- struct max9286_priv *priv = container_of(nb, struct max9286_priv, reboot_notifier); +- int idx; +- +- for (idx = 0; idx < priv->links; idx++) { +- if (!IS_ERR(priv->poc_gpio[idx])) +- gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ +- } +- +- return NOTIFY_OK; +-} +- +-static struct v4l2_subdev_core_ops max9286_subdev_core_ops = { +-#ifdef CONFIG_VIDEO_ADV_DEBUG +- .g_register = max9286_g_register, +- .s_register = max9286_s_register, +-#endif +- .s_power = max9286_s_power, +- .registered_async = max9286_registered_async, +-}; +- +-static int max9286_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +-{ +- return 0; +-} +- +-static int max9286_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +-{ +- struct max9286_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- struct v4l2_captureparm *cp = &parms->parm.capture; +- +- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +- return -EINVAL; +- if (cp->extendedmode != 0) +- return -EINVAL; +- +- if (priv->fps_denominator != cp->timeperframe.denominator || +- priv->fps_numerator != cp->timeperframe.numerator) { +- int f_period; +- +- f_period = priv->fsync_period * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; +- reg8_write(client, 0x06, f_period & 0xff); +- reg8_write(client, 0x07, (f_period >> 8) & 0xff); +- reg8_write(client, 0x08, f_period >> 16); +- +- priv->fps_numerator = cp->timeperframe.numerator; +- priv->fps_denominator = cp->timeperframe.denominator; +- } +- +- return 0; +-} +- +-static struct v4l2_subdev_video_ops max9286_video_ops = { +- .g_parm = max9286_g_parm, +- .s_parm = max9286_s_parm, +-}; +- +-static struct v4l2_subdev_ops max9286_subdev_ops = { +- .core = &max9286_subdev_core_ops, +- .video = &max9286_video_ops, +-}; +- +-static int max9286_parse_dt(struct i2c_client *client) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- struct device_node *np = client->dev.of_node; +- struct device_node *endpoint = NULL; +- struct property *prop; +- int err, pwen, i; +- int sensor_delay, gpio0 = 1, gpio1 = 1; +- u8 val = 0; +- char poc_name[10]; +- +- if (of_property_read_u32(np, "maxim,links", &priv->links)) +- priv->links = 4; +- +- if (of_property_read_u32(np, "maxim,lanes", &priv->lanes)) +- priv->lanes = 4; +- +- pwen = of_get_gpio(np, 0); +- if (pwen > 0) { +- err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev)); +- if (err) +- dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err); +- } +- +- mdelay(250); +- +- for (i = 0; i < 4; i++) { +- sprintf(poc_name, "POC%d", i); +- priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(poc_name, GFP_KERNEL), 0); +- } +- +- reg8_read(client, 0x1e, &val); /* read max9286 ID */ +- if (val != MAX9286_ID) { +- prop = of_find_property(np, "reg", NULL); +- if (prop) +- of_remove_property(np, prop); +- return -ENODEV; +- } +- +- if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) || +- !of_property_read_u32(np, "maxim,gpio1", &gpio1)) +- reg8_write(client, 0x0f, 0x08 | (gpio1 << 1) | gpio0); +- +- if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) { +- priv->gpio_resetb = -1; +- } else { +- if (of_property_read_bool(np, "maxim,resetb-active-high")) +- priv->active_low_resetb = 0; +- else +- priv->active_low_resetb = 1; +- } +- +- if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay)) +- mdelay(sensor_delay); +- if (of_property_read_string(np, "maxim,fsync-mode", &priv->fsync_mode)) +- priv->fsync_mode = fsync_mode_default; +- if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period)) +- priv->fsync_period = 3200000; /* 96MHz/30fps */ +- priv->pclk_rising_edge = true; +- if (of_property_read_bool(np, "maxim,pclk-falling-edge")) +- priv->pclk_rising_edge = false; +- if (of_property_read_u32(np, "maxim,timeout", &priv->timeout)) +- priv->timeout = 100; +- if (of_property_read_u32(np, "maxim,i2c-quirk", &priv->des_quirk_addr)) +- priv->des_quirk_addr = 0; +- if (of_property_read_u32(np, "maxim,him", &priv->him)) +- priv->him = 0; +- if (of_property_read_u32(np, "maxim,hsync", &priv->hsync)) +- priv->hsync = 0; +- if (of_property_read_u32(np, "maxim,vsync", &priv->vsync)) +- priv->vsync = 1; +- if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay)) +- priv->poc_delay = 50; +- if (of_property_read_u32(np, "maxim,bws", &priv->bws)) +- priv->bws = 0; +- if (of_property_read_u32(np, "maxim,dbl", &priv->dbl)) +- priv->dbl = 1; +- if (of_property_read_u32(np, "maxim,dt", &priv->dt)) +- priv->dt = 3; +- if (of_property_read_u32(np, "maxim,hsgen", &priv->hsgen)) +- priv->hsgen = 0; +- if (of_property_read_u32(np, "maxim,pclk", &priv->pclk)) +- priv->pclk = pclk; +- if (of_property_read_u32(np, "maxim,switchin", &priv->switchin)) +- priv->switchin = 0; +- if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar)) +- priv->crossbar = crossbar; +- +- /* module params override dts */ +- if (him) +- priv->him = him; +- if (fsync_period) { +- priv->fsync_period = fsync_period; +- priv->fsync_mode = fsync_mode_default; +- } +- if (hsync) +- priv->hsync = hsync; +- if (!vsync) +- priv->vsync = vsync; +- if (gpio_resetb) +- priv->gpio_resetb = gpio_resetb; +- if (active_low_resetb) +- priv->active_low_resetb = active_low_resetb; +- if (timeout_n) +- priv->timeout = timeout_n; +- if (poc_delay) +- priv->poc_delay = poc_delay; +- if (bws) +- priv->bws = bws; +- if (!dbl) +- priv->dbl = dbl; +- if (dt != 3) +- priv->dt = dt; +- if (hsgen) +- priv->hsgen = hsgen; +- if (pclk != 100) +- priv->pclk = pclk; +- if (switchin) +- priv->switchin = switchin; +- +- /* parse crossbar setup */ +- for (i = 0; i < 16; i++) { +- priv->cb[i] = priv->crossbar % 16; +- priv->crossbar /= 16; +- } +- +- for (i = 0; i < priv->links; i++) { +- endpoint = of_graph_get_next_endpoint(np, endpoint); +- if (!endpoint) +- break; +- +- if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr_map[i])) { +- of_node_put(endpoint); +- dev_err(&client->dev, "max9271-addr not set\n"); +- return -EINVAL; +- } +- +- priv->sd_fwnode[i] = of_fwnode_handle(endpoint); +- } +- +- of_node_put(endpoint); +- return 0; +-} +- +-static void max9286_setup_remote_endpoint(struct i2c_client *client) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- struct device_node *np = client->dev.of_node; +- struct device_node *endpoint = NULL, *rendpoint = NULL; +- int i; +- struct property *csi_rate_prop, *dvp_order_prop; +- +- for (i = 0; ; i++) { +- endpoint = of_graph_get_next_endpoint(np, endpoint); +- if (!endpoint) +- break; +- +- rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); +- if (!rendpoint) +- continue; +- +- csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL); +- if (csi_rate_prop) { +- /* CSI2_RATE = PCLK*bpp*links/lanes */ +- priv->csi_rate = cpu_to_be32(priv->pclk * dt2bpp[priv->dt] * hweight8(priv->links_mask) / priv->lanes); +- csi_rate_prop->value = &priv->csi_rate; +- of_update_property(rendpoint, csi_rate_prop); +- } +- +- dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL); +- if (dvp_order_prop) +- of_update_property(rendpoint, dvp_order_prop); +- } +- +- of_node_put(endpoint); +-} +- +-static const char *line_status[] = +-{ +- "BAT", +- "GND", +- "NORMAL", +- "OPEN" +-}; +- +-static ssize_t max9286_link_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- int i = -1; +- u8 val = 0; +- bool lenghterr, linebuffof, hlocked, prbsok, vsyncdet, configdet, videodet; +- int lf; +- u8 prbserr = 0, deterr = 0, correrr = 0; +- struct i2c_client *client = to_i2c_client(dev); +- struct max9286_priv *priv = i2c_get_clientdata(client); +- +- if (!sscanf(attr->attr.name, "link_%d", &i)) +- return -EINVAL; +- +- if ((i < 0) || (i > 3)) +- return -EINVAL; +- +- reg8_read(client, 0x20, &val); +- lf = (val >> (2 * i)) & 0x03; +- +- reg8_read(client, 0x21, &val); +- hlocked = !!(val & (1 << i)); +- prbsok = !!(val & (1 << (i + 4))); +- +- reg8_read(client, 0x22, &val); +- lenghterr = !!(val & (1 << i)); +- linebuffof = !!(val & (1 << (i + 4))); +- +- reg8_read(client, 0x23 + i, &prbserr); +- priv->prbserr[i] += prbserr; +- +- reg8_read(client, 0x27, &val); +- vsyncdet = !!(val & (1 << i)); +- +- reg8_read(client, 0x28 + i, &deterr); +- priv->deterr[i] += deterr; +- +- reg8_read(client, 0x2c + i, &correrr); +- priv->correrr[i] += correrr; +- +- reg8_read(client, 0x49, &val); +- configdet = !!(val & (1 << i)); +- videodet = !!(val & (1 << (i + 4))); +- +- return sprintf(buf, "LINK:%d LF:%s HLOCKED:%d PRBSOK:%d LINBUFFOF:%d" +- " LENGHTERR:%d VSYNCDET:%d CONFIGDET:%d VIDEODET:%d" +- " PRBSERR:%d(%d) DETEERR:%d(%d) CORRERR:%d(%d)\n", +- i, line_status[lf], hlocked, prbsok, lenghterr, +- linebuffof, vsyncdet, configdet, videodet, +- priv->prbserr[i], prbserr, +- priv->deterr[i], deterr, +- priv->correrr[i], correrr); +- return 0; +-} +- +-static DEVICE_ATTR(link_0, S_IRUGO, max9286_link_show, NULL); +-static DEVICE_ATTR(link_1, S_IRUGO, max9286_link_show, NULL); +-static DEVICE_ATTR(link_2, S_IRUGO, max9286_link_show, NULL); +-static DEVICE_ATTR(link_3, S_IRUGO, max9286_link_show, NULL); +- +-static struct attribute *max9286_attributes_links[] = { +- &dev_attr_link_0.attr, +- &dev_attr_link_1.attr, +- &dev_attr_link_2.attr, +- &dev_attr_link_3.attr, +- NULL +-}; +- +-static const struct attribute_group max9286_group = { +- .attrs = max9286_attributes_links, +-}; +- +-static int max9286_probe(struct i2c_client *client, +- const struct i2c_device_id *did) +-{ +- struct max9286_priv *priv; +- int err, i; +- +- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- i2c_set_clientdata(client, priv); +- priv->des_addr = client->addr; +- priv->client = client; +- atomic_set(&priv->use_count, 0); +- priv->csi2_outord = 0xff; +- priv->fps_numerator = 1; +- priv->fps_denominator = 30; +- +- err = max9286_parse_dt(client); +- if (err) +- goto out; +- +- err = max9286_initialize(client); +- if (err < 0) +- goto out; +- +- max9286_setup_remote_endpoint(client); +- +- for (i = 0; i < 4; i++) { +- v4l2_subdev_init(&priv->sd[i], &max9286_subdev_ops); +- priv->sd[i].owner = client->dev.driver->owner; +- priv->sd[i].dev = &client->dev; +- priv->sd[i].grp_id = i; +- v4l2_set_subdevdata(&priv->sd[i], priv); +- priv->sd[i].fwnode = priv->sd_fwnode[i]; +- +- snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x", +- client->dev.driver->name, i, i2c_adapter_id(client->adapter), +- client->addr); +- +- err = v4l2_async_register_subdev(&priv->sd[i]); +- if (err < 0) +- goto out; +- } +- +- priv->reboot_notifier.notifier_call = max9286_reboot_notifier; +- err = register_reboot_notifier(&priv->reboot_notifier); +- if (err) { +- dev_err(&client->dev, "failed to register reboot notifier\n"); +- goto out; +- } +- +- err = sysfs_create_group(&client->dev.kobj, +- &max9286_group); +- if (err < 0) +- dev_err(&client->dev, "Sysfs registration failed\n"); +-out: +- return err; +-} +- +-static int max9286_remove(struct i2c_client *client) +-{ +- struct max9286_priv *priv = i2c_get_clientdata(client); +- int i; +- +- sysfs_remove_group(&client->dev.kobj, &max9286_group); +- unregister_reboot_notifier(&priv->reboot_notifier); +- +- for (i = 0; i < 4; i++) { +- v4l2_async_unregister_subdev(&priv->sd[i]); +- v4l2_device_unregister_subdev(&priv->sd[i]); +- } +- +- return 0; +-} +- +-static const struct of_device_id max9286_dt_ids[] = { +- { .compatible = "maxim,max9286" }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, max9286_dt_ids); +- +-static const struct i2c_device_id max9286_id[] = { +- { "max9286", 0 }, +- { } +-}; +-MODULE_DEVICE_TABLE(i2c, max9286_id); +- +-static struct i2c_driver max9286_i2c_driver = { +- .driver = { +- .name = "max9286", +- .of_match_table = of_match_ptr(max9286_dt_ids), +- }, +- .probe = max9286_probe, +- .remove = max9286_remove, +- .id_table = max9286_id, +-}; +- +-module_i2c_driver(max9286_i2c_driver); +- +-MODULE_DESCRIPTION("GMSL driver for MAX9286"); +-MODULE_AUTHOR("Vladimir Barinov"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/max9288.c b/drivers/media/i2c/soc_camera/max9288.c +deleted file mode 100644 +index 4840795..0000000 +--- a/drivers/media/i2c/soc_camera/max9288.c ++++ /dev/null +@@ -1,768 +0,0 @@ +-/* +- * MAXIM max9288 GMSL driver +- * +- * Copyright (C) 2019 Cogent Embedded, Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- */ +- +-#include <linux/delay.h> +-#include <linux/i2c.h> +-#include <linux/module.h> +-#include <linux/notifier.h> +-#include <linux/of_gpio.h> +-#include <linux/of_graph.h> +-#include <linux/videodev2.h> +- +-#include <media/v4l2-common.h> +-#include <media/v4l2-device.h> +-#include <media/v4l2-subdev.h> +- +-#include "max9286.h" +- +-#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */ +-#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */ +-#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */ +-#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */ +-#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ +-#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ +-#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ +-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ +- +-struct max9288_priv { +- struct v4l2_subdev sd; +- struct fwnode_handle *sd_fwnode; +- int des_addr; +- int lanes; +- int csi_rate; +- int pclk; +- char pclk_rising_edge; +- int gpio_resetb; +- int active_low_resetb; +- int him; +- int hsync; +- int vsync; +- int timeout; +- int poc_delay; +- int bws; +- int dbl; +- int dt; +- int hsgen; +- int hts; +- int vts; +- int hts_delay; +- struct i2c_client *client; +- int max9271_addr; +- int ser_id; +- struct gpio_desc *poc_gpio; /* PoC power supply */ +-}; +- +-static int conf_link; +-module_param(conf_link, int, 0644); +-MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); +- +-static int poc_trig; +-module_param(poc_trig, int, 0644); +-MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock"); +- +-static int him = 0; +-module_param(him, int, 0644); +-MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)"); +- +-static int hsync; +-module_param(hsync, int, 0644); +-MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); +- +-static int vsync = 1; +-module_param(vsync, int, 0644); +-MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); +- +-static int gpio_resetb; +-module_param(gpio_resetb, int, 0644); +-MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)"); +- +-static int active_low_resetb; +-module_param(active_low_resetb, int, 0644); +-MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)"); +- +-static int timeout_n = 100; +-module_param(timeout_n, int, 0644); +-MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)"); +- +-static int poc_delay = 50; +-module_param(poc_delay, int, 0644); +-MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)"); +- +-static int bws = 0; +-module_param(bws, int, 0644); +-MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)"); +- +-static int dbl = 1; +-module_param(dbl, int, 0644); +-MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)"); +- +-static int dt = 3; +-module_param(dt, int, 0644); +-MODULE_PARM_DESC(dt, " DataType (default: 3 - YUV8), 0 - RGB888, 5 - RAW8, 6 - RAW10, 7 - RAW12, 8 - RAW14"); +- +-static int hsgen; +-module_param(hsgen, int, 0644); +-MODULE_PARM_DESC(hsgen, " Enable HS embedded generator (default: 0 - disabled)"); +- +-static int pclk = 100; +-module_param(pclk, int, 0644); +-MODULE_PARM_DESC(pclk, " PCLK rate (default: 100MHz)"); +- +-enum { +- RGB888_DT = 0, +- RGB565_DT, +- RGB666_DT, +- YUV8_DT, /* default */ +- YUV10_DT, +- RAW8_DT, +- RAW10_DT, +- RAW12_DT, +- RAW14_DT, +-}; +- +-static int dt2bpp [9] = { +- 24, /* RGB888 */ +- 16, /* RGB565 */ +- 18, /* RGB666 */ +- 8, /* YUV8 - default */ +- 10, /* YUV10 */ +- 8, /* RAW8/RAW16 */ +- 10, /* RAW10 */ +- 12, /* RAW12 */ +- 14, /* RAW14 */ +-}; +- +-static char* ser_name(int id) +-{ +- switch (id) { +- case MAX9271_ID: +- return "MAX9271"; +- case MAX96705_ID: +- return "MAX96705"; +- case MAX96707_ID: +- return "MAX96707"; +- default: +- return "unknown"; +- } +-} +- +-static void max9288_write_remote_verify(struct i2c_client *client, u8 reg, u8 val) +-{ +- struct max9288_priv *priv = i2c_get_clientdata(client); +- int timeout; +- +- for (timeout = 0; timeout < 10; timeout++) { +- u8 val2 = 0; +- +- reg8_write(client, reg, val); +- reg8_read(client, reg, &val2); +- if (val2 == val) +- break; +- +- usleep_range(1000, 1500); +- } +- +- if (timeout >= 10) +- dev_err(&client->dev, "timeout remote write acked\n"); +-} +- +- +-static void max9288_preinit(struct i2c_client *client, int addr) +-{ +- +- struct max9288_priv *priv = i2c_get_clientdata(client); +- +- client->addr = addr; /* MAX9288-CAMx I2C */ +- reg8_write(client, 0x04, 0x00); /* disable reverse control */ +- reg8_write(client, 0x16, (priv->him ? 0x80 : 0x00) | +- 0x5a); /* high-immunity/legacy mode */ +-} +- +-static void max9288_sensor_reset(struct i2c_client *client, int addr, int reset_on) +-{ +- struct max9288_priv *priv = i2c_get_clientdata(client); +- +- if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) +- return; +- +- /* sensor reset/unreset */ +- client->addr = addr; /* MAX9271-CAMx I2C */ +- reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */ +- ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on)); +- reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ +-} +- +-static int max9288_reverse_channel_setup(struct i2c_client *client) +-{ +- struct max9288_priv *priv = i2c_get_clientdata(client); +- u8 val = 0, lock_sts = 0; +- int timeout = priv->timeout; +- char timeout_str[40]; +- int ret = 0; +- +- /* Reverse channel enable */ +- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ +- reg8_write(client, 0x1c, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- reg8_write(client, 0x04, 0x03); /* enable reverse control */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- +- for (;;) { +- if (priv->him) { +- /* HIM mode setup */ +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +- reg8_write(client, 0x4d, 0xc0); +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- if (priv->bws) { +- reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) | +- (priv->dbl ? 0x80 : 0) | +- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS disabled enabled, DBL mode, BWS 24/32-bit */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- } +- } else { +- /* Legacy mode setup */ +- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ +- reg8_write(client, 0x13, 0x00); +- reg8_write(client, 0x11, 0x42); /* enable custom reverse channel & first pulse length */ +- reg8_write(client, 0x0a, 0x0f); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +- reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- if (priv->bws) { +- reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) | +- (priv->dbl ? 0x80 : 0) | +- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding disabled, DBL mode, BWS 24/32-bit */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- } +- reg8_write(client, 0x97, 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- +- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ +- reg8_write(client, 0x0a, 0x0c); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */ +- reg8_write(client, 0x13, 0x20); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- } +- +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +- reg8_read(client, 0x1e, &val); /* read max9271 ID */ +- if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID || --timeout == 0) { +- priv->ser_id = val; +- break; +- } +- +- /* Check if already initialized (after reboot/reset ?) */ +- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C */ +- reg8_read(client, 0x1e, &val); /* read max9271 ID */ +- if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) { +- priv->ser_id = val; +- reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ +- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ +- ret = -EADDRINUSE; +- break; +- } +- +- if (poc_trig) { +- if (!IS_ERR(priv->poc_gpio) && (timeout % poc_trig == 0)) { +- gpiod_direction_output(priv->poc_gpio, 0); /* POC power off */ +- mdelay(200); +- gpiod_direction_output(priv->poc_gpio, 1); /* POC power on */ +- mdelay(priv->poc_delay); +- } +- } +- } +- +- max9288_sensor_reset(client, client->addr, 1); /* sensor reset */ +- +- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ +- reg8_read(client, 0x04, &lock_sts); /* LOCK status */ +- +- if (!timeout) { +- ret = -ETIMEDOUT; +- goto out; +- } +- +-out: +- sprintf(timeout_str, "retries=%d lock_sts=%d", priv->timeout - timeout, !!(lock_sts & 0x80)); +- dev_info(&client->dev, "link %s %sat 0x%x %s %s\n", ser_name(priv->ser_id), +- ret == -EADDRINUSE ? "already " : "", priv->max9271_addr, +- ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", +- priv->timeout - timeout ? timeout_str : ""); +- +- return ret; +-} +- +-static void max9288_initial_setup(struct i2c_client *client) +-{ +- struct max9288_priv *priv = i2c_get_clientdata(client); +- +- /* Initial setup */ +- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ +- reg8_write(client, 0x09, 0x40); /* Automatic pixel count enable */ +- reg8_write(client, 0x15, 0x70); /* Enable HV and DE tracking by register 0x69 */ +- reg8_write(client, 0x60, (priv->dbl ? 0x20 : 0) | +- (priv->dt & 0xf)); /* VC=0, DBL mode, DataType */ +- reg8_write(client, 0x65, 0x47 | ((priv->lanes - 1) << 4)); /* setup CSI lanes, DE input is HS */ +- +- reg8_write(client, 0x08, 0x20); /* use D18/19 for HS/VS */ +- reg8_write(client, 0x14, (priv->vsync ? 0x80 : 0) | (priv->hsync ? 0x40 : 0)); /* setup HS/VS inversion */ +- reg8_write(client, 0x64, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */ +-} +- +-static void max9288_gmsl_link_setup(struct i2c_client *client) +-{ +- struct max9288_priv *priv = i2c_get_clientdata(client); +- +- /* GMSL setup */ +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +- reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ +- reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) | +- (priv->dbl ? 0x80 : 0) | +- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding disabled, DBL mode, BWS 24/32-bit */ +- usleep_range(2000, 2500); /* wait 2ms */ +- reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */ +- usleep_range(2000, 2500); /* wait 2ms */ +- +- if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) { +- switch (priv->dt) { +- case YUV8_DT: +- /* setup crossbar for YUV8/RAW8: reverse DVP bus */ +- reg8_write(client, 0x20, 3); +- reg8_write(client, 0x21, 4); +- reg8_write(client, 0x22, 5); +- reg8_write(client, 0x23, 6); +- reg8_write(client, 0x24, 7); +- reg8_write(client, 0x25, 0x40); +- reg8_write(client, 0x26, 0x40); +- if (priv->ser_id == MAX96705_ID) { +- reg8_write(client, 0x27, 14); /* HS: D14->D18 */ +- reg8_write(client, 0x28, 15); /* VS: D15->D19 */ +- } +- if (priv->ser_id == MAX96707_ID) { +- reg8_write(client, 0x27, 14); /* HS: D14->D18, this is a virtual NC pin, hence it is D14 at HS */ +- reg8_write(client, 0x28, 13); /* VS: D13->D19 */ +- } +- reg8_write(client, 0x29, 0x40); +- reg8_write(client, 0x2A, 0x40); +- +- /* this is second byte if DBL=1 */ +- reg8_write(client, 0x30, 0x10 + 0); +- reg8_write(client, 0x31, 0x10 + 1); +- reg8_write(client, 0x32, 0x10 + 2); +- reg8_write(client, 0x33, 0x10 + 3); +- reg8_write(client, 0x34, 0x10 + 4); +- reg8_write(client, 0x35, 0x10 + 5); +- reg8_write(client, 0x36, 0x10 + 6); +- reg8_write(client, 0x37, 0x10 + 7); +- reg8_write(client, 0x38, 0); +- reg8_write(client, 0x39, 1); +- reg8_write(client, 0x3A, 2); +- +- reg8_write(client, 0x67, 0xC4); /* DBL_ALIGN_TO = 100b */ +- +- break; +- case RAW12_DT: +-#if 0 /* Not supported yet */ +- /* setup crossbar for RAW12: reverse DVP bus */ +- reg8_write(client, 0x20, 11); +- reg8_write(client, 0x21, 10); +- reg8_write(client, 0x22, 9); +- reg8_write(client, 0x23, 8); +- reg8_write(client, 0x24, 7); +- reg8_write(client, 0x25, 6); +- reg8_write(client, 0x26, 5); +- reg8_write(client, 0x27, 4); +- reg8_write(client, 0x28, 3); +- reg8_write(client, 0x29, 2); +- reg8_write(client, 0x2a, 1); +- reg8_write(client, 0x2b, 0); +- +- /* this is second byte if DBL=1 */ +- reg8_write(client, 0x30, 27); +- reg8_write(client, 0x31, 26); +- reg8_write(client, 0x32, 25); +- reg8_write(client, 0x33, 24); +- reg8_write(client, 0x34, 23); +- reg8_write(client, 0x35, 22); +- reg8_write(client, 0x36, 21); +- reg8_write(client, 0x37, 20); +- reg8_write(client, 0x38, 19); +- reg8_write(client, 0x39, 18); +- reg8_write(client, 0x3a, 17); +- reg8_write(client, 0x3b, 16); +- +- if (!priv->bws && priv->dbl) +- dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n"); +-#endif +- break; +- } +- +- if (priv->hsgen) { +- /* HS/VS pins map */ +- reg8_write(client, 0x3f, 0x10); /* HS (NC) */ +- reg8_write(client, 0x41, 0x10); /* DE (NC) */ +- if (priv->ser_id == MAX96705_ID) +- reg8_write(client, 0x40, 15); /* VS (DIN13) */ +- if (priv->ser_id == MAX96707_ID) +- reg8_write(client, 0x40, 13); /* VS (DIN13) */ +-#if 0 +- /* following must come from imager */ +-#define SENSOR_WIDTH (1280*2) +-#define HTS (1288*2) +-#define VTS 960 +-#define HTS_DELAY 0x9 +- reg8_write(client, 0x4e, HTS_DELAY >> 16); /* HS delay */ +- reg8_write(client, 0x4f, (HTS_DELAY >> 8) & 0xff); +- reg8_write(client, 0x50, HTS_DELAY & 0xff); +- reg8_write(client, 0x54, SENSOR_WIDTH >> 8); /* HS high period */ +- reg8_write(client, 0x55, SENSOR_WIDTH & 0xff); +- reg8_write(client, 0x56, (HTS - SENSOR_WIDTH) >> 8); /* HS low period */ +- reg8_write(client, 0x57, (HTS - SENSOR_WIDTH) & 0xff); +- reg8_write(client, 0x58, VTS >> 8); /* HS count */ +- reg8_write(client, 0x59, VTS & 0xff ); +-#endif +- reg8_write(client, 0x43, 0x15); /* enable HS generator */ +- } +- } +- +- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ +- reg8_write(client, 0x1c, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ +- usleep_range(2000, 2500); /* wait 2ms */ +- +- /* I2C translator setup */ +- client->addr = 0x40; /* MAX9271-CAMx I2C */ +-// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */ +-// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */ +- reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */ +- reg8_write(client, 0x0C, priv->max9271_addr << 1); /* MAX9271-CAMx I2C new */ +- /* I2C addresse change */ +- reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9288 I2C */ +- reg8_write(client, 0x00, priv->max9271_addr << 1); /* MAX9271-CAM0 I2C new */ +- usleep_range(2000, 2500); /* wait 2ms */ +- /* put MAX9271 in configuration link state */ +- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */ +- reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ +- usleep_range(2000, 2500); /* wait 2ms */ +-#ifdef MAXIM_DUMP +- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ +- maxim_max927x_dump_regs(client); +- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */ +- maxim_max927x_dump_regs(client); +-#endif +-} +- +-static int max9288_initialize(struct i2c_client *client) +-{ +- struct max9288_priv *priv = i2c_get_clientdata(client); +- +- dev_info(&client->dev, "LANES=%d, PCLK edge=%s\n", +- priv->lanes, priv->pclk_rising_edge ? "rising" : "falling"); +- +- max9288_preinit(client, priv->des_addr); +- max9288_initial_setup(client); +- +- if (!IS_ERR(priv->poc_gpio)) { +- gpiod_direction_output(priv->poc_gpio, 1); /* POC power on */ +- mdelay(priv->poc_delay); +- } +- +- max9288_reverse_channel_setup(client); +- max9288_gmsl_link_setup(client); +- +- client->addr = priv->des_addr; +- +- return 0; +-} +- +-#ifdef CONFIG_VIDEO_ADV_DEBUG +-static int max9288_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) +-{ +- struct max9288_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- int ret; +- u8 val = 0; +- +- ret = reg8_read(client, (u8)reg->reg, &val); +- if (ret < 0) +- return ret; +- +- reg->val = val; +- reg->size = sizeof(u8); +- +- return 0; +-} +- +-static int max9288_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) +-{ +- struct max9288_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- +- return reg8_write(client, (u8)reg->reg, (u8)reg->val); +-} +-#endif +- +-static int max9288_s_power(struct v4l2_subdev *sd, int on) +-{ +- struct max9288_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- +- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */ +- max9288_write_remote_verify(client, 0x04, on ? (conf_link ? 0x43 : 0x83) : 0x43); /* enable serial_link or conf_link */ +- usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */ +- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ +- +- return 0; +-} +- +-static struct v4l2_subdev_core_ops max9288_subdev_core_ops = { +-#ifdef CONFIG_VIDEO_ADV_DEBUG +- .g_register = max9288_g_register, +- .s_register = max9288_s_register, +-#endif +- .s_power = max9288_s_power, +-}; +- +-static struct v4l2_subdev_ops max9288_subdev_ops = { +- .core = &max9288_subdev_core_ops, +-}; +- +-static int max9288_parse_dt(struct i2c_client *client) +-{ +- struct max9288_priv *priv = i2c_get_clientdata(client); +- struct device_node *np = client->dev.of_node; +- struct device_node *endpoint = NULL; +- struct property *prop; +- int err, pwen; +- int sensor_delay, gpio0 = 1, gpio1 = 1; +- u8 val = 0; +- char poc_name[10]; +- +- if (of_property_read_u32(np, "maxim,lanes", &priv->lanes)) +- priv->lanes = 4; +- +- pwen = of_get_gpio(np, 0); +- if (pwen > 0) { +- err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev)); +- if (err) +- dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err); +- } +- +- mdelay(250); +- +- sprintf(poc_name, "POC%d", 0); +- priv->poc_gpio = devm_gpiod_get_optional(&client->dev, kstrdup(poc_name, GFP_KERNEL), 0); +- +- reg8_read(client, 0x1e, &val); /* read max9288 ID */ +- if (val != MAX9288_ID) { +- prop = of_find_property(np, "reg", NULL); +- if (prop) +- of_remove_property(np, prop); +- return -ENODEV; +- } +- +- if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) || +- !of_property_read_u32(np, "maxim,gpio1", &gpio1)) +- reg8_write(client, 0x06, (gpio1 << 3) | (gpio0 << 1)); +- +- if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) { +- priv->gpio_resetb = -1; +- } else { +- if (of_property_read_bool(np, "maxim,resetb-active-high")) +- priv->active_low_resetb = 0; +- else +- priv->active_low_resetb = 1; +- } +- +- if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay)) +- mdelay(sensor_delay); +- priv->pclk_rising_edge = true; +- if (of_property_read_bool(np, "maxim,pclk-falling-edge")) +- priv->pclk_rising_edge = false; +- if (of_property_read_u32(np, "maxim,timeout", &priv->timeout)) +- priv->timeout = 100; +- if (of_property_read_u32(np, "maxim,him", &priv->him)) +- priv->him = 0; +- if (of_property_read_u32(np, "maxim,hsync", &priv->hsync)) +- priv->hsync = 0; +- if (of_property_read_u32(np, "maxim,vsync", &priv->vsync)) +- priv->vsync = 1; +- if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay)) +- priv->poc_delay = 50; +- if (of_property_read_u32(np, "maxim,bws", &priv->bws)) +- priv->bws = 0; +- if (of_property_read_u32(np, "maxim,dbl", &priv->dbl)) +- priv->dbl = 1; +- if (of_property_read_u32(np, "maxim,dt", &priv->dt)) +- priv->dt = 3; +- if (of_property_read_u32(np, "maxim,hsgen", &priv->hsgen)) +- priv->hsgen = 0; +- if (of_property_read_u32(np, "maxim,pclk", &priv->pclk)) +- priv->pclk = pclk; +- +- /* module params override dts */ +- if (him) +- priv->him = him; +- if (hsync) +- priv->hsync = hsync; +- if (!vsync) +- priv->vsync = vsync; +- if (gpio_resetb) +- priv->gpio_resetb = gpio_resetb; +- if (active_low_resetb) +- priv->active_low_resetb = active_low_resetb; +- if (timeout_n) +- priv->timeout = timeout_n; +- if (poc_delay) +- priv->poc_delay = poc_delay; +- if (bws) +- priv->bws = bws; +- if (!dbl) +- priv->dbl = dbl; +- if (dt != 3) +- priv->dt = dt; +- if (hsgen) +- priv->hsgen = hsgen; +- if (pclk != 100) +- priv->pclk = pclk; +- +- endpoint = of_graph_get_next_endpoint(np, endpoint); +- if (endpoint) { +- if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr)) { +- of_node_put(endpoint); +- dev_err(&client->dev, "max9271-addr not set\n"); +- return -EINVAL; +- } +- +- priv->sd_fwnode = of_fwnode_handle(endpoint); +- } +- +- of_node_put(endpoint); +- return 0; +-} +- +-static void max9288_setup_remote_endpoint(struct i2c_client *client) +-{ +- struct max9288_priv *priv = i2c_get_clientdata(client); +- struct device_node *np = client->dev.of_node; +- struct device_node *endpoint = NULL, *rendpoint = NULL; +- int i; +- struct property *csi_rate_prop, *dvp_order_prop; +- +- for (i = 0; ; i++) { +- endpoint = of_graph_get_next_endpoint(np, endpoint); +- if (!endpoint) +- break; +- +- rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); +- if (!rendpoint) +- continue; +- +- csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL); +- if (csi_rate_prop) { +- /* CSI2_RATE = PCLK*bpp/lanes */ +- priv->csi_rate = cpu_to_be32(priv->pclk * dt2bpp[priv->dt] / priv->lanes); +- csi_rate_prop->value = &priv->csi_rate; +- of_update_property(rendpoint, csi_rate_prop); +- } +- +- dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL); +- if (dvp_order_prop) +- of_update_property(rendpoint, dvp_order_prop); +- } +- +- of_node_put(endpoint); +-} +- +-static int max9288_probe(struct i2c_client *client, +- const struct i2c_device_id *did) +-{ +- struct max9288_priv *priv; +- int err; +- +- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- i2c_set_clientdata(client, priv); +- priv->des_addr = client->addr; +- priv->client = client; +- +- err = max9288_parse_dt(client); +- if (err) +- goto out; +- +- err = max9288_initialize(client); +- if (err < 0) +- goto out; +- +- max9288_setup_remote_endpoint(client); +- +- v4l2_subdev_init(&priv->sd, &max9288_subdev_ops); +- priv->sd.owner = client->dev.driver->owner; +- priv->sd.dev = &client->dev; +- v4l2_set_subdevdata(&priv->sd, priv); +- priv->sd.fwnode = priv->sd_fwnode; +- +- snprintf(priv->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x", +- client->dev.driver->name, i2c_adapter_id(client->adapter), +- client->addr); +- +- err = v4l2_async_register_subdev(&priv->sd); +- if (err < 0) +- goto out; +-out: +- return err; +-} +- +-static int max9288_remove(struct i2c_client *client) +-{ +- struct max9288_priv *priv = i2c_get_clientdata(client); +- +- v4l2_async_unregister_subdev(&priv->sd); +- v4l2_device_unregister_subdev(&priv->sd); +- +- return 0; +-} +- +-static const struct of_device_id max9288_dt_ids[] = { +- { .compatible = "maxim,max9288" }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, max9288_dt_ids); +- +-static const struct i2c_device_id max9288_id[] = { +- { "max9288", 0 }, +- { } +-}; +-MODULE_DEVICE_TABLE(i2c, max9288_id); +- +-static struct i2c_driver max9288_i2c_driver = { +- .driver = { +- .name = "max9288", +- .of_match_table = of_match_ptr(max9288_dt_ids), +- }, +- .probe = max9288_probe, +- .remove = max9288_remove, +- .id_table = max9288_id, +-}; +- +-module_i2c_driver(max9288_i2c_driver); +- +-MODULE_DESCRIPTION("GMSL driver for MAX9288"); +-MODULE_AUTHOR("Vladimir Barinov"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c +deleted file mode 100644 +index 340e61e..0000000 +--- a/drivers/media/i2c/soc_camera/ti9x4.c ++++ /dev/null +@@ -1,745 +0,0 @@ +- /* +- * TI DS90UB954/960/964 FPDLinkIII driver +- * +- * Copyright (C) 2017-2018 Cogent Embedded, Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- */ +- +-#include <linux/delay.h> +-#include <linux/i2c.h> +-#include <linux/module.h> +-#include <linux/notifier.h> +-#include <linux/of_gpio.h> +-#include <linux/of_graph.h> +-#include <linux/reboot.h> +-#include <linux/videodev2.h> +- +-#include <media/v4l2-common.h> +-#include <media/v4l2-clk.h> +-#include <media/v4l2-device.h> +-#include <media/v4l2-subdev.h> +- +-#include "ti9x4.h" +- +-struct ti9x4_priv { +- struct v4l2_subdev sd[4]; +- struct fwnode_handle *sd_fwnode[4]; +- int des_addr; +- int links; +- int lanes; +- int csi_rate; +- const char *forwarding_mode; +- int fs_time; +- int fps_numerator; +- int fps_denominator; +- int is_coax; +- int dvp_bus; +- int dvp_lsb; +- int hsync; +- int vsync; +- int poc_delay; +- atomic_t use_count; +- struct i2c_client *client; +- int ti9x3_addr_map[4]; +- char chip_id[6]; +- int ser_id; +- int vc_map; +- int csi_map; +- int gpio[4]; +- struct gpio_desc *pwen; /* chip power en */ +- struct gpio_desc *poc_gpio[4]; /* PoC power supply */ +- struct v4l2_clk *ref_clk; /* ref clock */ +- struct notifier_block reboot_notifier; +-}; +- +-static int ser_id; +-module_param(ser_id, int, 0644); +-MODULE_PARM_DESC(ser_id, " Serializer ID (default: TI913)"); +- +-static int is_stp; +-module_param(is_stp, int, 0644); +-MODULE_PARM_DESC(is_stp, " STP cable (default: Coax cable)"); +- +-static int dvp_bus = 8; +-module_param(dvp_bus, int, 0644); +-MODULE_PARM_DESC(dvp_bus, " DVP/CSI over FPDLink (default: DVP 8-bit)"); +- +-static int dvp_lsb = 0; +-module_param(dvp_lsb, int, 0644); +-MODULE_PARM_DESC(dvp_lsb, " DVP 8-bit LSB/MSB selection (default: DVP 8-bit MSB)"); +- +-static int hsync; +-module_param(hsync, int, 0644); +-MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); +- +-static int vsync = 1; +-module_param(vsync, int, 0644); +-MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); +- +-static int poc_delay; +-module_param(poc_delay, int, 0644); +-MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms)"); +- +-static int vc_map = 0x3210; +-module_param(vc_map, int, 0644); +-MODULE_PARM_DESC(vc_map, " CSI VC MAP (default: 0xe4 - linear map VCx=LINKx)"); +- +-static int csi_map = 0; +-module_param(csi_map, int, 0644); +-MODULE_PARM_DESC(csi_map, " CSI TX MAP (default: 0 - forwarding of all links to CSI0)"); +- +-static int gpio0 = 0, gpio1 = 0, gpio2 = 0, gpio3 = 0; +-module_param(gpio0, int, 0644); +-MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 low level)"); +-module_param(gpio1, int, 0644); +-MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 low level)"); +-module_param(gpio2, int, 0644); +-MODULE_PARM_DESC(gpio2, " GPIO2 function select (default: GPIO2 low level)"); +-module_param(gpio3, int, 0644); +-MODULE_PARM_DESC(gpio3, " GPIO3 function select (default: GPIO3 low level)"); +- +-#ifdef TI954_SILICON_ERRATA +-static int indirect_write(struct i2c_client *client, unsigned int page, u8 reg, u8 val) +-{ +- if (page > 7) +- return -EINVAL; +- +- reg8_write(client, 0xb0, page << 2); +- reg8_write(client, 0xb1, reg); +- reg8_write(client, 0xb2, val); +- +- return 0; +-} +- +-static int indirect_read(struct i2c_client *client, unsigned int page, u8 reg, u8 *val) +-{ +- if (page > 7) +- return -EINVAL; +- +- reg8_write(client, 0xb0, page << 2); +- reg8_write(client, 0xb1, reg); +- reg8_read(client, 0xb2, val); +- +- return 0; +-} +-#endif +- +-static void ti9x4_read_chipid(struct i2c_client *client) +-{ +- struct ti9x4_priv *priv = i2c_get_clientdata(client); +- +- /* Chip ID */ +- reg8_read(client, 0xf1, &priv->chip_id[0]); +- reg8_read(client, 0xf2, &priv->chip_id[1]); +- reg8_read(client, 0xf3, &priv->chip_id[2]); +- reg8_read(client, 0xf4, &priv->chip_id[3]); +- reg8_read(client, 0xf5, &priv->chip_id[4]); +- priv->chip_id[5] = '\0'; +-} +- +-static void ti9x4_initial_setup(struct i2c_client *client) +-{ +- struct ti9x4_priv *priv = i2c_get_clientdata(client); +- +- /* Initial setup */ +- client->addr = priv->des_addr; /* TI9x4 I2C */ +- reg8_write(client, 0x0d, 0xb9); /* VDDIO 3.3V */ +- switch (priv->csi_rate) { +- case 1600: /* REFCLK = 25MHZ */ +- case 1500: /* REFCLK = 23MHZ */ +- case 1450: /* REFCLK = 22.5MHZ */ +- reg8_write(client, 0x1f, 0x00); /* CSI rate 1.5/1.6Gbps */ +- break; +- case 1200: /* REFCLK = 25MHZ */ +- case 1100: /* REFCLK = 22.5MHZ */ +- reg8_write(client, 0x1f, 0x01); /* CSI rate 1.1/1.2Gbps */ +- break; +- case 800: /* REFCLK = 25MHZ */ +- case 700: /* REFCLK = 22.5MHZ */ +- reg8_write(client, 0x1f, 0x02); /* CSI rate 700/800Mbps */ +- break; +- case 400: /* REFCLK = 25MHZ */ +- case 350: /* REFCLK = 22.5MHZ */ +- reg8_write(client, 0x1f, 0x03); /* CSI rate 350/400Mbps */ +- break; +- default: +- dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate); +- } +- +- switch (priv->csi_rate) { +- case 1600: +- case 1200: +- case 800: +- case 400: +- /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/FPS/12mks=1/30/12e-6=2777 -> HI=2, LO=2775 */ +- priv->fs_time = 2790; +- break; +- case 1500: +- /* FrameSync setup for REFCLK=23MHz, FPS=30: period_counts=1/FPS/13.043mks=1/30/13.043e-6=2556 -> HI=2, LO=2554 */ +- priv->fs_time = 2570; +- break; +- case 1450: +- case 1100: +- case 700: +- case 350: +- /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/FPS/13.333mks=1/30/13.333e-6=2500 -> HI=2, LO=2498 */ +- priv->fs_time = 2513; +- break; +- default: +- priv->fs_time = 0; +- dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate); +- } +- +- if (strcmp(priv->forwarding_mode, "round-robin") == 0) { +- reg8_write(client, 0x21, 0x03); /* Round Robin forwarding enable for CSI0/CSI1 */ +- } else if (strcmp(priv->forwarding_mode, "synchronized") == 0) { +- reg8_write(client, 0x21, 0x54); /* Basic Syncronized forwarding enable (FrameSync must be enabled!!) for CSI0/CSI1 */ +- } +- +- reg8_write(client, 0x32, 0x03); /* Select TX for CSI0/CSI1, RX for CSI0 */ +- reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4); /* disable CSI output, set CSI lane count, non-continuous CSI mode */ +- reg8_write(client, 0x20, 0xf0 | priv->csi_map); /* disable port forwarding */ +-#if 0 +- /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/2/FPS*25MHz =1/2/30*25Mhz =416666 -> FS_TIME=416666 */ +- /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/2/FPS*22.5Mhz=1/2/30*22.5Mhz=375000 -> FS_TIME=375000 */ +-// #define FS_TIME (priv->csi_rate == 1450 ? 376000 : 417666) +- #define FS_TIME (priv->csi_rate == 1450 ? 385000 : 428000) // FPS=29.2 (new vendor's firmware AWB restriction?) +- reg8_write(client, 0x1a, FS_TIME >> 16); /* FrameSync time 24bit */ +- reg8_write(client, 0x1b, (FS_TIME >> 8) & 0xff); +- reg8_write(client, 0x1c, FS_TIME & 0xff); +- reg8_write(client, 0x18, 0x43); /* Enable FrameSync, 50/50 mode, Frame clock from 25MHz */ +-#else +- reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */ +- reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */ +- reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */ +- reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */ +- reg8_write(client, 0x18, 0x00); /* Disable FrameSync - must be enabled after all cameras are set up */ +-#endif +-} +- +-static void ti9x4_fpdlink3_setup(struct i2c_client *client, int idx) +-{ +- struct ti9x4_priv *priv = i2c_get_clientdata(client); +- u8 port_config = 0x78; +- u8 port_config2 = 0; +- +- /* FPDLinkIII setup */ +- client->addr = priv->des_addr; /* TI9x4 I2C */ +- reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */ +- usleep_range(2000, 2500); /* wait 2ms */ +- +- switch (priv->ser_id) { +- case TI913_ID: +- reg8_write(client, 0x58, 0x58); /* Back channel: Freq=2.5Mbps */ +- break; +- case TI953_ID: +- reg8_write(client, 0x58, 0x5e); /* Back channel: Freq=50Mbps */ +- break; +- default: +- break; +- } +- +- reg8_write(client, 0x5c, priv->ti9x3_addr_map[idx] << 1); /* TI9X3 I2C addr */ +-// reg8_write(client, 0x5d, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */ +-// reg8_write(client, 0x65, (0x60 + idx) << 1); /* SENSOR I2C translated - must be set by sensor driver */ +- +- if (priv->is_coax) +- port_config |= 0x04; /* Coax */ +- else +- port_config |= 0x00; /* STP */ +- +- switch (priv->dvp_bus) { +- case 8: +- port_config2 |= (priv->dvp_lsb ? 0xC0 : 0x80); /* RAW10 as 8-bit prosessing using LSB/MSB bits */ +- /* fall through */ +- case 10: +- port_config |= 0x03; /* DVP over FPDLink (TI913 compatible) RAW10/RAW8 */ +- break; +- case 12: +- port_config |= 0x02; /* DVP over FPDLink (TI913 compatible) RAW12 */ +- break; +- default: +- port_config |= 0x00; /* CSI over FPDLink (TI953 compatible) */ +- } +- +- if (priv->vsync) +- port_config2 |= 0x01; /* VSYNC acive low */ +- if (priv->hsync) +- port_config2 |= 0x02; /* HSYNC acive low */ +- +- reg8_write(client, 0x6d, port_config); +- reg8_write(client, 0x7c, port_config2); +- reg8_write(client, 0x70, ((priv->vc_map >> (idx * 4)) << 6) | 0x1e); /* CSI data type: yuv422 8-bit, assign VC */ +- reg8_write(client, 0x71, ((priv->vc_map >> (idx * 4)) << 6) | 0x2c); /* CSI data type: RAW12, assign VC */ +- reg8_write(client, 0xbc, 0x00); /* Setup minimal time between FV and LV to 3 PCLKs */ +- reg8_write(client, 0x72, priv->vc_map >> (idx * 4)); /* CSI VC MAP */ +-} +- +-static int ti9x4_initialize(struct i2c_client *client) +-{ +- struct ti9x4_priv *priv = i2c_get_clientdata(client); +- int idx, timeout; +- u8 port_sts1[4] = {0, 0, 0, 0}, port_sts2[4] = {0, 0, 0, 0}; +- +- dev_info(&client->dev, "LINKs=%d, LANES=%d, FORWARDING=%s, CABLE=%s, ID=%s\n", +- priv->links, priv->lanes, priv->forwarding_mode, priv->is_coax ? "coax" : "stp", priv->chip_id); +- +- ti9x4_initial_setup(client); +- +- for (idx = 0; idx < priv->links; idx++) { +- if (!IS_ERR(priv->poc_gpio[idx])) { +- gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */ +- mdelay(priv->poc_delay); +- } +- +- ti9x4_fpdlink3_setup(client, idx); +- } +- +- client->addr = priv->des_addr; +- +- /* check lock status */ +- for (timeout = 500 / priv->links; timeout > 0; timeout--) { +- for (idx = 0; idx < priv->links; idx++) { +- if ((port_sts1[idx] & 0x1) && (port_sts2[idx] & 0x4)) +- continue; +- +- reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */ +- usleep_range(1000, 1500); /* wait 1ms */ +- reg8_read(client, 0x4d, &port_sts1[idx]); /* Lock status */ +- reg8_read(client, 0x4e, &port_sts2[idx]); /* Freq stable */ +- } +- } +- +- if (!timeout) +- dev_info(&client->dev, "Receiver lock status [%d,%d,%d,%d]\n", +- (port_sts1[0] & 0x1) && (port_sts2[0] & 0x4), +- (port_sts1[1] & 0x1) && (port_sts2[1] & 0x4), +- (port_sts1[2] & 0x1) && (port_sts2[2] & 0x4), +- (port_sts1[3] & 0x1) && (port_sts2[3] & 0x4)); +- +- if (priv->poc_delay) +- mdelay(100); +- +- for (idx = 0; idx < priv->links; idx++) { +- reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */ +- usleep_range(1000, 1500); /* wait 1ms */ +- +- /* +- * Enable only FSIN for remote gpio, all permanent states (0 or 1) setup on serializer side: +- * this avoids intermittent remote gpio noise (f.e. reset or spuriouse fsin) caused by +- * unstable/bad link, hence unstable backchannel +- */ +- client->addr = priv->ti9x3_addr_map[idx]; /* TI9X3 I2C addr */ +- switch (priv->ser_id) { +- case TI913_ID: +- reg8_write(client, 0x0d, 0x55); /* Enable remote GPIO0/1 */ +- reg8_write(client, 0x11, 0x10); /* I2C high pulse width */ +- reg8_write(client, 0x12, 0x10); /* I2C low pulse width */ +- break; +- case TI953_ID: +- reg8_write(client, 0x0d, (priv->gpio[0] & 0x1) << 0 | +- (priv->gpio[1] & 0x1) << 1 | +- (priv->gpio[2] & 0x1) << 2 | +- (priv->gpio[3] & 0x1) << 3 | +- (priv->gpio[0] & 0x2) << 3 | +- (priv->gpio[1] & 0x2) << 4 | +- (priv->gpio[2] & 0x2) << 5 | +- (priv->gpio[3] & 0x2) << 6); /* Enable FSIN remote GPIOs and set local constant gpios */ +- reg8_write(client, 0x0e, (!!priv->gpio[0] << 4) | +- (!!priv->gpio[1] << 5) | +- (!!priv->gpio[2] << 6) | +- (!!priv->gpio[3] << 7)); /* Enable serializer GPIOs only for output */ +- reg8_write(client, 0x0b, 0x10); /* I2C high pulse width */ +- reg8_write(client, 0x0c, 0x10); /* I2C low pulse width */ +- break; +- } +- client->addr = priv->des_addr; +- +- reg8_write(client, 0x6e, 0x88 | (priv->gpio[1] << 4) | priv->gpio[0]); /* Remote GPIO1/GPIO0 setup */ +- reg8_write(client, 0x6f, 0x88 | (priv->gpio[3] << 4) | priv->gpio[2]); /* Remote GPIO3/GPIO2 setup */ +- } +- +- return 0; +-} +- +-#ifdef CONFIG_VIDEO_ADV_DEBUG +-static int ti9x4_g_register(struct v4l2_subdev *sd, +- struct v4l2_dbg_register *reg) +-{ +- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- int ret; +- u8 val = 0; +- +- ret = reg8_read(client, (u8)reg->reg, &val); +- if (ret < 0) +- return ret; +- +- reg->val = val; +- reg->size = sizeof(u8); +- +- return 0; +-} +- +-static int ti9x4_s_register(struct v4l2_subdev *sd, +- const struct v4l2_dbg_register *reg) +-{ +- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- +- return reg8_write(client, (u8)reg->reg, (u8)reg->val); +-} +-#endif +- +-static int ti9x4_s_power(struct v4l2_subdev *sd, int on) +-{ +- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- +- if (on) { +- if (atomic_inc_return(&priv->use_count) == 1) +- reg8_write(client, 0x20, 0x00 | priv->csi_map); /* enable port forwarding to CSI */ +- } else { +- if (atomic_dec_return(&priv->use_count) == 0) +- reg8_write(client, 0x20, 0xf0 | priv->csi_map); /* disable port forwarding to CSI */ +- } +- +- return 0; +-} +- +-static int ti9x4_registered_async(struct v4l2_subdev *sd) +-{ +- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- +- reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4 | 0x1); /* enable CSI output, set CSI lane count, non-continuous CSI mode */ +- reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */ +-// reg8_write(client, 0x18, 0x80); /* Enable FrameSync, Frame clock is external */ +- +- return 0; +-} +- +-static int ti9x4_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf) +-{ +- struct ti9x4_priv *priv = container_of(nb, struct ti9x4_priv, reboot_notifier); +- int idx; +- +- for (idx = 0; idx < priv->links; idx++) { +- if (!IS_ERR(priv->poc_gpio[idx])) +- gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ +- } +- +- return NOTIFY_OK; +-} +- +-static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = { +-#ifdef CONFIG_VIDEO_ADV_DEBUG +- .g_register = ti9x4_g_register, +- .s_register = ti9x4_s_register, +-#endif +- .s_power = ti9x4_s_power, +- .registered_async = ti9x4_registered_async, +-}; +- +-static int ti9x4_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +-{ +- return 0; +-} +- +-static int ti9x4_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +-{ +- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- struct v4l2_captureparm *cp = &parms->parm.capture; +- +- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +- return -EINVAL; +- if (cp->extendedmode != 0) +- return -EINVAL; +- +- if (priv->fps_denominator != cp->timeperframe.denominator || +- priv->fps_numerator != cp->timeperframe.numerator) { +- int f_time; +- +- f_time = priv->fs_time * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; +- reg8_write(client, 0x1b, f_time >> 8); /* FrameSync low time MSB */ +- reg8_write(client, 0x1c, f_time & 0xff); /* FrameSync low time LSB */ +- +- priv->fps_denominator = cp->timeperframe.denominator; +- priv->fps_numerator = cp->timeperframe.numerator; +- } +- +- return 0; +-} +- +-static struct v4l2_subdev_video_ops ti9x4_video_ops = { +- .g_parm = ti9x4_g_parm, +- .s_parm = ti9x4_s_parm, +-}; +- +-static struct v4l2_subdev_ops ti9x4_subdev_ops = { +- .core = &ti9x4_subdev_core_ops, +- .video = &ti9x4_video_ops, +-}; +- +-static int ti9x4_parse_dt(struct i2c_client *client) +-{ +- struct ti9x4_priv *priv = i2c_get_clientdata(client); +- struct device_node *np = client->dev.of_node; +- struct device_node *endpoint = NULL, *rendpoint = NULL; +- struct property *prop; +- int i; +- int sensor_delay; +- char forwarding_mode_default[20] = "round-robin"; /* round-robin, synchronized */ +- struct property *csi_rate_prop, *dvp_order_prop; +- u8 val = 0; +- char name[10]; +- +- if (of_property_read_u32(np, "ti,links", &priv->links)) +- priv->links = 4; +- +- if (of_property_read_u32(np, "ti,lanes", &priv->lanes)) +- priv->lanes = 4; +- +- priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk"); +- if (!IS_ERR(priv->ref_clk)) { +- dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000); +- v4l2_clk_enable(priv->ref_clk); +- } +- +- priv->pwen = devm_gpiod_get(&client->dev, NULL, GPIOF_OUT_INIT_HIGH); +- if (!IS_ERR(priv->pwen)) { +- mdelay(5); +- gpiod_direction_output(priv->pwen, 0); +- mdelay(5); +- } +- +- for (i = 0; i < 4; i++) { +- sprintf(name, "POC%d", i); +- priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(name, GFP_KERNEL), 0); +- } +- +- reg8_read(client, 0x00, &val); /* read TI9x4 I2C address */ +- if (val != (priv->des_addr << 1)) { +- prop = of_find_property(np, "reg", NULL); +- if (prop) +- of_remove_property(np, prop); +- return -ENODEV; +- } +- +- ti9x4_read_chipid(client); +- +-#ifdef TI954_SILICON_ERRATA +- indirect_write(client, 7, 0x15, 0x30); +- if (pwen > 0) +- gpio_set_value(pwen, 1); +- usleep_range(5000, 5500); /* wait 5ms */ +- indirect_write(client, 7, 0x15, 0); +-#endif +- if (!of_property_read_u32(np, "ti,sensor_delay", &sensor_delay)) +- mdelay(sensor_delay); +- if (of_property_read_string(np, "ti,forwarding-mode", &priv->forwarding_mode)) +- priv->forwarding_mode = forwarding_mode_default; +- if (of_property_read_bool(np, "ti,stp")) +- priv->is_coax = 0; +- else +- priv->is_coax = 1; +- if (of_property_read_u32(np, "ti,dvp_bus", &priv->dvp_bus)) +- priv->dvp_bus = 8; +- if (of_property_read_bool(np, "ti,dvp_lsb")) +- priv->dvp_lsb = 1; +- else +- priv->dvp_lsb = 0; +- if (of_property_read_u32(np, "ti,hsync", &priv->hsync)) +- priv->hsync = 0; +- if (of_property_read_u32(np, "ti,vsync", &priv->vsync)) +- priv->vsync = 1; +- if (of_property_read_u32(np, "ti,ser_id", &priv->ser_id)) +- priv->ser_id = TI913_ID; +- if (of_property_read_u32(np, "ti,poc-delay", &priv->poc_delay)) +- priv->poc_delay = 10; +- if (of_property_read_u32(np, "ti,vc-map", &priv->vc_map)) +- priv->vc_map = 0x3210; +- for (i = 0; i < 4; i++) { +- sprintf(name, "ti,gpio%d", i); +- if (of_property_read_u32(np, name, &priv->gpio[i])) +- priv->gpio[i] = 0; +- } +- +- /* +- * CSI forwarding of all links is to CSI0 by default. +- * Decide if any link will be forwarded to CSI1 instead CSI0 +- */ +- prop = of_find_property(np, "ti,csi1-links", NULL); +- if (prop) { +- const __be32 *link = NULL; +- u32 v; +- +- for (i = 0; i < 4; i++) { +- link = of_prop_next_u32(prop, link, &v); +- if (!link) +- break; +- priv->csi_map |= BIT(v); +- } +- } else { +- priv->csi_map = 0; +- } +- +- /* module params override dts */ +- if (is_stp) +- priv->is_coax = 0; +- if (dvp_bus != 8) +- priv->dvp_bus = dvp_bus; +- if (dvp_lsb) +- priv->dvp_lsb = dvp_lsb; +- if (hsync) +- priv->hsync = hsync; +- if (!vsync) +- priv->vsync = vsync; +- if (ser_id) +- priv->ser_id = ser_id; +- if (poc_delay) +- priv->poc_delay = poc_delay; +- if (vc_map != 0x3210) +- priv->vc_map = vc_map; +- if (csi_map) +- priv->csi_map = csi_map; +- if (gpio0) +- priv->gpio[0] = gpio0; +- if (gpio1) +- priv->gpio[1] = gpio1; +- if (gpio2) +- priv->gpio[2] = gpio2; +- if (gpio3) +- priv->gpio[3] = gpio3; +- +- for (i = 0; ; i++) { +- endpoint = of_graph_get_next_endpoint(np, endpoint); +- if (!endpoint) +- break; +- +- if (i < priv->links) { +- if (of_property_read_u32(endpoint, "ti9x3-addr", &priv->ti9x3_addr_map[i])) { +- of_node_put(endpoint); +- dev_err(&client->dev, "ti9x3-addr not set\n"); +- return -EINVAL; +- } +- priv->sd_fwnode[i] = of_fwnode_handle(endpoint); +- } +- +- rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); +- if (!rendpoint) +- continue; +- +- csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL); +- if (csi_rate_prop) { +- of_property_read_u32(endpoint, "csi-rate", &priv->csi_rate); +- of_update_property(rendpoint, csi_rate_prop); +- } +- +- dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL); +- if (dvp_order_prop) +- of_update_property(rendpoint, dvp_order_prop); +- } +- +- of_node_put(endpoint); +- return 0; +-} +- +-static int ti9x4_probe(struct i2c_client *client, +- const struct i2c_device_id *did) +-{ +- struct ti9x4_priv *priv; +- int err, i; +- +- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- i2c_set_clientdata(client, priv); +- priv->des_addr = client->addr; +- priv->client = client; +- atomic_set(&priv->use_count, 0); +- priv->fps_numerator = 1; +- priv->fps_denominator = 30; +- +- err = ti9x4_parse_dt(client); +- if (err) +- goto out; +- +- err = ti9x4_initialize(client); +- if (err < 0) +- goto out; +- +- for (i = 0; i < priv->links; i++) { +- v4l2_subdev_init(&priv->sd[i], &ti9x4_subdev_ops); +- priv->sd[i].owner = client->dev.driver->owner; +- priv->sd[i].dev = &client->dev; +- priv->sd[i].grp_id = i; +- v4l2_set_subdevdata(&priv->sd[i], priv); +- priv->sd[i].fwnode = priv->sd_fwnode[i]; +- +- snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x", +- client->dev.driver->name, i2c_adapter_id(client->adapter), +- client->addr); +- +- err = v4l2_async_register_subdev(&priv->sd[i]); +- if (err < 0) +- goto out; +- } +- +- priv->reboot_notifier.notifier_call = ti9x4_reboot_notifier; +- err = register_reboot_notifier(&priv->reboot_notifier); +- if (err) +- dev_err(&client->dev, "failed to register reboot notifier\n"); +- +-out: +- return err; +-} +- +-static int ti9x4_remove(struct i2c_client *client) +-{ +- struct ti9x4_priv *priv = i2c_get_clientdata(client); +- int i; +- +- unregister_reboot_notifier(&priv->reboot_notifier); +- +- for (i = 0; i < priv->links; i++) { +- v4l2_async_unregister_subdev(&priv->sd[i]); +- v4l2_device_unregister_subdev(&priv->sd[i]); +- } +- +- return 0; +-} +- +-static const struct of_device_id ti9x4_dt_ids[] = { +- { .compatible = "ti,ti9x4" }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, ti9x4_dt_ids); +- +-static const struct i2c_device_id ti9x4_id[] = { +- { "ti9x4", 0 }, +- { } +-}; +-MODULE_DEVICE_TABLE(i2c, ti9x4_id); +- +-static struct i2c_driver ti9x4_i2c_driver = { +- .driver = { +- .name = "ti9x4", +- .of_match_table = of_match_ptr(ti9x4_dt_ids), +- }, +- .probe = ti9x4_probe, +- .remove = ti9x4_remove, +- .id_table = ti9x4_id, +-}; +- +-module_i2c_driver(ti9x4_i2c_driver); +- +-MODULE_DESCRIPTION("FPDLinkIII driver for DS90UB9x4"); +-MODULE_AUTHOR("Vladimir Barinov"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/ti9x4.h b/drivers/media/i2c/soc_camera/ti9x4.h +deleted file mode 100644 +index 6825f8a..0000000 +--- a/drivers/media/i2c/soc_camera/ti9x4.h ++++ /dev/null +@@ -1,204 +0,0 @@ +-/* +- * TI FPDLinkIII driver include file +- * +- * Copyright (C) 2017 Cogent Embedded, Inc. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- */ +- +-#ifndef _TI9X4_H +-#define _TI9X4_H +- +-//#define DEBUG +-#ifdef DEBUG +-#undef dev_dbg +-#define dev_dbg dev_info +-#endif +- +-#define MAXIM_NUM_RETRIES 1 /* number of read/write retries */ +-#define TI913_ID 0x58 +-#define TI953_ID 0x30 /* or starapped to 0x32 */ +-#define TI9X4_ID 0x00 /* strapped */ +-#define BROADCAST 0x6f +- +-static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val) +-{ +- int ret, retries; +- +- for (retries = MAXIM_NUM_RETRIES; retries; retries--) { +- ret = i2c_smbus_read_byte_data(client, reg); +- if (!(ret < 0)) +- break; +- } +- +- if (ret < 0) { +- dev_dbg(&client->dev, +- "read fail: chip 0x%x register 0x%x: %d\n", +- client->addr, reg, ret); +- } else { +- *val = ret; +- } +- +- return ret < 0 ? ret : 0; +-} +- +-static inline int reg8_write(struct i2c_client *client, u8 reg, u8 val) +-{ +- int ret, retries; +- +- for (retries = MAXIM_NUM_RETRIES; retries; retries--) { +- ret = i2c_smbus_write_byte_data(client, reg, val); +- if (!(ret < 0)) +- break; +- } +- +- if (ret < 0) { +- dev_dbg(&client->dev, +- "write fail: chip 0x%x register 0x%x: %d\n", +- client->addr, reg, ret); +- } +- +- return ret < 0 ? ret : 0; +-} +- +-static inline int reg16_read(struct i2c_client *client, u16 reg, u8 *val) +-{ +- int ret, retries; +- u8 buf[2] = {reg >> 8, reg & 0xff}; +- +- for (retries = MAXIM_NUM_RETRIES; retries; retries--) { +- ret = i2c_master_send(client, buf, 2); +- if (ret == 2) { +- ret = i2c_master_recv(client, buf, 1); +- if (ret == 1) +- break; +- } +- } +- +- if (ret < 0) { +- dev_dbg(&client->dev, +- "read fail: chip 0x%x register 0x%x: %d\n", +- client->addr, reg, ret); +- } else { +- *val = buf[0]; +- } +- +- return ret < 0 ? ret : 0; +-} +- +-static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val) +-{ +- int ret, retries; +- u8 buf[3] = {reg >> 8, reg & 0xff, val}; +- +- for (retries = MAXIM_NUM_RETRIES; retries; retries--) { +- ret = i2c_master_send(client, buf, 3); +- if (ret == 3) +- break; +- } +- +- if (ret < 0) { +- dev_dbg(&client->dev, +- "write fail: chip 0x%x register 0x%x: %d\n", +- client->addr, reg, ret); +- } +- +- return ret < 0 ? ret : 0; +-} +- +-static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n) +-{ +- int ret, retries; +- u8 buf[2] = {reg >> 8, reg & 0xff}; +- +- for (retries = MAXIM_NUM_RETRIES; retries; retries--) { +- ret = i2c_master_send(client, buf, 2); +- if (ret == 2) { +- ret = i2c_master_recv(client, val, n); +- if (ret == n) +- break; +- } +- } +- +- if (ret < 0) { +- dev_dbg(&client->dev, +- "read fail: chip 0x%x registers 0x%x-0x%x: %d\n", +- client->addr, reg, reg + n, ret); +- } +- +- return ret < 0 ? ret : 0; +-} +- +-static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n) +-{ +- int ret, retries; +- u8 buf[2 + n]; +- +- buf[0] = reg >> 8; +- buf[1] = reg & 0xff; +- memcpy(&buf[2], val, n); +- +- for (retries = MAXIM_NUM_RETRIES; retries; retries--) { +- ret = i2c_master_send(client, buf, 2 + n); +- if (ret == 2 + n) +- break; +- } +- +- if (ret < 0) { +- dev_dbg(&client->dev, +- "write fail: chip 0x%x register 0x%x-0x%x: %d\n", +- client->addr, reg, reg + n, ret); +- } +- +- return ret < 0 ? ret : 0; +-} +- +-static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val) +-{ +- int ret, retries; +- u8 buf[2] = {reg >> 8, reg & 0xff}; +- +- for (retries = MAXIM_NUM_RETRIES; retries; retries--) { +- ret = i2c_master_send(client, buf, 2); +- if (ret == 2) { +- ret = i2c_master_recv(client, buf, 2); +- if (ret == 2) +- break; +- } +- } +- +- if (ret < 0) { +- dev_err(&client->dev, +- "read fail: chip 0x%x register 0x%x: %d\n", +- client->addr, reg, ret); +- } else { +- *val = ((u16)buf[0] << 8) | buf[1]; +- } +- +- return ret < 0 ? ret : 0; +-} +- +-static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val) +-{ +- int ret, retries; +- u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff}; +- +- for (retries = MAXIM_NUM_RETRIES; retries; retries--) { +- ret = i2c_master_send(client, buf, 4); +- if (ret == 4) +- break; +- } +- +- if (ret < 0) { +- dev_err(&client->dev, +- "write fail: chip 0x%x register 0x%x: %d\n", +- client->addr, reg, ret); +- } +- +- return ret < 0 ? ret : 0; +-} +-#endif /* _TI9X4_H */ +- +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch new file mode 100644 index 00000000..a9535a92 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch @@ -0,0 +1,4855 @@ +From 845697c2d8a9620131759d72483923ed5612063d Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 10:52:23 +0300 +Subject: [PATCH] media: i2c: add max96712 and max9296 + +This adds GMSL2 drivers for MAX96712 and MAX9296 + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/gmsl/Kconfig | 14 + + drivers/media/i2c/soc_camera/gmsl/Makefile | 2 + + drivers/media/i2c/soc_camera/gmsl/common.h | 499 +++++++ + drivers/media/i2c/soc_camera/gmsl/max9295.h | 29 + + drivers/media/i2c/soc_camera/gmsl/max9296.c | 1423 ++++++++++++++++++++ + drivers/media/i2c/soc_camera/gmsl/max9296.h | 281 ++++ + drivers/media/i2c/soc_camera/gmsl/max9296_debug.h | 462 +++++++ + drivers/media/i2c/soc_camera/gmsl/max96712.c | 1423 ++++++++++++++++++++ + drivers/media/i2c/soc_camera/gmsl/max96712.h | 263 ++++ + drivers/media/i2c/soc_camera/gmsl/max96712_debug.h | 362 +++++ + 10 files changed, 4758 insertions(+) + create mode 100644 drivers/media/i2c/soc_camera/gmsl/common.h + create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9295.h + create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9296.c + create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9296.h + create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9296_debug.h + create mode 100644 drivers/media/i2c/soc_camera/gmsl/max96712.c + create mode 100644 drivers/media/i2c/soc_camera/gmsl/max96712.h + create mode 100644 drivers/media/i2c/soc_camera/gmsl/max96712_debug.h + +diff --git a/drivers/media/i2c/soc_camera/gmsl/Kconfig b/drivers/media/i2c/soc_camera/gmsl/Kconfig +index c7a33bf..4a7dd6c 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/Kconfig ++++ b/drivers/media/i2c/soc_camera/gmsl/Kconfig +@@ -9,3 +9,17 @@ config SOC_CAMERA_MAX9288 + depends on I2C + help + This is a MAXIM max9288 GMSL driver ++ ++config SOC_CAMERA_MAX9296 ++ tristate "max9296 GMSL2 support" ++ depends on I2C ++ select REGMAP_I2C ++ help ++ This is a MAXIM max9296 GMSL2 driver ++ ++config SOC_CAMERA_MAX96712 ++ tristate "max96712 GMSL2 support" ++ depends on I2C ++ select REGMAP_I2C ++ help ++ This is a MAXIM max96712 GMSL2 driver +diff --git a/drivers/media/i2c/soc_camera/gmsl/Makefile b/drivers/media/i2c/soc_camera/gmsl/Makefile +index 9925314..bda7a58 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/Makefile ++++ b/drivers/media/i2c/soc_camera/gmsl/Makefile +@@ -1,3 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_SOC_CAMERA_MAX9286) += max9286.o + obj-$(CONFIG_SOC_CAMERA_MAX9288) += max9288.o ++obj-$(CONFIG_SOC_CAMERA_MAX9296) += max9296.o ++obj-$(CONFIG_SOC_CAMERA_MAX96712) += max96712.o +diff --git a/drivers/media/i2c/soc_camera/gmsl/common.h b/drivers/media/i2c/soc_camera/gmsl/common.h +new file mode 100644 +index 0000000..98bb1c0 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/common.h +@@ -0,0 +1,499 @@ ++/* ++ * MAXIM GMSL common header ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/i2c-mux.h> ++#include "max9295.h" ++ ++#define MAX9271_ID 0x09 ++#define MAX9286_ID 0x40 ++#define MAX9288_ID 0x2A ++#define MAX9290_ID 0x2C ++#define MAX9295A_ID 0x91 ++#define MAX9295B_ID 0x93 ++#define MAX9296A_ID 0x94 ++#define MAX96705_ID 0x41 ++#define MAX96706_ID 0x4A ++#define MAX96707_ID 0x45 /* MAX96715: same but lack of HS pin */ ++#define MAX96708_ID 0x4C ++#define MAX96712_ID 0x20 ++ ++#define UB960_ID 0x00 /* strapped */ ++ ++#define BROADCAST 0x6f ++ ++#define REG8_NUM_RETRIES 1 /* number of read/write retries */ ++#define REG16_NUM_RETRIES 10 /* number of read/write retries */ ++ ++static inline char* chip_name(int id) ++{ ++ switch (id) { ++ case MAX9271_ID: ++ return "MAX9271"; ++ case MAX9286_ID: ++ return "MAX9286"; ++ case MAX9288_ID: ++ return "MAX9288"; ++ case MAX9290_ID: ++ return "MAX9290"; ++ case MAX9295A_ID: ++ return "MAX9295A"; ++ case MAX9295B_ID: ++ return "MAX9295B"; ++ case MAX9296A_ID: ++ return "MAX9296A"; ++ case MAX96705_ID: ++ return "MAX96705"; ++ case MAX96706_ID: ++ return "MAX96706"; ++ case MAX96707_ID: ++ return "MAX96707"; ++ case MAX96712_ID: ++ return "MAX96712"; ++ default: ++ return "serializer"; ++ } ++} ++ ++enum gmsl_mode { ++ MODE_GMSL1 = 1, ++ MODE_GMSL2, ++}; ++ ++#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */ ++#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */ ++#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */ ++#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */ ++#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ ++#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ ++#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ ++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ ++ ++#define MIPI_DT_GENERIC 0x10 ++#define MIPI_DT_GENERIC_1 0x11 ++#define MIPI_DT_EMB 0x12 ++#define MIPI_DT_YUV8 0x1e ++#define MIPI_DT_YUV10 0x1f ++#define MIPI_DT_RGB565 0x22 ++#define MIPI_DT_RGB666 0x23 ++#define MIPI_DT_RGB888 0x24 ++#define MIPI_DT_RAW8 0x2a ++#define MIPI_DT_RAW10 0x2b ++#define MIPI_DT_RAW12 0x2c ++#define MIPI_DT_RAW14 0x2d ++#define MIPI_DT_RAW16 0x2e ++#define MIPI_DT_RAW20 0x2f ++#define MIPI_DT_YUV12 0x30 ++ ++static inline int mipi_dt_to_bpp(unsigned int dt) ++{ ++ switch (dt) { ++ case 0x2a: ++ case 0x10 ... 0x12: ++ case 0x31 ... 0x37: ++ return 0x08; ++ case 0x2b: ++ return 0x0a; ++ case 0x2c: ++ return 0x0c; ++ case 0x0d: ++ return 0x0e; ++ case 0x22: ++ case 0x1e: ++ case 0x2e: ++ return 0x10; ++ case 0x23: ++ return 0x12; ++ case 0x1f: ++ case 0x2f: ++ return 0x14; ++ case 0x24: ++ case 0x30: ++ return 0x18; ++ default: ++ return 0x08; ++ } ++} ++ ++static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val) ++{ ++ int ret, retries; ++ ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_smbus_read_byte_data(client, reg); ++ if (!(ret < 0)) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++ *val = ret; ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg8_write(struct i2c_client *client, u8 reg, u8 val) ++{ ++ int ret, retries; ++ ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_smbus_write_byte_data(client, reg, val); ++ if (!(ret < 0)) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++#ifdef WRITE_VERIFY ++ u8 val2; ++ reg8_read(client, reg, &val2); ++ if (val != val2) ++ dev_err(&client->dev, ++ "write verify mismatch: chip 0x%x reg=0x%x " ++ "0x%x->0x%x\n", client->addr, reg, val, val2); ++#endif ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_read(struct i2c_client *client, u16 reg, u8 *val) ++{ ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; ++ ++ for (retries = REG16_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, buf, 1); ++ if (ret == 1) ++ break; ++ } ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++ *val = buf[0]; ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val) ++{ ++ int ret, retries; ++ u8 buf[3] = {reg >> 8, reg & 0xff, val}; ++ ++ for (retries = REG16_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 3); ++ if (ret == 3) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++#ifdef WRITE_VERIFY ++ u8 val2; ++ reg16_read(client, reg, &val2); ++ if (val != val2) ++ dev_err(&client->dev, ++ "write verify mismatch: chip 0x%x reg=0x%x " ++ "0x%x->0x%x\n", client->addr, reg, val, val2); ++#endif ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val) ++{ ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; ++ ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, buf, 2); ++ if (ret == 2) ++ break; ++ } ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++ *val = ((u16)buf[0] << 8) | buf[1]; ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val) ++{ ++ int ret, retries; ++ u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff}; ++ ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 4); ++ if (ret == 4) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n) ++{ ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; ++ ++ for (retries = REG16_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, val, n); ++ if (ret == n) ++ break; ++ } ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x registers 0x%x-0x%x: %d\n", ++ client->addr, reg, reg + n, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n) ++{ ++ int ret, retries; ++ u8 buf[2 + n]; ++ ++ buf[0] = reg >> 8; ++ buf[1] = reg & 0xff; ++ memcpy(&buf[2], val, n); ++ ++ for (retries = REG16_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2 + n); ++ if (ret == 2 + n) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x-0x%x: %d\n", ++ client->addr, reg, reg + n, ret); ++ } else { ++#ifdef WRITE_VERIFY ++ u8 val2[n]; ++ ret = reg16_read_n(client, reg, val2, n); ++ if (ret < 0) ++ return ret; ++ ++ if (memcmp(val, val2, n)) { ++ dev_err(&client->dev, ++ "write verify mismatch: chip 0x%x reg=0x%x-0x%x " ++ "'%*phN'->'%*phN'\n", client->addr, reg, reg + n, ++ n, val, n, val2); ++ ret = -EBADE; ++ } ++#endif ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg8_read_addr(struct i2c_client *client, int addr, u8 reg, u8 *val) ++{ ++ int ret, retries; ++ union i2c_smbus_data data; ++ ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_smbus_xfer(client->adapter, addr, client->flags, ++ I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data); ++ if (!(ret < 0)) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ addr, reg, ret); ++ } else { ++ *val = data.byte; ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static inline int reg8_write_addr(struct i2c_client *client, u8 addr, u8 reg, u8 val) ++{ ++ int ret, retries; ++ union i2c_smbus_data data; ++ ++ data.byte = val; ++ ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_smbus_xfer(client->adapter, addr, client->flags, ++ I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &data); ++ if (!(ret < 0)) ++ break; ++ } ++ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x value 0x%0x: %d\n", ++ addr, reg, val, ret); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++ ++static inline int reg16_write_addr(struct i2c_client *client, int chip, u16 reg, u8 val) ++{ ++ struct i2c_msg msg[1]; ++ u8 wbuf[3]; ++ int ret; ++ ++ msg->addr = chip; ++ msg->flags = 0; ++ msg->len = 3; ++ msg->buf = wbuf; ++ wbuf[0] = reg >> 8; ++ wbuf[1] = reg & 0xff; ++ wbuf[2] = val; ++ ++ ret = i2c_transfer(client->adapter, msg, 1); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "i2c fail: chip 0x%02x wr 0x%04x (0x%02x): %d\n", ++ chip, reg, val, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static inline int reg16_read_addr(struct i2c_client *client, int chip, u16 reg, int *val) ++{ ++ struct i2c_msg msg[2]; ++ u8 wbuf[2]; ++ u8 rbuf[1]; ++ int ret; ++ ++ msg[0].addr = chip; ++ msg[0].flags = 0; ++ msg[0].len = 2; ++ msg[0].buf = wbuf; ++ wbuf[0] = reg >> 8; ++ wbuf[1] = reg & 0xff; ++ ++ msg[1].addr = chip; ++ msg[1].flags = I2C_M_RD; ++ msg[1].len = 1; ++ msg[1].buf = rbuf; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "i2c fail: chip 0x%02x rd 0x%04x: %d\n", chip, reg, ret); ++ return ret; ++ } ++ ++ *val = rbuf[0]; ++ ++ return 0; ++} ++ ++#define __reg8_read(addr, reg, val) reg8_read_addr(priv->client, addr, reg, val) ++#define __reg8_write(addr, reg, val) reg8_write_addr(priv->client, addr, reg, val) ++#define __reg16_read(addr, reg, val) reg16_read_addr(priv->client, addr, reg, val) ++#define __reg16_write(addr, reg, val) reg16_write_addr(priv->client, addr, reg, val) ++ ++/* copy this struct from drivers/i2c/i2c-mux.c for getting muxc from adapter private data */ ++struct i2c_mux_priv { ++ struct i2c_adapter adap; ++ struct i2c_algorithm algo; ++ struct i2c_mux_core *muxc; ++ u32 chan_id; ++}; ++ ++static inline int get_des_id(struct i2c_client *client) ++{ ++ struct i2c_mux_priv *mux_priv = client->adapter->algo_data; ++ ++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max9286")) ++ return MAX9286_ID; ++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max9288")) ++ return MAX9288_ID; ++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max9296")) ++ return MAX9296A_ID; ++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max96706")) ++ return MAX96706_ID; ++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max96712")) ++ return MAX96712_ID; ++ if (!strcmp(mux_priv->muxc->dev->driver->name, "ti9x4")) ++ return UB960_ID; ++ ++ return -EINVAL; ++} ++ ++static inline int get_des_addr(struct i2c_client *client) ++{ ++ struct i2c_mux_priv *mux_priv = client->adapter->algo_data; ++ ++ return to_i2c_client(mux_priv->muxc->dev)->addr; ++} ++ ++static inline void setup_i2c_translator(struct i2c_client *client, int ser_addr, int sensor_addr, int gmsl_mode) ++{ ++ switch (get_des_id(client)) { ++ case MAX9286_ID: ++ case MAX9288_ID: ++ case MAX9296A_ID: ++ case MAX96706_ID: ++ case MAX96712_ID: ++ if (gmsl_mode == MODE_GMSL1) { ++ reg8_write_addr(client, ser_addr, 0x09, client->addr << 1); /* Sensor translated I2C address */ ++ reg8_write_addr(client, ser_addr, 0x0A, sensor_addr << 1); /* Sensor native I2C address */ ++ } ++ if (gmsl_mode == MODE_GMSL2) { ++ reg16_write_addr(client, ser_addr, MAX9295_I2C2, client->addr << 1); /* Sensor translated I2C address */ ++ reg16_write_addr(client, ser_addr, MAX9295_I2C3, sensor_addr << 1); /* Sensor native I2C address */ ++ } ++ break; ++ case UB960_ID: ++ reg8_write_addr(client, get_des_addr(client), 0x65, client->addr << 1); /* Sensor translated I2C address */ ++ reg8_write_addr(client, get_des_addr(client), 0x5d, sensor_addr << 1); /* Sensor native I2C address */ ++ break; ++ } ++ usleep_range(2000, 2500); ++} +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9295.h b/drivers/media/i2c/soc_camera/gmsl/max9295.h +new file mode 100644 +index 0000000..cf12d3c +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/max9295.h +@@ -0,0 +1,29 @@ ++/* ++ * MAXIM max9295 GMSL2 driver header ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#define MAX9295_REG2 0x02 ++#define MAX9295_REG7 0x07 ++#define MAX9295_CTRL0 0x10 ++#define MAX9295_I2C2 0x42 ++#define MAX9295_I2C3 0x43 ++#define MAX9295_I2C4 0x44 ++#define MAX9295_I2C5 0x45 ++#define MAX9295_I2C6 0x46 ++ ++#define MAX9295_CROSS(n) (0x1b0 + n) ++ ++#define MAX9295_GPIO_A(n) (0x2be + (3 * n)) ++#define MAX9295_GPIO_B(n) (0x2bf + (3 * n)) ++#define MAX9295_GPIO_C(n) (0x2c0 + (3 * n)) ++ ++#define MAX9295_VIDEO_TX_BASE(n) (0x100 + (0x8 * n)) ++#define MAX9295_VIDEO_TX0(n) (MAX9295_VIDEO_TX_BASE(n) + 0) ++#define MAX9295_VIDEO_TX1(n) (MAX9295_VIDEO_TX_BASE(n) + 1) +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.c b/drivers/media/i2c/soc_camera/gmsl/max9296.c +new file mode 100644 +index 0000000..a6d286f +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.c +@@ -0,0 +1,1423 @@ ++/* ++ * MAXIM max9296 GMSL2 driver ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/i2c.h> ++#include <linux/i2c-mux.h> ++#include <linux/module.h> ++#include <linux/regulator/consumer.h> ++#include <linux/notifier.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_gpio.h> ++#include <linux/of_graph.h> ++#include <linux/reboot.h> ++#include <linux/regmap.h> ++#include <linux/videodev2.h> ++ ++#include <media/v4l2-common.h> ++#include <media/v4l2-clk.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-subdev.h> ++ ++#include "common.h" ++#include "max9296.h" ++#include "max9296_debug.h" ++ ++static char mbus_default[10] = "dvp"; /* mipi, dvp */ ++ ++static int conf_link; ++module_param(conf_link, int, 0644); ++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); ++ ++static int poc_trig; ++module_param(poc_trig, int, 0644); ++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during RC setup. Useful on systems with dedicated PoC and unstable ser-des lock"); ++ ++static int him; ++module_param(him, int, 0644); ++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)"); ++ ++static int fsync_period; ++module_param(fsync_period, int, 0644); ++MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)"); ++ ++static int hsync; ++module_param(hsync, int, 0644); ++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); ++ ++static int vsync = 1; ++module_param(vsync, int, 0644); ++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); ++ ++static int gpio_resetb; ++module_param(gpio_resetb, int, 0644); ++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)"); ++ ++static int active_low_resetb; ++module_param(active_low_resetb, int, 0644); ++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)"); ++ ++static int timeout_n = 100; ++module_param(timeout_n, int, 0644); ++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)"); ++ ++static int poc_delay = 50; ++module_param(poc_delay, int, 0644); ++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)"); ++ ++static int bws; ++module_param(bws, int, 0644); ++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)"); ++ ++static int dbl = 1; ++module_param(dbl, int, 0644); ++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)"); ++ ++static int dt = MIPI_DT_YUV8; ++module_param(dt, int, 0644); ++MODULE_PARM_DESC(dt, " DataType (default: 0x1e - YUV8)"); ++ ++static unsigned long crossbar = 0xba9876543210; ++module_param(crossbar, ulong, 0644); ++MODULE_PARM_DESC(crossbar, " Serializer crossbar setup (default: ba9876543210 - reversed)"); ++ ++static int gmsl = MODE_GMSL2; ++module_param(gmsl, int, 0644); ++MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)"); ++ ++static char *mbus = "dvp"; ++module_param(mbus, charp, 0644); ++MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)"); ++ ++static int gpio0 = -1, gpio1 = -1, gpio7 = -1, gpio8 = -1; ++module_param(gpio0, int, 0644); ++MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 tri-state)"); ++module_param(gpio1, int, 0644); ++MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 tri-state)"); ++module_param(gpio7, int, 0644); ++MODULE_PARM_DESC(gpio7, " GPIO7 function select (default: GPIO7 tri-state)"); ++module_param(gpio8, int, 0644); ++MODULE_PARM_DESC(gpio8, " GPIO8 function select (default: GPIO8 tri-state)"); ++ ++static const struct regmap_config max9296_regmap[] = { ++ { ++ /* max9296 */ ++ .reg_bits = 16, ++ .val_bits = 8, ++ .max_register = 0x1f03, ++ }, { ++ /* max9271/max96705 */ ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = 0xff, ++ }, { ++ /* max9695 */ ++ .reg_bits = 16, ++ .val_bits = 8, ++ .max_register = 0x1b03, ++ } ++}; ++ ++static void max9296_write_remote_verify(struct max9296_priv *priv, int link_n, u8 reg, int val) ++{ ++ struct max9296_link *link = priv->link[link_n]; ++ int timeout; ++ ++ for (timeout = 0; timeout < 10; timeout++) { ++ int sts = 0; ++ u8 val2 = 0; ++ ++ ser_write(reg, val); ++ des_read(MAX9296_COMMON1, &sts); ++ /* check ACKed */ ++ if (sts & BIT(link_n)) { ++ ser_read(reg, &val2); ++ if (val2 == val) ++ break; ++ } ++ ++ usleep_range(1000, 1500); ++ } ++ ++ if (timeout >= 10) ++ dev_err(&priv->client->dev, "timeout remote write acked\n"); ++} ++ ++static void max9296_reset_oneshot(struct max9296_priv *priv) ++{ ++ int timeout; ++ int reg = 0; ++ ++ des_update_bits(MAX9296_CTRL0, BIT(5), BIT(5)); /* set reset one-shot */ ++ ++ /* wait for one-shot bit self-cleared */ ++ for (timeout = 0; timeout < 100; timeout++) { ++ des_read(MAX9296_CTRL0, ®); ++ if (!(reg & BIT(5))) ++ break; ++ ++ msleep(1); ++ } ++ ++ if (reg & BIT(5)) ++ dev_err(&priv->client->dev, "Failed reset oneshot\n"); ++} ++ ++/* ----------------------------------------------------------------------------- ++ * MIPI, mapping, routing ++ */ ++ ++static void max9296_pipe_override(struct max9296_priv *priv, unsigned int pipe, ++ unsigned int dt, unsigned int vc) ++{ ++ int bpp, bank; ++ ++ bpp = mipi_dt_to_bpp(dt); ++ bank = pipe / 4; ++ pipe %= 4; ++ ++ if (priv->dbl == 1) { ++ /* DBL=1 is MUX mode, DBL=0 is Normal mode */ ++ des_update_bits(MAX_BACKTOP27(bank), BIT(pipe + 4), BIT(pipe + 4)); /* enable MUX mode */ ++ bpp = bpp / 2; /* divide because of MUX=1 */ ++ } ++ ++ switch (pipe) { ++ case 0: ++ /* Pipe X: 0 or 4 */ ++ des_update_bits(MAX_BACKTOP12(bank), 0x1f << 3, bpp << 3); ++ des_update_bits(MAX_BACKTOP13(bank), 0x0f, vc); ++ des_update_bits(MAX_BACKTOP15(bank), 0x3f, dt); ++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(6), BIT(6)); /* enalbe s/w override */ ++ break; ++ case 1: ++ /* Pipe Y: 1 or 5 */ ++ des_update_bits(MAX_BACKTOP18(bank), 0x1f, bpp); ++ des_update_bits(MAX_BACKTOP13(bank), 0x0f << 4, vc << 4); ++ des_update_bits(MAX_BACKTOP16(bank), 0x0f, dt & 0x0f); ++ des_update_bits(MAX_BACKTOP15(bank), 0x03 << 6, (dt & 0x30) << 2); ++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(7), BIT(7)); /* enable s/w override */ ++ break; ++ case 2: ++ /* Pipe Z: 2 or 6 */ ++ des_update_bits(MAX_BACKTOP19(bank), 0x03, bpp & 0x03); ++ des_update_bits(MAX_BACKTOP18(bank), 0xe0, (bpp & 0x1c) << 3); ++ des_update_bits(MAX_BACKTOP14(bank), 0x0f, vc); ++ des_update_bits(MAX_BACKTOP17(bank), 0x03, dt & 0x03); ++ des_update_bits(MAX_BACKTOP16(bank), 0x0f << 4, (dt & 0x3c) << 2); ++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(6), BIT(6)); /* enable s/w override */ ++ break; ++ case 3: ++ /* Pipe U: 3 or 7 */ ++ des_update_bits(MAX_BACKTOP19(bank), 0xfc, bpp << 2); ++ des_update_bits(MAX_BACKTOP14(bank), 0x0f << 4, vc << 4); ++ des_update_bits(MAX_BACKTOP17(bank), 0x3f << 2, dt << 2); ++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(7), BIT(7)); /* enable s/w override */ ++ break; ++ } ++} ++ ++static void max9296_set_pipe_to_mipi_mapping(struct max9296_priv *priv, ++ unsigned int pipe, unsigned int map_n, ++ unsigned int in_dt, unsigned int in_vc, ++ unsigned int out_dt, unsigned int out_vc, unsigned int out_mipi) ++{ ++ int offset = 2 * (map_n % 4); ++ ++ des_write(MAX_MIPI_MAP_SRC(pipe, map_n), (in_vc << 6) | in_dt); ++ des_write(MAX_MIPI_MAP_DST(pipe, map_n), (out_vc << 6) | out_dt); ++ des_update_bits(MAX_MIPI_MAP_DST_PHY(pipe, map_n / 4), 0x03 << offset, out_mipi << offset); ++ des_update_bits(MAX_MIPI_TX11(pipe), BIT(map_n), BIT(map_n)); /* enable SRC_n to DST_n mapping */ ++} ++ ++static void max9296_mipi_setup(struct max9296_priv *priv) ++{ ++ des_write(MAX9296_REG2, 0); /* disable all pipes */ ++ ++ des_write(MAX_MIPI_PHY0, 0x04); /* MIPI Phy 2x4 mode */ ++ des_write(MAX_MIPI_PHY3, 0xe4); /* Lane map: straight */ ++ des_write(MAX_MIPI_PHY4, 0xe4); /* Lane map: straight */ ++ //des_write(MAX_MIPI_PHY5, 0x00); /* HS_prepare time, non-inverted polarity */ ++ //des_write(MAX_MIPI_PHY6, 0x00); ++ ++ des_write(MAX_MIPI_TX10(1), 0xc0); /* MIPI1: 4 lanes */ ++ des_write(MAX_MIPI_TX10(2), 0xc0); /* MIPI2: 4 lanes */ ++ ++ des_update_bits(MAX_BACKTOP22(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5)); /* MIPI rate */ ++ des_update_bits(MAX_BACKTOP25(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5)); ++ des_update_bits(MAX_BACKTOP28(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5)); ++ des_update_bits(MAX_BACKTOP31(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5)); ++ ++ des_update_bits(MAX_MIPI_PHY2, 0xf0, 0xf0); /* enable all MIPI PHYs */ ++} ++ ++/* ----------------------------------------------------------------------------- ++ * GMSL1 ++ */ ++ ++static int max9296_gmsl1_sensor_reset(struct max9296_priv *priv, int link_n, int reset_on) ++{ ++ struct max9296_link *link = priv->link[link_n]; ++ ++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) ++ return -EINVAL; ++ ++ /* sensor reset/unreset */ ++ ser_write(0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */ ++ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on)); ++ ser_write(0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ ++ ++ return 0; ++} ++ ++static void max9296_gmsl1_cc_enable(struct max9296_priv *priv, int link, int on) ++{ ++ des_update_bits(MAX_GMSL1_4(link), 0x03, on ? 0x03 : 0x00); ++ usleep_range(2000, 2500); ++} ++ ++static int max9296_gmsl1_get_link_lock(struct max9296_priv *priv, int link_n) ++{ ++ int val = 0; ++ ++ des_read(MAX_GMSL1_CB(link_n), &val); ++ ++ return !!(val & BIT(0)); ++} ++ ++static void max9296_gmsl1_link_crossbar_setup(struct max9296_priv *priv, int link, int dt) ++{ ++ /* Always decode reversed bus, since we always reverse on serializer (old imagers need this) */ ++ switch (dt) { ++ case MIPI_DT_YUV8: ++ des_write(MAX_CROSS(link, 0), 7); ++ des_write(MAX_CROSS(link, 1), 6); ++ des_write(MAX_CROSS(link, 2), 5); ++ des_write(MAX_CROSS(link, 3), 4); ++ des_write(MAX_CROSS(link, 4), 3); ++ des_write(MAX_CROSS(link, 5), 2); ++ des_write(MAX_CROSS(link, 6), 1); ++ des_write(MAX_CROSS(link, 7), 0); ++ ++ if (priv->dbl == 0) { ++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */ ++ des_write(MAX_CROSS(link, 8), 15); ++ des_write(MAX_CROSS(link, 9), 14); ++ des_write(MAX_CROSS(link, 10), 13); ++ des_write(MAX_CROSS(link, 11), 12); ++ des_write(MAX_CROSS(link, 12), 11); ++ des_write(MAX_CROSS(link, 13), 10); ++ des_write(MAX_CROSS(link, 14), 9); ++ des_write(MAX_CROSS(link, 15), 8); ++ } ++ break; ++ case MIPI_DT_RAW12: ++ des_write(MAX_CROSS(link, 0), 11); ++ des_write(MAX_CROSS(link, 1), 10); ++ des_write(MAX_CROSS(link, 2), 9); ++ des_write(MAX_CROSS(link, 3), 8); ++ des_write(MAX_CROSS(link, 4), 7); ++ des_write(MAX_CROSS(link, 5), 6); ++ des_write(MAX_CROSS(link, 6), 5); ++ des_write(MAX_CROSS(link, 7), 4); ++ des_write(MAX_CROSS(link, 8), 3); ++ des_write(MAX_CROSS(link, 9), 2); ++ des_write(MAX_CROSS(link, 10), 1); ++ des_write(MAX_CROSS(link, 11), 0); ++ ++ if (priv->dbl == 0) { ++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */ ++ des_write(MAX_CROSS(link, 12), 23); ++ des_write(MAX_CROSS(link, 13), 22); ++ des_write(MAX_CROSS(link, 14), 21); ++ des_write(MAX_CROSS(link, 15), 20); ++ des_write(MAX_CROSS(link, 16), 19); ++ des_write(MAX_CROSS(link, 17), 18); ++ des_write(MAX_CROSS(link, 18), 17); ++ des_write(MAX_CROSS(link, 19), 16); ++ des_write(MAX_CROSS(link, 20), 15); ++ des_write(MAX_CROSS(link, 21), 14); ++ des_write(MAX_CROSS(link, 22), 13); ++ des_write(MAX_CROSS(link, 23), 12); ++ } ++ break; ++ default: ++ dev_err(&priv->client->dev, "crossbar for dt %d is not supported\n", dt); ++ break; ++ } ++ ++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */ ++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */ ++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */ ++} ++ ++static void max9296_gmsl1_initial_setup(struct max9296_priv *priv) ++{ ++ int i; ++ ++ des_write(MAX9296_REG6, 0x10); /* set GMSL1 mode */ ++ des_write(MAX9296_REG1, 0x01); /* 187.5M/3G */ ++ ++ for (i = 0; i < priv->n_links; i++) { ++ des_write(MAX_GMSL1_2(i), 0x03); /* Autodetect serial data rate range */ ++ des_write(MAX_GMSL1_4(i), 0); /* disable REV/FWD CC */ ++ des_update_bits(MAX_GMSL1_6(i), BIT(7), priv->him ? BIT(7) : 0); /* HIM/Legacy mode */ ++ des_write(MAX_GMSL1_7(i), (priv->dbl ? BIT(7) : 0) | /* DBL mode */ ++ (priv->bws ? BIT(5) : 0) | /* BWS 32/24-bit */ ++ (priv->hibw ? BIT(3) : 0) | /* High-bandwidth mode */ ++ (priv->hven ? BIT(2) : 0)); /* HS/VS encoding enable */ ++ des_write(MAX_GMSL1_D(i), 0); /* disable artificial ACKs, RC conf disable */ ++ des_write(MAX_GMSL1_F(i), 0); /* disable DE processing */ ++ des_write(MAX_GMSL1_96(i), (0x13 << 3) | 0x3); /* color map: RAW12 double - i.e. bypass packet as is */ ++ } ++} ++ ++static int max9296_gmsl1_reverse_channel_setup(struct max9296_priv *priv, int link_n) ++{ ++ struct max9296_link *link = priv->link[link_n]; ++ int ser_addrs[] = { 0x40 }; /* possible MAX9271/MAX96705 addresses on i2c bus */ ++ int lock_sts; ++ int timeout = priv->timeout; ++ char timeout_str[40]; ++ u8 val = 0; ++ int ret = 0; ++ ++ des_write(MAX_GMSL1_D(link_n), 0x81); /* enable artificial ACKs, RC conf mode */ ++ des_write(MAX_RLMSC5(link_n), 0xa0); /* override RC pulse length */ ++ des_write(MAX_RLMSC4(link_n), 0x80); /* override RC rise/fall time */ ++ usleep_range(2000, 2500); ++ des_write(MAX_GMSL1_4(link_n), 0x3); /* enable REV/FWD CC */ ++ des_write(MAX9296_GMSL1_EN, BIT(link_n)); /* enable GMSL link# */ ++ des_update_bits(MAX9296_CTRL0, 0x13, BIT(link_n)); /* enable GMSL link# */ ++ max9296_reset_oneshot(priv); ++ usleep_range(2000, 2500); ++ ++ for (; timeout > 0; timeout--) { ++ if (priv->him) { ++ /* HIM mode setup */ ++ __reg8_write(ser_addrs[0], 0x4d, 0xc0); ++ usleep_range(2000, 2500); ++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */ ++ usleep_range(2000, 2500); ++ if (priv->bws) { ++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */ ++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */ ++ (0x80) | /* DBL=1 in serializer */ ++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */ ++ usleep_range(2000, 2500); ++ } ++ } else { ++ /* Legacy mode setup */ ++ des_write(MAX_RLMS95(link_n), 0x88); /* override RC Tx amplitude */ ++ usleep_range(2000, 2500); ++ ++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */ ++ usleep_range(2000, 2500); ++ __reg8_write(ser_addrs[0], 0x08, 0x01); /* RC receiver high threshold enable */ ++ __reg8_write(ser_addrs[0], 0x97, 0x5f); /* enable RC programming (MAX96705-MAX96711 only) */ ++ usleep_range(2000, 2500); ++ ++ if (priv->bws) { ++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */ ++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */ ++ (0x80) | /* DBL=1 in serializer */ ++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */ ++ usleep_range(2000, 2500); ++ } ++ ++ des_write(MAX_RLMS95(link_n), 0xd3); /* increase RC Tx amplitude */ ++ usleep_range(2000, 2500); ++ } ++ ++ __reg8_read(ser_addrs[0], 0x1e, &val); ++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) { ++ link->ser_id = val; ++ __reg8_write(ser_addrs[0], 0x00, link->ser_addr << 1); /* relocate serizlizer on I2C bus */ ++ usleep_range(2000, 2500); ++ break; ++ } ++ ++ /* Check if already initialized (after reboot/reset ?) */ ++ ser_read(0x1e, &val); ++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) { ++ link->ser_id = val; ++ ser_write(0x04, 0x43); /* enable RC, conf_link */ ++ usleep_range(2000, 2500); ++ ret = -EADDRINUSE; ++ break; ++ } ++ ++ if (poc_trig) { ++ if (!IS_ERR(link->poc_reg) && (timeout % poc_trig == 0)) { ++ regulator_disable(link->poc_reg); /* POC power off */ ++ mdelay(200); ++ ret = regulator_enable(link->poc_reg); /* POC power on */ ++ if (ret) ++ dev_err(&link->client->dev, "failed to enable poc regulator\n"); ++ mdelay(priv->poc_delay); ++ } ++ } ++ } ++ ++ max9296_gmsl1_sensor_reset(priv, link_n, 0); /* sensor un-reset */ ++ ++ des_write(MAX_GMSL1_D(link_n), 0); /* disable artificial ACKs, RC conf disable */ ++ usleep_range(2000, 2500); ++ des_read(MAX_GMSL1_CB(link_n), &lock_sts); ++ lock_sts = !!(lock_sts & 0x01); ++ ++ if (!timeout) { ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++ priv->links_mask |= BIT(link_n); ++ ++out: ++ sprintf(timeout_str, " retries=%d lock_sts=%d", priv->timeout - timeout, lock_sts); ++ dev_info(&priv->client->dev, "GMSL1 link%d %s %sat 0x%x %s %s\n", link_n, chip_name(link->ser_id), ++ ret == -EADDRINUSE ? "already " : "", link->ser_addr, ++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", ++ priv->timeout - timeout ? timeout_str : ""); ++ return ret; ++} ++ ++static int max9296_gmsl1_link_serializer_setup(struct max9296_priv *priv, int link_n) ++{ ++ struct max9296_link *link = priv->link[link_n]; ++ ++ /* GMSL setup */ ++ ser_write(0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ ++ ser_write(0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */ ++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */ ++ (0x80) | /* DBL=1 in serializer */ ++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */ ++ usleep_range(2000, 2500); ++ ser_write(0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */ ++ usleep_range(2000, 2500); ++ ++ if (link->ser_id != MAX9271_ID) { ++ switch (priv->dt) { ++ case MIPI_DT_YUV8: ++ if (priv->dbl == 1) { ++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */ ++ ser_write(0x20, priv->cb[7]); ++ ser_write(0x21, priv->cb[6]); ++ ser_write(0x22, priv->cb[5]); ++ ser_write(0x23, priv->cb[4]); ++ ser_write(0x24, priv->cb[3]); ++ ser_write(0x25, priv->cb[2]); ++ ser_write(0x26, priv->cb[1]); ++ ser_write(0x27, priv->cb[0]); ++ ++ /* this is second byte in the packet (DBL=1 in serializer always) */ ++ ser_write(0x30, priv->cb[7] + 16); ++ ser_write(0x31, priv->cb[6] + 16); ++ ser_write(0x32, priv->cb[5] + 16); ++ ser_write(0x33, priv->cb[4] + 16); ++ ser_write(0x34, priv->cb[3] + 16); ++ ser_write(0x35, priv->cb[2] + 16); ++ ser_write(0x36, priv->cb[1] + 16); ++ ser_write(0x37, priv->cb[0] + 16); ++ } else { ++ /* setup crossbar for YUV8/RAW8: reversed DVP bus */ ++ ser_write(0x20, priv->cb[4]); ++ ser_write(0x21, priv->cb[3]); ++ ser_write(0x22, priv->cb[2]); ++ ser_write(0x23, priv->cb[1]); ++ ser_write(0x24, priv->cb[0]); ++ ser_write(0x25, 0x40); ++ ser_write(0x26, 0x40); ++ if (link->ser_id == MAX96705_ID) { ++ ser_write(0x27, 14); /* HS: D14->D18 */ ++ ser_write(0x28, 15); /* VS: D15->D19 */ ++ ser_write(0x29, 14); /* DE: D14->D20 */ ++ } ++ if (link->ser_id == MAX96707_ID) { ++ ser_write(0x27, 12); /* HS: D12->D18, this is a virtual NC pin, hence it is D14 at HS */ ++ ser_write(0x28, 13); /* VS: D13->D19 */ ++ ser_write(0x29, 12); /* DE: D12->D20 */ ++ } ++ ser_write(0x2A, 0x40); ++ ++ /* this is second byte in the packet (DBL=1 in serializer) */ ++ ser_write(0x30, 0x10 + priv->cb[7]); ++ ser_write(0x31, 0x10 + priv->cb[6]); ++ ser_write(0x32, 0x10 + priv->cb[5]); ++ ser_write(0x33, 0x10 + priv->cb[4]); ++ ser_write(0x34, 0x10 + priv->cb[3]); ++ ser_write(0x35, 0x10 + priv->cb[2]); ++ ser_write(0x36, 0x10 + priv->cb[1]); ++ ser_write(0x37, 0x10 + priv->cb[0]); ++ ser_write(0x38, priv->cb[7]); ++ ser_write(0x39, priv->cb[6]); ++ ser_write(0x3A, priv->cb[5]); ++ ++ ser_write(0x67, 0xC4); /* DBL_ALIGN_TO = 100b */ ++ } ++ break; ++ case MIPI_DT_RAW12: ++ /* setup crossbar for RAW12: reverse DVP bus */ ++ ser_write(0x20, priv->cb[11]); ++ ser_write(0x21, priv->cb[10]); ++ ser_write(0x22, priv->cb[9]); ++ ser_write(0x23, priv->cb[8]); ++ ser_write(0x24, priv->cb[7]); ++ ser_write(0x25, priv->cb[6]); ++ ser_write(0x26, priv->cb[5]); ++ ser_write(0x27, priv->cb[4]); ++ ser_write(0x28, priv->cb[3]); ++ ser_write(0x29, priv->cb[2]); ++ ser_write(0x2a, priv->cb[1]); ++ ser_write(0x2b, priv->cb[0]); ++ ++ /* this is second byte in the packet (DBL=1 in serializer) */ ++ ser_write(0x30, priv->cb[11] + 16); ++ ser_write(0x31, priv->cb[10] + 16); ++ ser_write(0x32, priv->cb[9] + 16); ++ ser_write(0x33, priv->cb[8] + 16); ++ ser_write(0x34, priv->cb[7] + 16); ++ ser_write(0x35, priv->cb[6] + 16); ++ ser_write(0x36, priv->cb[5] + 16); ++ ser_write(0x37, priv->cb[4] + 16); ++ ser_write(0x38, priv->cb[3] + 16); ++ ser_write(0x39, priv->cb[2] + 16); ++ ser_write(0x3a, priv->cb[1] + 16); ++ ser_write(0x3b, priv->cb[0] + 16); ++ ++ if (!(priv->bws || priv->hibw) && priv->dbl) ++ dev_err(&priv->client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n"); ++ break; ++ } ++ } ++ ++ /* I2C translator setup */ ++// ser_write(0x09, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */ ++// ser_write(0x0A, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */ ++ ser_write(0x0B, BROADCAST << 1); /* serializer broadcast I2C translated */ ++ ser_write(0x0C, link->ser_addr << 1); /* serializer broadcast I2C native */ ++ /* put serializer in configuration link state */ ++ ser_write(0x04, 0x43); /* enable RC, conf_link */ ++ usleep_range(2000, 2500); ++ ++ return 0; ++} ++ ++static void max9296_gmsl1_link_pipe_setup(struct max9296_priv *priv, int link_n) ++{ ++ struct max9296_link *link = priv->link[link_n]; ++ int pipe = link_n; /* straight map */ ++ int dt = priv->dt; /* should come from imager */ ++ int in_vc = 0; ++ ++ max9296_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */ ++ ++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */ ++ des_write(MAX_MIPI_TX12(pipe), 0x00); ++ ++ /* use map #0 for payload data */ ++ max9296_set_pipe_to_mipi_mapping(priv, pipe, 0, /* pipe, map# */ ++ dt, in_vc, /* src DT, VC */ ++ dt, link->out_vc, /* dst DT, VC */ ++ link->out_mipi); /* dst MIPI PHY */ ++ /* use map #1 for FS */ ++ max9296_set_pipe_to_mipi_mapping(priv, pipe, 1, /* pipe, map# */ ++ 0x00, in_vc, /* src DT, VC */ ++ 0x00, link->out_vc, /* dst DT, VC */ ++ link->out_mipi); /* dst MIPI PHY */ ++ /* use map #2 for FE */ ++ max9296_set_pipe_to_mipi_mapping(priv, pipe, 2, /* pipe, map# */ ++ 0x01, in_vc, /* src DT, VC */ ++ 0x01, link->out_vc, /* dst DT, VC */ ++ link->out_mipi); /* dst MIPI PHY */ ++ usleep_range(5000, 5500); ++ ++ link->pipes_mask |= BIT(pipe); ++} ++ ++static void max9296_gmsl1_postinit(struct max9296_priv *priv) ++{ ++ int i; ++ u8 val = 0; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ struct max9296_link *link = priv->link[i]; ++ ++ if (!(priv->links_mask & BIT(i))) ++ continue; ++ ++ des_write(MAX_GMSL1_4(i), 0x3); /* enable REV/FWD CC */ ++ des_write(MAX9296_GMSL1_EN, BIT(i)); /* enable GMSL link# */ ++ des_update_bits(MAX9296_CTRL0, 0x13, BIT(i)); /* enable GMSL link# */ ++ max9296_reset_oneshot(priv); ++ usleep_range(2000, 2500); ++ ++ ser_read(0x15, &val); ++ if (!(val & BIT(1))) ++ dev_warn(&priv->client->dev, "link%d valid PCLK is not detected\n", i); ++ ++ /* switch to GMSL serial_link for streaming video */ ++ max9296_write_remote_verify(priv, i, 0x04, conf_link ? 0x43 : 0x83); ++ usleep_range(2000, 2500); ++ ++ des_write(MAX_GMSL1_4(i), 0x00); /* disable REV/FWD CC */ ++ ++ switch (priv->link[i]->ser_id) { ++ case MAX9271_ID: ++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x01); /* use D14/15 for HS/VS */ ++ break; ++ case MAX96705_ID: ++ case MAX96707_ID: ++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x00); /* use D18/D19 for HS/VS */ ++ break; ++ } ++ } ++ ++ for (i = 0; i < priv->n_links; i++) ++ des_write(MAX_GMSL1_4(i), priv->links_mask & BIT(i) ? 0x03 : 0); /* enable REV/FWD CC */ ++ ++ des_write(MAX9296_GMSL1_EN, priv->links_mask); /* enable detected links */ ++ des_update_bits(MAX9296_CTRL0, 0x13, priv->links_mask == 3 ? 0x13 : priv->links_mask); /* enable detected links */ ++ max9296_reset_oneshot(priv); /* one-shot reset links */ ++} ++ ++static void max9296_gmsl1_fsync_setup(struct max9296_priv *priv) ++{ ++ des_write(MAX9296_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */ ++ des_write(MAX9296_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */ ++ des_write(MAX9296_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */ ++ //des_write(MAX9296_FSYNC_8, 0x00); /* Disable Err Thresh */ ++ //des_write(MAX9296_FSYNC_9, 0x00); /* Disable Err Thresh */ ++ des_write(MAX9296_FSYNC_10, 0x00); /* Disable Overlap */ ++ des_write(MAX9296_FSYNC_11, 0x00); ++ ++ des_write(MAX9296_FSYNC_0, 0x00); /* Manual method, Internal GMSL1 generator mode */ ++ ++ des_write(MAX_GMSL1_8(0), 0x11); /* Fsync Tx Enable on Link A */ ++ des_write(MAX_GMSL1_8(1), 0x11); /* Fsync Tx Enable on Link B */ ++ des_write(MAX_GMSL1_8(2), 0x11); /* Fsync Tx Enable on Link C */ ++ des_write(MAX_GMSL1_8(3), 0x11); /* Fsync Tx Enable on Link D */ ++ ++ des_write(MAX9296_FSYNC_15, 0x1f); /* GMSL1 Type Fsync, Enable all pipes */ ++} ++ ++/* ----------------------------------------------------------------------------- ++ * GMSL2 ++ */ ++ ++static void max9296_gmsl2_cc_enable(struct max9296_priv *priv, int link, int on) ++{ ++ /* nothing */ ++} ++ ++static int max9296_gmsl2_get_link_lock(struct max9296_priv *priv, int link_n) ++{ ++ int val = 0; ++ ++ des_read(MAX9296_CTRL3, &val); ++ ++ return !!(val & BIT(3)) && (val & BIT(link_n + 4)); ++} ++ ++static void max9296_gmsl2_initial_setup(struct max9296_priv *priv) ++{ ++ des_write(MAX9296_REG6, 0xC0 | 0x10); /* set GMSL2 mode */ ++ des_write(MAX9296_REG1, 0x02); /* 187.5M/6G */ ++} ++ ++static int max9296_gmsl2_reverse_channel_setup(struct max9296_priv *priv, int link_n) ++{ ++ struct max9296_link *link = priv->link[link_n]; ++ int ser_addrs[] = {0x40, 0x42, 0x60, 0x62}; /* possible MAX9295 addresses on i2c bus */ ++ int timeout = priv->timeout; ++ int ret = 0; ++ int i = 0; ++ ++ des_update_bits(MAX9296_CTRL0, 0x13, BIT(link_n)); /* enable GMSL link# */ ++ max9296_reset_oneshot(priv); ++ ++ /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */ ++ while ((!max9296_gmsl2_get_link_lock(priv, link_n)) && (--timeout)) ++ msleep(1); ++ ++ if (!timeout) { ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(ser_addrs); i++) { ++ int val = 0; ++ ++ __reg16_read(ser_addrs[i], 0x000d, &val); /* read serializer ID */ ++ if (val == MAX9295A_ID || val == MAX9295B_ID) { ++ link->ser_id = val; ++ __reg16_write(ser_addrs[i], 0x0000, link->ser_addr << 1); /* relocate serizlizer on I2C bus */ ++ usleep_range(2000, 2500); ++ break; ++ } ++ } ++ ++ if (i == ARRAY_SIZE(ser_addrs)) { ++ dev_err(&priv->client->dev, "serializer not found\n"); ++ goto out; ++ } ++ ++ priv->links_mask |= BIT(link_n); ++ ++out: ++ dev_info(&priv->client->dev, "link%d %s %sat 0x%x (0x%x) %s\n", link_n, chip_name(link->ser_id), ++ ret == -EADDRINUSE ? "already " : "", link->ser_addr, ser_addrs[i], ++ ret == -ETIMEDOUT ? "not found: timeout GMSL2 link establish" : ""); ++ return ret; ++} ++ ++static int max9296_gmsl2_link_serializer_setup(struct max9296_priv *priv, int link_n) ++{ ++ struct max9296_link *link = priv->link[link_n]; ++ int i; ++ ++ //ser_write(MAX9295_CTRL0, 0x31); /* link reset */ ++ //msleep(100); ++ ser_write(MAX9295_REG2, 0x03); /* disable all pipes */ ++ ++ if (strcmp(priv->mbus, "dvp") == 0) { ++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */ ++ (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */ ++ ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */ ++ ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */ ++ } ++ ++ ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */ ++ ++ switch (priv->dt) { ++ case MIPI_DT_YUV8: ++ case MIPI_DT_RAW12: ++ /* setup crossbar: strait DVP mapping */ ++ ser_write(MAX9295_CROSS(0), priv->cb[0]); ++ ser_write(MAX9295_CROSS(1), priv->cb[1]); ++ ser_write(MAX9295_CROSS(2), priv->cb[2]); ++ ser_write(MAX9295_CROSS(3), priv->cb[3]); ++ ser_write(MAX9295_CROSS(4), priv->cb[4]); ++ ser_write(MAX9295_CROSS(5), priv->cb[5]); ++ ser_write(MAX9295_CROSS(6), priv->cb[6]); ++ ser_write(MAX9295_CROSS(7), priv->cb[7]); ++ ser_write(MAX9295_CROSS(8), priv->cb[8]); ++ ser_write(MAX9295_CROSS(9), priv->cb[9]); ++ ser_write(MAX9295_CROSS(10), priv->cb[10]); ++ ser_write(MAX9295_CROSS(11), priv->cb[11]); ++ break; ++ } ++ ++ for (i = 0; i < 11; i++) { ++ if (priv->gpio[i] == 0) { ++ /* GPIO set 0 */ ++ ser_write(MAX9295_GPIO_A(i), 0x80); /* 1MOm, GPIO output low */ ++ ser_write(MAX9295_GPIO_B(i), 0xa0); /* push-pull, pull-down */ ++ } ++ if (priv->gpio[i] == 1) { ++ /* GPIO set 1 */ ++ ser_write(MAX9295_GPIO_A(i), 0x90); /* 1MOm, GPIO output high */ ++ ser_write(MAX9295_GPIO_B(i), 0x60); /* push-pull, pull-up */ ++ } ++ if (priv->gpio[i] == 2) { ++ /* GPIO FSIN */ ++ ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */ ++ ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */ ++ } ++ if (priv->gpio[i] == 3) { ++ /* GPIO Interrupt */ ++ ser_write(MAX9295_GPIO_A(i), 0x63); /* 40kOm, GMSL2 TX to deserializer */ ++ ser_write(MAX9295_GPIO_B(i), 0x25); /* push-pull, pull-none, GPIO stream ID=5 */ ++ } ++ } ++ ++ /* I2C translator setup */ ++// ser_write(MAX9295_I2C2, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */ ++// ser_write(MAX9295_I2C3, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */ ++ ser_write(MAX9295_I2C4, BROADCAST << 1); /* serializer broadcast I2C translated */ ++ ser_write(MAX9295_I2C5, link->ser_addr << 1); /* serializer broadcast I2C native */ ++ usleep_range(2000, 2500); ++ ++ return 0; ++} ++ ++static struct { ++ int in_dt; ++ int out_dt; ++} gmsl2_pipe_maps[] = { ++ {0x00, 0x00}, /* FS */ ++ {0x01, 0x01}, /* FE */ ++ {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */ ++}; ++ ++static void max9296_gmsl2_pipe_set_source(struct max9296_priv *priv, int pipe, int phy, int in_pipe) ++{ ++ // TODO ++} ++ ++static void max9296_gmsl2_link_pipe_setup(struct max9296_priv *priv, int link_n) ++{ ++ struct max9296_link *link = priv->link[link_n]; ++ int pipe = link_n; /* straight mapping */ ++ int dt = priv->dt; /* must come from imager */ ++ int in_vc = 0; ++ int i; ++ ++ max9296_gmsl2_pipe_set_source(priv, pipe, link_n, 0); /* route Pipe X only */ ++ ++ if (strcmp(priv->mbus, "dvp") == 0) { ++ des_write(MAX9296_RX0(pipe), 0); /* stream_id = 0 */ ++ //des_update_bits(MAX_VIDEO_RX0(pipe), BIT(0), BIT(0)); /* disable Packet detector */ ++ max9296_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */ ++ } ++ ++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */ ++ des_write(MAX_MIPI_TX12(pipe), 0x00); ++ ++ for (i = 0; i < ARRAY_SIZE(gmsl2_pipe_maps); i++) { ++ max9296_set_pipe_to_mipi_mapping(priv, pipe, i, /* pipe, map# */ ++ gmsl2_pipe_maps[i].in_dt, in_vc, /* src DT, VC */ ++ gmsl2_pipe_maps[i].out_dt, link->out_vc, /* dst DT, VC */ ++ link->out_mipi); /* dst MIPI PHY */ ++ } ++ ++ link->pipes_mask |= BIT(pipe); ++} ++ ++static void max9296_gmsl2_postinit(struct max9296_priv *priv) ++{ ++ des_update_bits(MAX9296_CTRL0, 0x13, priv->links_mask == 3 ? 0x13 : priv->links_mask); /* enable detected links */ ++ max9296_reset_oneshot(priv); /* one-shot reset links */ ++} ++ ++static void max9296_gmsl2_link_crossbar_setup(struct max9296_priv *priv, int link, int dt) ++{ ++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */ ++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */ ++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */ ++} ++ ++static void max9296_gmsl2_fsync_setup(struct max9296_priv *priv) ++{ ++ /* TODO */ ++} ++ ++/* ----------------------------------------------------------------------------- ++ * I2C Multiplexer ++ */ ++ ++static int max9296_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan) ++{ ++ /* Do nothing! */ ++ return 0; ++} ++ ++static int max9296_i2c_mux_init(struct max9296_priv *priv) ++{ ++ struct i2c_client *client = priv->client; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) ++ return -ENODEV; ++ ++ priv->mux = i2c_mux_alloc(client->adapter, &client->dev, ++ priv->n_links, 0, I2C_MUX_LOCKED, ++ max9296_i2c_mux_select, NULL); ++ if (!priv->mux) ++ return -ENOMEM; ++ ++ priv->mux->priv = priv; ++ ++ return 0; ++} ++ ++#define max9296_cc_enable(priv,i,en) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_cc_enable(priv, i, en) : \ ++ max9296_gmsl1_cc_enable(priv, i, en)) ++#define max9296_initial_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_initial_setup(priv) : \ ++ max9296_gmsl1_initial_setup(priv)) ++#define max9296_reverse_channel_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_reverse_channel_setup(priv, i) : \ ++ max9296_gmsl1_reverse_channel_setup(priv, i)) ++#define max9296_link_serializer_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_link_serializer_setup(priv, i) : \ ++ max9296_gmsl1_link_serializer_setup(priv, i)) ++#define max9296_link_pipe_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_link_pipe_setup(priv, i) : \ ++ max9296_gmsl1_link_pipe_setup(priv, i)) ++#define max9296_link_crossbar_setup(priv,i,dt) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_link_crossbar_setup(priv, i, dt) : \ ++ max9296_gmsl1_link_crossbar_setup(priv, i, dt)) ++#define max9296_postinit(priv) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_postinit(priv) : \ ++ max9296_gmsl1_postinit(priv)) ++#define max9296_fsync_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_fsync_setup(priv) : \ ++ max9296_gmsl1_fsync_setup(priv)) ++ ++static int max9296_preinit(struct max9296_priv *priv) ++{ ++ int i; ++ ++ des_update_bits(MAX9296_CTRL0, BIT(7), BIT(7)); /* reset chip */ ++ mdelay(5); ++ ++ /* enable internal regulator for 1.2V VDD supply */ ++ des_update_bits(MAX9296_CTRL0, BIT(2), BIT(2)); /* REG_ENABLE = 1 */ ++ des_update_bits(MAX9296_CTRL2, BIT(4), BIT(4)); /* REG_MNL = 1 */ ++ ++ /* this is needed for engineering samples */ ++ for (i = 0; i < priv->n_links; i++) { ++ des_write(MAX_RLMS4(i), 0x29); ++ des_write(MAX_RLMSA4(i), 0xc8); ++ des_write(MAX_RLMSA(i), 0x00); ++ des_write(MAX_RLMSB(i), 0x00); ++ } ++ ++ /* I2C-I2C timings */ ++ des_write(MAX9296_I2C_PT_0, 0x01); /* Fast mode Plus, 1mS timeout */ ++ des_write(MAX9296_I2C_PT_1, 0x51); /* i2c speed: 397Kbps, 32mS timeout */ ++ des_write(MAX9296_I2C_0, 0x01); /* Fast mode Plus, 1mS timeout */ ++ des_write(MAX9296_I2C_1, 0x51); /* i2c speed: 397Kbps, 1mS timeout */ ++ ++ des_write(MAX9296_CTRL1, priv->is_coax ? 0x5 : 0); /* cable mode */ ++ des_write(MAX9296_GMSL1_EN, 0); /* disable all links */ ++ des_update_bits(MAX9296_CTRL0, 0x13, 0); /* disable all links */ ++ ++ return 0; ++} ++ ++static int max9296_initialize(struct max9296_priv *priv) ++{ ++ int ret, i; ++ ++ max9296_preinit(priv); ++ max9296_initial_setup(priv); ++ max9296_mipi_setup(priv); ++ ++ for (i = 0; i < priv->n_links; i++) { ++ if (!IS_ERR(priv->link[i]->poc_reg)) { ++ ret = regulator_enable(priv->link[i]->poc_reg); /* POC power on */ ++ if (ret) { ++ dev_err(&priv->link[i]->client->dev, "failed to enable poc regulator\n"); ++ continue; ++ } ++ mdelay(priv->poc_delay); ++ } ++ ++ ret = max9296_reverse_channel_setup(priv, i); ++ if (ret == -ETIMEDOUT) ++ continue; ++ if (!ret) ++ max9296_link_serializer_setup(priv, i); ++ ++ max9296_link_pipe_setup(priv, i); ++ max9296_link_crossbar_setup(priv, i, priv->dt); ++ ++ i2c_mux_add_adapter(priv->mux, 0, i, 0); ++ max9296_cc_enable(priv, i, 0); ++ } ++ ++ max9296_postinit(priv); ++ max9296_fsync_setup(priv); ++ ++ return 0; ++} ++ ++static int max9296_reboot_notifier(struct notifier_block *nb, unsigned long code, void *data) ++{ ++ struct max9296_priv *priv = container_of(nb, struct max9296_priv, reboot_nb); ++ int i; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ if (!IS_ERR(priv->link[i]->poc_reg)) ++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */ ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static int max9296_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct max9296_priv *priv = v4l2_get_subdevdata(sd); ++ ++ if (on) { ++ if (atomic_inc_return(&priv->use_count) == 1) ++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0x02); /* CSI output enable */ ++ } else { ++ if (atomic_dec_return(&priv->use_count) == 0) ++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0); /* CSI output disable */ ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int max9296_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ struct max9296_priv *priv = v4l2_get_subdevdata(sd); ++ int ret; ++ int val = 0; ++ ++ ret = des_read(reg->reg, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = sizeof(u16); ++ ++ return 0; ++} ++ ++static int max9296_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ struct max9296_priv *priv = v4l2_get_subdevdata(sd); ++ ++ return des_write(reg->reg, (u8)reg->val); ++} ++#endif ++ ++static struct v4l2_subdev_core_ops max9296_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = max9296_g_register, ++ .s_register = max9296_s_register, ++#endif ++ .s_power = max9296_s_power, ++}; ++ ++static struct v4l2_subdev_ops max9296_subdev_ops = { ++ .core = &max9296_subdev_core_ops, ++}; ++ ++static const struct of_device_id max9296_dt_ids[] = { ++ { .compatible = "maxim,max9296" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, max9296_dt_ids); ++ ++static int max9296_parse_dt(struct i2c_client *client) ++{ ++ struct max9296_priv *priv = i2c_get_clientdata(client); ++ struct device_node *np = client->dev.of_node; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ struct property *prop; ++ char name[16]; ++ int i, csi_rate; ++ ++ if (of_property_read_u32(np, "maxim,links", &priv->n_links)) ++ priv->n_links = MAX9296_MAX_LINKS; ++ if (of_property_read_u32(np, "maxim,gmsl", &priv->gmsl_mode)) ++ priv->gmsl_mode = MODE_GMSL2; ++ if (of_property_read_bool(np, "maxim,stp")) ++ priv->is_coax = 0; ++ else ++ priv->is_coax = 1; ++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) { ++ priv->gpio_resetb = -1; ++ } else { ++ if (of_property_read_bool(np, "maxim,resetb-active-high")) ++ priv->active_low_resetb = 0; ++ else ++ priv->active_low_resetb = 1; ++ } ++ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period)) ++ priv->fsync_period = 3210000;/* 96MHz/30fps */ ++ priv->pclk_rising_edge = true; ++ if (of_property_read_bool(np, "maxim,pclk-falling-edge")) ++ priv->pclk_rising_edge = false; ++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout)) ++ priv->timeout = 100; ++ if (of_property_read_u32(np, "maxim,him", &priv->him)) ++ priv->him = 0; ++ if (of_property_read_u32(np, "maxim,bws", &priv->bws)) ++ priv->bws = 0; ++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl)) ++ priv->dbl = 1; ++ if (of_property_read_u32(np, "maxim,hven", &priv->hven)) ++ priv->hven = 1; ++ if (of_property_read_u32(np, "maxim,hibw", &priv->hibw)) ++ priv->hibw = 0; ++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync)) ++ priv->hsync = 0; ++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync)) ++ priv->vsync = 1; ++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay)) ++ priv->poc_delay = 50; ++ if (of_property_read_u32(np, "maxim,dt", &priv->dt)) ++ priv->dt = MIPI_DT_YUV8; ++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar)) ++ priv->crossbar = crossbar; ++ if (of_property_read_string(np, "maxim,mbus", &priv->mbus)) ++ priv->mbus = mbus_default; ++ for (i = 0; i < 11; i++) { ++ sprintf(name, "maxim,gpio%d", i); ++ if (of_property_read_u32(np, name, &priv->gpio[i])) ++ priv->gpio[i] = -1; ++ } ++ ++ /* module params override dts */ ++ if (gmsl != MODE_GMSL2) ++ priv->gmsl_mode = gmsl; ++ if (him) ++ priv->him = him; ++ if (fsync_period) { ++ priv->fsync_period = fsync_period; ++// priv->fsync_mode = fsync_mode_default; ++ } ++ if (hsync) ++ priv->hsync = hsync; ++ if (!vsync) ++ priv->vsync = vsync; ++ if (gpio_resetb) ++ priv->gpio_resetb = gpio_resetb; ++ if (active_low_resetb) ++ priv->active_low_resetb = active_low_resetb; ++ if (timeout_n) ++ priv->timeout = timeout_n; ++ if (poc_delay) ++ priv->poc_delay = poc_delay; ++ if (bws) ++ priv->bws = bws; ++ if (!dbl) ++ priv->dbl = dbl; ++ if (dt != MIPI_DT_YUV8) ++ priv->dt = dt; ++// if (hsgen) ++// priv->hsgen = hsgen; ++ if (gpio0 >= 0) ++ priv->gpio[0] = gpio0; ++ if (gpio1 >= 0) ++ priv->gpio[1] = gpio1; ++ if (gpio7 >= 0) ++ priv->gpio[7] = gpio7; ++ if (gpio8 >= 0) ++ priv->gpio[8] = gpio8; ++ ++ /* parse serializer crossbar setup */ ++ for (i = 0; i < 16; i++) { ++ priv->cb[i] = priv->crossbar % 16; ++ priv->crossbar /= 16; ++ } ++ ++ for (i = 0; ; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; ++ ++ if (i < priv->n_links) { ++ if (of_property_read_u32(endpoint, "ser-addr", &priv->link[i]->ser_addr)) { ++ of_node_put(endpoint); ++ dev_err(&client->dev, "ser-addr not set\n"); ++ return -EINVAL; ++ } ++ priv->link[i]->sd_fwnode = of_fwnode_handle(endpoint); ++ } ++ ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; ++ ++ prop = of_find_property(endpoint, "csi-rate", NULL); ++ if (prop) { ++ of_property_read_u32(endpoint, "csi-rate", &csi_rate); ++ of_update_property(rendpoint, prop); ++ } ++ ++ prop = of_find_property(endpoint, "dvp-order", NULL); ++ if (prop) ++ of_update_property(rendpoint, prop); ++ } ++ ++ of_node_put(endpoint); ++ ++ for (i = 0; i < priv->n_links; i++) { ++ priv->link[i]->out_mipi = 1; /* CSI default forwarding is to MIPI1 */ ++ priv->link[i]->out_vc = i; /* Default VC map: 0 1 2 3 */ ++ } ++ ++ prop = of_find_property(np, "maxim,links-mipi-map", NULL); ++ if (prop) { ++ const __be32 *map = NULL; ++ u32 val; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ map = of_prop_next_u32(prop, map, &val); ++ if (!map) ++ break; ++ if (val >= MAX9296_MAX_MIPI) ++ return -EINVAL; ++ priv->link[i]->out_mipi = val; ++ } ++ } ++ ++ for (i = 0; i < priv->n_links; i++) ++ priv->csi_rate[priv->link[i]->out_mipi] = csi_rate; ++ ++ prop = of_find_property(np, "maxim,links-vc-map", NULL); ++ if (prop) { ++ const __be32 *map = NULL; ++ u32 val; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ map = of_prop_next_u32(prop, map, &val); ++ if (!map) ++ break; ++ if (val >= 4) ++ return -EINVAL; ++ priv->link[i]->out_vc = val; ++ } ++ } ++ ++ dev_dbg(&client->dev, "Link# | MIPI rate | Map | VC\n"); ++ for (i = 0; i < priv->n_links; i++) ++ dev_dbg(&client->dev, "%5d | %9d | %3d | %2d\n", i, priv->csi_rate[i], priv->link[i]->out_mipi, priv->link[i]->out_vc); ++ ++ return 0; ++} ++ ++static int max9296_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct max9296_priv *priv; ++ struct gpio_desc *pwdn_gpio; ++ int ret, i; ++ int val = 0; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->regmap = devm_regmap_init_i2c(client, &max9296_regmap[0]); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ i2c_set_clientdata(client, priv); ++ priv->client = client; ++ atomic_set(&priv->use_count, 0); ++ ++ priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk"); ++ if (!IS_ERR(priv->ref_clk)) { ++ dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000); ++ v4l2_clk_enable(priv->ref_clk); ++ } ++ ++ pwdn_gpio = devm_gpiod_get_optional(&client->dev, "shutdown", GPIOD_OUT_HIGH); ++ if (!IS_ERR(pwdn_gpio)) { ++ udelay(5); ++ gpiod_set_value_cansleep(pwdn_gpio, 0); ++ usleep_range(3000, 5000); ++ } ++ ++ des_read(MAX9296_REG13, &val); ++ if (val != MAX9296A_ID) ++ return -ENODEV; ++ ++ for (i = 0; i < MAX9296_MAX_LINKS; i++) { ++ priv->link[i] = devm_kzalloc(&client->dev, sizeof(*priv->link[i]), GFP_KERNEL); ++ if (!priv->link[i]) ++ return -ENOMEM; ++ } ++ ++ ret = max9296_parse_dt(client); ++ if (ret) ++ goto out; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ char poc_name[10]; ++ ++ sprintf(poc_name, "poc%d", i); ++ priv->link[i]->poc_reg = devm_regulator_get(&client->dev, poc_name); ++ if (PTR_ERR(priv->link[i]->poc_reg) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ } ++ ++ for (i = 0; i < priv->n_links; i++) { ++ priv->link[i]->client = i2c_new_dummy(client->adapter, priv->link[i]->ser_addr); ++ if (!priv->link[i]->client) ++ return -ENOMEM; ++ ++ priv->link[i]->regmap = regmap_init_i2c(priv->link[i]->client, &max9296_regmap[priv->gmsl_mode]); ++ if (IS_ERR(priv->link[i]->regmap)) ++ return PTR_ERR(priv->link[i]->regmap); ++ } ++ ++ ret = max9296_i2c_mux_init(priv); ++ if (ret) { ++ dev_err(&client->dev, "Unable to initialize I2C multiplexer\n"); ++ goto out; ++ } ++ ++ ret = max9296_initialize(priv); ++ if (ret < 0) ++ goto out; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ v4l2_subdev_init(&priv->link[i]->sd, &max9296_subdev_ops); ++ priv->link[i]->sd.owner = client->dev.driver->owner; ++ priv->link[i]->sd.dev = &client->dev; ++ priv->link[i]->sd.grp_id = i; ++ v4l2_set_subdevdata(&priv->link[i]->sd, priv); ++ priv->link[i]->sd.fwnode = priv->link[i]->sd_fwnode; ++ ++ snprintf(priv->link[i]->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x", ++ client->dev.driver->name, i, i2c_adapter_id(client->adapter), ++ client->addr); ++ ++ ret = v4l2_async_register_subdev(&priv->link[i]->sd); ++ if (ret < 0) ++ goto out; ++ } ++ ++ priv->reboot_nb.notifier_call = max9296_reboot_notifier; ++ ret = register_reboot_notifier(&priv->reboot_nb); ++ if (ret) { ++ dev_err(&client->dev, "failed to register reboot notifier\n"); ++ goto out; ++ } ++ ++ //max9296_debug_add(priv); ++out: ++ return ret; ++} ++ ++static int max9296_remove(struct i2c_client *client) ++{ ++ struct max9296_priv *priv = i2c_get_clientdata(client); ++ int i; ++ ++ //max9296_debug_remove(priv); ++ i2c_mux_del_adapters(priv->mux); ++ unregister_reboot_notifier(&priv->reboot_nb); ++ ++ for (i = 0; i < priv->n_links; i++) { ++ v4l2_async_unregister_subdev(&priv->link[i]->sd); ++ v4l2_device_unregister_subdev(&priv->link[i]->sd); ++ if (!IS_ERR(priv->link[i]->poc_reg)) ++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */ ++ } ++ ++ return 0; ++} ++ ++static const struct i2c_device_id max9296_id[] = { ++ { "max9296", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max9296_id); ++ ++static struct i2c_driver max9296_i2c_driver = { ++ .driver = { ++ .name = "max9296", ++ .of_match_table = of_match_ptr(max9296_dt_ids), ++ }, ++ .probe = max9296_probe, ++ .remove = max9296_remove, ++ .id_table = max9296_id, ++}; ++ ++module_i2c_driver(max9296_i2c_driver); ++ ++MODULE_DESCRIPTION("GMSL2 driver for MAX9296"); ++MODULE_AUTHOR("Andrey Gusakov, Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.h b/drivers/media/i2c/soc_camera/gmsl/max9296.h +new file mode 100644 +index 0000000..800df43 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.h +@@ -0,0 +1,281 @@ ++/* ++ * MAXIM max9296 GMSL2 driver header ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#define MAX9296_MAX_LINKS 2 ++#define MAX9296_MAX_PIPES 4 ++#define MAX9296_MAX_PIPE_MAPS 16 ++#define MAX9296_MAX_MIPI 4 ++ ++struct max9296_link { ++ struct v4l2_subdev sd; ++ struct fwnode_handle *sd_fwnode; ++ struct i2c_client *client; ++ struct regmap *regmap; ++ int ser_id; ++ int ser_addr; ++ int pipes_mask; /* mask of pipes used by this link */ ++ int out_mipi; /* MIPI# */ ++ int out_vc; /* VC# */ ++ struct regulator *poc_reg; /* PoC power supply */ ++}; ++ ++struct max9296_priv { ++ struct i2c_client *client; ++ struct regmap *regmap; ++ struct i2c_mux_core *mux; ++ int n_links; ++ int links_mask; ++ enum gmsl_mode gmsl_mode; ++ struct max9296_link *link[MAX9296_MAX_LINKS]; ++ int gpio_resetb; ++ int active_low_resetb; ++ bool pclk_rising_edge; ++ bool is_coax; ++ int him; ++ int bws; ++ int dbl; ++ int hibw; ++ int hven; ++ int hsync; ++ int vsync; ++ int dt; ++ u64 crossbar; ++ char cb[16]; ++ const char *mbus; ++ int gpio[11]; ++ int timeout; ++ int poc_delay; ++ struct v4l2_clk *ref_clk; ++ int csi_rate[MAX9296_MAX_MIPI]; ++ int fsync_period; ++ atomic_t use_count; ++ struct notifier_block reboot_nb; ++}; ++ ++#define MAX9296_REG1 0x01 ++#define MAX9296_REG2 0x02 ++#define MAX9296_REG3 0x03 ++#define MAX9296_REG4 0x04 ++#define MAX9296_REG5 0x05 ++#define MAX9296_REG6 0x06 ++#define MAX9296_REG13 0x0d ++#define MAX9296_REG14 0x0e ++#define MAX9296_REG26 0x26 ++ ++#define MAX9296_INTR3 0x1b ++#define MAX9296_INTR5 0x1d ++#define MAX9296_INTR7 0x1f ++#define MAX9296_DEC_ERR_A 0x22 ++#define MAX9296_DEC_ERR_B 0x23 ++#define MAX9296_IDLE_ERR 0x24 ++#define MAX9296_PKT_CNT 0x25 ++#define MAX9296_RX_0 0x2c ++#define MAX9296_RX_3 0x2f ++ ++#define MAX9296_CTRL0 0x17 ++#define MAX9296_CTRL1 0x18 ++#define MAX9296_CTRL2 0x19 ++#define MAX9296_CTRL3 0x1a ++#define MAX9296_CTRL11 0x22 ++#define MAX9296_CTRL12 0x0a ++#define MAX9296_CTRL13 0x0b ++#define MAX9296_CTRL14 0x0c ++ ++#define MAX9296_CNT(n) (0x22 + n) ++ ++#define MAX9296_I2C_PT_0 0x4c ++#define MAX9296_I2C_PT_1 0x4d ++ ++#define MAX9296_CNT4 0x55c ++ ++#define MAX9296_GMSL1_EN 0xf00 ++#define MAX9296_COMMON1 0xf02 ++#define MAX9296_I2C_0 0xf05 ++#define MAX9296_I2C_1 0xf06 ++#define MAX9296_I2C_2 0xf07 ++#define MAX9296_I2C_3 0xf08 ++#define MAX9296_I2C_4 0xf09 ++#define MAX9296_I2C_5 0xf0a ++ ++#define MAX9296_RX0(n) (0x50 + n) ++ ++#define MAX_VIDEO_RX_BASE(n) (n < 5 ? (0x100 + (0x12 * n)) : \ ++ (0x160 + (0x12 * (n - 5)))) ++#define MAX_VIDEO_RX0(n) (MAX_VIDEO_RX_BASE(n) + 0x00) ++#define MAX_VIDEO_RX3(n) (MAX_VIDEO_RX_BASE(n) + 0x03) ++#define MAX_VIDEO_RX8(n) (MAX_VIDEO_RX_BASE(n) + 0x08) ++#define MAX_VIDEO_RX10(n) (MAX_VIDEO_RX_BASE(n) + 0x0a) ++ ++#define MAX_VPRBS(n) (0x1dc + (0x20 * n)) ++ ++#define MAX_CROSS_BASE(n) (0x1c0 + (0x20 * n)) ++#define MAX_CROSS(n, m) (MAX_CROSS_BASE(n) + m) ++ ++#define MAX_BACKTOP_BASE(bank) (0x400 + (0x20 * bank)) ++#define MAX_BACKTOP1(bank) (MAX_BACKTOP_BASE(bank) + 0x00) ++#define MAX_BACKTOP11(bank) (MAX_BACKTOP_BASE(bank) + 0x0a) ++#define MAX_BACKTOP12(bank) (MAX_BACKTOP_BASE(bank) + 0x0b) ++#define MAX_BACKTOP13(bank) (MAX_BACKTOP_BASE(bank) + 0x0c) ++#define MAX_BACKTOP14(bank) (MAX_BACKTOP_BASE(bank) + 0x0d) ++#define MAX_BACKTOP15(bank) (MAX_BACKTOP_BASE(bank) + 0x0e) ++#define MAX_BACKTOP16(bank) (MAX_BACKTOP_BASE(bank) + 0x0f) ++#define MAX_BACKTOP17(bank) (MAX_BACKTOP_BASE(bank) + 0x10) ++#define MAX_BACKTOP18(bank) (MAX_BACKTOP_BASE(bank) + 0x11) ++#define MAX_BACKTOP19(bank) (MAX_BACKTOP_BASE(bank) + 0x12) ++#define MAX_BACKTOP20(bank) (MAX_BACKTOP_BASE(bank) + 0x13) ++#define MAX_BACKTOP21(bank) (MAX_BACKTOP_BASE(bank) + 0x14) ++#define MAX_BACKTOP22(bank) (MAX_BACKTOP_BASE(bank) + 0x15) ++#define MAX_BACKTOP23(bank) (MAX_BACKTOP_BASE(bank) + 0x16) ++#define MAX_BACKTOP24(bank) (MAX_BACKTOP_BASE(bank) + 0x17) ++#define MAX_BACKTOP25(bank) (MAX_BACKTOP_BASE(bank) + 0x18) ++#define MAX_BACKTOP26(bank) (MAX_BACKTOP_BASE(bank) + 0x19) ++#define MAX_BACKTOP27(bank) (MAX_BACKTOP_BASE(bank) + 0x1a) ++#define MAX_BACKTOP28(bank) (MAX_BACKTOP_BASE(bank) + 0x1b) ++#define MAX_BACKTOP29(bank) (MAX_BACKTOP_BASE(bank) + 0x1c) ++#define MAX_BACKTOP30(bank) (MAX_BACKTOP_BASE(bank) + 0x1d) ++#define MAX_BACKTOP31(bank) (MAX_BACKTOP_BASE(bank) + 0x1e) ++#define MAX_BACKTOP32(bank) (MAX_BACKTOP_BASE(bank) + 0x1f) ++ ++#define MAX9296_FSYNC_0 0x3a0 ++#define MAX9296_FSYNC_5 0x3a5 ++#define MAX9296_FSYNC_6 0x3a6 ++#define MAX9296_FSYNC_7 0x3a7 ++#define MAX9296_FSYNC_8 0x3a8 ++#define MAX9296_FSYNC_9 0x3a9 ++#define MAX9296_FSYNC_10 0x3aa ++#define MAX9296_FSYNC_11 0x3ab ++#define MAX9296_FSYNC_15 0x3af ++ ++#define MAX_MIPI_PHY_BASE 0x8a0 ++#define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00) ++#define MAX_MIPI_PHY2 (MAX_MIPI_PHY_BASE + 0x02) ++#define MAX_MIPI_PHY3 (MAX_MIPI_PHY_BASE + 0x03) ++#define MAX_MIPI_PHY4 (MAX_MIPI_PHY_BASE + 0x04) ++#define MAX_MIPI_PHY5 (MAX_MIPI_PHY_BASE + 0x05) ++#define MAX_MIPI_PHY6 (MAX_MIPI_PHY_BASE + 0x06) ++#define MAX_MIPI_PHY8 (MAX_MIPI_PHY_BASE + 0x08) ++#define MAX_MIPI_PHY9 (MAX_MIPI_PHY_BASE + 0x09) ++#define MAX_MIPI_PHY10 (MAX_MIPI_PHY_BASE + 0x0a) ++#define MAX_MIPI_PHY11 (MAX_MIPI_PHY_BASE + 0x0b) ++#define MAX_MIPI_PHY13 (MAX_MIPI_PHY_BASE + 0x0d) ++#define MAX_MIPI_PHY14 (MAX_MIPI_PHY_BASE + 0x0e) ++ ++#define MAX_MIPI_TX_BASE(n) (0x900 + 0x40 * n) ++#define MAX_MIPI_TX2(n) (MAX_MIPI_TX_BASE(n) + 0x02) ++#define MAX_MIPI_TX10(n) (MAX_MIPI_TX_BASE(n) + 0x0a) ++#define MAX_MIPI_TX11(n) (MAX_MIPI_TX_BASE(n) + 0x0b) ++#define MAX_MIPI_TX12(n) (MAX_MIPI_TX_BASE(n) + 0x0c) ++ ++/* 16 pairs of source-dest registers */ ++#define MAX_MIPI_MAP_SRC(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0d + (2 * n)) ++#define MAX_MIPI_MAP_DST(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0e + (2 * n)) ++/* Phy dst. Each reg contains 4 dest */ ++#define MAX_MIPI_MAP_DST_PHY(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x2d + n) ++ ++#define MAX_GMSL1_2(ch) (0xb02 + (0x100 * ch)) ++#define MAX_GMSL1_4(ch) (0xb04 + (0x100 * ch)) ++#define MAX_GMSL1_6(ch) (0xb06 + (0x100 * ch)) ++#define MAX_GMSL1_7(ch) (0xb07 + (0x100 * ch)) ++#define MAX_GMSL1_8(ch) (0xb08 + (0x100 * ch)) ++#define MAX_GMSL1_D(ch) (0xb0d + (0x100 * ch)) ++#define MAX_GMSL1_F(ch) (0xb0f + (0x100 * ch)) ++#define MAX_GMSL1_19(ch) (0xb19 + (0x100 * ch)) ++#define MAX_GMSL1_1B(ch) (0xb1b + (0x100 * ch)) ++#define MAX_GMSL1_1D(ch) (0xb1d + (0x100 * ch)) ++#define MAX_GMSL1_20(ch) (0xb20 + (0x100 * ch)) ++#define MAX_GMSL1_96(ch) (0xb96 + (0x100 * ch)) ++#define MAX_GMSL1_CA(ch) (0xbca + (0x100 * ch)) ++#define MAX_GMSL1_CB(ch) (0xbcb + (0x100 * ch)) ++ ++#define MAX_RLMS4(ch) (0x1404 + (0x100 * ch)) ++#define MAX_RLMSA(ch) (0x140A + (0x100 * ch)) ++#define MAX_RLMSB(ch) (0x140B + (0x100 * ch)) ++#define MAX_RLMSA4(ch) (0x14a4 + (0x100 * ch)) ++ ++#define MAX_RLMS58(ch) (0x1458 + (0x100 * ch)) ++#define MAX_RLMS59(ch) (0x1459 + (0x100 * ch)) ++#define MAX_RLMS95(ch) (0x1495 + (0x100 * ch)) ++#define MAX_RLMSC4(ch) (0x14c4 + (0x100 * ch)) ++#define MAX_RLMSC5(ch) (0x14c5 + (0x100 * ch)) ++ ++static inline int max9296_write(struct max9296_priv *priv, int reg, int val) ++{ ++ int ret; ++ ++ ret = regmap_write(priv->regmap, reg, val); ++ if (ret) ++ dev_dbg(&priv->client->dev, "write register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++static inline int max9296_read(struct max9296_priv *priv, int reg, int *val) ++{ ++ int ret; ++ ++ ret = regmap_read(priv->regmap, reg, val); ++ if (ret) ++ dev_dbg(&priv->client->dev, "read register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++static inline int max9296_update_bits(struct max9296_priv *priv, int reg, int mask, int bits) ++{ ++ int ret; ++ ++ ret = regmap_update_bits(priv->regmap, reg, mask, bits); ++ if (ret) ++ dev_dbg(&priv->client->dev, "update register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++#define des_read(reg, val) max9296_read(priv, reg, val) ++#define des_write(reg, val) max9296_write(priv, reg, val) ++#define des_update_bits(reg, mask, bits) max9296_update_bits(priv, reg, mask, bits) ++ ++static inline int max9296_ser_write(struct max9296_link *link, int reg, int val) ++{ ++ int ret; ++ ++ ret = regmap_write(link->regmap, reg, val); ++ if (ret < 0) ++ dev_dbg(&link->client->dev, "write register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++static inline int max9296_ser_read(struct max9296_link *link, int reg, u8 *val) ++{ ++ int ret; ++ ++ ret = regmap_read(link->regmap, reg, (int *)val); ++ if (ret) ++ dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++static inline int max9296_ser_update_bits(struct max9296_link *link, int reg, int mask, int bits) ++{ ++ int ret; ++ ++ ret = regmap_update_bits(link->regmap, reg, mask, bits); ++ if (ret) ++ dev_dbg(&link->client->dev, "update register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++#define ser_read(reg, val) max9296_ser_read(link, reg, val) ++#define ser_write(reg, val) max9296_ser_write(link, reg, val) ++#define ser_update_bits(reg, mask, bits) max9296_ser_update_bits(link, reg, mask, bits) +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296_debug.h b/drivers/media/i2c/soc_camera/gmsl/max9296_debug.h +new file mode 100644 +index 0000000..6bf03a2 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/max9296_debug.h +@@ -0,0 +1,462 @@ ++/* ++ * MAXIM max9296 GMSL2 driver debug stuff ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++static char *max9296_link_mode[4] = { ++ "Splitter mode", ++ "Link A", ++ "Link B", ++ "Dual link", ++}; ++ ++static char *line_status[8] = { ++ "Short to battery", ++ "Short to GND", ++ "Normal operation", ++ "Line open", ++ "Line-to-line short", ++ "Line-to-line short", ++ "Line-to-line short", ++ "Line-to-line short" ++}; ++ ++static char *paxket_cnt_types[] = { ++ "None", ++ "VIDEO", ++ "AUDIO", ++ "INFO Frame", ++ "SPI", ++ "I2C", ++ "UART", ++ "GPIO", ++ "AHDCP", ++ "RGMII", ++ "Reserved", ++ "Reserved", ++ "Reserved", ++ "Reserved", ++ "All", ++ "Unknown and packets with error", ++}; ++ ++static int max9296_gmsl1_get_link_lock(struct max9296_priv *priv, int link_n); ++static int max9296_gmsl2_get_link_lock(struct max9296_priv *priv, int link_n); ++ ++#define reg_bits(x, y) ((reg >> (x)) & ((1 << (y)) - 1)) ++ ++static ssize_t max_link_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct max9296_priv *priv = i2c_get_clientdata(client); ++ int i = -1; ++ int j; ++ int gmsl2; ++ u32 crc = 0 ; ++ char *_buf = buf; ++ int reg = 0; ++ ++ if (!sscanf(attr->attr.name, "link_%d", &i)) ++ return -EINVAL; ++ ++ if (i < 0) ++ return -EINVAL; ++ ++ if (i >= priv->n_links) { ++ buf += sprintf(buf, "\n"); ++ return (buf - _buf); ++ } ++ ++ buf += sprintf(buf, "Link %c status\n", 'A' + i); ++ ++ des_read(MAX9296_REG6, ®); ++ gmsl2 = !!(reg & BIT(6 + i)); ++ buf += sprintf(buf, "Link mode: %s\n", gmsl2 ? "GMSL2" : "GMSL1"); ++ ++ if (gmsl2) { ++ buf += sprintf(buf, "GMSL2 Link lock: %d\n", ++ max9296_gmsl2_get_link_lock(priv, i)); ++ } else { ++ reg = max9296_gmsl1_get_link_lock(priv, i); ++ buf += sprintf(buf, ++ "GMSL1_CB: 0x%02x:\t" ++ "LOCKED_G1: %d\n", ++ reg, reg_bits(0, 1)); ++ ++ des_read(MAX_GMSL1_CA(i), ®); ++ buf += sprintf(buf, ++ "GMSL1_CA: 0x%02x:\t" ++ "PHASELOCK: %d, WBLOCK_G1: %d, DATAOK: %d\n", ++ reg, reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ ++ des_read(MAX_GMSL1_1B(i), ®); ++ buf += sprintf(buf, ++ "GMSL1_1B: 0x%02x:\t" ++ "LINE_CRC_ERR: %d ", ++ reg, reg_bits(2, 1)); ++ for (j = 0; j < 4; j++) { ++ des_read(MAX_GMSL1_20(i) + j, ®); ++ crc = crc | ((reg & 0xff) << (j * 8)); ++ } ++ buf += sprintf(buf, "last crc 0x%08x\n", crc); ++ ++ des_read(MAX_GMSL1_19(i), ®); ++ buf += sprintf(buf, ++ "GMSL1_19: CC_CRC_ERRCNT %d\n", ++ reg); ++ ++ des_read(MAX_GMSL1_1D(i), ®); ++ buf += sprintf(buf, ++ "GMSL1_1D: 0x%02x:\t" ++ "UNDERBOOST: %d, AEQ-BST: %d\n", ++ reg, reg_bits(4, 1), reg_bits(0, 4)); ++ ++ { ++ des_read(MAX9296_CTRL1, ®); ++ buf += sprintf(buf, ++ "CTRL1: 0x%02x:\t" ++ "Cable: %s\n", ++ reg, ++ reg_bits(i * 2, 1) ? "coax" : "stp"); ++ ++ des_read(MAX9296_REG26, ®); ++ buf += sprintf(buf, ++ "REG26: 0x%02x:\t" ++ "Line status: %s\n", ++ reg, ++ line_status[reg_bits(i * 4, 3)]); ++ ++ des_read(MAX9296_CNT(i), ®); ++ buf += sprintf(buf, ++ "CNT%d: DEC_ERR_x: %d\n", ++ i, reg); ++ } ++ /* TODO: add same for 96712 */ ++ } ++ ++ return (buf - _buf); ++} ++ ++static ssize_t max_pipe_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct max9296_priv *priv = i2c_get_clientdata(client); ++ char *_buf = buf; ++ int pipe = 0; ++ int map; ++ int maps_en = 0; ++ int pipes_en; ++ int reg = 0; ++ ++ if (!sscanf(attr->attr.name, "pipe_%d", &pipe)) ++ return -EINVAL; ++ ++ if (pipe < 0) ++ return -EINVAL; ++ ++ if (pipe >= MAX9296_MAX_PIPES) { ++ buf += sprintf(buf, "\n"); ++ return (buf - _buf); ++ } ++ ++ des_read(MAX9296_REG2, &pipes_en); ++ pipes_en = pipes_en >> 4; ++ ++ buf += sprintf(buf, "Video Pipe %d %s\n", ++ pipe, (pipes_en & BIT(pipe)) ? "ENABLED" : "disabled"); ++ if (!(pipes_en & BIT(pipe))) ++ goto out; ++ ++ des_read(MAX_VPRBS(pipe), ®); ++ /* bit 5 is not valid for MAX96712 */ ++ buf += sprintf(buf, ++ "\tVPRBS: 0x%02x\t" ++ "VPRBS_FAIL: %d," ++ "VIDEO_LOCK: %d\n", ++ reg, ++ reg_bits(5, 1), reg_bits(0, 1)); ++ ++ /* show source */ ++ /* TODO */ ++ ++ /* show maps */ ++ des_read(MAX_MIPI_TX11(pipe), &maps_en); ++ des_read(MAX_MIPI_TX12(pipe), ®); ++ maps_en |= reg << 8; ++ ++ for (map = 0; map < MAX9296_MAX_PIPE_MAPS; map++) { ++ int src, dst, mipi; ++ if (!(maps_en & BIT(map))) ++ continue; ++ ++ des_read(MAX_MIPI_MAP_SRC(pipe, map), &src); ++ des_read(MAX_MIPI_MAP_DST(pipe, map), &dst); ++ des_read(MAX_MIPI_MAP_DST_PHY(pipe, map / 4), &mipi); ++ ++ buf += sprintf(buf, " MAP%d: DT %02x, VC %d -> DT %02x, VC %d MIPI %d\n", ++ map, ++ src & 0x3f, (src >> 6) & 0x03, dst & 0x3f, (dst >> 6) & 0x03, ++ (mipi >> ((map % 4) * 2)) & 0x03); ++ } ++ ++ des_read(MAX9296_CNT4 + pipe, ®); ++ buf += sprintf(buf, "VID_PXL_CRC_ERR: 0x%02x\n", reg); ++ ++ des_read(MAX_VIDEO_RX0(pipe), ®); ++ buf += sprintf(buf, ++ "VIDEO_RX0: 0x%02x\t" ++ "LCRC_ERR: %d, " ++ "LINE_CRC_SEL: %d, " ++ "LINE_CRC_EN: %d, " ++ "DIS_PKT_DET: %d\n", ++ reg, ++ reg_bits(7, 1), ++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ des_read(MAX_VIDEO_RX3(pipe), ®); ++ buf += sprintf(buf, ++ "VIDEO_RX3: 0x%02x\t" ++ "HD_TR_MODE: %d, " ++ "DLOCKED: %d, " ++ "VLOCKED: %d, " ++ "HLOCKED: %d, " ++ "DTRACKEN: %d, " ++ "VTRACKEN: %d, " ++ "HTRACKEN: %d\n", ++ reg, ++ reg_bits(6, 1), ++ reg_bits(5, 1), reg_bits(4, 1), reg_bits(3, 1), ++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ des_read(MAX_VIDEO_RX8(pipe), ®); ++ buf += sprintf(buf, ++ "VIDEO_RX8: 0x%02x\t" ++ "VID_BLK_LEN_ERR: %d, " ++ "VID_LOCK: %d, " ++ "VID_PKT_DET: %d, " ++ "VID_SEQ_ERR: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), ++ reg_bits(5, 1), reg_bits(4, 1)); ++ des_read(MAX_VIDEO_RX10(pipe), ®); ++ buf += sprintf(buf, ++ "VIDEO_RX10: 0x%02x\t" ++ "MASK_VIDEO_DE: %d\n", ++ reg, ++ reg_bits(6, 1)); ++ ++out: ++ return (buf - _buf); ++} ++ ++static ssize_t max_stat_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct max9296_priv *priv = i2c_get_clientdata(client); ++ int i; ++ char *_buf = buf; ++ int reg = 0, reg2 = 0; ++ ++ des_read(MAX9296_REG3, ®); ++ buf += sprintf(buf, ++ "REG_REG3: 0x%02x\t" ++ "LOCK_CFG: %d\n", ++ reg, reg_bits(7, 1)); ++ ++ des_read(MAX9296_CTRL0, ®); ++ buf += sprintf(buf, ++ "CTRL0: 0x%02x\n", ++ reg); ++ ++ des_read(MAX9296_CTRL3, ®); ++ buf += sprintf(buf, ++ "CTRL3: 0x%02x:\t" ++ "LINK_MODE: %s, " ++ "GMSL2 LOCKED: %d, ERROR: %d, " ++ "CMU_LOCKED: %d\n", ++ reg, ++ max9296_link_mode[reg_bits(4, 2)], ++ reg_bits(3, 1), reg_bits(2 ,1), ++ reg_bits(1, 1)); ++ /* get errors */ ++ if (reg_bits(2, 1)) { ++ des_read(MAX9296_INTR3, ®); ++ buf += sprintf(buf, ++ "INTR3: 0x%02x:\t" ++ "PHY_INT_OEN_B: %d " ++ "PHY_INT_OEN_A: %d " ++ "REM_ERR_FLAG: %d " ++ "MEM_INT_ERR_FLAG: %d " ++ "LFLT_INT: %d " ++ "IDLE_ERR_FLAG: %d " ++ "DEC_ERR_FLAG_B: %d " ++ "DEC_ERR_FLAG_A: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1), ++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ des_read(MAX9296_INTR5, ®); ++ buf += sprintf(buf, ++ "INTR5: 0x%02x:\t" ++ "EOM_ERR_FLAG_B: %d " ++ "EOM_ERR_FLAG_A: %d " ++ "MAX_RT_FLAG: %d " ++ "RT_CNT_FLAG: %d " ++ "PKT_CNT_FLAG: %d " ++ "WM_ERR_FLAG: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), ++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ des_read(MAX9296_INTR7, ®); ++ buf += sprintf(buf, ++ "INTR7: 0x%02x:\t" ++ "VDDCMP_INT_FLAG: %d " ++ "PORZ_INT_FLAG: %d " ++ "VDDBAD_INT_FLAG: %d " ++ "LCRC_ERR_FLAG: %d " ++ "VPRBS_ERR_FLAG: %d " ++ "VID_PXL_CRC_ERR: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), ++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(0, 1)); ++ ++ des_read(MAX9296_DEC_ERR_A, ®); ++ buf += sprintf(buf, ++ "ERR_A: 0x%02x\n", reg); ++ des_read(MAX9296_DEC_ERR_B, ®); ++ buf += sprintf(buf, ++ "ERR_B: 0x%02x\n", reg); ++ des_read(MAX9296_IDLE_ERR, ®); ++ buf += sprintf(buf, ++ "IDLE_ERR: 0x%02x\n", reg); ++ des_read(MAX9296_PKT_CNT, ®); ++ buf += sprintf(buf, ++ "PKT_CNT: 0x%02x\n", reg); ++ ++ } ++ ++ des_read(MAX9296_CNT(2), ®); ++ buf += sprintf(buf, ++ "CNT2: IDLE_ERR: %d\n", ++ reg); ++ ++ des_read(MAX9296_CNT(3), ®); ++ des_read(MAX9296_RX_0, ®2); ++ buf += sprintf(buf, ++ "CNT3: PKT_CNT: 0x%02x (type %x: %s)\n", ++ reg, reg2 & 0x0f, ++ paxket_cnt_types[reg2 & 0x0f]); ++ ++ des_read(MAX9296_RX_3, ®); ++ buf += sprintf(buf, ++ "RX3: 0x%02x:\t" ++ "PRBS_SYNCED_B: %d, " ++ "SYNC_LOCKED_B: %d, " ++ "WBLOCK_B: %d, " ++ "FAILLOCK_B: %d, " ++ "PRBS_SYNCED_A: %d, " ++ "SYNC_LOCKED_A: %d, " ++ "WBLOCK_A: %d, " ++ "FAILLOCK_A: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1), ++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ ++ des_read(MAX_BACKTOP1(0), ®); ++ buf += sprintf(buf, ++ "BACKTOP1: 0x%02x:\t" ++ "CSIPLLU_LOCK: %d, " ++ "CSIPLLZ_LOCK: %d, " ++ "CSIPLLY_LOCK: %d, " ++ "CSIPLLX_LOCK: %d, " ++ "LINE_SPL2: %d, " ++ "LINE_SPL1: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1), ++ reg_bits(3, 1), reg_bits(2, 1)); ++ ++ des_read(MAX_BACKTOP11(0), ®); ++ buf += sprintf(buf, ++ "BACKTOP11: 0x%02x:\t" ++ "CMD_OWERFLOW4: %d, " ++ "CMD_OWERFLOW3: %d, " ++ "CMD_OWERFLOW2: %d, " ++ "CMD_OWERFLOW1: %d, " ++ "LMO_Z: %d, " ++ "LMO_Y: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1), ++ reg_bits(2, 1), reg_bits(1, 1)); ++ ++ for (i = 0; i < MAX9296_MAX_MIPI; i++) { ++ buf += sprintf(buf, "MIPI %d\n", i); ++ des_read(MAX_MIPI_TX2(i), ®); ++ buf += sprintf(buf, ++ "\tMIPI_TX2: 0x%02x\n", ++ reg); ++ } ++ ++ return (buf - _buf); ++} ++ ++static DEVICE_ATTR(link_0, S_IRUGO, max_link_show, NULL); ++static DEVICE_ATTR(link_1, S_IRUGO, max_link_show, NULL); ++static DEVICE_ATTR(link_2, S_IRUGO, max_link_show, NULL); ++static DEVICE_ATTR(link_3, S_IRUGO, max_link_show, NULL); ++static DEVICE_ATTR(pipe_0, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_1, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_2, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_3, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_4, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_5, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_6, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_7, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(stat, S_IRUGO, max_stat_show, NULL); ++ ++static struct attribute *max9296_attributes[] = { ++ &dev_attr_link_0.attr, ++ &dev_attr_link_1.attr, ++ &dev_attr_link_2.attr, ++ &dev_attr_link_3.attr, ++ &dev_attr_pipe_0.attr, ++ &dev_attr_pipe_1.attr, ++ &dev_attr_pipe_2.attr, ++ &dev_attr_pipe_3.attr, ++ &dev_attr_pipe_4.attr, ++ &dev_attr_pipe_5.attr, ++ &dev_attr_pipe_6.attr, ++ &dev_attr_pipe_7.attr, ++ &dev_attr_stat.attr, ++ NULL ++}; ++ ++static const struct attribute_group max9296_group = { ++ .attrs = max9296_attributes, ++}; ++ ++int max9296_debug_add(struct max9296_priv *priv) ++{ ++ int ret; ++ ++ ret = sysfs_create_group(&priv->client->dev.kobj, &max9296_group); ++ if (ret < 0) { ++ dev_err(&priv->client->dev, "Sysfs registration failed\n"); ++ return ret; ++ } ++ ++ /* count video packets */ ++ des_update_bits(MAX9296_RX_0, 0x0f, 0x01); ++ ++ return ret; ++} ++ ++void max9296_debug_remove(struct max9296_priv *priv) ++{ ++ sysfs_remove_group(&priv->client->dev.kobj, &max9296_group); ++} +diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c +new file mode 100644 +index 0000000..af5e1d7 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c +@@ -0,0 +1,1423 @@ ++/* ++ * MAXIM max96712 GMSL2 driver ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/i2c.h> ++#include <linux/i2c-mux.h> ++#include <linux/module.h> ++#include <linux/regulator/consumer.h> ++#include <linux/notifier.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_gpio.h> ++#include <linux/of_graph.h> ++#include <linux/reboot.h> ++#include <linux/regmap.h> ++#include <linux/videodev2.h> ++ ++#include <media/v4l2-common.h> ++#include <media/v4l2-clk.h> ++#include <media/v4l2-device.h> ++#include <media/v4l2-subdev.h> ++ ++#include "common.h" ++#include "max96712.h" ++#include "max96712_debug.h" ++ ++static char mbus_default[10] = "dvp"; /* mipi, dvp */ ++ ++static int conf_link; ++module_param(conf_link, int, 0644); ++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); ++ ++static int poc_trig; ++module_param(poc_trig, int, 0644); ++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during RC setup. Useful on systems with dedicated PoC and unstable ser-des lock"); ++ ++static int him; ++module_param(him, int, 0644); ++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)"); ++ ++static int fsync_period; ++module_param(fsync_period, int, 0644); ++MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)"); ++ ++static int hsync; ++module_param(hsync, int, 0644); ++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); ++ ++static int vsync = 1; ++module_param(vsync, int, 0644); ++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); ++ ++static int gpio_resetb; ++module_param(gpio_resetb, int, 0644); ++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)"); ++ ++static int active_low_resetb; ++module_param(active_low_resetb, int, 0644); ++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)"); ++ ++static int timeout_n = 100; ++module_param(timeout_n, int, 0644); ++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)"); ++ ++static int poc_delay = 50; ++module_param(poc_delay, int, 0644); ++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)"); ++ ++static int bws; ++module_param(bws, int, 0644); ++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)"); ++ ++static int dbl = 1; ++module_param(dbl, int, 0644); ++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)"); ++ ++static int dt = MIPI_DT_YUV8; ++module_param(dt, int, 0644); ++MODULE_PARM_DESC(dt, " DataType (default: 0x1e - YUV8)"); ++ ++static unsigned long crossbar = 0xba9876543210; ++module_param(crossbar, ulong, 0644); ++MODULE_PARM_DESC(crossbar, " Serializer crossbar setup (default: ba9876543210 - reversed)"); ++ ++static int gmsl = MODE_GMSL2; ++module_param(gmsl, int, 0644); ++MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)"); ++ ++static char *mbus = "dvp"; ++module_param(mbus, charp, 0644); ++MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)"); ++ ++static int gpio0 = -1, gpio1 = -1, gpio7 = -1, gpio8 = -1; ++module_param(gpio0, int, 0644); ++MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 tri-state)"); ++module_param(gpio1, int, 0644); ++MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 tri-state)"); ++module_param(gpio7, int, 0644); ++MODULE_PARM_DESC(gpio7, " GPIO7 function select (default: GPIO7 tri-state)"); ++module_param(gpio8, int, 0644); ++MODULE_PARM_DESC(gpio8, " GPIO8 function select (default: GPIO8 tri-state)"); ++ ++static const struct regmap_config max96712_regmap[] = { ++ { ++ /* max96712 */ ++ .reg_bits = 16, ++ .val_bits = 8, ++ .max_register = 0x1f03, ++ }, { ++ /* max9271/max96705 */ ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = 0xff, ++ }, { ++ /* max9695 */ ++ .reg_bits = 16, ++ .val_bits = 8, ++ .max_register = 0x1b03, ++ } ++}; ++ ++static void max96712_write_remote_verify(struct max96712_priv *priv, int link_n, u8 reg, int val) ++{ ++ struct max96712_link *link = priv->link[link_n]; ++ int timeout; ++ ++ for (timeout = 0; timeout < 10; timeout++) { ++ u8 val2 = 0; ++ ++ ser_write(reg, val); ++ ser_read(reg, &val2); ++ if (val2 == val) ++ break; ++ ++ usleep_range(1000, 1500); ++ } ++ ++ if (timeout >= 10) ++ dev_err(&priv->client->dev, "timeout remote write acked\n"); ++} ++ ++static void max96712_reset_oneshot(struct max96712_priv *priv, int mask) ++{ ++ int timeout; ++ int reg = 0; ++ ++ mask &= 0x0f; ++ des_update_bits(MAX96712_CTRL1, mask, mask); /* set reset one-shot */ ++ ++ /* wait for one-shot bit self-cleared */ ++ for (timeout = 0; timeout < 100; timeout++) { ++ des_read(MAX96712_CTRL1, ®); ++ if (!(reg & mask)) ++ break; ++ ++ msleep(1); ++ } ++ ++ if (reg & mask) ++ dev_err(&priv->client->dev, "Failed reset oneshot 0x%x\n", mask); ++} ++ ++/* ----------------------------------------------------------------------------- ++ * MIPI, mapping, routing ++ */ ++ ++static void max96712_pipe_override(struct max96712_priv *priv, unsigned int pipe, ++ unsigned int dt, unsigned int vc) ++{ ++ int bpp, bank; ++ ++ bpp = mipi_dt_to_bpp(dt); ++ bank = pipe / 4; ++ pipe %= 4; ++ ++ if (priv->dbl == 1) { ++ /* DBL=1 is MUX mode, DBL=0 is Normal mode */ ++ des_update_bits(MAX_BACKTOP27(bank), BIT(pipe + 4), BIT(pipe + 4)); /* enable MUX mode */ ++ bpp = bpp / 2; /* divide because of MUX=1 */ ++ } ++ ++ switch (pipe) { ++ case 0: ++ /* Pipe X: 0 or 4 */ ++ des_update_bits(MAX_BACKTOP12(bank), 0x1f << 3, bpp << 3); ++ des_update_bits(MAX_BACKTOP13(bank), 0x0f, vc); ++ des_update_bits(MAX_BACKTOP15(bank), 0x3f, dt); ++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(6), BIT(6)); /* enalbe s/w override */ ++ break; ++ case 1: ++ /* Pipe Y: 1 or 5 */ ++ des_update_bits(MAX_BACKTOP18(bank), 0x1f, bpp); ++ des_update_bits(MAX_BACKTOP13(bank), 0x0f << 4, vc << 4); ++ des_update_bits(MAX_BACKTOP16(bank), 0x0f, dt & 0x0f); ++ des_update_bits(MAX_BACKTOP15(bank), 0x03 << 6, (dt & 0x30) << 2); ++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(7), BIT(7)); /* enable s/w override */ ++ break; ++ case 2: ++ /* Pipe Z: 2 or 6 */ ++ des_update_bits(MAX_BACKTOP19(bank), 0x03, bpp & 0x03); ++ des_update_bits(MAX_BACKTOP18(bank), 0xe0, (bpp & 0x1c) << 3); ++ des_update_bits(MAX_BACKTOP14(bank), 0x0f, vc); ++ des_update_bits(MAX_BACKTOP17(bank), 0x03, dt & 0x03); ++ des_update_bits(MAX_BACKTOP16(bank), 0x0f << 4, (dt & 0x3c) << 2); ++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(6), BIT(6)); /* enable s/w override */ ++ break; ++ case 3: ++ /* Pipe U: 3 or 7 */ ++ des_update_bits(MAX_BACKTOP19(bank), 0xfc, bpp << 2); ++ des_update_bits(MAX_BACKTOP14(bank), 0x0f << 4, vc << 4); ++ des_update_bits(MAX_BACKTOP17(bank), 0x3f << 2, dt << 2); ++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(7), BIT(7)); /* enable s/w override */ ++ break; ++ } ++} ++ ++static void max96712_set_pipe_to_mipi_mapping(struct max96712_priv *priv, ++ unsigned int pipe, unsigned int map_n, ++ unsigned int in_dt, unsigned int in_vc, ++ unsigned int out_dt, unsigned int out_vc, unsigned int out_mipi) ++{ ++ int offset = 2 * (map_n % 4); ++ ++ des_write(MAX_MIPI_MAP_SRC(pipe, map_n), (in_vc << 6) | in_dt); ++ des_write(MAX_MIPI_MAP_DST(pipe, map_n), (out_vc << 6) | out_dt); ++ des_update_bits(MAX_MIPI_MAP_DST_PHY(pipe, map_n / 4), 0x03 << offset, out_mipi << offset); ++ des_update_bits(MAX_MIPI_TX11(pipe), BIT(map_n), BIT(map_n)); /* enable SRC_n to DST_n mapping */ ++} ++ ++static void max96712_mipi_setup(struct max96712_priv *priv) ++{ ++ des_write(MAX96712_VIDEO_PIPE_EN, 0); /* disable all pipes */ ++ ++ des_write(MAX_MIPI_PHY0, 0x04); /* MIPI Phy 2x4 mode */ ++ des_write(MAX_MIPI_PHY3, 0xe4); /* Lane map: straight */ ++ des_write(MAX_MIPI_PHY4, 0xe4); /* Lane map: straight */ ++ //des_write(MAX_MIPI_PHY5, 0x00); /* HS_prepare time, non-inverted polarity */ ++ //des_write(MAX_MIPI_PHY6, 0x00); ++ ++ des_write(MAX_MIPI_TX10(1), 0xc0); /* MIPI1: 4 lanes */ ++ des_write(MAX_MIPI_TX10(2), 0xc0); /* MIPI2: 4 lanes */ ++ ++ des_update_bits(MAX_BACKTOP22(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5)); /* MIPI rate */ ++ des_update_bits(MAX_BACKTOP25(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5)); ++ des_update_bits(MAX_BACKTOP28(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5)); ++ des_update_bits(MAX_BACKTOP31(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5)); ++ ++ des_update_bits(MAX_MIPI_PHY2, 0xf0, 0xf0); /* enable all MIPI PHYs */ ++} ++ ++/* ----------------------------------------------------------------------------- ++ * GMSL1 ++ */ ++ ++static int max96712_gmsl1_sensor_reset(struct max96712_priv *priv, int link_n, int reset_on) ++{ ++ struct max96712_link *link = priv->link[link_n]; ++ ++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) ++ return -EINVAL; ++ ++ /* sensor reset/unreset */ ++ ser_write(0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */ ++ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on)); ++ ser_write(0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ ++ ++ return 0; ++} ++ ++static void max96712_gmsl1_cc_enable(struct max96712_priv *priv, int link, int on) ++{ ++ des_update_bits(MAX_GMSL1_4(link), 0x03, on ? 0x03 : 0x00); ++ usleep_range(2000, 2500); ++} ++ ++static int max96712_gmsl1_get_link_lock(struct max96712_priv *priv, int link_n) ++{ ++ int val = 0; ++ ++ des_read(MAX_GMSL1_CB(link_n), &val); ++ ++ return !!(val & BIT(0)); ++} ++ ++static void max96712_gmsl1_link_crossbar_setup(struct max96712_priv *priv, int link, int dt) ++{ ++ /* Always decode reversed bus, since we always reverse on serializer (old imagers need this) */ ++ switch (dt) { ++ case MIPI_DT_YUV8: ++ des_write(MAX_CROSS(link, 0), 7); ++ des_write(MAX_CROSS(link, 1), 6); ++ des_write(MAX_CROSS(link, 2), 5); ++ des_write(MAX_CROSS(link, 3), 4); ++ des_write(MAX_CROSS(link, 4), 3); ++ des_write(MAX_CROSS(link, 5), 2); ++ des_write(MAX_CROSS(link, 6), 1); ++ des_write(MAX_CROSS(link, 7), 0); ++ ++ if (priv->dbl == 0) { ++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */ ++ des_write(MAX_CROSS(link, 8), 15); ++ des_write(MAX_CROSS(link, 9), 14); ++ des_write(MAX_CROSS(link, 10), 13); ++ des_write(MAX_CROSS(link, 11), 12); ++ des_write(MAX_CROSS(link, 12), 11); ++ des_write(MAX_CROSS(link, 13), 10); ++ des_write(MAX_CROSS(link, 14), 9); ++ des_write(MAX_CROSS(link, 15), 8); ++ } ++ break; ++ case MIPI_DT_RAW12: ++ des_write(MAX_CROSS(link, 0), 11); ++ des_write(MAX_CROSS(link, 1), 10); ++ des_write(MAX_CROSS(link, 2), 9); ++ des_write(MAX_CROSS(link, 3), 8); ++ des_write(MAX_CROSS(link, 4), 7); ++ des_write(MAX_CROSS(link, 5), 6); ++ des_write(MAX_CROSS(link, 6), 5); ++ des_write(MAX_CROSS(link, 7), 4); ++ des_write(MAX_CROSS(link, 8), 3); ++ des_write(MAX_CROSS(link, 9), 2); ++ des_write(MAX_CROSS(link, 10), 1); ++ des_write(MAX_CROSS(link, 11), 0); ++ ++ if (priv->dbl == 0) { ++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */ ++ des_write(MAX_CROSS(link, 12), 23); ++ des_write(MAX_CROSS(link, 13), 22); ++ des_write(MAX_CROSS(link, 14), 21); ++ des_write(MAX_CROSS(link, 15), 20); ++ des_write(MAX_CROSS(link, 16), 19); ++ des_write(MAX_CROSS(link, 17), 18); ++ des_write(MAX_CROSS(link, 18), 17); ++ des_write(MAX_CROSS(link, 19), 16); ++ des_write(MAX_CROSS(link, 20), 15); ++ des_write(MAX_CROSS(link, 21), 14); ++ des_write(MAX_CROSS(link, 22), 13); ++ des_write(MAX_CROSS(link, 23), 12); ++ } ++ break; ++ default: ++ dev_err(&priv->client->dev, "crossbar for dt %d is not supported\n", dt); ++ break; ++ } ++ ++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */ ++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */ ++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */ ++} ++ ++static void max96712_gmsl1_initial_setup(struct max96712_priv *priv) ++{ ++ int i; ++ ++ des_update_bits(MAX96712_REG6, 0xf0, 0); /* set GMSL1 mode */ ++ des_write(MAX96712_REG26, 0x11); /* 187.5M/3G */ ++ des_write(MAX96712_REG27, 0x11); /* 187.5M/3G */ ++ ++ for (i = 0; i < priv->n_links; i++) { ++ des_write(MAX_GMSL1_2(i), 0x03); /* Autodetect serial data rate range */ ++ des_write(MAX_GMSL1_4(i), 0); /* disable REV/FWD CC */ ++ des_update_bits(MAX_GMSL1_6(i), BIT(7), priv->him ? BIT(7) : 0); /* HIM/Legacy mode */ ++ des_write(MAX_GMSL1_7(i), (priv->dbl ? BIT(7) : 0) | /* DBL mode */ ++ (priv->bws ? BIT(5) : 0) | /* BWS 32/24-bit */ ++ (priv->hibw ? BIT(3) : 0) | /* High-bandwidth mode */ ++ (priv->hven ? BIT(2) : 0)); /* HS/VS encoding enable */ ++ des_write(MAX_GMSL1_D(i), 0); /* disable artificial ACKs, RC conf disable */ ++ des_write(MAX_GMSL1_F(i), 0); /* disable DE processing */ ++ des_write(MAX_GMSL1_96(i), (0x13 << 3) | 0x3); /* color map: RAW12 double - i.e. bypass packet as is */ ++ } ++} ++ ++static int max96712_gmsl1_reverse_channel_setup(struct max96712_priv *priv, int link_n) ++{ ++ struct max96712_link *link = priv->link[link_n]; ++ int ser_addrs[] = { 0x40 }; /* possible MAX9271/MAX96705 addresses on i2c bus */ ++ int lock_sts; ++ int timeout = priv->timeout; ++ char timeout_str[40]; ++ u8 val = 0; ++ int ret = 0; ++ ++ des_write(MAX_GMSL1_D(link_n), 0x81); /* enable artificial ACKs, RC conf mode */ ++ des_write(MAX_RLMSC5(link_n), 0xa0); /* override RC pulse length */ ++ des_write(MAX_RLMSC4(link_n), 0x80); /* override RC rise/fall time */ ++ usleep_range(2000, 2500); ++ des_write(MAX_GMSL1_4(link_n), 0x3); /* enable REV/FWD CC */ ++ des_write(MAX96712_REG6, BIT(link_n)); /* GMSL1 mode, enable GMSL link# */ ++ max96712_reset_oneshot(priv, BIT(link_n)); ++ usleep_range(2000, 2500); ++ ++ for (; timeout > 0; timeout--) { ++ if (priv->him) { ++ /* HIM mode setup */ ++ __reg8_write(ser_addrs[0], 0x4d, 0xc0); ++ usleep_range(2000, 2500); ++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */ ++ usleep_range(2000, 2500); ++ if (priv->bws) { ++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */ ++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */ ++ (0x80) | /* DBL=1 in serializer */ ++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */ ++ usleep_range(2000, 2500); ++ } ++ } else { ++ /* Legacy mode setup */ ++ des_write(MAX_RLMS95(link_n), 0x88); /* override RC Tx amplitude */ ++ usleep_range(2000, 2500); ++ ++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */ ++ usleep_range(2000, 2500); ++ __reg8_write(ser_addrs[0], 0x08, 0x01); /* RC receiver high threshold enable */ ++ __reg8_write(ser_addrs[0], 0x97, 0x5f); /* enable RC programming (MAX96705-MAX96711 only) */ ++ usleep_range(2000, 2500); ++ ++ if (priv->bws) { ++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */ ++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */ ++ (0x80) | /* DBL=1 in serializer */ ++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */ ++ usleep_range(2000, 2500); ++ } ++ ++ des_write(MAX_RLMS95(link_n), 0xd3); /* increase RC Tx amplitude */ ++ usleep_range(2000, 2500); ++ } ++ ++ __reg8_read(ser_addrs[0], 0x1e, &val); ++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) { ++ link->ser_id = val; ++ __reg8_write(ser_addrs[0], 0x00, link->ser_addr << 1); /* relocate serizlizer on I2C bus */ ++ usleep_range(2000, 2500); ++ break; ++ } ++ ++ /* Check if already initialized (after reboot/reset ?) */ ++ ser_read(0x1e, &val); ++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) { ++ link->ser_id = val; ++ ser_write(0x04, 0x43); /* enable RC, conf_link */ ++ usleep_range(2000, 2500); ++ ret = -EADDRINUSE; ++ break; ++ } ++ ++ if (poc_trig) { ++ if (!IS_ERR(link->poc_reg) && (timeout % poc_trig == 0)) { ++ regulator_disable(link->poc_reg); /* POC power off */ ++ mdelay(200); ++ ret = regulator_enable(link->poc_reg); /* POC power on */ ++ if (ret) ++ dev_err(&link->client->dev, "failed to enable poc regulator\n"); ++ mdelay(priv->poc_delay); ++ } ++ } ++ } ++ ++ max96712_gmsl1_sensor_reset(priv, link_n, 0); /* sensor un-reset */ ++ ++ des_write(MAX_GMSL1_D(link_n), 0); /* disable artificial ACKs, RC conf disable */ ++ usleep_range(2000, 2500); ++ des_read(MAX_GMSL1_CB(link_n), &lock_sts); ++ lock_sts = !!(lock_sts & 0x01); ++ ++ if (!timeout) { ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++ priv->links_mask |= BIT(link_n); ++ ++out: ++ sprintf(timeout_str, " retries=%d lock_sts=%d", priv->timeout - timeout, lock_sts); ++ dev_info(&priv->client->dev, "GMSL1 link%d %s %sat 0x%x %s %s\n", link_n, chip_name(link->ser_id), ++ ret == -EADDRINUSE ? "already " : "", link->ser_addr, ++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", ++ priv->timeout - timeout ? timeout_str : ""); ++ return ret; ++} ++ ++static int max96712_gmsl1_link_serializer_setup(struct max96712_priv *priv, int link_n) ++{ ++ struct max96712_link *link = priv->link[link_n]; ++ ++ /* GMSL setup */ ++ ser_write(0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ ++ ser_write(0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */ ++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */ ++ (0x80) | /* DBL=1 in serializer */ ++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */ ++ usleep_range(2000, 2500); ++ ser_write(0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */ ++ usleep_range(2000, 2500); ++ ++ if (link->ser_id != MAX9271_ID) { ++ switch (priv->dt) { ++ case MIPI_DT_YUV8: ++ if (priv->dbl == 1) { ++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */ ++ ser_write(0x20, priv->cb[7]); ++ ser_write(0x21, priv->cb[6]); ++ ser_write(0x22, priv->cb[5]); ++ ser_write(0x23, priv->cb[4]); ++ ser_write(0x24, priv->cb[3]); ++ ser_write(0x25, priv->cb[2]); ++ ser_write(0x26, priv->cb[1]); ++ ser_write(0x27, priv->cb[0]); ++ ++ /* this is second byte in the packet (DBL=1 in serializer always) */ ++ ser_write(0x30, priv->cb[7] + 16); ++ ser_write(0x31, priv->cb[6] + 16); ++ ser_write(0x32, priv->cb[5] + 16); ++ ser_write(0x33, priv->cb[4] + 16); ++ ser_write(0x34, priv->cb[3] + 16); ++ ser_write(0x35, priv->cb[2] + 16); ++ ser_write(0x36, priv->cb[1] + 16); ++ ser_write(0x37, priv->cb[0] + 16); ++ } else { ++ /* setup crossbar for YUV8/RAW8: reversed DVP bus */ ++ ser_write(0x20, priv->cb[4]); ++ ser_write(0x21, priv->cb[3]); ++ ser_write(0x22, priv->cb[2]); ++ ser_write(0x23, priv->cb[1]); ++ ser_write(0x24, priv->cb[0]); ++ ser_write(0x25, 0x40); ++ ser_write(0x26, 0x40); ++ if (link->ser_id == MAX96705_ID) { ++ ser_write(0x27, 14); /* HS: D14->D18 */ ++ ser_write(0x28, 15); /* VS: D15->D19 */ ++ ser_write(0x29, 14); /* DE: D14->D20 */ ++ } ++ if (link->ser_id == MAX96707_ID) { ++ ser_write(0x27, 12); /* HS: D12->D18, this is a virtual NC pin, hence it is D14 at HS */ ++ ser_write(0x28, 13); /* VS: D13->D19 */ ++ ser_write(0x29, 12); /* DE: D12->D20 */ ++ } ++ ser_write(0x2A, 0x40); ++ ++ /* this is second byte in the packet (DBL=1 in serializer) */ ++ ser_write(0x30, 0x10 + priv->cb[7]); ++ ser_write(0x31, 0x10 + priv->cb[6]); ++ ser_write(0x32, 0x10 + priv->cb[5]); ++ ser_write(0x33, 0x10 + priv->cb[4]); ++ ser_write(0x34, 0x10 + priv->cb[3]); ++ ser_write(0x35, 0x10 + priv->cb[2]); ++ ser_write(0x36, 0x10 + priv->cb[1]); ++ ser_write(0x37, 0x10 + priv->cb[0]); ++ ser_write(0x38, priv->cb[7]); ++ ser_write(0x39, priv->cb[6]); ++ ser_write(0x3A, priv->cb[5]); ++ ++ ser_write(0x67, 0xC4); /* DBL_ALIGN_TO = 100b */ ++ } ++ break; ++ case MIPI_DT_RAW12: ++ /* setup crossbar for RAW12: reverse DVP bus */ ++ ser_write(0x20, priv->cb[11]); ++ ser_write(0x21, priv->cb[10]); ++ ser_write(0x22, priv->cb[9]); ++ ser_write(0x23, priv->cb[8]); ++ ser_write(0x24, priv->cb[7]); ++ ser_write(0x25, priv->cb[6]); ++ ser_write(0x26, priv->cb[5]); ++ ser_write(0x27, priv->cb[4]); ++ ser_write(0x28, priv->cb[3]); ++ ser_write(0x29, priv->cb[2]); ++ ser_write(0x2a, priv->cb[1]); ++ ser_write(0x2b, priv->cb[0]); ++ ++ /* this is second byte in the packet (DBL=1 in serializer) */ ++ ser_write(0x30, priv->cb[11] + 16); ++ ser_write(0x31, priv->cb[10] + 16); ++ ser_write(0x32, priv->cb[9] + 16); ++ ser_write(0x33, priv->cb[8] + 16); ++ ser_write(0x34, priv->cb[7] + 16); ++ ser_write(0x35, priv->cb[6] + 16); ++ ser_write(0x36, priv->cb[5] + 16); ++ ser_write(0x37, priv->cb[4] + 16); ++ ser_write(0x38, priv->cb[3] + 16); ++ ser_write(0x39, priv->cb[2] + 16); ++ ser_write(0x3a, priv->cb[1] + 16); ++ ser_write(0x3b, priv->cb[0] + 16); ++ ++ if (!(priv->bws || priv->hibw) && priv->dbl) ++ dev_err(&priv->client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n"); ++ break; ++ } ++ } ++ ++ /* I2C translator setup */ ++// ser_write(0x09, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */ ++// ser_write(0x0A, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */ ++ ser_write(0x0B, BROADCAST << 1); /* serializer broadcast I2C translated */ ++ ser_write(0x0C, link->ser_addr << 1); /* serializer broadcast I2C native */ ++ /* put serializer in configuration link state */ ++ ser_write(0x04, 0x43); /* enable RC, conf_link */ ++ usleep_range(2000, 2500); ++ ++ return 0; ++} ++ ++static void max96712_gmsl1_link_pipe_setup(struct max96712_priv *priv, int link_n) ++{ ++ struct max96712_link *link = priv->link[link_n]; ++ int pipe = link_n; /* straight map */ ++ int dt = priv->dt; /* should come from imager */ ++ int in_vc = 0; ++ ++ max96712_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */ ++ ++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */ ++ des_write(MAX_MIPI_TX12(pipe), 0x00); ++ ++ /* use map #0 for payload data */ ++ max96712_set_pipe_to_mipi_mapping(priv, pipe, 0, /* pipe, map# */ ++ dt, in_vc, /* src DT, VC */ ++ dt, link->out_vc, /* dst DT, VC */ ++ link->out_mipi); /* dst MIPI PHY */ ++ /* use map #1 for FS */ ++ max96712_set_pipe_to_mipi_mapping(priv, pipe, 1, /* pipe, map# */ ++ 0x00, in_vc, /* src DT, VC */ ++ 0x00, link->out_vc, /* dst DT, VC */ ++ link->out_mipi); /* dst MIPI PHY */ ++ /* use map #2 for FE */ ++ max96712_set_pipe_to_mipi_mapping(priv, pipe, 2, /* pipe, map# */ ++ 0x01, in_vc, /* src DT, VC */ ++ 0x01, link->out_vc, /* dst DT, VC */ ++ link->out_mipi); /* dst MIPI PHY */ ++ usleep_range(5000, 5500); ++ ++ link->pipes_mask |= BIT(pipe); ++} ++ ++static void max96712_gmsl1_postinit(struct max96712_priv *priv) ++{ ++ int i; ++ u8 val = 0; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ struct max96712_link *link = priv->link[i]; ++ ++ if (!(priv->links_mask & BIT(i))) ++ continue; ++ ++ des_write(MAX_GMSL1_4(i), 0x3); /* enable REV/FWD CC */ ++ des_write(MAX96712_REG6, BIT(i)); /* GMSL1 mode, enable GMSL link# */ ++ max96712_reset_oneshot(priv, BIT(i)); ++ usleep_range(2000, 2500); ++ ++ ser_read(0x15, &val); ++ if (!(val & BIT(1))) ++ dev_warn(&priv->client->dev, "link%d valid PCLK is not detected\n", i); ++ ++ /* switch to GMSL serial_link for streaming video */ ++ max96712_write_remote_verify(priv, i, 0x04, conf_link ? 0x43 : 0x83); ++ usleep_range(2000, 2500); ++ ++ des_write(MAX_GMSL1_4(i), 0x00); /* disable REV/FWD CC */ ++ ++ switch (priv->link[i]->ser_id) { ++ case MAX9271_ID: ++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x01); /* use D14/15 for HS/VS */ ++ break; ++ case MAX96705_ID: ++ case MAX96707_ID: ++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x00); /* use D18/D19 for HS/VS */ ++ break; ++ } ++ } ++ ++ for (i = 0; i < priv->n_links; i++) ++ des_write(MAX_GMSL1_4(i), priv->links_mask & BIT(i) ? 0x03 : 0); /* enable REV/FWD CC */ ++ ++ des_update_bits(MAX96712_REG6, 0x0f, priv->links_mask); /* enable detected links */ ++ max96712_reset_oneshot(priv, priv->links_mask); /* one-shot reset valid links */ ++} ++ ++static void max96712_gmsl1_fsync_setup(struct max96712_priv *priv) ++{ ++ des_write(MAX96712_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */ ++ des_write(MAX96712_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */ ++ des_write(MAX96712_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */ ++ //des_write(MAX96712_FSYNC_8, 0x00); /* Disable Err Thresh */ ++ //des_write(MAX96712_FSYNC_9, 0x00); /* Disable Err Thresh */ ++ des_write(MAX96712_FSYNC_10, 0x00); /* Disable Overlap */ ++ des_write(MAX96712_FSYNC_11, 0x00); ++ ++ des_write(MAX96712_FSYNC_0, 0x00); /* Manual method, Internal GMSL1 generator mode */ ++ ++ des_write(MAX_GMSL1_8(0), 0x11); /* Fsync Tx Enable on Link A */ ++ des_write(MAX_GMSL1_8(1), 0x11); /* Fsync Tx Enable on Link B */ ++ des_write(MAX_GMSL1_8(2), 0x11); /* Fsync Tx Enable on Link C */ ++ des_write(MAX_GMSL1_8(3), 0x11); /* Fsync Tx Enable on Link D */ ++ ++ des_write(MAX96712_FSYNC_15, 0x1f); /* GMSL1 Type Fsync, Enable all pipes */ ++} ++ ++/* ----------------------------------------------------------------------------- ++ * GMSL2 ++ */ ++ ++static void max96712_gmsl2_cc_enable(struct max96712_priv *priv, int link, int on) ++{ ++ /* nothing */ ++} ++ ++static int max96712_gmsl2_get_link_lock(struct max96712_priv *priv, int link_n) ++{ ++ int lock_reg[] = {MAX96712_CTRL3, MAX96712_CTRL12, MAX96712_CTRL13, MAX96712_CTRL14}; ++ int val = 0; ++ ++ des_read(lock_reg[link_n], &val); ++ ++ return !!(val & BIT(3)); ++} ++ ++static void max96712_gmsl2_initial_setup(struct max96712_priv *priv) ++{ ++ des_update_bits(MAX96712_REG6, 0xf0, 0xf0); /* set GMSL2 mode */ ++ des_write(MAX96712_REG26, 0x22); /* 187.5M/6G */ ++ des_write(MAX96712_REG27, 0x22); /* 187.5M/6G */ ++} ++ ++static int max96712_gmsl2_reverse_channel_setup(struct max96712_priv *priv, int link_n) ++{ ++ struct max96712_link *link = priv->link[link_n]; ++ int ser_addrs[] = {0x40, 0x42, 0x60, 0x62}; /* possible MAX9295 addresses on i2c bus */ ++ int timeout = priv->timeout; ++ int ret = 0; ++ int i = 0; ++ ++ des_write(MAX96712_REG6, 0xf0 | BIT(link_n)); /* GMSL2 mode, enable GMSL link# */ ++ max96712_reset_oneshot(priv, BIT(link_n)); ++ ++ /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */ ++ while ((!max96712_gmsl2_get_link_lock(priv, link_n)) && (--timeout)) ++ msleep(1); ++ ++ if (!timeout) { ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(ser_addrs); i++) { ++ int val = 0; ++ ++ __reg16_read(ser_addrs[i], 0x000d, &val); /* read serializer ID */ ++ if (val == MAX9295A_ID || val == MAX9295B_ID) { ++ link->ser_id = val; ++ __reg16_write(ser_addrs[i], 0x0000, link->ser_addr << 1); /* relocate serizlizer on I2C bus */ ++ usleep_range(2000, 2500); ++ break; ++ } ++ } ++ ++ if (i == ARRAY_SIZE(ser_addrs)) { ++ dev_err(&priv->client->dev, "serializer not found\n"); ++ goto out; ++ } ++ ++ priv->links_mask |= BIT(link_n); ++ ++out: ++ dev_info(&priv->client->dev, "link%d %s %sat 0x%x (0x%x) %s\n", link_n, chip_name(link->ser_id), ++ ret == -EADDRINUSE ? "already " : "", link->ser_addr, ser_addrs[i], ++ ret == -ETIMEDOUT ? "not found: timeout GMSL2 link establish" : ""); ++ return ret; ++} ++ ++static int max96712_gmsl2_link_serializer_setup(struct max96712_priv *priv, int link_n) ++{ ++ struct max96712_link *link = priv->link[link_n]; ++ int i; ++ ++ //ser_write(MAX9295_CTRL0, 0x31); /* link reset */ ++ //msleep(100); ++ ser_write(MAX9295_REG2, 0x03); /* disable all pipes */ ++ ++ if (strcmp(priv->mbus, "dvp") == 0) { ++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */ ++ (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */ ++ ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */ ++ ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */ ++ } ++ ++ ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */ ++ ++ switch (priv->dt) { ++ case MIPI_DT_YUV8: ++ case MIPI_DT_RAW12: ++ /* setup crossbar: strait DVP mapping */ ++ ser_write(MAX9295_CROSS(0), priv->cb[0]); ++ ser_write(MAX9295_CROSS(1), priv->cb[1]); ++ ser_write(MAX9295_CROSS(2), priv->cb[2]); ++ ser_write(MAX9295_CROSS(3), priv->cb[3]); ++ ser_write(MAX9295_CROSS(4), priv->cb[4]); ++ ser_write(MAX9295_CROSS(5), priv->cb[5]); ++ ser_write(MAX9295_CROSS(6), priv->cb[6]); ++ ser_write(MAX9295_CROSS(7), priv->cb[7]); ++ ser_write(MAX9295_CROSS(8), priv->cb[8]); ++ ser_write(MAX9295_CROSS(9), priv->cb[9]); ++ ser_write(MAX9295_CROSS(10), priv->cb[10]); ++ ser_write(MAX9295_CROSS(11), priv->cb[11]); ++ break; ++ } ++ ++ for (i = 0; i < 11; i++) { ++ if (priv->gpio[i] == 0) { ++ /* GPIO set 0 */ ++ ser_write(MAX9295_GPIO_A(i), 0x80); /* 1MOm, GPIO output low */ ++ ser_write(MAX9295_GPIO_B(i), 0xa0); /* push-pull, pull-down */ ++ } ++ if (priv->gpio[i] == 1) { ++ /* GPIO set 1 */ ++ ser_write(MAX9295_GPIO_A(i), 0x90); /* 1MOm, GPIO output high */ ++ ser_write(MAX9295_GPIO_B(i), 0x60); /* push-pull, pull-up */ ++ } ++ if (priv->gpio[i] == 2) { ++ /* GPIO FSIN */ ++ ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */ ++ ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */ ++ } ++ if (priv->gpio[i] == 3) { ++ /* GPIO Interrupt */ ++ ser_write(MAX9295_GPIO_A(i), 0x63); /* 40kOm, GMSL2 TX to deserializer */ ++ ser_write(MAX9295_GPIO_B(i), 0x25); /* push-pull, pull-none, GPIO stream ID=5 */ ++ } ++ } ++ ++ /* I2C translator setup */ ++// ser_write(MAX9295_I2C2, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */ ++// ser_write(MAX9295_I2C3, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */ ++ ser_write(MAX9295_I2C4, BROADCAST << 1); /* serializer broadcast I2C translated */ ++ ser_write(MAX9295_I2C5, link->ser_addr << 1); /* serializer broadcast I2C native */ ++ usleep_range(2000, 2500); ++ ++ return 0; ++} ++ ++static struct { ++ int in_dt; ++ int out_dt; ++} gmsl2_pipe_maps[] = { ++ {0x00, 0x00}, /* FS */ ++ {0x01, 0x01}, /* FE */ ++ {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */ ++}; ++ ++static void max96712_gmsl2_pipe_set_source(struct max96712_priv *priv, int pipe, int phy, int in_pipe) ++{ ++ int offset = (pipe % 2) * 4; ++ ++ des_update_bits(MAX96712_VIDEO_PIPE_SEL(pipe / 2), 0x0f << offset, (phy << (offset + 2)) | ++ (in_pipe << offset)); ++} ++ ++static void max96712_gmsl2_link_pipe_setup(struct max96712_priv *priv, int link_n) ++{ ++ struct max96712_link *link = priv->link[link_n]; ++ int pipe = link_n; /* straight mapping */ ++ int dt = priv->dt; /* must come from imager */ ++ int in_vc = 0; ++ int i; ++ ++ max96712_gmsl2_pipe_set_source(priv, pipe, link_n, 0); /* route Pipe X only */ ++ ++ if (strcmp(priv->mbus, "dvp") == 0) { ++ des_write(MAX96712_RX0(pipe), 0); /* stream_id = 0 */ ++ //des_update_bits(MAX_VIDEO_RX0(pipe), BIT(0), BIT(0)); /* disable Packet detector */ ++ max96712_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */ ++ } ++ ++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */ ++ des_write(MAX_MIPI_TX12(pipe), 0x00); ++ ++ for (i = 0; i < ARRAY_SIZE(gmsl2_pipe_maps); i++) { ++ max96712_set_pipe_to_mipi_mapping(priv, pipe, i, /* pipe, map# */ ++ gmsl2_pipe_maps[i].in_dt, in_vc, /* src DT, VC */ ++ gmsl2_pipe_maps[i].out_dt, link->out_vc, /* dst DT, VC */ ++ link->out_mipi); /* dst MIPI PHY */ ++ } ++ ++ link->pipes_mask |= BIT(pipe); ++} ++ ++static void max96712_gmsl2_postinit(struct max96712_priv *priv) ++{ ++ des_update_bits(MAX96712_REG6, 0x0f, priv->links_mask); /* enable detected links */ ++ max96712_reset_oneshot(priv, priv->links_mask); /* one-shot reset valid links */ ++} ++ ++static void max96712_gmsl2_link_crossbar_setup(struct max96712_priv *priv, int link, int dt) ++{ ++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */ ++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */ ++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */ ++} ++ ++static void max96712_gmsl2_fsync_setup(struct max96712_priv *priv) ++{ ++ /* TODO */ ++} ++ ++/* ----------------------------------------------------------------------------- ++ * I2C Multiplexer ++ */ ++ ++static int max96712_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan) ++{ ++ /* Do nothing! */ ++ return 0; ++} ++ ++static int max96712_i2c_mux_init(struct max96712_priv *priv) ++{ ++ struct i2c_client *client = priv->client; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) ++ return -ENODEV; ++ ++ priv->mux = i2c_mux_alloc(client->adapter, &client->dev, ++ priv->n_links, 0, I2C_MUX_LOCKED, ++ max96712_i2c_mux_select, NULL); ++ if (!priv->mux) ++ return -ENOMEM; ++ ++ priv->mux->priv = priv; ++ ++ return 0; ++} ++ ++#define max96712_cc_enable(priv,i,en) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_cc_enable(priv, i, en) : \ ++ max96712_gmsl1_cc_enable(priv, i, en)) ++#define max96712_initial_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_initial_setup(priv) : \ ++ max96712_gmsl1_initial_setup(priv)) ++#define max96712_reverse_channel_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_reverse_channel_setup(priv, i) : \ ++ max96712_gmsl1_reverse_channel_setup(priv, i)) ++#define max96712_link_serializer_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_link_serializer_setup(priv, i) : \ ++ max96712_gmsl1_link_serializer_setup(priv, i)) ++#define max96712_link_pipe_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_link_pipe_setup(priv, i) : \ ++ max96712_gmsl1_link_pipe_setup(priv, i)) ++#define max96712_link_crossbar_setup(priv,i,dt) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_link_crossbar_setup(priv, i, dt) : \ ++ max96712_gmsl1_link_crossbar_setup(priv, i, dt)) ++#define max96712_postinit(priv) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_postinit(priv) : \ ++ max96712_gmsl1_postinit(priv)) ++#define max96712_fsync_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_fsync_setup(priv) : \ ++ max96712_gmsl1_fsync_setup(priv)) ++ ++static int max96712_preinit(struct max96712_priv *priv) ++{ ++ int i; ++ ++ des_update_bits(MAX96712_PWR1, BIT(6), BIT(6)); /* reset chip */ ++ mdelay(5); ++ ++ /* enable internal regulator for 1.2V VDD supply */ ++ des_update_bits(MAX96712_CTRL0, BIT(2), BIT(2)); /* REG_ENABLE = 1 */ ++ des_update_bits(MAX96712_CTRL2, BIT(4), BIT(4)); /* REG_MNL = 1 */ ++ ++ //for (i = 0; i < priv->n_links; i++) { ++ // des_write(MAX_RLMS58(i), 0x28); ++ // des_write(MAX_RLMS59(i), 0x68); ++ // max96712_reset_oneshot(priv, BIT(i)); ++ //} ++ ++ /* I2C-I2C timings */ ++ for (i = 0; i < 8; i++) { ++ des_write(MAX96712_I2C_0(i), 0x01); /* Fast mode Plus, 1mS timeout */ ++ des_write(MAX96712_I2C_1(i), 0x51); /* i2c speed: 397Kbps, 1mS timeout */ ++ } ++ ++ des_update_bits(MAX96712_CTRL11, 0x55, priv->is_coax ? 0x55 : 0); /* cable mode */ ++ des_update_bits(MAX96712_REG6, 0x0f, 0); /* disable all links */ ++ ++ return 0; ++} ++ ++static int max96712_initialize(struct max96712_priv *priv) ++{ ++ int ret, i; ++ ++ max96712_preinit(priv); ++ max96712_initial_setup(priv); ++ max96712_mipi_setup(priv); ++ ++ for (i = 0; i < priv->n_links; i++) { ++ if (!IS_ERR(priv->link[i]->poc_reg)) { ++ ret = regulator_enable(priv->link[i]->poc_reg); /* POC power on */ ++ if (ret) { ++ dev_err(&priv->link[i]->client->dev, "failed to enable poc regulator\n"); ++ continue; ++ } ++ mdelay(priv->poc_delay); ++ } ++ ++ ret = max96712_reverse_channel_setup(priv, i); ++ if (ret == -ETIMEDOUT) ++ continue; ++ if (!ret) ++ max96712_link_serializer_setup(priv, i); ++ ++ max96712_link_pipe_setup(priv, i); ++ max96712_link_crossbar_setup(priv, i, priv->dt); ++ ++ i2c_mux_add_adapter(priv->mux, 0, i, 0); ++ max96712_cc_enable(priv, i, 0); ++ } ++ ++ max96712_postinit(priv); ++ max96712_fsync_setup(priv); ++ ++ return 0; ++} ++ ++static int max96712_reboot_notifier(struct notifier_block *nb, unsigned long code, void *data) ++{ ++ struct max96712_priv *priv = container_of(nb, struct max96712_priv, reboot_nb); ++ int i; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ if (!IS_ERR(priv->link[i]->poc_reg)) ++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */ ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static int max96712_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct max96712_priv *priv = v4l2_get_subdevdata(sd); ++ int i = sd->grp_id; ++ int pipes_mask = priv->link[i]->pipes_mask; ++ ++ if (on) { ++ des_update_bits(MAX96712_VIDEO_PIPE_EN, pipes_mask, pipes_mask); /* enable link pipes */ ++ if (atomic_inc_return(&priv->use_count) == 1) ++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0x02); /* CSI output enable */ ++ } else { ++ if (atomic_dec_return(&priv->use_count) == 0) ++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0); /* CSI output disable */ ++ des_update_bits(MAX96712_VIDEO_PIPE_EN, pipes_mask, 0); /* disable link pipes */ ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int max96712_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ struct max96712_priv *priv = v4l2_get_subdevdata(sd); ++ int ret; ++ int val = 0; ++ ++ ret = des_read(reg->reg, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = sizeof(u16); ++ ++ return 0; ++} ++ ++static int max96712_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ struct max96712_priv *priv = v4l2_get_subdevdata(sd); ++ ++ return des_write(reg->reg, (u8)reg->val); ++} ++#endif ++ ++static struct v4l2_subdev_core_ops max96712_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = max96712_g_register, ++ .s_register = max96712_s_register, ++#endif ++ .s_power = max96712_s_power, ++}; ++ ++static struct v4l2_subdev_ops max96712_subdev_ops = { ++ .core = &max96712_subdev_core_ops, ++}; ++ ++static const struct of_device_id max96712_dt_ids[] = { ++ { .compatible = "maxim,max96712" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, max96712_dt_ids); ++ ++static int max96712_parse_dt(struct i2c_client *client) ++{ ++ struct max96712_priv *priv = i2c_get_clientdata(client); ++ struct device_node *np = client->dev.of_node; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ struct property *prop; ++ char name[16]; ++ int i, csi_rate; ++ ++ if (of_property_read_u32(np, "maxim,links", &priv->n_links)) ++ priv->n_links = MAX96712_MAX_LINKS; ++ if (of_property_read_u32(np, "maxim,gmsl", &priv->gmsl_mode)) ++ priv->gmsl_mode = MODE_GMSL2; ++ if (of_property_read_bool(np, "maxim,stp")) ++ priv->is_coax = 0; ++ else ++ priv->is_coax = 1; ++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) { ++ priv->gpio_resetb = -1; ++ } else { ++ if (of_property_read_bool(np, "maxim,resetb-active-high")) ++ priv->active_low_resetb = 0; ++ else ++ priv->active_low_resetb = 1; ++ } ++ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period)) ++ priv->fsync_period = 3210000;/* 96MHz/30fps */ ++ priv->pclk_rising_edge = true; ++ if (of_property_read_bool(np, "maxim,pclk-falling-edge")) ++ priv->pclk_rising_edge = false; ++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout)) ++ priv->timeout = 100; ++ if (of_property_read_u32(np, "maxim,him", &priv->him)) ++ priv->him = 0; ++ if (of_property_read_u32(np, "maxim,bws", &priv->bws)) ++ priv->bws = 0; ++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl)) ++ priv->dbl = 1; ++ if (of_property_read_u32(np, "maxim,hven", &priv->hven)) ++ priv->hven = 1; ++ if (of_property_read_u32(np, "maxim,hibw", &priv->hibw)) ++ priv->hibw = 0; ++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync)) ++ priv->hsync = 0; ++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync)) ++ priv->vsync = 1; ++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay)) ++ priv->poc_delay = 50; ++ if (of_property_read_u32(np, "maxim,dt", &priv->dt)) ++ priv->dt = MIPI_DT_YUV8; ++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar)) ++ priv->crossbar = crossbar; ++ if (of_property_read_string(np, "maxim,mbus", &priv->mbus)) ++ priv->mbus = mbus_default; ++ for (i = 0; i < 11; i++) { ++ sprintf(name, "maxim,gpio%d", i); ++ if (of_property_read_u32(np, name, &priv->gpio[i])) ++ priv->gpio[i] = -1; ++ } ++ ++ /* module params override dts */ ++ if (gmsl != MODE_GMSL2) ++ priv->gmsl_mode = gmsl; ++ if (him) ++ priv->him = him; ++ if (fsync_period) { ++ priv->fsync_period = fsync_period; ++// priv->fsync_mode = fsync_mode_default; ++ } ++ if (hsync) ++ priv->hsync = hsync; ++ if (!vsync) ++ priv->vsync = vsync; ++ if (gpio_resetb) ++ priv->gpio_resetb = gpio_resetb; ++ if (active_low_resetb) ++ priv->active_low_resetb = active_low_resetb; ++ if (timeout_n) ++ priv->timeout = timeout_n; ++ if (poc_delay) ++ priv->poc_delay = poc_delay; ++ if (bws) ++ priv->bws = bws; ++ if (!dbl) ++ priv->dbl = dbl; ++ if (dt != MIPI_DT_YUV8) ++ priv->dt = dt; ++// if (hsgen) ++// priv->hsgen = hsgen; ++ if (gpio0 >= 0) ++ priv->gpio[0] = gpio0; ++ if (gpio1 >= 0) ++ priv->gpio[1] = gpio1; ++ if (gpio7 >= 0) ++ priv->gpio[7] = gpio7; ++ if (gpio8 >= 0) ++ priv->gpio[8] = gpio8; ++ ++ /* parse serializer crossbar setup */ ++ for (i = 0; i < 16; i++) { ++ priv->cb[i] = priv->crossbar % 16; ++ priv->crossbar /= 16; ++ } ++ ++ for (i = 0; ; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; ++ ++ if (i < priv->n_links) { ++ if (of_property_read_u32(endpoint, "ser-addr", &priv->link[i]->ser_addr)) { ++ of_node_put(endpoint); ++ dev_err(&client->dev, "ser-addr not set\n"); ++ return -EINVAL; ++ } ++ priv->link[i]->sd_fwnode = of_fwnode_handle(endpoint); ++ } ++ ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; ++ ++ prop = of_find_property(endpoint, "csi-rate", NULL); ++ if (prop) { ++ of_property_read_u32(endpoint, "csi-rate", &csi_rate); ++ of_update_property(rendpoint, prop); ++ } ++ ++ prop = of_find_property(endpoint, "dvp-order", NULL); ++ if (prop) ++ of_update_property(rendpoint, prop); ++ } ++ ++ of_node_put(endpoint); ++ ++ for (i = 0; i < priv->n_links; i++) { ++ priv->link[i]->out_mipi = 1; /* CSI default forwarding is to MIPI1 */ ++ priv->link[i]->out_vc = i; /* Default VC map: 0 1 2 3 */ ++ } ++ ++ prop = of_find_property(np, "maxim,links-mipi-map", NULL); ++ if (prop) { ++ const __be32 *map = NULL; ++ u32 val; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ map = of_prop_next_u32(prop, map, &val); ++ if (!map) ++ break; ++ if (val >= MAX96712_MAX_MIPI) ++ return -EINVAL; ++ priv->link[i]->out_mipi = val; ++ } ++ } ++ ++ for (i = 0; i < priv->n_links; i++) ++ priv->csi_rate[priv->link[i]->out_mipi] = csi_rate; ++ ++ prop = of_find_property(np, "maxim,links-vc-map", NULL); ++ if (prop) { ++ const __be32 *map = NULL; ++ u32 val; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ map = of_prop_next_u32(prop, map, &val); ++ if (!map) ++ break; ++ if (val >= 4) ++ return -EINVAL; ++ priv->link[i]->out_vc = val; ++ } ++ } ++ ++ dev_dbg(&client->dev, "Link# | MIPI rate | Map | VC\n"); ++ for (i = 0; i < priv->n_links; i++) ++ dev_dbg(&client->dev, "%5d | %9d | %3d | %2d\n", i, priv->csi_rate[i], priv->link[i]->out_mipi, priv->link[i]->out_vc); ++ ++ return 0; ++} ++ ++static int max96712_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct max96712_priv *priv; ++ struct gpio_desc *pwdn_gpio; ++ int ret, i; ++ int val = 0; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->regmap = devm_regmap_init_i2c(client, &max96712_regmap[0]); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ i2c_set_clientdata(client, priv); ++ priv->client = client; ++ atomic_set(&priv->use_count, 0); ++ ++ priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk"); ++ if (!IS_ERR(priv->ref_clk)) { ++ dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000); ++ v4l2_clk_enable(priv->ref_clk); ++ } ++ ++ pwdn_gpio = devm_gpiod_get_optional(&client->dev, "shutdown", GPIOD_OUT_HIGH); ++ if (!IS_ERR(pwdn_gpio)) { ++ udelay(5); ++ gpiod_set_value_cansleep(pwdn_gpio, 0); ++ usleep_range(3000, 5000); ++ } ++ ++ des_read(MAX96712_DEV_ID, &val); ++ if (val != MAX96712_ID) ++ return -ENODEV; ++ ++ for (i = 0; i < MAX96712_MAX_LINKS; i++) { ++ priv->link[i] = devm_kzalloc(&client->dev, sizeof(*priv->link[i]), GFP_KERNEL); ++ if (!priv->link[i]) ++ return -ENOMEM; ++ } ++ ++ ret = max96712_parse_dt(client); ++ if (ret) ++ goto out; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ char poc_name[10]; ++ ++ sprintf(poc_name, "poc%d", i); ++ priv->link[i]->poc_reg = devm_regulator_get(&client->dev, poc_name); ++ if (PTR_ERR(priv->link[i]->poc_reg) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ } ++ ++ for (i = 0; i < priv->n_links; i++) { ++ priv->link[i]->client = i2c_new_dummy(client->adapter, priv->link[i]->ser_addr); ++ if (!priv->link[i]->client) ++ return -ENOMEM; ++ ++ priv->link[i]->regmap = regmap_init_i2c(priv->link[i]->client, &max96712_regmap[priv->gmsl_mode]); ++ if (IS_ERR(priv->link[i]->regmap)) ++ return PTR_ERR(priv->link[i]->regmap); ++ } ++ ++ ret = max96712_i2c_mux_init(priv); ++ if (ret) { ++ dev_err(&client->dev, "Unable to initialize I2C multiplexer\n"); ++ goto out; ++ } ++ ++ ret = max96712_initialize(priv); ++ if (ret < 0) ++ goto out; ++ ++ for (i = 0; i < priv->n_links; i++) { ++ v4l2_subdev_init(&priv->link[i]->sd, &max96712_subdev_ops); ++ priv->link[i]->sd.owner = client->dev.driver->owner; ++ priv->link[i]->sd.dev = &client->dev; ++ priv->link[i]->sd.grp_id = i; ++ v4l2_set_subdevdata(&priv->link[i]->sd, priv); ++ priv->link[i]->sd.fwnode = priv->link[i]->sd_fwnode; ++ ++ snprintf(priv->link[i]->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x", ++ client->dev.driver->name, i, i2c_adapter_id(client->adapter), ++ client->addr); ++ ++ ret = v4l2_async_register_subdev(&priv->link[i]->sd); ++ if (ret < 0) ++ goto out; ++ } ++ ++ priv->reboot_nb.notifier_call = max96712_reboot_notifier; ++ ret = register_reboot_notifier(&priv->reboot_nb); ++ if (ret) { ++ dev_err(&client->dev, "failed to register reboot notifier\n"); ++ goto out; ++ } ++ ++ //max96712_debug_add(priv); ++out: ++ return ret; ++} ++ ++static int max96712_remove(struct i2c_client *client) ++{ ++ struct max96712_priv *priv = i2c_get_clientdata(client); ++ int i; ++ ++ //max96712_debug_remove(priv); ++ i2c_mux_del_adapters(priv->mux); ++ unregister_reboot_notifier(&priv->reboot_nb); ++ ++ for (i = 0; i < priv->n_links; i++) { ++ v4l2_async_unregister_subdev(&priv->link[i]->sd); ++ v4l2_device_unregister_subdev(&priv->link[i]->sd); ++ if (!IS_ERR(priv->link[i]->poc_reg)) ++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */ ++ } ++ ++ return 0; ++} ++ ++static const struct i2c_device_id max96712_id[] = { ++ { "max96712", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max96712_id); ++ ++static struct i2c_driver max96712_i2c_driver = { ++ .driver = { ++ .name = "max96712", ++ .of_match_table = of_match_ptr(max96712_dt_ids), ++ }, ++ .probe = max96712_probe, ++ .remove = max96712_remove, ++ .id_table = max96712_id, ++}; ++ ++module_i2c_driver(max96712_i2c_driver); ++ ++MODULE_DESCRIPTION("GMSL2 driver for MAX96712"); ++MODULE_AUTHOR("Andrey Gusakov, Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.h b/drivers/media/i2c/soc_camera/gmsl/max96712.h +new file mode 100644 +index 0000000..2976027 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.h +@@ -0,0 +1,263 @@ ++/* ++ * MAXIM max96712 GMSL2 driver header ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#define MAX96712_MAX_LINKS 4 ++#define MAX96712_MAX_PIPES 8 ++#define MAX96712_MAX_PIPE_MAPS 16 ++#define MAX96712_MAX_MIPI 4 ++ ++struct max96712_link { ++ struct v4l2_subdev sd; ++ struct fwnode_handle *sd_fwnode; ++ struct i2c_client *client; ++ struct regmap *regmap; ++ int ser_id; ++ int ser_addr; ++ int pipes_mask; /* mask of pipes used by this link */ ++ int out_mipi; /* MIPI# */ ++ int out_vc; /* VC# */ ++ struct regulator *poc_reg; /* PoC power supply */ ++}; ++ ++struct max96712_priv { ++ struct i2c_client *client; ++ struct regmap *regmap; ++ struct i2c_mux_core *mux; ++ int n_links; ++ int links_mask; ++ enum gmsl_mode gmsl_mode; ++ struct max96712_link *link[MAX96712_MAX_LINKS]; ++ int gpio_resetb; ++ int active_low_resetb; ++ bool pclk_rising_edge; ++ bool is_coax; ++ int him; ++ int bws; ++ int dbl; ++ int hibw; ++ int hven; ++ int hsync; ++ int vsync; ++ int dt; ++ u64 crossbar; ++ char cb[16]; ++ const char *mbus; ++ int gpio[11]; ++ int timeout; ++ int poc_delay; ++ struct v4l2_clk *ref_clk; ++ int csi_rate[MAX96712_MAX_MIPI]; ++ int fsync_period; ++ atomic_t use_count; ++ struct notifier_block reboot_nb; ++}; ++ ++#define MAX96712_REG4 0x04 ++#define MAX96712_REG5 0x05 ++#define MAX96712_REG6 0x06 ++#define MAX96712_REG14 0x0e ++#define MAX96712_REG26 0x10 ++#define MAX96712_REG27 0x11 ++ ++#define MAX96712_CTRL0 0x17 ++#define MAX96712_CTRL1 0x18 ++#define MAX96712_CTRL2 0x19 ++#define MAX96712_CTRL3 0x1a ++#define MAX96712_CTRL11 0x22 ++#define MAX96712_CTRL12 0x0a ++#define MAX96712_CTRL13 0x0b ++#define MAX96712_CTRL14 0x0c ++ ++#define MAX96712_PWR1 0x13 ++ ++#define MAX96712_DEV_ID 0x4a ++#define MAX96712_REV 0x4c ++ ++#define MAX96712_VIDEO_PIPE_SEL(n) (0xf0 + n) ++#define MAX96712_VIDEO_PIPE_EN 0xf4 ++ ++#define MAX96712_I2C_0(n) (0x640 + (0x10 * n)) ++#define MAX96712_I2C_1(n) (0x641 + (0x10 * n)) ++ ++#define MAX96712_RX0(n) (0x50 + n) ++ ++#define MAX_VIDEO_RX_BASE(n) (n < 5 ? (0x100 + (0x12 * n)) : \ ++ (0x160 + (0x12 * (n - 5)))) ++#define MAX_VIDEO_RX0(n) (MAX_VIDEO_RX_BASE(n) + 0x00) ++#define MAX_VIDEO_RX3(n) (MAX_VIDEO_RX_BASE(n) + 0x03) ++#define MAX_VIDEO_RX8(n) (MAX_VIDEO_RX_BASE(n) + 0x08) ++#define MAX_VIDEO_RX10(n) (MAX_VIDEO_RX_BASE(n) + 0x0a) ++ ++#define MAX_VPRBS(n) (0x1dc + (0x20 * n)) ++ ++#define MAX_CROSS_BASE(n) (0x1c0 + (0x20 * n)) ++#define MAX_CROSS(n, m) (MAX_CROSS_BASE(n) + m) ++ ++#define MAX_BACKTOP_BASE(bank) (0x400 + (0x20 * bank)) ++#define MAX_BACKTOP1(bank) (MAX_BACKTOP_BASE(bank) + 0x00) ++#define MAX_BACKTOP11(bank) (MAX_BACKTOP_BASE(bank) + 0x0a) ++#define MAX_BACKTOP12(bank) (MAX_BACKTOP_BASE(bank) + 0x0b) ++#define MAX_BACKTOP13(bank) (MAX_BACKTOP_BASE(bank) + 0x0c) ++#define MAX_BACKTOP14(bank) (MAX_BACKTOP_BASE(bank) + 0x0d) ++#define MAX_BACKTOP15(bank) (MAX_BACKTOP_BASE(bank) + 0x0e) ++#define MAX_BACKTOP16(bank) (MAX_BACKTOP_BASE(bank) + 0x0f) ++#define MAX_BACKTOP17(bank) (MAX_BACKTOP_BASE(bank) + 0x10) ++#define MAX_BACKTOP18(bank) (MAX_BACKTOP_BASE(bank) + 0x11) ++#define MAX_BACKTOP19(bank) (MAX_BACKTOP_BASE(bank) + 0x12) ++#define MAX_BACKTOP20(bank) (MAX_BACKTOP_BASE(bank) + 0x13) ++#define MAX_BACKTOP21(bank) (MAX_BACKTOP_BASE(bank) + 0x14) ++#define MAX_BACKTOP22(bank) (MAX_BACKTOP_BASE(bank) + 0x15) ++#define MAX_BACKTOP23(bank) (MAX_BACKTOP_BASE(bank) + 0x16) ++#define MAX_BACKTOP24(bank) (MAX_BACKTOP_BASE(bank) + 0x17) ++#define MAX_BACKTOP25(bank) (MAX_BACKTOP_BASE(bank) + 0x18) ++#define MAX_BACKTOP26(bank) (MAX_BACKTOP_BASE(bank) + 0x19) ++#define MAX_BACKTOP27(bank) (MAX_BACKTOP_BASE(bank) + 0x1a) ++#define MAX_BACKTOP28(bank) (MAX_BACKTOP_BASE(bank) + 0x1b) ++#define MAX_BACKTOP29(bank) (MAX_BACKTOP_BASE(bank) + 0x1c) ++#define MAX_BACKTOP30(bank) (MAX_BACKTOP_BASE(bank) + 0x1d) ++#define MAX_BACKTOP31(bank) (MAX_BACKTOP_BASE(bank) + 0x1e) ++#define MAX_BACKTOP32(bank) (MAX_BACKTOP_BASE(bank) + 0x1f) ++ ++#define MAX96712_FSYNC_0 0x4a0 ++#define MAX96712_FSYNC_5 0x4a5 ++#define MAX96712_FSYNC_6 0x4a6 ++#define MAX96712_FSYNC_7 0x4a7 ++#define MAX96712_FSYNC_8 0x4a8 ++#define MAX96712_FSYNC_9 0x4a9 ++#define MAX96712_FSYNC_10 0x4aa ++#define MAX96712_FSYNC_11 0x4ab ++#define MAX96712_FSYNC_15 0x4af ++ ++#define MAX_MIPI_PHY_BASE 0x8a0 ++#define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00) ++#define MAX_MIPI_PHY2 (MAX_MIPI_PHY_BASE + 0x02) ++#define MAX_MIPI_PHY3 (MAX_MIPI_PHY_BASE + 0x03) ++#define MAX_MIPI_PHY4 (MAX_MIPI_PHY_BASE + 0x04) ++#define MAX_MIPI_PHY5 (MAX_MIPI_PHY_BASE + 0x05) ++#define MAX_MIPI_PHY6 (MAX_MIPI_PHY_BASE + 0x06) ++#define MAX_MIPI_PHY8 (MAX_MIPI_PHY_BASE + 0x08) ++#define MAX_MIPI_PHY9 (MAX_MIPI_PHY_BASE + 0x09) ++#define MAX_MIPI_PHY10 (MAX_MIPI_PHY_BASE + 0x0a) ++#define MAX_MIPI_PHY11 (MAX_MIPI_PHY_BASE + 0x0b) ++#define MAX_MIPI_PHY13 (MAX_MIPI_PHY_BASE + 0x0d) ++#define MAX_MIPI_PHY14 (MAX_MIPI_PHY_BASE + 0x0e) ++ ++#define MAX_MIPI_TX_BASE(n) (0x900 + 0x40 * n) ++#define MAX_MIPI_TX2(n) (MAX_MIPI_TX_BASE(n) + 0x02) ++#define MAX_MIPI_TX10(n) (MAX_MIPI_TX_BASE(n) + 0x0a) ++#define MAX_MIPI_TX11(n) (MAX_MIPI_TX_BASE(n) + 0x0b) ++#define MAX_MIPI_TX12(n) (MAX_MIPI_TX_BASE(n) + 0x0c) ++ ++/* 16 pairs of source-dest registers */ ++#define MAX_MIPI_MAP_SRC(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0d + (2 * n)) ++#define MAX_MIPI_MAP_DST(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0e + (2 * n)) ++/* Phy dst. Each reg contains 4 dest */ ++#define MAX_MIPI_MAP_DST_PHY(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x2d + n) ++ ++#define MAX_GMSL1_2(ch) (0xb02 + (0x100 * ch)) ++#define MAX_GMSL1_4(ch) (0xb04 + (0x100 * ch)) ++#define MAX_GMSL1_6(ch) (0xb06 + (0x100 * ch)) ++#define MAX_GMSL1_7(ch) (0xb07 + (0x100 * ch)) ++#define MAX_GMSL1_8(ch) (0xb08 + (0x100 * ch)) ++#define MAX_GMSL1_D(ch) (0xb0d + (0x100 * ch)) ++#define MAX_GMSL1_F(ch) (0xb0f + (0x100 * ch)) ++#define MAX_GMSL1_19(ch) (0xb19 + (0x100 * ch)) ++#define MAX_GMSL1_1B(ch) (0xb1b + (0x100 * ch)) ++#define MAX_GMSL1_1D(ch) (0xb1d + (0x100 * ch)) ++#define MAX_GMSL1_20(ch) (0xb20 + (0x100 * ch)) ++#define MAX_GMSL1_96(ch) (0xb96 + (0x100 * ch)) ++#define MAX_GMSL1_CA(ch) (0xbca + (0x100 * ch)) ++#define MAX_GMSL1_CB(ch) (0xbcb + (0x100 * ch)) ++ ++#define MAX_RLMS4(ch) (0x1404 + (0x100 * ch)) ++#define MAX_RLMSA(ch) (0x140A + (0x100 * ch)) ++#define MAX_RLMSB(ch) (0x140B + (0x100 * ch)) ++#define MAX_RLMSA4(ch) (0x14a4 + (0x100 * ch)) ++ ++#define MAX_RLMS58(ch) (0x1458 + (0x100 * ch)) ++#define MAX_RLMS59(ch) (0x1459 + (0x100 * ch)) ++#define MAX_RLMS95(ch) (0x1495 + (0x100 * ch)) ++#define MAX_RLMSC4(ch) (0x14c4 + (0x100 * ch)) ++#define MAX_RLMSC5(ch) (0x14c5 + (0x100 * ch)) ++ ++static inline int max96712_write(struct max96712_priv *priv, int reg, int val) ++{ ++ int ret; ++ ++ ret = regmap_write(priv->regmap, reg, val); ++ if (ret) ++ dev_dbg(&priv->client->dev, "write register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++static inline int max96712_read(struct max96712_priv *priv, int reg, int *val) ++{ ++ int ret; ++ ++ ret = regmap_read(priv->regmap, reg, val); ++ if (ret) ++ dev_dbg(&priv->client->dev, "read register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++static inline int max96712_update_bits(struct max96712_priv *priv, int reg, int mask, int bits) ++{ ++ int ret; ++ ++ ret = regmap_update_bits(priv->regmap, reg, mask, bits); ++ if (ret) ++ dev_dbg(&priv->client->dev, "update register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++#define des_read(reg, val) max96712_read(priv, reg, val) ++#define des_write(reg, val) max96712_write(priv, reg, val) ++#define des_update_bits(reg, mask, bits) max96712_update_bits(priv, reg, mask, bits) ++ ++static inline int max96712_ser_write(struct max96712_link *link, int reg, int val) ++{ ++ int ret; ++ ++ ret = regmap_write(link->regmap, reg, val); ++ if (ret < 0) ++ dev_dbg(&link->client->dev, "write register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++static inline int max96712_ser_read(struct max96712_link *link, int reg, u8 *val) ++{ ++ int ret; ++ ++ ret = regmap_read(link->regmap, reg, (int *)val); ++ if (ret) ++ dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++static inline int max96712_ser_update_bits(struct max96712_link *link, int reg, int mask, int bits) ++{ ++ int ret; ++ ++ ret = regmap_update_bits(link->regmap, reg, mask, bits); ++ if (ret) ++ dev_dbg(&link->client->dev, "update register 0x%04x failed (%d)\n", reg, ret); ++ ++ return ret; ++} ++ ++#define ser_read(reg, val) max96712_ser_read(link, reg, val) ++#define ser_write(reg, val) max96712_ser_write(link, reg, val) ++#define ser_update_bits(reg, mask, bits) max96712_ser_update_bits(link, reg, mask, bits) +diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712_debug.h b/drivers/media/i2c/soc_camera/gmsl/max96712_debug.h +new file mode 100644 +index 0000000..ee47c04 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/gmsl/max96712_debug.h +@@ -0,0 +1,362 @@ ++/* ++ * MAXIM max96712 GMSL2 driver debug stuff ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++static char *pipe_names[4] = { ++ "X", "Y", "Z", "U" ++}; ++ ++static int max96712_gmsl1_get_link_lock(struct max96712_priv *priv, int link_n); ++static int max96712_gmsl2_get_link_lock(struct max96712_priv *priv, int link_n); ++ ++#define reg_bits(x, y) ((reg >> (x)) & ((1 << (y)) - 1)) ++ ++static ssize_t max_link_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct max96712_priv *priv = i2c_get_clientdata(client); ++ int i = -1; ++ int j; ++ int gmsl2; ++ u32 crc = 0 ; ++ char *_buf = buf; ++ int reg = 0; ++ ++ if (!sscanf(attr->attr.name, "link_%d", &i)) ++ return -EINVAL; ++ ++ if (i < 0) ++ return -EINVAL; ++ ++ if (i >= priv->n_links) { ++ buf += sprintf(buf, "\n"); ++ return (buf - _buf); ++ } ++ ++ buf += sprintf(buf, "Link %c status\n", 'A' + i); ++ ++ des_read(MAX96712_REG6, ®); ++ gmsl2 = !!(reg & BIT(4 + i)); ++ buf += sprintf(buf, "Link mode: %s\n", gmsl2 ? "GMSL2" : "GMSL1"); ++ ++ if (gmsl2) { ++ buf += sprintf(buf, "GMSL2 Link lock: %d\n", max96712_gmsl2_get_link_lock(priv, i)); ++ } else { ++ reg = max96712_gmsl1_get_link_lock(priv, i); ++ buf += sprintf(buf, ++ "GMSL1_CB: 0x%02x:\t" ++ "LOCKED_G1: %d\n", ++ reg, reg_bits(0, 1)); ++ ++ des_read(MAX_GMSL1_CA(i), ®); ++ buf += sprintf(buf, ++ "GMSL1_CA: 0x%02x:\t" ++ "PHASELOCK: %d, WBLOCK_G1: %d, DATAOK: %d\n", ++ reg, reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ ++ des_read(MAX_GMSL1_1B(i), ®); ++ buf += sprintf(buf, ++ "GMSL1_1B: 0x%02x:\t" ++ "LINE_CRC_ERR: %d ", ++ reg, reg_bits(2, 1)); ++ for (j = 0; j < 4; j++) { ++ des_read(MAX_GMSL1_20(i) + j, ®); ++ crc = crc | ((reg & 0xff) << (j * 8)); ++ } ++ buf += sprintf(buf, "last crc 0x%08x\n", crc); ++ ++ des_read(MAX_GMSL1_19(i), ®); ++ buf += sprintf(buf, ++ "GMSL1_19: CC_CRC_ERRCNT %d\n", ++ reg); ++ ++ des_read(MAX_GMSL1_1D(i), ®); ++ buf += sprintf(buf, ++ "GMSL1_1D: 0x%02x:\t" ++ "UNDERBOOST: %d, AEQ-BST: %d\n", ++ reg, reg_bits(4, 1), reg_bits(0, 4)); ++ } ++ ++ return (buf - _buf); ++} ++ ++static ssize_t max_pipe_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct max96712_priv *priv = i2c_get_clientdata(client); ++ char *_buf = buf; ++ int pipe = 0; ++ int map; ++ int maps_en = 0; ++ int pipes_en; ++ int reg = 0; ++ int shift; ++ ++ if (!sscanf(attr->attr.name, "pipe_%d", &pipe)) ++ return -EINVAL; ++ ++ if (pipe < 0) ++ return -EINVAL; ++ ++ if (pipe >= MAX96712_MAX_PIPES) { ++ buf += sprintf(buf, "\n"); ++ return (buf - _buf); ++ } ++ ++ des_read(MAX96712_VIDEO_PIPE_EN, &pipes_en); ++ ++ buf += sprintf(buf, "Video Pipe %d %s\n", ++ pipe, (pipes_en & BIT(pipe)) ? "ENABLED" : "disabled"); ++ if (!(pipes_en & BIT(pipe))) ++ goto out; ++ ++ des_read(MAX_VPRBS(pipe), ®); ++ /* bit 5 is not valid for MAX96712 */ ++ buf += sprintf(buf, ++ "\tVPRBS: 0x%02x\t" ++ "VPRBS_FAIL: %d," ++ "VIDEO_LOCK: %d\n", ++ reg, ++ reg_bits(5, 1), reg_bits(0, 1)); ++ ++ /* show source */ ++ shift = (pipe % 2) * 4; ++ des_read(MAX96712_VIDEO_PIPE_SEL(pipe / 2), ®); ++ buf += sprintf(buf, "SRC: PHY %c, PIPE %s\n", ++ 'A' + (char)((reg >> (shift + 2)) & 0x03), ++ pipe_names[(reg >> shift) & 0x03]); ++ ++ /* show maps */ ++ des_read(MAX_MIPI_TX11(pipe), &maps_en); ++ des_read(MAX_MIPI_TX12(pipe), ®); ++ maps_en |= reg << 8; ++ ++ for (map = 0; map < MAX96712_MAX_PIPE_MAPS; map++) { ++ int src, dst, mipi; ++ if (!(maps_en & BIT(map))) ++ continue; ++ ++ des_read(MAX_MIPI_MAP_SRC(pipe, map), &src); ++ des_read(MAX_MIPI_MAP_DST(pipe, map), &dst); ++ des_read(MAX_MIPI_MAP_DST_PHY(pipe, map / 4), &mipi); ++ ++ buf += sprintf(buf, " MAP%d: DT %02x, VC %d -> DT %02x, VC %d MIPI %d\n", ++ map, ++ src & 0x3f, (src >> 6) & 0x03, dst & 0x3f, (dst >> 6) & 0x03, ++ (mipi >> ((map % 4) * 2)) & 0x03); ++ } ++ ++ des_read(MAX_VIDEO_RX0(pipe), ®); ++ buf += sprintf(buf, ++ "VIDEO_RX0: 0x%02x\t" ++ "LCRC_ERR: %d, " ++ "LINE_CRC_SEL: %d, " ++ "LINE_CRC_EN: %d, " ++ "DIS_PKT_DET: %d\n", ++ reg, ++ reg_bits(7, 1), ++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ des_read(MAX_VIDEO_RX3(pipe), ®); ++ buf += sprintf(buf, ++ "VIDEO_RX3: 0x%02x\t" ++ "HD_TR_MODE: %d, " ++ "DLOCKED: %d, " ++ "VLOCKED: %d, " ++ "HLOCKED: %d, " ++ "DTRACKEN: %d, " ++ "VTRACKEN: %d, " ++ "HTRACKEN: %d\n", ++ reg, ++ reg_bits(6, 1), ++ reg_bits(5, 1), reg_bits(4, 1), reg_bits(3, 1), ++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ des_read(MAX_VIDEO_RX8(pipe), ®); ++ buf += sprintf(buf, ++ "VIDEO_RX8: 0x%02x\t" ++ "VID_BLK_LEN_ERR: %d, " ++ "VID_LOCK: %d, " ++ "VID_PKT_DET: %d, " ++ "VID_SEQ_ERR: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), ++ reg_bits(5, 1), reg_bits(4, 1)); ++ des_read(MAX_VIDEO_RX10(pipe), ®); ++ buf += sprintf(buf, ++ "VIDEO_RX10: 0x%02x\t" ++ "MASK_VIDEO_DE: %d\n", ++ reg, ++ reg_bits(6, 1)); ++ ++out: ++ return (buf - _buf); ++} ++ ++static ssize_t max_stat_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct max96712_priv *priv = i2c_get_clientdata(client); ++ int i; ++ char *_buf = buf; ++ int reg = 0; ++ ++ /* TODO: add same for 96712 */ ++ des_read(MAX96712_REG4, ®); ++ buf += sprintf(buf, ++ "REG_REG4: 0x%02x\t" ++ "LOCK_CFG: %d\n", ++ reg, reg_bits(5, 1)); ++ ++ des_read(MAX_BACKTOP1(0), ®); ++ buf += sprintf(buf, ++ "BACKTOP1: 0x%02x:\t" ++ "CSIPLL3_LOCK: %d, " ++ "CSIPLL2_LOCK: %d, " ++ "CSIPLL1_LOCK: %d, " ++ "CSIPLL0_LOCK: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1)); ++ ++ des_read(MAX_BACKTOP11(0), ®); ++ buf += sprintf(buf, ++ "BACKTOP11: 0x%02x:\t" ++ "CMD_OWERFLOW4: %d, " ++ "CMD_OWERFLOW3: %d, " ++ "CMD_OWERFLOW2: %d, " ++ "CMD_OWERFLOW1: %d, " ++ "LMO_3: %d, " ++ "LMO_2: %d, " ++ "LMO_1: %d, " ++ "LMO_0: %d\n", ++ reg, ++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1), ++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1)); ++ ++ for (i = 0; i < MAX96712_MAX_MIPI; i++) { ++ buf += sprintf(buf, "MIPI %d\n", i); ++ des_read(MAX_MIPI_TX2(i), ®); ++ buf += sprintf(buf, ++ "\tMIPI_TX2: 0x%02x\n", ++ reg); ++ } ++ ++ return (buf - _buf); ++} ++ ++static DEVICE_ATTR(link_0, S_IRUGO, max_link_show, NULL); ++static DEVICE_ATTR(link_1, S_IRUGO, max_link_show, NULL); ++static DEVICE_ATTR(link_2, S_IRUGO, max_link_show, NULL); ++static DEVICE_ATTR(link_3, S_IRUGO, max_link_show, NULL); ++static DEVICE_ATTR(pipe_0, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_1, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_2, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_3, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_4, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_5, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_6, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(pipe_7, S_IRUGO, max_pipe_show, NULL); ++static DEVICE_ATTR(stat, S_IRUGO, max_stat_show, NULL); ++ ++static struct attribute *max96712_attributes[] = { ++ &dev_attr_link_0.attr, ++ &dev_attr_link_1.attr, ++ &dev_attr_link_2.attr, ++ &dev_attr_link_3.attr, ++ &dev_attr_pipe_0.attr, ++ &dev_attr_pipe_1.attr, ++ &dev_attr_pipe_2.attr, ++ &dev_attr_pipe_3.attr, ++ &dev_attr_pipe_4.attr, ++ &dev_attr_pipe_5.attr, ++ &dev_attr_pipe_6.attr, ++ &dev_attr_pipe_7.attr, ++ &dev_attr_stat.attr, ++ NULL ++}; ++ ++static const struct attribute_group max96712_group = { ++ .attrs = max96712_attributes, ++}; ++ ++int max96712_debug_add(struct max96712_priv *priv) ++{ ++ int ret; ++ ++ ret = sysfs_create_group(&priv->client->dev.kobj, &max96712_group); ++ if (ret < 0) { ++ dev_err(&priv->client->dev, "Sysfs registration failed\n"); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++void max96712_debug_remove(struct max96712_priv *priv) ++{ ++ sysfs_remove_group(&priv->client->dev.kobj, &max96712_group); ++} ++ ++#if 0 ++int max96712_patgen(struct max96712_priv *priv) ++{ ++ int ret = 0; ++ ++ const u32 xres = 1280; ++ const u32 yres = 800; ++ const u32 hbp = 128; ++ const u32 hfp = 80; ++ const u32 hsa = 32; ++ const u32 vbp = 17; ++ const u32 vfp = 4; ++ const u32 vsa = 3; ++ ++ u32 vtotal = vfp + vsa + vbp + yres; ++ u32 htotal = xres + hfp + hbp + hsa; ++ u32 vs_high = vsa * htotal; ++ u32 vs_low = (vfp + yres + vbp) * htotal; ++ u32 v2h = (vsa + vbp) * htotal + hfp; ++ u32 hs_high = hsa; ++ u32 hs_low = xres + hfp + hbp; ++ u32 v2d = v2h + hsa + hbp; ++ u32 de_high = xres; ++ u32 de_low = hfp + hsa + hbp; ++ u32 de_cnt = yres; ++ ++ /* DEBUG_EXTRA & PATGEN_CLK_SRC = 75Mhz pclk */ ++ des_write(0x0009, 0x01); /* if DEBUG_EXTRA[1:0] = 2b01, PCLK Frequency is 75MHz (don't care PATGEN_CLK_SRC) */ ++ des_write(0x01dc, 0x00); ++ ++ des_write_n(0x1052, 3, 0); /* vs delay */ ++ des_write_n(0x1055, 3, vs_high); ++ des_write_n(0x1058, 3, vs_low); ++ des_write_n(0x105B, 3, v2h); ++ des_write_n(0x105E, 2, hs_high); ++ des_write_n(0x1060, 2, hs_low); ++ des_write_n(0x1062, 2, vtotal); /* hs cnt */ ++ des_write_n(0x1064, 3, v2d); ++ des_write_n(0x1067, 2, de_high); ++ des_write_n(0x1069, 2, de_low); ++ des_write_n(0x106B, 2, de_cnt); ++ ++ des_write_n(0x106E, 3, 0xff0000); /* color A */ ++ des_write_n(0x1071, 3, 0x0000ff); /* color B */ ++ ++ des_write(0x1074, 0x50); /* chkr_rpt_a = 80 */ ++ des_write(0x1075, 0x50); /* chkr_rpt_b = 80 */ ++ des_write(0x1076, 0x50); /* chkr_alt = 80 */ ++ ++ des_write(0x1050, 0xfb); /* gen_vs,gen_hs,gen_de, vtg[0:1] */ ++ des_write(0x1051, 0x10); /* patgen_mode[5:4] = 0b1,checkerboard */ ++ ++out: ++ return ret; ++} ++#endif +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0494-media-i2c-max9286-max9288-use-common.h-file.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0494-media-i2c-max9286-max9288-use-common.h-file.patch new file mode 100644 index 00000000..ea20fd1d --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0494-media-i2c-max9286-max9288-use-common.h-file.patch @@ -0,0 +1,218 @@ +From 083a58c074efe94a68fbb2deac66d404f7644e32 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 10:56:45 +0300 +Subject: [PATCH] media: i2c: max9286,max9288: use common.h file + +Use common.h file for all gmsl drivers + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/gmsl/max9286.c | 61 +++++++++-------------------- + drivers/media/i2c/soc_camera/gmsl/max9288.c | 54 +++++++------------------ + 2 files changed, 34 insertions(+), 81 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9286.c b/drivers/media/i2c/soc_camera/gmsl/max9286.c +index 2d56b41..c37e972 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max9286.c ++++ b/drivers/media/i2c/soc_camera/gmsl/max9286.c +@@ -22,16 +22,7 @@ + #include <media/v4l2-device.h> + #include <media/v4l2-subdev.h> + +-#include "../max9286.h" +- +-#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */ +-#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */ +-#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */ +-#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */ +-#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ +-#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ +-#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ +-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ ++#include "common.h" + + struct max9286_priv { + struct v4l2_subdev sd[4]; +@@ -174,20 +165,6 @@ static int dt2bpp [9] = { + 14, /* RAW14 */ + }; + +-static char* ser_name(int id) +-{ +- switch (id) { +- case MAX9271_ID: +- return "MAX9271"; +- case MAX96705_ID: +- return "MAX96705"; +- case MAX96707_ID: +- return "MAX96707"; +- default: +- return "unknown"; +- } +-} +- + static void max9286_write_remote_verify(struct i2c_client *client, int idx, u8 reg, u8 val) + { + struct max9286_priv *priv = i2c_get_clientdata(client); +@@ -384,7 +361,7 @@ static int max9286_reverse_channel_setup(struct i2c_client *client, int idx) + + out: + sprintf(timeout_str, "retries=%d lock_sts=%d link_sts=0x%x", priv->timeout - timeout, !!(lock_sts & 0x80), link_sts & (0x11 << idx)); +- dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, ser_name(priv->ser_id), ++ dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, chip_name(priv->ser_id), + ret == -EADDRINUSE ? "already " : "", priv->max9271_addr_map[idx], + ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", + priv->timeout - timeout ? timeout_str : ""); +@@ -576,6 +553,22 @@ static int max9286_initialize(struct i2c_client *client) + return 0; + } + ++static int max9286_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ if (on) { ++ if (atomic_inc_return(&priv->use_count) == 1) ++ reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */ ++ } else { ++ if (atomic_dec_return(&priv->use_count) == 0) ++ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ ++ } ++ ++ return 0; ++} ++ + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int max9286_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +@@ -605,22 +598,6 @@ static int max9286_s_register(struct v4l2_subdev *sd, + } + #endif + +-static int max9286_s_power(struct v4l2_subdev *sd, int on) +-{ +- struct max9286_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- +- if (on) { +- if (atomic_inc_return(&priv->use_count) == 1) +- reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */ +- } else { +- if (atomic_dec_return(&priv->use_count) == 0) +- reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ +- } +- +- return 0; +-} +- + static int max9286_registered_async(struct v4l2_subdev *sd) + { + struct max9286_priv *priv = v4l2_get_subdevdata(sd); +@@ -656,7 +633,7 @@ static int max9286_reboot_notifier(struct notifier_block *nb, unsigned long even + gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ + } + +- return NOTIFY_OK; ++ return NOTIFY_DONE; + } + + static struct v4l2_subdev_core_ops max9286_subdev_core_ops = { +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9288.c b/drivers/media/i2c/soc_camera/gmsl/max9288.c +index 7de1f9e..ce44e2b 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max9288.c ++++ b/drivers/media/i2c/soc_camera/gmsl/max9288.c +@@ -21,16 +21,7 @@ + #include <media/v4l2-device.h> + #include <media/v4l2-subdev.h> + +-#include "../max9286.h" +- +-#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */ +-#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */ +-#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */ +-#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */ +-#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ +-#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ +-#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ +-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ ++#include "common.h" + + struct max9288_priv { + struct v4l2_subdev sd; +@@ -140,23 +131,8 @@ static int dt2bpp [9] = { + 14, /* RAW14 */ + }; + +-static char* ser_name(int id) +-{ +- switch (id) { +- case MAX9271_ID: +- return "MAX9271"; +- case MAX96705_ID: +- return "MAX96705"; +- case MAX96707_ID: +- return "MAX96707"; +- default: +- return "unknown"; +- } +-} +- + static void max9288_write_remote_verify(struct i2c_client *client, u8 reg, u8 val) + { +- struct max9288_priv *priv = i2c_get_clientdata(client); + int timeout; + + for (timeout = 0; timeout < 10; timeout++) { +@@ -297,7 +273,7 @@ static int max9288_reverse_channel_setup(struct i2c_client *client) + + out: + sprintf(timeout_str, "retries=%d lock_sts=%d", priv->timeout - timeout, !!(lock_sts & 0x80)); +- dev_info(&client->dev, "link %s %sat 0x%x %s %s\n", ser_name(priv->ser_id), ++ dev_info(&client->dev, "link %s %sat 0x%x %s %s\n", chip_name(priv->ser_id), + ret == -EADDRINUSE ? "already " : "", priv->max9271_addr, + ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", + priv->timeout - timeout ? timeout_str : ""); +@@ -487,6 +463,19 @@ static int max9288_initialize(struct i2c_client *client) + return 0; + } + ++static int max9288_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct max9288_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */ ++ max9288_write_remote_verify(client, 0x04, on ? (conf_link ? 0x43 : 0x83) : 0x43); /* enable serial_link or conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */ ++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ ++ ++ return 0; ++} ++ + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int max9288_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +@@ -516,19 +505,6 @@ static int max9288_s_register(struct v4l2_subdev *sd, + } + #endif + +-static int max9288_s_power(struct v4l2_subdev *sd, int on) +-{ +- struct max9288_priv *priv = v4l2_get_subdevdata(sd); +- struct i2c_client *client = priv->client; +- +- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */ +- max9288_write_remote_verify(client, 0x04, on ? (conf_link ? 0x43 : 0x83) : 0x43); /* enable serial_link or conf_link */ +- usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */ +- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */ +- +- return 0; +-} +- + static struct v4l2_subdev_core_ops max9288_subdev_core_ops = { + #ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = max9288_g_register, +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0495-media-i2c-ti9x4-fix-rebot_notify-and-gpiod_request.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0495-media-i2c-ti9x4-fix-rebot_notify-and-gpiod_request.patch new file mode 100644 index 00000000..9069ad63 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0495-media-i2c-ti9x4-fix-rebot_notify-and-gpiod_request.patch @@ -0,0 +1,62 @@ +From 6ecc8987af944ca48a3565111bd1af7293d5a3ac Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 10:59:10 +0300 +Subject: [PATCH] media: i2c: ti9x4: fix rebot_notify and gpiod_request + +This fixed reboot return value and initialize power gpiod +during request + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/fpdlink/ti9x4.c | 8 ++++---- + drivers/media/i2c/soc_camera/fpdlink/ti9x4.h | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c +index 340e61e..24ac2e5 100644 +--- a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c ++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c +@@ -1,7 +1,7 @@ +- /* ++/* + * TI DS90UB954/960/964 FPDLinkIII driver + * +- * Copyright (C) 2017-2018 Cogent Embedded, Inc. ++ * Copyright (C) 2017-2020 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the +@@ -433,7 +433,7 @@ static int ti9x4_reboot_notifier(struct notifier_block *nb, unsigned long event, + gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */ + } + +- return NOTIFY_OK; ++ return NOTIFY_DONE; + } + + static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = { +@@ -511,7 +511,7 @@ static int ti9x4_parse_dt(struct i2c_client *client) + v4l2_clk_enable(priv->ref_clk); + } + +- priv->pwen = devm_gpiod_get(&client->dev, NULL, GPIOF_OUT_INIT_HIGH); ++ priv->pwen = devm_gpiod_get(&client->dev, NULL, GPIOD_OUT_HIGH); + if (!IS_ERR(priv->pwen)) { + mdelay(5); + gpiod_direction_output(priv->pwen, 0); +diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h +index 6825f8a..964ab78 100644 +--- a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h ++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h +@@ -1,7 +1,7 @@ + /* + * TI FPDLinkIII driver include file + * +- * Copyright (C) 2017 Cogent Embedded, Inc. ++ * Copyright (C) 2017-2020 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0496-media-i2c-add-interim-LVDS-imager-drivers.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0496-media-i2c-add-interim-LVDS-imager-drivers.patch new file mode 100644 index 00000000..267cff29 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0496-media-i2c-add-interim-LVDS-imager-drivers.patch @@ -0,0 +1,5202 @@ +From b60ec01692d2a2e8ee28e6aae58fe78fd806d733 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 11:02:31 +0300 +Subject: [PATCH] media: i2c: add interim LVDS imager drivers + +This adds new LVDS imager drivers that support all enabled +serializers + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imagers/Makefile | 5 + + .../media/i2c/soc_camera/imagers/ap0101_ar014x.c | 618 +++++++++++ + .../media/i2c/soc_camera/imagers/ap0101_ar014x.h | 28 + + .../media/i2c/soc_camera/imagers/ap0201_ar023x.c | 588 ++++++++++ + .../media/i2c/soc_camera/imagers/ap0201_ar023x.h | 24 + + drivers/media/i2c/soc_camera/imagers/ov10635.c | 690 ++++++++++++ + drivers/media/i2c/soc_camera/imagers/ov10635.h | 1143 ++++++++++++++++++++ + .../media/i2c/soc_camera/imagers/ov10635_debug.h | 54 + + drivers/media/i2c/soc_camera/imagers/ov2311.c | 571 ++++++++++ + drivers/media/i2c/soc_camera/imagers/ov2311.h | 217 ++++ + drivers/media/i2c/soc_camera/imagers/ov490.c | 1051 ++++++++++++++++++ + drivers/media/i2c/soc_camera/imagers/ov490.h | 102 ++ + 12 files changed, 5091 insertions(+) + create mode 100644 drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c + create mode 100644 drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h + create mode 100644 drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c + create mode 100644 drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h + create mode 100644 drivers/media/i2c/soc_camera/imagers/ov10635.c + create mode 100644 drivers/media/i2c/soc_camera/imagers/ov10635.h + create mode 100644 drivers/media/i2c/soc_camera/imagers/ov10635_debug.h + create mode 100644 drivers/media/i2c/soc_camera/imagers/ov2311.c + create mode 100644 drivers/media/i2c/soc_camera/imagers/ov2311.h + create mode 100644 drivers/media/i2c/soc_camera/imagers/ov490.c + create mode 100644 drivers/media/i2c/soc_camera/imagers/ov490.h + +diff --git a/drivers/media/i2c/soc_camera/imagers/Makefile b/drivers/media/i2c/soc_camera/imagers/Makefile +index ca10bbc..0d0ff32 100644 +--- a/drivers/media/i2c/soc_camera/imagers/Makefile ++++ b/drivers/media/i2c/soc_camera/imagers/Makefile +@@ -1,2 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov10635.o ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov2311.o ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov490.o ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0101_ar014x.o ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0201_ar023x.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += dummy.o +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c +new file mode 100644 +index 0000000..1df3f3b +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c +@@ -0,0 +1,618 @@ ++/* ++ * ON Semiconductor AP0101-AR014X sensor camera driver ++ * ++ * Copyright (C) 2018-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++#include "../gmsl/common.h" ++#include "ap0101_ar014x.h" ++ ++static const int ap0101_i2c_addr[] = {0x5d, 0x48}; ++ ++#define AP0101_PID_REG 0x0000 ++#define AP0101_REV_REG 0x0058 ++#define AP0101_PID 0x0160 ++ ++#define AP0101_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8 ++ ++struct ap0101_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int max_width; ++ int max_height; ++ int init_complete; ++ u8 id[6]; ++ int exposure; ++ int gain; ++ int autogain; ++ /* serializers */ ++ int ser_addr; ++ int hts; ++ int vts; ++ int frame_preamble; ++}; ++ ++static inline struct ap0101_priv *to_ap0101(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ap0101_priv, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ap0101_priv, hdl)->sd; ++} ++ ++static int ap0101_set_regs(struct i2c_client *client, ++ const struct ap0101_reg *regs, int nr_regs) ++{ ++ int i; ++ ++ for (i = 0; i < nr_regs; i++) { ++ if (regs[i].reg == AP0101_DELAY) { ++ mdelay(regs[i].val); ++ continue; ++ } ++ ++ reg16_write16(client, regs[i].reg, regs[i].val); ++ } ++ ++ return 0; ++} ++ ++static u16 ap0101_ar014x_read(struct i2c_client *client, u16 addr) ++{ ++ u16 reg_val = 0; ++ ++ reg16_write16(client, 0x0040, 0x8d00); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0xfc00, addr); ++ reg16_write16(client, 0xfc02, 0x0200); /* 2 bytes */ ++ reg16_write16(client, 0x0040, 0x8d05); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0x0040, 0x8d08); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_read16(client, 0xfc00, ®_val); ++ reg16_write16(client, 0x0040, 0x8d02); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ ++ return reg_val; ++} ++ ++static void ap0101_ar014x_write(struct i2c_client *client, u16 addr, u16 val) ++{ ++ reg16_write16(client, 0x0040, 0x8d00); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0xfc00, addr); ++ reg16_write16(client, 0xfc02, 0x0200 | (val >> 8)); /* 2 bytes */ ++ reg16_write16(client, 0xfc04, (val & 0xff) << 8); ++ reg16_write16(client, 0x0040, 0x8d06); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0x0040, 0x8d08); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0x0040, 0x8d02); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++} ++ ++static void ap0101_otp_id_read(struct i2c_client *client) ++{ ++ struct ap0101_priv *priv = to_ap0101(client); ++ int i; ++ ++ /* read camera id from ar014x OTP memory */ ++ ap0101_ar014x_write(client, 0x3054, 0x400); ++ ap0101_ar014x_write(client, 0x304a, 0x110); ++ usleep_range(25000, 25500); /* wait 25 ms */ ++ ++ for (i = 0; i < 6; i += 2) { ++ /* first 4 bytes are equal on all ar014x */ ++ priv->id[i] = (ap0101_ar014x_read(client, 0x3800 + i + 4) >> 8) ^ (ap0101_ar014x_read(client, 0x3800 + i + 16) >> 8); ++ priv->id[i + 1] = (ap0101_ar014x_read(client, 0x3800 + i + 4) & 0xff) ^ (ap0101_ar014x_read(client, 0x3800 + i + 16) & 0xff); ++ } ++} ++ ++static int ap0101_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int ap0101_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0101_priv *priv = to_ap0101(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = AP0101_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ap0101_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ ++ mf->code = AP0101_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int ap0101_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = AP0101_MEDIA_BUS_FMT; ++ ++ return 0; ++} ++ ++static int ap0101_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0101_priv *priv = to_ap0101(client); ++ ++ ap0101_otp_id_read(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = AP0101_PID >> 8; ++ edid->edid[9] = AP0101_PID & 0xff; ++ ++ return 0; ++} ++ ++static int ap0101_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0101_priv *priv = to_ap0101(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > priv->max_width) || ++ (rect->top + rect->height > priv->max_height)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ return 0; ++} ++ ++static int ap0101_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0101_priv *priv = to_ap0101(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ap0101_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ap0101_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ __be64 be_val; ++ ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); ++ ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); ++ ++ return ret; ++} ++ ++static int ap0101_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); ++ ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ return reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++} ++#endif ++ ++static struct v4l2_subdev_core_ops ap0101_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ap0101_g_register, ++ .s_register = ap0101_s_register, ++#endif ++}; ++ ++static int ap0101_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0101_priv *priv = to_ap0101(client); ++ int ret = -EINVAL; ++ u16 val = 0; ++ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ case V4L2_CID_SHARPNESS: ++ case V4L2_CID_AUTOGAIN: ++ case V4L2_CID_GAIN: ++ case V4L2_CID_EXPOSURE: ++ break; ++ case V4L2_CID_HFLIP: ++ reg16_read16(client, 0xc846, &val); ++ if (ctrl->val) ++ val |= 0x01; ++ else ++ val &= ~0x01; ++ reg16_write16(client, 0xc846, val); ++ reg16_write16(client, 0xfc00, 0x2800); ++ ret = reg16_write16(client, 0x0040, 0x8100); ++ break; ++ case V4L2_CID_VFLIP: ++ reg16_read16(client, 0xc846, &val); ++ if (ctrl->val) ++ val |= 0x02; ++ else ++ val &= ~0x02; ++ reg16_write16(client, 0xc846, val); ++ reg16_write16(client, 0xfc00, 0x2800); ++ ret = reg16_write16(client, 0x0040, 0x8100); ++ break; ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ret = 0; ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ap0101_ctrl_ops = { ++ .s_ctrl = ap0101_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops ap0101_video_ops = { ++ .s_stream = ap0101_s_stream, ++ .g_mbus_config = ap0101_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops ap0101_subdev_pad_ops = { ++ .get_edid = ap0101_get_edid, ++ .enum_mbus_code = ap0101_enum_mbus_code, ++ .get_selection = ap0101_get_selection, ++ .set_selection = ap0101_set_selection, ++ .get_fmt = ap0101_get_fmt, ++ .set_fmt = ap0101_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops ap0101_subdev_ops = { ++ .core = &ap0101_core_ops, ++ .video = &ap0101_video_ops, ++ .pad = &ap0101_subdev_pad_ops, ++}; ++ ++static ssize_t ap0101_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0101_priv *priv = to_ap0101(client); ++ ++ ap0101_otp_id_read(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_ap0101, S_IRUGO, ap0101_otp_id_show, NULL); ++ ++static int ap0101_initialize(struct i2c_client *client) ++{ ++ struct ap0101_priv *priv = to_ap0101(client); ++ u16 pid = 0, rev = 0, val = 0; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ap0101_i2c_addr); i++) { ++ setup_i2c_translator(client, priv->ser_addr, ap0101_i2c_addr[i], MODE_GMSL1); ++ ++ /* check model ID */ ++ reg16_read16(client, AP0101_PID_REG, &pid); ++ if (pid == AP0101_PID) ++ break; ++ } ++ ++ if (pid != AP0101_PID) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ return -ENODEV; ++ } ++ ++ reg16_read16(client, AP0101_REV_REG, &rev); ++#if 1 ++ /* read resolution used by current firmware */ ++ reg16_read16(client, 0xca90, &val); ++ priv->max_width = val; ++ reg16_read16(client, 0xca92, &val); ++ priv->max_height = val; ++#else ++ priv->max_width = AP0101_MAX_WIDTH; ++ priv->max_height = AP0101_MAX_HEIGHT; ++#endif ++ /* Program wizard registers */ ++ ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard)); ++ /* Read OTP IDs */ ++ ap0101_otp_id_read(client); ++ ++ switch (get_des_id(client)) { ++ case MAX9286_ID: ++ case MAX9288_ID: ++ case MAX9296A_ID: ++ case MAX96712_ID: ++ /* setup serializer HS generator */ ++ priv->frame_preamble = 5; ++ priv->hts = 1280 * 2 + 548; ++ priv->vts = 960; ++ reg8_write_addr(client, priv->ser_addr, 0x4e, priv->frame_preamble >> 16); /* HS delay */ ++ reg8_write_addr(client, priv->ser_addr, 0x4f, (priv->frame_preamble >> 8) & 0xff); ++ reg8_write_addr(client, priv->ser_addr, 0x50, priv->frame_preamble & 0xff); ++ reg8_write_addr(client, priv->ser_addr, 0x54, (priv->max_width * 2) >> 8); /* HS high period */ ++ reg8_write_addr(client, priv->ser_addr, 0x55, (priv->max_width * 2) & 0xff); ++ reg8_write_addr(client, priv->ser_addr, 0x56, (priv->hts - priv->max_width * 2) >> 8); /* HS low period */ ++ reg8_write_addr(client, priv->ser_addr, 0x57, (priv->hts - priv->max_width * 2) & 0xff); ++ reg8_write_addr(client, priv->ser_addr, 0x58, priv->vts >> 8); /* HS count */ ++ reg8_write_addr(client, priv->ser_addr, 0x59, priv->vts & 0xff); ++ break; ++ } ++ ++ dev_info(&client->dev, "ap0101 PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, rev, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ return 0; ++} ++ ++static const struct i2c_device_id ap0101_id[] = { ++ { "ap0101", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ap0101_id); ++ ++static const struct of_device_id ap0101_of_ids[] = { ++ { .compatible = "onsemi,ap0101", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ap0101_of_ids); ++ ++static int ap0101_parse_dt(struct device_node *np, struct ap0101_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ u32 addrs[2], naddrs; ++ ++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32)); ++ if (naddrs != 2) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ priv->ser_addr = addrs[1]; ++ ++ return 0; ++} ++ ++static int ap0101_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ap0101_priv *priv; ++ struct v4l2_ctrl *ctrl; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &ap0101_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ priv->exposure = 0x100; ++ priv->gain = 0x100; ++ priv->autogain = 1; ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 1); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 1); ++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops, ++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); ++ if (ctrl) ++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = ap0101_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = ap0101_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = priv->max_width; ++ priv->rect.height = priv->max_height; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ap0101) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ return ret; ++} ++ ++static int ap0101_remove(struct i2c_client *client) ++{ ++ struct ap0101_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_ap0101); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++static struct i2c_driver ap0101_i2c_driver = { ++ .driver = { ++ .name = "ap0101", ++ .of_match_table = ap0101_of_ids, ++ }, ++ .probe = ap0101_probe, ++ .remove = ap0101_remove, ++ .id_table = ap0101_id, ++}; ++ ++module_i2c_driver(ap0101_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for AP0101"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h +new file mode 100644 +index 0000000..d0d6205 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h +@@ -0,0 +1,28 @@ ++/* ++ * ON Semiconductor ap0101-ar014x sensor camera wizard 1280x720@30/UYVY/BT601/8bit ++ * ++ * Copyright (C) 2018-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#define AP0101_MAX_WIDTH 1280 ++#define AP0101_MAX_HEIGHT 720 ++ ++#define AP0101_DELAY 0xffff ++ ++struct ap0101_reg { ++ u16 reg; ++ u16 val; ++}; ++ ++static const struct ap0101_reg ap0101_regs_wizard[] = { ++/* enable FSIN */ ++{0xc88c, 0x0303}, ++{0xfc00, 0x2800}, ++{0x0040, 0x8100}, ++{AP0101_DELAY, 100}, ++}; +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +new file mode 100644 +index 0000000..35169b8 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +@@ -0,0 +1,588 @@ ++/* ++ * ON Semiconductor AP0201-AR023X sensor camera driver ++ * ++ * Copyright (C) 2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++#include "ap0201_ar023x.h" ++#include "../gmsl/common.h" ++ ++static const int ap0201_i2c_addr[] = {0x5d, 0x48}; ++ ++#define AP0201_PID_REG 0x0000 ++#define AP0201_REV_REG 0x0058 ++#define AP0201_PID 0x0064 ++ ++#define AP0201_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8 ++ ++struct ap0201_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int max_width; ++ int max_height; ++ int init_complete; ++ u8 id[6]; ++ int exposure; ++ int gain; ++ int autogain; ++ /* serializer */ ++ int ser_addr; ++}; ++ ++static inline struct ap0201_priv *to_ap0201(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ap0201_priv, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ap0201_priv, hdl)->sd; ++} ++ ++static int ap0201_set_regs(struct i2c_client *client, ++ const struct ap0201_reg *regs, int nr_regs) ++{ ++ int i; ++ ++ for (i = 0; i < nr_regs; i++) { ++ if (regs[i].reg == AP0201_DELAY) { ++ mdelay(regs[i].val); ++ continue; ++ } ++ ++ reg16_write16(client, regs[i].reg, regs[i].val); ++ } ++ ++ return 0; ++} ++ ++static u16 ap0201_ar023x_read(struct i2c_client *client, u16 addr) ++{ ++ u16 reg_val = 0; ++ ++ reg16_write16(client, 0x0040, 0x8d00); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0xfc00, addr); ++ reg16_write16(client, 0xfc02, 0x0200); /* 2 bytes */ ++ reg16_write16(client, 0x0040, 0x8d05); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0x0040, 0x8d08); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_read16(client, 0xfc00, ®_val); ++ reg16_write16(client, 0x0040, 0x8d02); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ ++ return reg_val; ++} ++ ++static void ap0201_ar023x_write(struct i2c_client *client, u16 addr, u16 val) ++{ ++ reg16_write16(client, 0x0040, 0x8d00); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0xfc00, addr); ++ reg16_write16(client, 0xfc02, 0x0200 | (val >> 8)); /* 2 bytes */ ++ reg16_write16(client, 0xfc04, (val & 0xff) << 8); ++ reg16_write16(client, 0x0040, 0x8d06); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0x0040, 0x8d08); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++ reg16_write16(client, 0x0040, 0x8d02); ++ usleep_range(1000, 1500); /* wait 1000 us */ ++} ++ ++static void ap0201_otp_id_read(struct i2c_client *client) ++{ ++ struct ap0201_priv *priv = to_ap0201(client); ++ int i; ++ ++ /* read camera id from ar023x OTP memory */ ++ ap0201_ar023x_write(client, 0x3054, 0x400); ++ ap0201_ar023x_write(client, 0x304a, 0x110); ++ usleep_range(25000, 25500); /* wait 25 ms */ ++ ++ for (i = 0; i < 6; i += 2) { ++ u16 val = 0; ++ /* first 4 bytes are equal on all ar023x */ ++ val = ap0201_ar023x_read(client, 0x3800 + i + 4); ++ priv->id[i] = val >> 8; ++ priv->id[i + 1] = val & 0xff; ++ } ++} ++ ++static int ap0201_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int ap0201_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0201_priv *priv = to_ap0201(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = AP0201_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ap0201_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ ++ mf->code = AP0201_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int ap0201_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = AP0201_MEDIA_BUS_FMT; ++ ++ return 0; ++} ++ ++static int ap0201_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0201_priv *priv = to_ap0201(client); ++ ++ ap0201_otp_id_read(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = AP0201_PID >> 8; ++ edid->edid[9] = AP0201_PID & 0xff; ++ ++ return 0; ++} ++ ++static int ap0201_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0201_priv *priv = to_ap0201(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > priv->max_width) || ++ (rect->top + rect->height > priv->max_height)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ return 0; ++} ++ ++static int ap0201_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0201_priv *priv = to_ap0201(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ap0201_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ap0201_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ u16 val = 0; ++ ++ ret = reg16_read16(client, (u16)reg->reg, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = sizeof(u16); ++ ++ return 0; ++} ++ ++static int ap0201_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ return reg16_write16(client, (u16)reg->reg, (u16)reg->val); ++} ++#endif ++ ++static struct v4l2_subdev_core_ops ap0201_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ap0201_g_register, ++ .s_register = ap0201_s_register, ++#endif ++}; ++ ++static int ap0201_change_config(struct i2c_client *client) ++{ ++ reg16_write16(client, 0x098e, 0x7c00); ++ usleep_range(1000, 1500); /* wait 1 ms */ ++ reg16_write16(client, 0xfc00, 0x2800); ++ reg16_write16(client, 0x0040, 0x8100); ++ ++ return 0; ++} ++ ++static int ap0201_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0201_priv *priv = to_ap0201(client); ++ int ret = -EINVAL; ++ u16 val = 0; ++ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ case V4L2_CID_SHARPNESS: ++ case V4L2_CID_AUTOGAIN: ++ case V4L2_CID_GAIN: ++ case V4L2_CID_EXPOSURE: ++ break; ++ case V4L2_CID_HFLIP: ++ reg16_read16(client, 0xc846, &val); ++ if (ctrl->val) ++ val |= 0x01; ++ else ++ val &= ~0x01; ++ reg16_write16(client, 0xc846, val); ++ ret = ap0201_change_config(client); ++ break; ++ case V4L2_CID_VFLIP: ++ reg16_read16(client, 0xc846, &val); ++ if (ctrl->val) ++ val |= 0x02; ++ else ++ val &= ~0x02; ++ reg16_write16(client, 0xc846, val); ++ ret = ap0201_change_config(client); ++ break; ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ret = 0; ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ap0201_ctrl_ops = { ++ .s_ctrl = ap0201_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops ap0201_video_ops = { ++ .s_stream = ap0201_s_stream, ++ .g_mbus_config = ap0201_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops ap0201_subdev_pad_ops = { ++ .get_edid = ap0201_get_edid, ++ .enum_mbus_code = ap0201_enum_mbus_code, ++ .get_selection = ap0201_get_selection, ++ .set_selection = ap0201_set_selection, ++ .get_fmt = ap0201_get_fmt, ++ .set_fmt = ap0201_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops ap0201_subdev_ops = { ++ .core = &ap0201_core_ops, ++ .video = &ap0201_video_ops, ++ .pad = &ap0201_subdev_pad_ops, ++}; ++ ++static ssize_t ap0201_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ap0201_priv *priv = to_ap0201(client); ++ ++ ap0201_otp_id_read(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_ap0201, S_IRUGO, ap0201_otp_id_show, NULL); ++ ++static int ap0201_initialize(struct i2c_client *client) ++{ ++ struct ap0201_priv *priv = to_ap0201(client); ++ u16 pid = 0, rev = 0, val = 0; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ap0201_i2c_addr); i++) { ++ setup_i2c_translator(client, priv->ser_addr, ap0201_i2c_addr[i], MODE_GMSL2); ++ ++ /* check product ID */ ++ reg16_read16(client, AP0201_PID_REG, &pid); ++ if (pid == AP0201_PID) ++ break; ++ } ++ ++ if (pid != AP0201_PID) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ return -ENODEV; ++ } ++ ++ reg16_read16(client, AP0201_REV_REG, &rev); ++#if 1 ++ /* read resolution used by current firmware */ ++ reg16_read16(client, 0xcae4, &val); ++ priv->max_width = val; ++ reg16_read16(client, 0xcae6, &val); ++ priv->max_height = val; ++#else ++ priv->max_width = AP0201_MAX_WIDTH; ++ priv->max_height = AP0201_MAX_HEIGHT; ++#endif ++ /* Program wizard registers */ ++ ap0201_set_regs(client, ap0201_regs_wizard, ARRAY_SIZE(ap0201_regs_wizard)); ++ /* Read OTP IDs */ ++ ap0201_otp_id_read(client); ++ ++ dev_info(&client->dev, "ap0201 PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, rev, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ return 0; ++} ++ ++static const struct i2c_device_id ap0201_id[] = { ++ { "ap0201", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ap0201_id); ++ ++static const struct of_device_id ap0201_of_ids[] = { ++ { .compatible = "onsemi,ap0201", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ap0201_of_ids); ++ ++static int ap0201_parse_dt(struct device_node *np, struct ap0201_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ u32 addrs[2], naddrs; ++ ++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32)); ++ if (naddrs != 2) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ priv->ser_addr = addrs[1]; ++ ++ return 0; ++} ++ ++static int ap0201_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ap0201_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &ap0201_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ priv->exposure = 0x100; ++ priv->gain = 0x100; ++ priv->autogain = 1; ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = ap0201_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = ap0201_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = priv->max_width; ++ priv->rect.height = priv->max_height; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ap0201) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ return ret; ++} ++ ++static int ap0201_remove(struct i2c_client *client) ++{ ++ struct ap0201_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_ap0201); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++static struct i2c_driver ap0201_i2c_driver = { ++ .driver = { ++ .name = "ap0201", ++ .of_match_table = ap0201_of_ids, ++ }, ++ .probe = ap0201_probe, ++ .remove = ap0201_remove, ++ .id_table = ap0201_id, ++}; ++ ++module_i2c_driver(ap0201_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for AP0201"); ++MODULE_AUTHOR("Andrey Gusakov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h +new file mode 100644 +index 0000000..c857edc +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h +@@ -0,0 +1,24 @@ ++/* ++ * ON Semiconductor AP0201-AR023X sensor camera ++ * ++ * Copyright (C) 2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#define AP0201_MAX_WIDTH 1920 ++#define AP0201_MAX_HEIGHT 1200 ++ ++#define AP0201_DELAY 0xffff ++ ++struct ap0201_reg { ++ u16 reg; ++ u16 val; ++}; ++ ++static const struct ap0201_reg ap0201_regs_wizard[] = { ++/* enable FSIN */ ++}; +diff --git a/drivers/media/i2c/soc_camera/imagers/ov10635.c b/drivers/media/i2c/soc_camera/imagers/ov10635.c +new file mode 100644 +index 0000000..b9813f7 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ov10635.c +@@ -0,0 +1,690 @@ ++/* ++ * OmniVision ov10635 sensor camera driver ++ * ++ * Copyright (C) 2015-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++#include "../gmsl/common.h" ++#include "ov10635.h" ++ ++#define OV10635_I2C_ADDR 0x30 ++ ++#define OV10635_PID_REGA 0x300a ++#define OV10635_PID_REGB 0x300b ++#define OV10635_PID 0xa635 ++ ++struct ov10635_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int subsampling; ++ int fps_denominator; ++ int init_complete; ++ u8 id[6]; ++ int dvp_order; ++ /* serializers */ ++ int ser_addr; ++}; ++ ++static int dvp_order = 0; ++module_param(dvp_order, int, 0644); ++MODULE_PARM_DESC(dvp_order, " DVP bus bits order"); ++ ++static inline struct ov10635_priv *to_ov10635(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov10635_priv, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov10635_priv, hdl)->sd; ++} ++ ++static int ov10635_set_regs(struct i2c_client *client, ++ const struct ov10635_reg *regs, int nr_regs) ++{ ++ int i; ++ ++ for (i = 0; i < nr_regs; i++) { ++ if (reg16_write(client, regs[i].reg, regs[i].val)) { ++ usleep_range(100, 150); /* wait 100ns */ ++ if (reg16_write(client, regs[i].reg, regs[i].val)) ++ printk("ov10635 reg 0x%04x write failed\n", regs[i].reg); ++ } ++ } ++ ++ return 0; ++} ++ ++static void ov10635_otp_id_read(struct i2c_client *client) ++{ ++ struct ov10635_priv *priv = to_ov10635(client); ++ int i; ++ ++ /* read camera id from OTP memory */ ++ reg16_write(client, 0x3d10, 1); ++ ++ usleep_range(15000, 16000); /* wait 15ms */ ++ ++ for (i = 0; i < 6; i++) ++ reg16_read(client, 0x3d00 + i, &priv->id[i]); ++} ++ ++static int ov10635_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int ov10635_set_window(struct v4l2_subdev *sd, int subsampling) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ ++ /* disable clocks */ ++ reg16_write(client, 0x302e, 0x00); ++ reg16_write(client, 0x301b, 0xff); ++ reg16_write(client, 0x301c, 0xff); ++ reg16_write(client, 0x301a, 0xff); ++ ++ /* setup resolution */ ++ reg16_write(client, 0x3808, priv->rect.width >> 8); ++ reg16_write(client, 0x3809, priv->rect.width & 0xff); ++ reg16_write(client, 0x380a, priv->rect.height >> 8); ++ reg16_write(client, 0x380b, priv->rect.height & 0xff); ++ ++ /* enable/disable subsampling */ ++ reg16_write(client, 0x5005, subsampling ? 0x89 : 0x08); ++ reg16_write(client, 0x3007, subsampling ? 0x02 : 0x01); ++ reg16_write(client, 0x4004, subsampling ? 0x02 : 0x04); ++ ++#if 0 /* This is implemented in VIN via SOC_CAMERA layer, hence skip */ ++ /* horiz crop start */ ++ reg16_write(client, 0x3800, priv->rect.left >> 8); ++ reg16_write(client, 0x3801, priv->rect.left & 0xff); ++ /* horiz crop end */ ++ reg16_write(client, 0x3804, (priv->rect.left + priv->rect.width + 1) >> 8); ++ reg16_write(client, 0x3805, (priv->rect.left + priv->rect.width + 1) & 0xff); ++ /* vert crop start */ ++ reg16_write(client, 0x3802, priv->rect.top >> 8); ++ reg16_write(client, 0x3803, priv->rect.top & 0xff); ++ /* vert crop end */ ++ reg16_write(client, 0x3806, (priv->rect.top + priv->rect.height + 1) >> 8); ++ reg16_write(client, 0x3807, (priv->rect.top + priv->rect.height + 1) & 0xff); ++#endif ++ /* enable clocks */ ++ reg16_write(client, 0x301b, 0xf0); ++ reg16_write(client, 0x301c, 0xf0); ++ reg16_write(client, 0x301a, 0xf0); ++ reg16_write(client, 0x302e, 0x01); ++ ++ return 0; ++}; ++ ++static int ov10635_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov10635_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ ++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int ov10635_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_YUYV8_2X8; ++ ++ return 0; ++} ++ ++static int ov10635_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = OV10635_PID >> 8; ++ edid->edid[9] = OV10635_PID & 0xff; ++ ++ return 0; ++} ++ ++static int ov10635_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ int subsampling = 0; ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > OV10635_MAX_WIDTH) || ++ (rect->top + rect->height > OV10635_MAX_HEIGHT)) ++ *rect = priv->rect; ++ ++ if (rect->width == OV10635_MAX_WIDTH / 2 && ++ rect->height == OV10635_MAX_HEIGHT / 2) ++ subsampling = 1; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ /* change window only for subsampling, crop is done by VIN */ ++ if (subsampling != priv->subsampling) { ++ ov10635_set_window(sd, subsampling); ++ priv->subsampling = subsampling; ++ } ++ ++ return 0; ++} ++ ++static int ov10635_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = OV10635_MAX_WIDTH; ++ sel->r.height = OV10635_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = OV10635_MAX_WIDTH; ++ sel->r.height = OV10635_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ov10635_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++static int ov10635_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ memset(cp, 0, sizeof(struct v4l2_captureparm)); ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = 1; ++ cp->timeperframe.denominator = priv->fps_denominator; ++ ++ return 0; ++} ++ ++static int ov10635_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ int ret = 0; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator) { ++ switch (cp->timeperframe.denominator) { ++ case 5: ++ ret = ov10635_set_regs(client, ov10635_regs_5fps, ++ ARRAY_SIZE(ov10635_regs_5fps)); ++ break; ++ case 10: ++ ret = ov10635_set_regs(client, ov10635_regs_10fps, ++ ARRAY_SIZE(ov10635_regs_10fps)); ++ break; ++ case 15: ++ ret = ov10635_set_regs(client, ov10635_regs_15fps, ++ ARRAY_SIZE(ov10635_regs_15fps)); ++ break; ++ case 30: ++ ret = ov10635_set_regs(client, ov10635_regs_30fps, ++ ARRAY_SIZE(ov10635_regs_30fps)); ++ break; ++ default: ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++ ++out: ++ return ret; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov10635_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ __be64 be_val; ++ ++ if (!reg->size) ++ reg->size = sizeof(u8); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); ++ ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); ++ ++ return ret; ++} ++ ++static int ov10635_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u8); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); ++ ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; ++} ++#endif ++ ++static struct v4l2_subdev_core_ops ov10635_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov10635_g_register, ++ .s_register = ov10635_s_register, ++#endif ++}; ++ ++static int ov10635_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ int ret = -EINVAL; ++ u8 val = 0; ++ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ /* AEC/AGC target */ ++ ret = reg16_write(client, 0xc46a, ctrl->val); ++ break; ++ case V4L2_CID_CONTRAST: ++ udelay(100); ++ ret = ov10635_set_regs(client, &ov10635_regs_contrast[ctrl->val][0], 18); ++ break; ++ case V4L2_CID_SATURATION: ++ ret = reg16_write(client, 0xc316, ctrl->val); ++ break; ++ case V4L2_CID_HUE: ++ /* CMX ? */ ++ ret = 0; ++ break; ++ case V4L2_CID_GAMMA: ++ ret = reg16_write(client, 0xc4be, ctrl->val >> 8); ++ ret |= reg16_write(client, 0xc4bf, ctrl->val & 0xff); ++ break; ++ case V4L2_CID_AUTOGAIN: ++ /* automatic gain/exposure */ ++ ret = reg16_write(client, 0x56d0, !ctrl->val); ++ break; ++ case V4L2_CID_GAIN: ++ /* manual gain */ ++ ret = reg16_write(client, 0x3504, 0); ++ ret |= reg16_write(client, 0x56d1, ctrl->val >> 8); ++ ret |= reg16_write(client, 0x56d2, ctrl->val & 0xff); ++ ret |= reg16_write(client, 0x3504, 1); /* validate gain */ ++ break; ++ case V4L2_CID_EXPOSURE: ++ /* manual exposure */ ++ ret = reg16_write(client, 0x3504, 0); ++ ret |= reg16_write(client, 0x56d5, ctrl->val >> 8); ++ ret |= reg16_write(client, 0x56d6, ctrl->val & 0xff); ++ ret |= reg16_write(client, 0x3504, 1); /* validate exposure */ ++ break; ++ case V4L2_CID_HFLIP: ++ ret = reg16_read(client, 0x381d, &val); ++ if (ctrl->val) ++ val |= 0x3; ++ else ++ val &= ~0x3; ++ ret |= reg16_write(client, 0x381d, val); ++ break; ++ case V4L2_CID_VFLIP: ++ ret = reg16_read(client, 0x381c, &val); ++ if (ctrl->val) ++ val |= 0xc0; ++ else ++ val &= ~0xc0; ++ ret |= reg16_write(client, 0x381c, val); ++ break; ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ret = 0; ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov10635_ctrl_ops = { ++ .s_ctrl = ov10635_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops ov10635_video_ops = { ++ .s_stream = ov10635_s_stream, ++ .g_mbus_config = ov10635_g_mbus_config, ++ .g_parm = ov10635_g_parm, ++ .s_parm = ov10635_s_parm, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov10635_subdev_pad_ops = { ++ .get_edid = ov10635_get_edid, ++ .enum_mbus_code = ov10635_enum_mbus_code, ++ .get_selection = ov10635_get_selection, ++ .set_selection = ov10635_set_selection, ++ .get_fmt = ov10635_get_fmt, ++ .set_fmt = ov10635_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops ov10635_subdev_ops = { ++ .core = &ov10635_core_ops, ++ .video = &ov10635_video_ops, ++ .pad = &ov10635_subdev_pad_ops, ++}; ++ ++static ssize_t ov10635_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_ov10635, S_IRUGO, ov10635_otp_id_show, NULL); ++ ++static int ov10635_initialize(struct i2c_client *client) ++{ ++ struct ov10635_priv *priv = to_ov10635(client); ++ u8 val = 0; ++ u16 pid = 0; ++ ++ setup_i2c_translator(client, priv->ser_addr, OV10635_I2C_ADDR, MODE_GMSL1); ++ udelay(100); ++ ++ reg16_read(client, OV10635_PID_REGA, &val); ++ pid = val; ++ reg16_read(client, OV10635_PID_REGB, &val); ++ pid = (pid << 8) | val; ++ ++ if (pid != OV10635_PID) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ return -ENODEV; ++ } ++ ++ /* s/w reset sensor */ ++ reg16_write(client, 0x103, 0x1); ++ udelay(100); ++ /* Program wizard registers */ ++ ov10635_set_regs(client, ov10635_regs_wizard, ARRAY_SIZE(ov10635_regs_wizard)); ++ /* Set DVP bit swap */ ++ reg16_write(client, 0x4709, priv->dvp_order << 4); ++ /* Read OTP IDs */ ++ ov10635_otp_id_read(client); ++ ++ dev_info(&client->dev, "ov10635 PID %x, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ return 0; ++} ++ ++static const struct i2c_device_id ov10635_id[] = { ++ { "ov10635", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov10635_id); ++ ++static const struct of_device_id ov10635_of_ids[] = { ++ { .compatible = "ovti,ov10635", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ov10635_of_ids); ++ ++static int ov10635_parse_dt(struct device_node *np, struct ov10635_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ u32 addrs[2], naddrs; ++ ++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32)); ++ if (naddrs != 2) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ priv->ser_addr = addrs[1]; ++ ++ if (of_property_read_u32(np, "dvp-order", &priv->dvp_order)) ++ priv->dvp_order = 0; ++ ++ /* module params override dts */ ++ if (dvp_order) ++ priv->dvp_order = dvp_order; ++ ++ return 0; ++} ++ ++static int ov10635_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov10635_priv *priv; ++ struct v4l2_ctrl *ctrl; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &ov10635_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = OV10635_MAX_WIDTH; ++ priv->rect.height = OV10635_MAX_HEIGHT; ++ priv->fps_denominator = 30; ++ ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x30); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 4, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 0xff, 1, 0xff); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_HUE, 0, 255, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_GAMMA, 0, 0xffff, 1, 0x233); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, 1); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_GAIN, 0, 0x3ff, 1, 0x10); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, 0x80); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); ++ if (ctrl) ++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = ov10635_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = ov10635_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov10635) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ return ret; ++} ++ ++static int ov10635_remove(struct i2c_client *client) ++{ ++ struct ov10635_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_ov10635); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++static struct i2c_driver ov10635_i2c_driver = { ++ .driver = { ++ .name = "ov10635", ++ .of_match_table = ov10635_of_ids, ++ }, ++ .probe = ov10635_probe, ++ .remove = ov10635_remove, ++ .id_table = ov10635_id, ++}; ++ ++module_i2c_driver(ov10635_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for OV10635"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/imagers/ov10635.h b/drivers/media/i2c/soc_camera/imagers/ov10635.h +new file mode 100644 +index 0000000..38b4256 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ov10635.h +@@ -0,0 +1,1143 @@ ++/* ++ * OmniVision ov10635 sensor camera wizard 1280x800@30/UYVY/BT601/8bit ++ * ++ * Copyright (C) 2015-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++//#define OV10635_DISPLAY_PATTERN ++ ++#define OV10635_SENSOR_WIDTH 1312 ++#define OV10635_SENSOR_HEIGHT 814 ++ ++#define OV10635_MAX_WIDTH 1280 ++#define OV10635_MAX_HEIGHT 800 ++ ++#define OV10635_PCLK_96MHZ ++//#define OV10635_PCLK_88MHZ ++ ++#if defined(OV10635_PCLK_96MHZ) ++/* VTS=PCLK/FPS/HTS/2 (=96MHz/30/1750/2) */ ++ #define OV10635_HTS 1750 ++ #define OV10635_VTS 914 /* fps=30 */ ++#elif defined(OV10635_PCLK_88MHZ) ++/* VTS=PCLK/FPS/HTS/2 (=88MHz/1572/30/2) */ ++ #define OV10635_HTS 1572 ++ #define OV10635_VTS 933 /* fps=29.9998 */ ++#else ++ #error PCLK not defined ++#endif ++ ++struct ov10635_reg { ++ u16 reg; ++ u8 val; ++}; ++ ++static const struct ov10635_reg ov10635_regs_wizard[] = { ++//{0x0103, 0x01}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x301B, 0xFF}, ++{0x301C, 0xFF}, ++{0x301A, 0xFF}, ++{0x3011, 0x42}, ++{0x6900, 0x0C}, ++{0x6901, 0x19}, ++{0x3503, 0x10}, ++{0x3025, 0x03}, ++#if defined(OV10635_PCLK_96MHZ) ++{0x3003, 0x20}, ++{0x3004, 0x21}, ++#elif defined(OV10635_PCLK_88MHZ) ++{0x3003, 0x16}, ++{0x3004, 0x30}, ++#endif ++{0x3005, 0x40}, ++{0x3006, 0x91}, ++{0x3600, 0x74}, ++{0x3601, 0x2B}, ++{0x3612, 0x00}, ++{0x3611, 0x67}, ++{0x3633, 0xCA}, ++{0x3602, 0xAF}, ++{0x3603, 0x04}, ++{0x3630, 0x28}, ++{0x3631, 0x16}, ++{0x3714, 0x10}, ++{0x371D, 0x01}, ++{0x4300, 0x3A}, ++{0x3007, 0x01}, ++{0x3024, 0x03}, ++{0x3020, 0x0A}, ++{0x3702, 0x0D}, ++{0x3703, 0x20}, ++{0x3704, 0x15}, ++{0x3709, 0xA8}, ++{0x370C, 0xC7}, ++{0x370D, 0x80}, ++{0x3712, 0x00}, ++{0x3713, 0x20}, ++{0x3715, 0x04}, ++{0x381D, 0x40}, ++{0x381C, 0x00}, ++{0x3822, 0x50}, ++{0x3824, 0x10}, ++{0x3815, 0x8C}, ++{0x3804, 0x05}, ++{0x3805, 0x1F}, ++{0x3800, 0x00}, ++{0x3801, 0x00}, ++{0x3806, 0x03}, ++{0x3807, 0x28}, ++{0x3802, 0x00}, ++{0x3803, 0x07}, ++{0x3808, 0x05}, ++{0x3809, 0x00}, ++{0x380A, 0x03}, ++{0x380B, 0x20}, ++{0x380C, OV10635_HTS >> 8}, ++{0x380D, OV10635_HTS & 0xff}, ++{0x380E, OV10635_VTS >> 8}, ++{0x380F, OV10635_VTS & 0xff}, ++{0x3813, 0x02}, ++{0x3811, 0x08}, ++{0x381F, 0x0C}, ++{0x3819, 0x04}, ++{0x3804, 0x01}, ++{0x3805, 0x00}, ++{0x3828, 0x03}, ++{0x3829, 0x10}, ++{0x382A, 0x10}, ++{0x3621, 0x63}, ++{0x5005, 0x08}, ++{0x56D5, 0x00}, ++{0x56D6, 0x80}, ++{0x56D7, 0x00}, ++{0x56D8, 0x00}, ++{0x56D9, 0x00}, ++{0x56DA, 0x80}, ++{0x56DB, 0x00}, ++{0x56DC, 0x00}, ++{0x56E8, 0x00}, ++{0x56E9, 0x7F}, ++{0x56EA, 0x00}, ++{0x56EB, 0x7F}, ++{0x5100, 0x00}, ++{0x5101, 0x80}, ++{0x5102, 0x00}, ++{0x5103, 0x80}, ++{0x5104, 0x00}, ++{0x5105, 0x80}, ++{0x5106, 0x00}, ++{0x5107, 0x80}, ++{0x5108, 0x00}, ++{0x5109, 0x00}, ++{0x510A, 0x00}, ++{0x510B, 0x00}, ++{0x510C, 0x00}, ++{0x510D, 0x00}, ++{0x510E, 0x00}, ++{0x510F, 0x00}, ++{0x5110, 0x00}, ++{0x5111, 0x80}, ++{0x5112, 0x00}, ++{0x5113, 0x80}, ++{0x5114, 0x00}, ++{0x5115, 0x80}, ++{0x5116, 0x00}, ++{0x5117, 0x80}, ++{0x5118, 0x00}, ++{0x5119, 0x00}, ++{0x511A, 0x00}, ++{0x511B, 0x00}, ++{0x511C, 0x00}, ++{0x511D, 0x00}, ++{0x511E, 0x00}, ++{0x511F, 0x00}, ++{0x56D0, 0x00}, ++{0x5006, 0x04}, ++{0x5608, 0x05}, ++{0x52D7, 0x06}, ++{0x528D, 0x08}, ++{0x5293, 0x12}, ++{0x52D3, 0x12}, ++{0x5288, 0x06}, ++{0x5289, 0x20}, ++{0x52C8, 0x06}, ++{0x52C9, 0x20}, ++{0x52CD, 0x04}, ++{0x5381, 0x00}, ++{0x5382, 0xFF}, ++{0x5589, 0x76}, ++{0x558A, 0x47}, ++{0x558B, 0xEF}, ++{0x558C, 0xC9}, ++{0x558D, 0x49}, ++{0x558E, 0x30}, ++{0x558F, 0x67}, ++{0x5590, 0x3F}, ++{0x5591, 0xF0}, ++{0x5592, 0x10}, ++{0x55A2, 0x6D}, ++{0x55A3, 0x55}, ++{0x55A4, 0xC3}, ++{0x55A5, 0xB5}, ++{0x55A6, 0x43}, ++{0x55A7, 0x38}, ++{0x55A8, 0x5F}, ++{0x55A9, 0x4B}, ++{0x55AA, 0xF0}, ++{0x55AB, 0x10}, ++{0x5581, 0x52}, ++{0x5300, 0x01}, ++{0x5301, 0x00}, ++{0x5302, 0x00}, ++{0x5303, 0x0E}, ++{0x5304, 0x00}, ++{0x5305, 0x0E}, ++{0x5306, 0x00}, ++{0x5307, 0x36}, ++{0x5308, 0x00}, ++{0x5309, 0xD9}, ++{0x530A, 0x00}, ++{0x530B, 0x0F}, ++{0x530C, 0x00}, ++{0x530D, 0x2C}, ++{0x530E, 0x00}, ++{0x530F, 0x59}, ++{0x5310, 0x00}, ++{0x5311, 0x7B}, ++{0x5312, 0x00}, ++{0x5313, 0x22}, ++{0x5314, 0x00}, ++{0x5315, 0xD5}, ++{0x5316, 0x00}, ++{0x5317, 0x13}, ++{0x5318, 0x00}, ++{0x5319, 0x18}, ++{0x531A, 0x00}, ++{0x531B, 0x26}, ++{0x531C, 0x00}, ++{0x531D, 0xDC}, ++{0x531E, 0x00}, ++{0x531F, 0x02}, ++{0x5320, 0x00}, ++{0x5321, 0x24}, ++{0x5322, 0x00}, ++{0x5323, 0x56}, ++{0x5324, 0x00}, ++{0x5325, 0x85}, ++{0x5326, 0x00}, ++{0x5327, 0x20}, ++{0x5609, 0x01}, ++{0x560A, 0x40}, ++{0x560B, 0x01}, ++{0x560C, 0x40}, ++{0x560D, 0x00}, ++{0x560E, 0xFA}, ++{0x560F, 0x00}, ++{0x5610, 0xFA}, ++{0x5611, 0x02}, ++{0x5612, 0x80}, ++{0x5613, 0x02}, ++{0x5614, 0x80}, ++{0x5615, 0x01}, ++{0x5616, 0x2C}, ++{0x5617, 0x01}, ++{0x5618, 0x2C}, ++{0x563B, 0x01}, ++{0x563C, 0x01}, ++{0x563D, 0x01}, ++{0x563E, 0x01}, ++{0x563F, 0x03}, ++{0x5640, 0x03}, ++{0x5641, 0x03}, ++{0x5642, 0x05}, ++{0x5643, 0x09}, ++{0x5644, 0x05}, ++{0x5645, 0x05}, ++{0x5646, 0x05}, ++{0x5647, 0x05}, ++{0x5651, 0x00}, ++{0x5652, 0x80}, ++{0x521A, 0x01}, ++{0x521B, 0x03}, ++{0x521C, 0x06}, ++{0x521D, 0x0A}, ++{0x521E, 0x0E}, ++{0x521F, 0x12}, ++{0x5220, 0x16}, ++{0x5223, 0x02}, ++{0x5225, 0x04}, ++{0x5227, 0x08}, ++{0x5229, 0x0C}, ++{0x522B, 0x12}, ++{0x522D, 0x18}, ++{0x522F, 0x1E}, ++{0x5241, 0x04}, ++{0x5242, 0x01}, ++{0x5243, 0x03}, ++{0x5244, 0x06}, ++{0x5245, 0x0A}, ++{0x5246, 0x0E}, ++{0x5247, 0x12}, ++{0x5248, 0x16}, ++{0x524A, 0x03}, ++{0x524C, 0x04}, ++{0x524E, 0x08}, ++{0x5250, 0x0C}, ++{0x5252, 0x12}, ++{0x5254, 0x18}, ++{0x5256, 0x1E}, ++{0x4606, (2*OV10635_HTS) >> 8}, /* fifo_line_length = 2*hts */ ++{0x4607, (2*OV10635_HTS) & 0xff}, ++{0x460a, (2*(OV10635_HTS-OV10635_MAX_WIDTH)) >> 8}, /* fifo_hsync_start = 2*(hts - xres) */ ++{0x460b, (2*(OV10635_HTS-OV10635_MAX_WIDTH)) & 0xff }, ++{0x460C, 0x00}, ++{0x4620, 0x0E}, ++#if 0 ++{0x4700, 0x02}, // BT656: mode is acceptable but artefact lines on left/bottom due to BT656 SAV/EAV are parsed as image data ++#else ++{0x4700, 0x04}, // BT601: 0x08 is also accaptable as HS/VS mode ++#endif ++{0x4701, 0x00}, ++{0x4702, 0x01}, ++{0x4004, 0x04}, ++{0x4005, 0x18}, ++{0x4001, 0x06}, ++{0x4050, 0x22}, ++{0x4051, 0x24}, ++{0x4052, 0x02}, ++{0x4057, 0x9C}, ++{0x405A, 0x00}, ++{0x4202, 0x02}, ++{0x3023, 0x10}, ++{0x0100, 0x01}, ++{0x0100, 0x01}, ++{0x0100, 0x01}, ++{0x0100, 0x01}, ++{0x0100, 0x01}, ++{0x0100, 0x01}, ++{0x6F10, 0x07}, ++{0x6F11, 0x82}, ++{0x6F12, 0x04}, ++{0x6F13, 0x00}, ++{0xD000, 0x19}, ++{0xD001, 0xA0}, ++{0xD002, 0x00}, ++{0xD003, 0x01}, ++{0xD004, 0xA9}, ++{0xD005, 0xAD}, ++{0xD006, 0x10}, ++{0xD007, 0x40}, ++{0xD008, 0x44}, ++{0xD009, 0x00}, ++{0xD00A, 0x68}, ++{0xD00B, 0x00}, ++{0xD00C, 0x15}, ++{0xD00D, 0x00}, ++{0xD00E, 0x00}, ++{0xD00F, 0x00}, ++{0xD040, 0x9C}, ++{0xD041, 0x21}, ++{0xD042, 0xFF}, ++{0xD043, 0xF8}, ++{0xD044, 0xD4}, ++{0xD045, 0x01}, ++{0xD046, 0x48}, ++{0xD047, 0x00}, ++{0xD048, 0xD4}, ++{0xD049, 0x01}, ++{0xD04A, 0x50}, ++{0xD04B, 0x04}, ++{0xD04C, 0x18}, ++{0xD04D, 0x60}, ++{0xD04E, 0x00}, ++{0xD04F, 0x01}, ++{0xD050, 0xA8}, ++{0xD051, 0x63}, ++{0xD052, 0x02}, ++{0xD053, 0xA4}, ++{0xD054, 0x85}, ++{0xD055, 0x43}, ++{0xD056, 0x00}, ++{0xD057, 0x00}, ++{0xD058, 0x18}, ++{0xD059, 0x60}, ++{0xD05A, 0x00}, ++{0xD05B, 0x01}, ++{0xD05C, 0xA8}, ++{0xD05D, 0x63}, ++{0xD05E, 0x03}, ++{0xD05F, 0xF0}, ++{0xD060, 0x98}, ++{0xD061, 0xA3}, ++{0xD062, 0x00}, ++{0xD063, 0x00}, ++{0xD064, 0x8C}, ++{0xD065, 0x6A}, ++{0xD066, 0x00}, ++{0xD067, 0x6E}, ++{0xD068, 0xE5}, ++{0xD069, 0x85}, ++{0xD06A, 0x18}, ++{0xD06B, 0x00}, ++{0xD06C, 0x10}, ++{0xD06D, 0x00}, ++{0xD06E, 0x00}, ++{0xD06F, 0x10}, ++{0xD070, 0x9C}, ++{0xD071, 0x80}, ++{0xD072, 0x00}, ++{0xD073, 0x03}, ++{0xD074, 0x18}, ++{0xD075, 0x60}, ++{0xD076, 0x00}, ++{0xD077, 0x01}, ++{0xD078, 0xA8}, ++{0xD079, 0x63}, ++{0xD07A, 0x07}, ++{0xD07B, 0x80}, ++{0xD07C, 0x07}, ++{0xD07D, 0xFF}, ++{0xD07E, 0xF9}, ++{0xD07F, 0x03}, ++{0xD080, 0x8C}, ++{0xD081, 0x63}, ++{0xD082, 0x00}, ++{0xD083, 0x00}, ++{0xD084, 0xA5}, ++{0xD085, 0x6B}, ++{0xD086, 0x00}, ++{0xD087, 0xFF}, ++{0xD088, 0x18}, ++{0xD089, 0x80}, ++{0xD08A, 0x00}, ++{0xD08B, 0x01}, ++{0xD08C, 0xA8}, ++{0xD08D, 0x84}, ++{0xD08E, 0x01}, ++{0xD08F, 0x04}, ++{0xD090, 0xE1}, ++{0xD091, 0x6B}, ++{0xD092, 0x58}, ++{0xD093, 0x00}, ++{0xD094, 0x94}, ++{0xD095, 0x6A}, ++{0xD096, 0x00}, ++{0xD097, 0x70}, ++{0xD098, 0xE1}, ++{0xD099, 0x6B}, ++{0xD09A, 0x20}, ++{0xD09B, 0x00}, ++{0xD09C, 0x95}, ++{0xD09D, 0x6B}, ++{0xD09E, 0x00}, ++{0xD09F, 0x00}, ++{0xD0A0, 0xE4}, ++{0xD0A1, 0x8B}, ++{0xD0A2, 0x18}, ++{0xD0A3, 0x00}, ++{0xD0A4, 0x0C}, ++{0xD0A5, 0x00}, ++{0xD0A6, 0x00}, ++{0xD0A7, 0x23}, ++{0xD0A8, 0x15}, ++{0xD0A9, 0x00}, ++{0xD0AA, 0x00}, ++{0xD0AB, 0x00}, ++{0xD0AC, 0x18}, ++{0xD0AD, 0x60}, ++{0xD0AE, 0x80}, ++{0xD0AF, 0x06}, ++{0xD0B0, 0xA8}, ++{0xD0B1, 0x83}, ++{0xD0B2, 0x40}, ++{0xD0B3, 0x08}, ++{0xD0B4, 0xA8}, ++{0xD0B5, 0xE3}, ++{0xD0B6, 0x38}, ++{0xD0B7, 0x2A}, ++{0xD0B8, 0xA8}, ++{0xD0B9, 0xC3}, ++{0xD0BA, 0x40}, ++{0xD0BB, 0x09}, ++{0xD0BC, 0xA8}, ++{0xD0BD, 0xA3}, ++{0xD0BE, 0x38}, ++{0xD0BF, 0x29}, ++{0xD0C0, 0x8C}, ++{0xD0C1, 0x65}, ++{0xD0C2, 0x00}, ++{0xD0C3, 0x00}, ++{0xD0C4, 0xD8}, ++{0xD0C5, 0x04}, ++{0xD0C6, 0x18}, ++{0xD0C7, 0x00}, ++{0xD0C8, 0x8C}, ++{0xD0C9, 0x67}, ++{0xD0CA, 0x00}, ++{0xD0CB, 0x00}, ++{0xD0CC, 0xD8}, ++{0xD0CD, 0x06}, ++{0xD0CE, 0x18}, ++{0xD0CF, 0x00}, ++{0xD0D0, 0x18}, ++{0xD0D1, 0x60}, ++{0xD0D2, 0x80}, ++{0xD0D3, 0x06}, ++{0xD0D4, 0xA8}, ++{0xD0D5, 0xE3}, ++{0xD0D6, 0x67}, ++{0xD0D7, 0x02}, ++{0xD0D8, 0xA9}, ++{0xD0D9, 0x03}, ++{0xD0DA, 0x67}, ++{0xD0DB, 0x03}, ++{0xD0DC, 0xA8}, ++{0xD0DD, 0xC3}, ++{0xD0DE, 0x3D}, ++{0xD0DF, 0x05}, ++{0xD0E0, 0x8C}, ++{0xD0E1, 0x66}, ++{0xD0E2, 0x00}, ++{0xD0E3, 0x00}, ++{0xD0E4, 0xB8}, ++{0xD0E5, 0x63}, ++{0xD0E6, 0x00}, ++{0xD0E7, 0x18}, ++{0xD0E8, 0xB8}, ++{0xD0E9, 0x63}, ++{0xD0EA, 0x00}, ++{0xD0EB, 0x98}, ++{0xD0EC, 0xBC}, ++{0xD0ED, 0x03}, ++{0xD0EE, 0x00}, ++{0xD0EF, 0x00}, ++{0xD0F0, 0x10}, ++{0xD0F1, 0x00}, ++{0xD0F2, 0x00}, ++{0xD0F3, 0x16}, ++{0xD0F4, 0xB8}, ++{0xD0F5, 0x83}, ++{0xD0F6, 0x00}, ++{0xD0F7, 0x19}, ++{0xD0F8, 0x8C}, ++{0xD0F9, 0x67}, ++{0xD0FA, 0x00}, ++{0xD0FB, 0x00}, ++{0xD0FC, 0xB8}, ++{0xD0FD, 0xA4}, ++{0xD0FE, 0x00}, ++{0xD0FF, 0x98}, ++{0xD100, 0xB8}, ++{0xD101, 0x83}, ++{0xD102, 0x00}, ++{0xD103, 0x08}, ++{0xD104, 0x8C}, ++{0xD105, 0x68}, ++{0xD106, 0x00}, ++{0xD107, 0x00}, ++{0xD108, 0xE0}, ++{0xD109, 0x63}, ++{0xD10A, 0x20}, ++{0xD10B, 0x04}, ++{0xD10C, 0xE0}, ++{0xD10D, 0x65}, ++{0xD10E, 0x18}, ++{0xD10F, 0x00}, ++{0xD110, 0xA4}, ++{0xD111, 0x83}, ++{0xD112, 0xFF}, ++{0xD113, 0xFF}, ++{0xD114, 0xB8}, ++{0xD115, 0x64}, ++{0xD116, 0x00}, ++{0xD117, 0x48}, ++{0xD118, 0xD8}, ++{0xD119, 0x07}, ++{0xD11A, 0x18}, ++{0xD11B, 0x00}, ++{0xD11C, 0xD8}, ++{0xD11D, 0x08}, ++{0xD11E, 0x20}, ++{0xD11F, 0x00}, ++{0xD120, 0x9C}, ++{0xD121, 0x60}, ++{0xD122, 0x00}, ++{0xD123, 0x00}, ++{0xD124, 0xD8}, ++{0xD125, 0x06}, ++{0xD126, 0x18}, ++{0xD127, 0x00}, ++{0xD128, 0x00}, ++{0xD129, 0x00}, ++{0xD12A, 0x00}, ++{0xD12B, 0x08}, ++{0xD12C, 0x15}, ++{0xD12D, 0x00}, ++{0xD12E, 0x00}, ++{0xD12F, 0x00}, ++{0xD130, 0x8C}, ++{0xD131, 0x6A}, ++{0xD132, 0x00}, ++{0xD133, 0x76}, ++{0xD134, 0xBC}, ++{0xD135, 0x23}, ++{0xD136, 0x00}, ++{0xD137, 0x00}, ++{0xD138, 0x13}, ++{0xD139, 0xFF}, ++{0xD13A, 0xFF}, ++{0xD13B, 0xE6}, ++{0xD13C, 0x18}, ++{0xD13D, 0x60}, ++{0xD13E, 0x80}, ++{0xD13F, 0x06}, ++{0xD140, 0x03}, ++{0xD141, 0xFF}, ++{0xD142, 0xFF}, ++{0xD143, 0xDD}, ++{0xD144, 0xA8}, ++{0xD145, 0x83}, ++{0xD146, 0x40}, ++{0xD147, 0x08}, ++{0xD148, 0x85}, ++{0xD149, 0x21}, ++{0xD14A, 0x00}, ++{0xD14B, 0x00}, ++{0xD14C, 0x85}, ++{0xD14D, 0x41}, ++{0xD14E, 0x00}, ++{0xD14F, 0x04}, ++{0xD150, 0x44}, ++{0xD151, 0x00}, ++{0xD152, 0x48}, ++{0xD153, 0x00}, ++{0xD154, 0x9C}, ++{0xD155, 0x21}, ++{0xD156, 0x00}, ++{0xD157, 0x08}, ++{0x6F0E, 0x03}, ++{0x6F0F, 0x00}, ++{0x460E, 0x08}, ++{0x460F, 0x01}, ++{0x4610, 0x00}, ++{0x4611, 0x01}, ++{0x4612, 0x00}, ++{0x4613, 0x01}, ++{0x4605, 0x08}, // 8bit ++//{0x4709, 0x10}, // swap data bits order [9:0] -> [0:9] ++{0x4608, 0x00}, ++{0x4609, 0x08}, ++{0x6804, 0x00}, ++{0x6805, 0x06}, ++{0x6806, 0x00}, ++{0x5120, 0x00}, ++{0x3510, 0x00}, ++{0x3504, 0x00}, ++{0x6800, 0x00}, ++{0x6F0D, 0x01}, ++{0x4708, 0x03}, // PCLK rising edge ++{0x5000, 0xFF}, ++{0x5001, 0xBF}, ++{0x5002, 0x7E}, ++#ifdef OV10635_DISPLAY_PATTERN ++{0x503d, 0x80}, ++#else ++{0x503D, 0x00}, ++#endif ++{0xC450, 0x01}, /* AA mode */ ++{0xC452, 0x04}, ++{0xC453, 0x00}, ++{0xC454, 0x00}, ++{0xC455, 0x01}, ++{0xC456, 0x01}, ++{0xC457, 0x00}, ++{0xC458, 0x00}, ++{0xC459, 0x00}, ++{0xC45B, 0x00}, ++{0xC45C, 0x01}, ++{0xC45D, 0x00}, ++{0xC45E, 0x00}, ++{0xC45F, 0x00}, ++{0xC460, 0x00}, ++{0xC461, 0x01}, ++{0xC462, 0x01}, ++{0xC464, 0x03}, ++{0xC465, 0x00}, ++{0xC466, 0x8A}, ++{0xC467, 0x00}, ++{0xC468, 0x86}, ++{0xC469, 0x00}, ++{0xC46A, 0x30}, ++{0xC46B, 0x50}, ++{0xC46C, 0x30}, ++{0xC46D, 0x28}, ++{0xC46E, 0x60}, ++{0xC46F, 0x40}, ++{0xC47C, 0x01}, ++{0xC47D, 0x38}, ++{0xC47E, 0x00}, ++{0xC47F, 0x00}, ++{0xC480, 0x00}, ++{0xC481, 0xFF}, ++{0xC482, 0x00}, ++{0xC483, 0x40}, ++{0xC484, 0x00}, ++{0xC485, 0x18}, ++{0xC486, 0x00}, ++{0xC487, 0x18}, ++{0xC488, (OV10635_VTS-8)*16 >> 8}, ++{0xC489, (OV10635_VTS-8)*16 & 0xff}, ++{0xC48A, (OV10635_VTS-8)*16 >> 8}, ++{0xC48B, (OV10635_VTS-8)*16 & 0xff}, ++{0xC48C, 0x00}, ++{0xC48D, 0x04}, ++{0xC48E, 0x00}, ++{0xC48F, 0x04}, ++{0xC490, 0x03}, ++{0xC492, 0x20}, ++{0xC493, 0x08}, ++{0xC498, 0x02}, ++{0xC499, 0x00}, ++{0xC49A, 0x02}, ++{0xC49B, 0x00}, ++{0xC49C, 0x02}, ++{0xC49D, 0x00}, ++{0xC49E, 0x02}, ++{0xC49F, 0x60}, ++{0xC4A0, 0x03}, ++{0xC4A1, 0x00}, ++{0xC4A2, 0x04}, ++{0xC4A3, 0x00}, ++{0xC4A4, 0x00}, ++{0xC4A5, 0x10}, ++{0xC4A6, 0x00}, ++{0xC4A7, 0x40}, ++{0xC4A8, 0x00}, ++{0xC4A9, 0x80}, ++{0xC4AA, 0x0D}, ++{0xC4AB, 0x00}, ++{0xC4AC, 0x0F}, ++{0xC4AD, 0xC0}, ++{0xC4B4, 0x01}, ++{0xC4B5, 0x01}, ++{0xC4B6, 0x00}, ++{0xC4B7, 0x01}, ++{0xC4B8, 0x00}, ++{0xC4B9, 0x01}, ++{0xC4BA, 0x01}, ++{0xC4BB, 0x00}, ++{0xC4BC, 0x01}, ++{0xC4BD, 0x60}, ++{0xC4BE, 0x02}, ++{0xC4BF, 0x33}, ++{0xC4C8, 0x03}, ++{0xC4C9, 0xD0}, ++{0xC4CA, 0x0E}, ++{0xC4CB, 0x00}, ++{0xC4CC, 0x0E}, ++{0xC4CD, 0x51}, ++{0xC4CE, 0x0E}, ++{0xC4CF, 0x51}, ++{0xC4D0, 0x04}, ++{0xC4D1, 0x80}, ++{0xC4E0, 0x04}, ++{0xC4E1, 0x02}, ++{0xC4E2, 0x01}, ++{0xC4E4, 0x10}, ++{0xC4E5, 0x20}, ++{0xC4E6, 0x30}, ++{0xC4E7, 0x40}, ++{0xC4E8, 0x50}, ++{0xC4E9, 0x60}, ++{0xC4EA, 0x70}, ++{0xC4EB, 0x80}, ++{0xC4EC, 0x90}, ++{0xC4ED, 0xA0}, ++{0xC4EE, 0xB0}, ++{0xC4EF, 0xC0}, ++{0xC4F0, 0xD0}, ++{0xC4F1, 0xE0}, ++{0xC4F2, 0xF0}, ++{0xC4F3, 0x80}, ++{0xC4F4, 0x00}, ++{0xC4F5, 0x20}, ++{0xC4F6, 0x02}, ++{0xC4F7, 0x00}, ++{0xC4F8, 0x00}, ++{0xC4F9, 0x00}, ++{0xC4FA, 0x00}, ++{0xC4FB, 0x01}, ++{0xC4FC, 0x01}, ++{0xC4FD, 0x00}, ++{0xC4FE, 0x04}, ++{0xC4FF, 0x02}, ++{0xC500, 0x48}, ++{0xC501, 0x74}, ++{0xC502, 0x58}, ++{0xC503, 0x80}, ++{0xC504, 0x05}, ++{0xC505, 0x80}, ++{0xC506, 0x03}, ++{0xC507, 0x80}, ++{0xC508, 0x01}, ++{0xC509, 0xC0}, ++{0xC50A, 0x01}, ++{0xC50B, 0xA0}, ++{0xC50C, 0x01}, ++{0xC50D, 0x2C}, ++{0xC50E, 0x01}, ++{0xC50F, 0x0A}, ++{0xC510, 0x00}, ++{0xC511, 0x00}, ++{0xC512, 0xE5}, ++{0xC513, 0x14}, ++{0xC514, 0x04}, ++{0xC515, 0x00}, ++{0xC518, OV10635_VTS >> 8}, ++{0xC519, OV10635_VTS & 0xff}, ++{0xC51A, OV10635_HTS >> 8}, ++{0xC51B, OV10635_HTS & 0xff}, ++{0xC2E0, 0x00}, ++{0xC2E1, 0x51}, ++{0xC2E2, 0x00}, ++{0xC2E3, 0xD6}, ++{0xC2E4, 0x01}, ++{0xC2E5, 0x5E}, ++{0xC2E9, 0x01}, ++{0xC2EA, 0x7A}, ++{0xC2EB, 0x90}, ++{0xC2ED, 0x00}, ++{0xC2EE, 0x7A}, ++{0xC2EF, 0x64}, ++{0xC308, 0x00}, ++{0xC309, 0x00}, ++{0xC30A, 0x00}, ++{0xC30C, 0x00}, ++{0xC30D, 0x01}, ++{0xC30E, 0x00}, ++{0xC30F, 0x00}, ++{0xC310, 0x01}, ++{0xC311, 0x60}, ++{0xC312, 0xFF}, ++{0xC313, 0x08}, ++{0xC314, 0x01}, ++{0xC315, 0x00}, /* min saturation gain */ ++{0xC316, 0xFF}, /* max saturation gain */ ++{0xC317, 0x0B}, ++{0xC318, 0x00}, ++{0xC319, 0x0C}, ++{0xC31A, 0x00}, ++{0xC31B, 0xE0}, ++{0xC31C, 0x00}, ++{0xC31D, 0x14}, ++{0xC31E, 0x00}, ++{0xC31F, 0xC5}, ++{0xC320, 0xFF}, ++{0xC321, 0x4B}, ++{0xC322, 0xFF}, ++{0xC323, 0xF0}, ++{0xC324, 0xFF}, ++{0xC325, 0xE8}, ++{0xC326, 0x00}, ++{0xC327, 0x46}, ++{0xC328, 0xFF}, ++{0xC329, 0xD2}, ++{0xC32A, 0xFF}, ++{0xC32B, 0xE4}, ++{0xC32C, 0xFF}, ++{0xC32D, 0xBB}, ++{0xC32E, 0x00}, ++{0xC32F, 0x61}, ++{0xC330, 0xFF}, ++{0xC331, 0xF9}, ++{0xC332, 0x00}, ++{0xC333, 0xD9}, ++{0xC334, 0x00}, ++{0xC335, 0x2E}, ++{0xC336, 0x00}, ++{0xC337, 0xB1}, ++{0xC338, 0xFF}, ++{0xC339, 0x64}, ++{0xC33A, 0xFF}, ++{0xC33B, 0xEB}, ++{0xC33C, 0xFF}, ++{0xC33D, 0xE8}, ++{0xC33E, 0x00}, ++{0xC33F, 0x48}, ++{0xC340, 0xFF}, ++{0xC341, 0xD0}, ++{0xC342, 0xFF}, ++{0xC343, 0xED}, ++{0xC344, 0xFF}, ++{0xC345, 0xAD}, ++{0xC346, 0x00}, ++{0xC347, 0x66}, ++{0xC348, 0x01}, ++{0xC349, 0x00}, ++{0x6700, 0x04}, ++{0x6701, 0x7B}, ++{0x6702, 0xFD}, ++{0x6703, 0xF9}, ++{0x6704, 0x3D}, ++{0x6705, 0x71}, ++{0x6706, 0x78}, ++{0x6708, 0x05}, ++{0x6F06, 0x6F}, ++{0x6F07, 0x00}, ++{0x6F0A, 0x6F}, ++{0x6F0B, 0x00}, ++{0x6F00, 0x03}, ++{0xC34C, 0x01}, ++{0xC34D, 0x00}, ++{0xC34E, 0x46}, ++{0xC34F, 0x55}, ++{0xC350, 0x00}, ++{0xC351, 0x40}, ++{0xC352, 0x00}, ++{0xC353, 0xFF}, ++{0xC354, 0x04}, ++{0xC355, 0x08}, ++{0xC356, 0x01}, ++{0xC357, 0xEF}, ++{0xC358, 0x30}, ++{0xC359, 0x01}, ++{0xC35A, 0x64}, ++{0xC35B, 0x46}, ++{0xC35C, 0x00}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0xC261, 0x01}, ++{0x301B, 0xF0}, ++{0x301C, 0xF0}, ++{0x301A, 0xF0}, ++{0x6F00, 0xC3}, ++{0xC46A, 0x30}, ++{0xC46D, 0x20}, ++{0xC464, 0x84}, ++{0xC465, 0x00}, ++{0x6F00, 0x03}, ++{0x6F00, 0x43}, ++{0x381C, 0x00}, ++{0x381D, 0x40}, ++{0xC454, 0x01}, ++{0x6F00, 0xC3}, ++{0xC454, 0x00}, ++{0xC4B1, 0x02}, ++{0xC4B2, 0x01}, ++{0xC4B3, 0x03}, ++{0x6F00, 0x03}, ++{0x6F00, 0x43}, ++/* enable FSIN (FRAMESYNC input) functionality */ ++{0x3832, (0x0d+2*0x20+0x15+38) >> 8}, ++{0x3833, (0x0d+2*0x20+0x15+38) & 0xff}, ++{0x3834, OV10635_VTS >> 8}, ++{0x3835, OV10635_VTS & 0xff}, ++{0x302E, 0x01}, ++}; ++ ++static const struct ov10635_reg ov10635_regs_30fps[] = { ++/* disable clocks */ ++{0x301b, 0xff}, ++{0x301c, 0xff}, ++{0x301a, 0xff}, ++/* clk = 24Mhz/2*32/2(1+1)=96Mhz, 30fps */ ++{0x3003, 0x20}, ++{0x3004, 0x21}, ++/* enable clocks */ ++{0x301b, 0xf0}, ++{0x301c, 0xf0}, ++{0x301a, 0xf0}, ++}; ++ ++static const struct ov10635_reg ov10635_regs_15fps[] = { ++/* disable clocks */ ++{0x301b, 0xff}, ++{0x301c, 0xff}, ++{0x301a, 0xff}, ++/* clk = 24Mhz/2*32/2(1+3)=48Mhz, 15fps */ ++{0x3003, 0x20}, ++{0x3004, 0x23}, ++/* enable clocks */ ++{0x301b, 0xf0}, ++{0x301c, 0xf0}, ++{0x301a, 0xf0}, ++}; ++ ++static const struct ov10635_reg ov10635_regs_10fps[] = { ++/* disable clocks */ ++{0x301b, 0xff}, ++{0x301c, 0xff}, ++{0x301a, 0xff}, ++/* clk = 24Mhz/2*32/2(1+5)=32Mhz, 10fps */ ++{0x3003, 0x20}, ++{0x3004, 0x25}, ++/* enable clocks */ ++{0x301b, 0xf0}, ++{0x301c, 0xf0}, ++{0x301a, 0xf0}, ++}; ++ ++static const struct ov10635_reg ov10635_regs_5fps[] = { ++/* disable clocks */ ++{0x301b, 0xff}, ++{0x301c, 0xff}, ++{0x301a, 0xff}, ++/* clk = 24Mhz/4*32/2(1+5)=96Mhz, 5fps */ ++{0x3003, 0x20}, ++{0x3004, 0x45}, ++/* enable clocks */ ++{0x301b, 0xf0}, ++{0x301c, 0xf0}, ++{0x301a, 0xf0}, ++}; ++ ++static const struct ov10635_reg ov10635_regs_contrast[5][18] = { ++{ ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x20}, ++ {0xc4e5, 0x40}, ++ {0xc4e6, 0x60}, ++ {0xc4e7, 0x80}, ++ {0xc4e8, 0xa0}, ++ {0xc4e9, 0xb4}, ++ {0xc4ea, 0xc0}, ++ {0xc4eb, 0xcb}, ++ {0xc4ec, 0xd5}, ++ {0xc4ed, 0xde}, ++ {0xc4ee, 0xe6}, ++ {0xc4ef, 0xed}, ++ {0xc4f0, 0xf3}, ++ {0xc4f1, 0xf8}, ++ {0xc4f2, 0xfc}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++}, { ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x18}, ++ {0xc4e5, 0x30}, ++ {0xc4e6, 0x48}, ++ {0xc4e7, 0x60}, ++ {0xc4e8, 0x78}, ++ {0xc4e9, 0x90}, ++ {0xc4ea, 0xa4}, ++ {0xc4eb, 0xb4}, ++ {0xc4ec, 0xc2}, ++ {0xc4ed, 0xcf}, ++ {0xc4ee, 0xdb}, ++ {0xc4ef, 0xe5}, ++ {0xc4f0, 0xee}, ++ {0xc4f1, 0xf6}, ++ {0xc4f2, 0xfc}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++}, { ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x10}, ++ {0xc4e5, 0x20}, ++ {0xc4e6, 0x30}, ++ {0xc4e7, 0x40}, ++ {0xc4e8, 0x50}, ++ {0xc4e9, 0x60}, ++ {0xc4ea, 0x70}, ++ {0xc4eb, 0x80}, ++ {0xc4ec, 0x90}, ++ {0xc4ed, 0xa0}, ++ {0xc4ee, 0xb0}, ++ {0xc4ef, 0xc0}, ++ {0xc4f0, 0xd0}, ++ {0xc4f1, 0xe0}, ++ {0xc4f2, 0xf0}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++}, { ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x0c}, ++ {0xc4e5, 0x18}, ++ {0xc4e6, 0x24}, ++ {0xc4e7, 0x30}, ++ {0xc4e8, 0x3c}, ++ {0xc4e9, 0x48}, ++ {0xc4ea, 0x54}, ++ {0xc4eb, 0x62}, ++ {0xc4ec, 0x72}, ++ {0xc4ed, 0x84}, ++ {0xc4ee, 0x94}, ++ {0xc4ef, 0xa6}, ++ {0xc4f0, 0xb9}, ++ {0xc4f1, 0xcd}, ++ {0xc4f2, 0xe2}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++}, { ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x06}, ++ {0xc4e5, 0x0d}, ++ {0xc4e6, 0x15}, ++ {0xc4e7, 0x1e}, ++ {0xc4e8, 0x28}, ++ {0xc4e9, 0x32}, ++ {0xc4ea, 0x3c}, ++ {0xc4eb, 0x48}, ++ {0xc4ec, 0x56}, ++ {0xc4ed, 0x66}, ++ {0xc4ee, 0x78}, ++ {0xc4ef, 0x8c}, ++ {0xc4f0, 0xa2}, ++ {0xc4f1, 0xba}, ++ {0xc4f2, 0xd4}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++} ++}; +diff --git a/drivers/media/i2c/soc_camera/imagers/ov10635_debug.h b/drivers/media/i2c/soc_camera/imagers/ov10635_debug.h +new file mode 100644 +index 0000000..4c3515a +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ov10635_debug.h +@@ -0,0 +1,54 @@ ++ ++#if 0 ++{0x4700, 0x02}, // BT656 ++{0x381d, 0x40}, // mirror off ++{0x381c, 0x00}, // flip off ++{0x4300, 0x3a}, // YUV: UYVY ++{0x4708, 0x00}, // PCLK rising edge ++ ++// clk = 24Mhz/3*22/2= 88Mhz ++{0x3003, 0x16}, ++{0x3004, 0x30}, ++#endif ++ ++#define WIDTH 1280 ++#define HEIGHT 720 ++ ++// DVP frame size ++{0x3808, WIDTH >> 8}, ++{0x3809, WIDTH & 0xff}, ++{0x380a, HEIGHT >> 8}, ++{0x380b, HEIGHT & 0xff}, ++ ++{0x3802, ((814 - HEIGHT)/2) >> 8}, // vert crop start ++{0x3803, ((814 - HEIGHT)/2) & 0xff}, ++{0x3806, ((814 - HEIGHT)/2 + HEIGHT + 1) >> 8}, // vert crop end ++{0x3807, ((814 - HEIGHT)/2 + HEIGHT + 1) & 0xff}, ++ ++#if 0 ++#define HTS 0x6f6 // got from above table 1782 ++#define VTS (0x2ec+80) // got from above table 748 + 80 ++ ++{0x380c, HTS >> 8}, // hts ++{0x380d, HTS & 0xff}, ++{0x380e, VTS >> 8}, // vts ++{0x380f, VTS & 0xff}, ++ ++// fifo ++{0x4606, (2*HTS) >> 8}, // fifo_line_length = 2*hts ++{0x4607, (2*HTS) & 0xff}, ++{0x460a, (2*(HTS-1280)) >> 8}, // fifo_hsync_start = 2*(hts - xres) ++{0x460b, (2*(HTS-1280)) & 0xff }, ++ ++// exposure ++{0xC488, (VTS-8)*16 >> 8}, ++{0xC489, (VTS-8)*16 & 0xff}, ++{0xC48A, (VTS-8)*16 >> 8}, ++{0xC48B, (VTS-8)*16 & 0xff}, ++ ++// vts/hts ++{0xC518, VTS >> 8}, ++{0xC519, VTS & 0xff}, ++{0xC51A, HTS >> 8}, ++{0xC51B, HTS & 0xff}, ++#endif +diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.c b/drivers/media/i2c/soc_camera/imagers/ov2311.c +new file mode 100644 +index 0000000..ce4999b +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.c +@@ -0,0 +1,571 @@ ++/* ++ * OmniVision ov2311 sensor camera driver ++ * ++ * Copyright (C) 2015-2019 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++#include "../gmsl/common.h" ++#include "ov2311.h" ++ ++#define OV2311_I2C_ADDR 0x60 ++ ++#define OV2311_PID_REGA 0x300a ++#define OV2311_PID_REGB 0x300b ++#define OV2311_REV_REG 0x300c ++#define OV2311_PID 0x2311 ++ ++#define OV2311_MEDIA_BUS_FMT MEDIA_BUS_FMT_Y8_1X8 ++ ++struct ov2311_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int subsampling; ++ int fps_denominator; ++ int init_complete; ++ u8 id[6]; ++ int dvp_order; ++ /* serializers */ ++ int ser_addr; ++}; ++ ++static inline struct ov2311_priv *to_ov2311(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov2311_priv, sd); ++} ++ ++static inline struct v4l2_subdev *ov2311_to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov2311_priv, hdl)->sd; ++} ++ ++static int ov2311_set_regs(struct i2c_client *client, ++ const struct ov2311_reg *regs, int nr_regs) ++{ ++ int i; ++ ++ for (i = 0; i < nr_regs; i++) { ++ if (regs[i].reg == OV2311_DELAY) { ++ mdelay(regs[i].val); ++ continue; ++ } ++ ++ if (reg16_write(client, regs[i].reg, regs[i].val)) { ++ usleep_range(100, 150); /* wait 100ns */ ++ reg16_write(client, regs[i].reg, regs[i].val); ++ } ++ } ++ ++ return 0; ++} ++ ++static void ov2311_otp_id_read(struct i2c_client *client) ++{ ++ struct ov2311_priv *priv = to_ov2311(client); ++ int i; ++ ++ reg16_write(client, 0x3d81, 1); ++ usleep_range(25000, 25500); /* wait 25 ms */ ++ ++ for (i = 0; i < 6; i++) { ++ /* first 6 bytes are equal on all ov2311 */ ++ reg16_read(client, 0x7000 + i + 6, &priv->id[i]); ++ } ++} ++ ++static int ov2311_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int ov2311_set_window(struct v4l2_subdev *sd) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2311_priv *priv = to_ov2311(client); ++ ++ dev_dbg(&client->dev, "L=%d T=%d %dx%d\n", priv->rect.left, priv->rect.top, priv->rect.width, priv->rect.height); ++#if 0 ++ /* setup resolution */ ++ reg16_write(client, 0x3808, priv->rect.width >> 8); ++ reg16_write(client, 0x3809, priv->rect.width & 0xff); ++ reg16_write(client, 0x380a, priv->rect.height >> 8); ++ reg16_write(client, 0x380b, priv->rect.height & 0xff); ++ ++ /* horiz isp windowstart */ ++ reg16_write(client, 0x3810, priv->rect.left >> 8); ++ reg16_write(client, 0x3811, priv->rect.left & 0xff); ++ reg16_write(client, 0x3812, priv->rect.top >> 8); ++ reg16_write(client, 0x3813, priv->rect.top & 0xff); ++#endif ++ return 0; ++}; ++ ++static int ov2311_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2311_priv *priv = to_ov2311(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = OV2311_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov2311_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ ++ mf->code = OV2311_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int ov2311_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = OV2311_MEDIA_BUS_FMT; ++ ++ return 0; ++} ++ ++static int ov2311_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2311_priv *priv = to_ov2311(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = OV2311_PID >> 8; ++ edid->edid[9] = OV2311_PID & 0xff; ++ ++ return 0; ++} ++ ++static int ov2311_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2311_priv *priv = to_ov2311(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > OV2311_MAX_WIDTH) || ++ (rect->top + rect->height > OV2311_MAX_HEIGHT)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ ov2311_set_window(sd); ++ ++ return 0; ++} ++ ++static int ov2311_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2311_priv *priv = to_ov2311(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = OV2311_MAX_WIDTH; ++ sel->r.height = OV2311_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = OV2311_MAX_WIDTH; ++ sel->r.height = OV2311_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ov2311_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov2311_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ __be64 be_val; ++ ++ if (!reg->size) ++ reg->size = sizeof(u8); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); ++ ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); ++ ++ return ret; ++} ++ ++static int ov2311_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u8); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); ++ ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; ++} ++#endif ++ ++static struct v4l2_subdev_core_ops ov2311_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov2311_g_register, ++ .s_register = ov2311_s_register, ++#endif ++}; ++ ++static int ov2311_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ov2311_to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2311_priv *priv = to_ov2311(client); ++ int ret = 0; ++ u8 val = 0; ++ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ break; ++ case V4L2_CID_GAIN: ++ reg16_write(client, 0x350A, ctrl->val / 0x3ff); // COARSE: 4.10 format ++ reg16_write(client, 0x350B, (ctrl->val % 0x3ff) >> 2); // FINE: 4.10 format ++ reg16_write(client, 0x350C, (ctrl->val % 0x3ff) << 6); // FINE: 4.10 format ++ break; ++ case V4L2_CID_ANALOGUE_GAIN: ++ reg16_write(client, 0x3508, ctrl->val / 0xf); // COARSE: 5.4 format ++ reg16_write(client, 0x3509, (ctrl->val % 0xf) << 4); // FINE: 5.4 format ++ break; ++ case V4L2_CID_EXPOSURE: ++ reg16_write(client, 0x3501, ctrl->val >> 8); ++ reg16_write(client, 0x3502, ctrl->val & 0xff); ++ break; ++ case V4L2_CID_HFLIP: ++ reg16_read(client, 0x3821, &val); ++ val &= ~0x04; ++ val |= (ctrl->val ? 0x04 : 0); ++ reg16_write(client, 0x3821, val); ++ break; ++ case V4L2_CID_VFLIP: ++ reg16_read(client, 0x3820, &val); ++ val &= ~0x44; ++ val |= (ctrl->val ? 0x44 : 0); ++ reg16_write(client, 0x3820, val); ++ break; ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ret = 0; ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov2311_ctrl_ops = { ++ .s_ctrl = ov2311_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops ov2311_video_ops = { ++ .s_stream = ov2311_s_stream, ++ .g_mbus_config = ov2311_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov2311_subdev_pad_ops = { ++ .get_edid = ov2311_get_edid, ++ .enum_mbus_code = ov2311_enum_mbus_code, ++ .get_selection = ov2311_get_selection, ++ .set_selection = ov2311_set_selection, ++ .get_fmt = ov2311_get_fmt, ++ .set_fmt = ov2311_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops ov2311_subdev_ops = { ++ .core = &ov2311_core_ops, ++ .video = &ov2311_video_ops, ++ .pad = &ov2311_subdev_pad_ops, ++}; ++ ++static ssize_t ov2311_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2311_priv *priv = to_ov2311(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_ov2311, S_IRUGO, ov2311_otp_id_show, NULL); ++ ++static int ov2311_initialize(struct i2c_client *client) ++{ ++ struct ov2311_priv *priv = to_ov2311(client); ++ u16 pid; ++ u8 val = 0, rev = 0; ++ int ret = 0; ++ ++ setup_i2c_translator(client, priv->ser_addr, OV2311_I2C_ADDR, MODE_GMSL2); ++ ++ reg16_read(client, OV2311_PID_REGA, &val); ++ pid = val; ++ reg16_read(client, OV2311_PID_REGB, &val); ++ pid = (pid << 8) | val; ++ ++ if (pid != OV2311_PID) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ return -ENODEV; ++ } ++ ++ if (get_des_id(client) == UB960_ID) ++ reg8_write_addr(client, priv->ser_addr, 0x02, 0x13); /* MIPI 2-lanes */ ++ ++ /* check revision */ ++ reg16_read(client, OV2311_REV_REG, &rev); ++ /* Program wizard registers */ ++ ov2311_set_regs(client, ov2311_regs_wizard_r1c, ARRAY_SIZE(ov2311_regs_wizard_r1c)); ++ /* Read OTP IDs */ ++ ov2311_otp_id_read(client); ++ ++ dev_info(&client->dev, "ov2311 PID %x (rev %x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, rev, OV2311_MAX_WIDTH, OV2311_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ return ret; ++} ++ ++static const struct i2c_device_id ov2311_id[] = { ++ { "ov2311", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov2311_id); ++ ++static const struct of_device_id ov2311_of_ids[] = { ++ { .compatible = "ovti,ov2311", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ov2311_of_ids); ++ ++static int ov2311_parse_dt(struct device_node *np, struct ov2311_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ u32 addrs[2], naddrs; ++ ++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32)); ++ if (naddrs != 2) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ priv->ser_addr = addrs[1]; ++ ++ return 0; ++} ++ ++static int ov2311_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov2311_priv *priv; ++ struct v4l2_ctrl *ctrl; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &ov2311_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = OV2311_MAX_WIDTH; ++ priv->rect.height = OV2311_MAX_HEIGHT; ++ priv->fps_denominator = 30; ++ ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x30); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 4, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 0xff, 1, 0xff); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_HUE, 0, 255, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_GAMMA, 0, 0xffff, 1, 0x233); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_GAIN, 0, 0x3ff*4, 1, 0x3ff); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 0xf*5, 1, 0xf); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 0x580, 1, 0x57c); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops, ++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); ++ if (ctrl) ++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = ov2311_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = ov2311_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov2311) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ return ret; ++} ++ ++static int ov2311_remove(struct i2c_client *client) ++{ ++ struct ov2311_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_ov2311); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++static struct i2c_driver ov2311_i2c_driver = { ++ .driver = { ++ .name = "ov2311", ++ .of_match_table = ov2311_of_ids, ++ }, ++ .probe = ov2311_probe, ++ .remove = ov2311_remove, ++ .id_table = ov2311_id, ++}; ++ ++module_i2c_driver(ov2311_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for OV2311"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.h b/drivers/media/i2c/soc_camera/imagers/ov2311.h +new file mode 100644 +index 0000000..3a56b0b +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.h +@@ -0,0 +1,217 @@ ++/* ++ * OmniVision ov2311 sensor camera wizard 1600x130@30/GREY8/MIPI ++ * ++ * Copyright (C) 2015-2017 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++//#define OV2311_DISPLAY_PATTERN ++//#define OV2311_FSIN_ENABLE ++ ++#define OV2311_MAX_WIDTH 1600 ++#define OV2311_MAX_HEIGHT 1300 ++ ++#define OV2311_DELAY 0xffff ++ ++#define OV2311_SENSOR_WIDTH 1616 ++#define OV2311_SENSOR_HEIGHT 1316 ++ ++#define OV2311_X_START ((OV2311_SENSOR_WIDTH - OV2311_MAX_WIDTH) / 2) ++#define OV2311_Y_START ((OV2311_SENSOR_HEIGHT - OV2311_MAX_HEIGHT) / 2) ++#define OV2311_X_END (OV2311_X_START + OV2311_MAX_WIDTH - 1) ++#define OV2311_Y_END (OV2311_Y_START + OV2311_MAX_HEIGHT - 1) ++ ++struct ov2311_reg { ++ u16 reg; ++ u8 val; ++}; ++ ++/* R1600x1300 RAW10 MIPI 60fps */ ++static const struct ov2311_reg ov2311_regs_wizard_r1c[] = { ++{0x0103, 0x01}, ++{0x0100, 0x00}, ++{0x010c, 0x02}, ++{0x010b, 0x01}, ++{0x0300, 0x01}, ++{0x0302, 0x32}, ++{0x0303, 0x00}, ++{0x0304, 0x03}, ++{0x0305, 0x02}, ++{0x0306, 0x01}, ++{0x030d, 0x5a}, ++{0x030e, 0x04}, ++{0x3001, 0x02}, ++{0x3004, 0x00}, ++{0x3005, 0x00}, ++{0x3006, 0x0a}, ++{0x3011, 0x0d}, ++{0x3014, 0x04}, ++{0x301c, 0xf0}, ++{0x3020, 0x20}, ++{0x302c, 0x00}, ++{0x302d, 0x00}, ++{0x302e, 0x00}, ++{0x302f, 0x03}, ++{0x3030, 0x10}, ++{0x303f, 0x03}, ++{0x3103, 0x00}, ++{0x3106, 0x08}, ++{0x31ff, 0x01}, ++{0x3501, 0x05}, ++{0x3502, 0x7c}, ++{0x3506, 0x00}, ++{0x3507, 0x00}, ++{0x3620, 0x67}, ++{0x3633, 0x78}, ++{0x3662, 0x65}, ++{0x3664, 0xb0}, ++{0x3666, 0x70}, ++{0x3670, 0x68}, ++{0x3674, 0x10}, ++{0x3675, 0x00}, ++{0x367e, 0x90}, ++{0x3680, 0x84}, ++{0x36a2, 0x04}, ++{0x36a3, 0x80}, ++{0x36b0, 0x00}, ++{0x3700, 0x35}, ++{0x3704, 0x39}, ++{0x370a, 0x50}, ++{0x3712, 0x00}, ++{0x3713, 0x02}, ++{0x3778, 0x00}, ++{0x379b, 0x01}, ++{0x379c, 0x10}, ++{0x3800, 0x00}, ++{0x3801, 0x00}, ++{0x3802, 0x00}, ++{0x3803, 0x00}, ++{0x3804, 0x06}, ++{0x3805, 0x4f}, ++{0x3806, 0x05}, ++{0x3807, 0x23}, ++{0x3808, OV2311_MAX_WIDTH >> 8}, ++{0x3809, OV2311_MAX_WIDTH & 0xff}, ++{0x380a, OV2311_MAX_HEIGHT >> 8}, ++{0x380b, OV2311_MAX_HEIGHT & 0xff}, ++{0x380c, 0x03}, ++{0x380d, 0xa8}, ++{0x380e, 0x05}, ++{0x380f, 0x88}, ++{0x3810, OV2311_X_START >> 8}, ++{0x3811, OV2311_X_START & 0xff}, ++{0x3812, OV2311_Y_START >> 8}, ++{0x3813, OV2311_X_START & 0xff}, ++{0x3814, 0x11}, ++{0x3815, 0x11}, ++{0x3816, 0x00}, ++{0x3817, 0x01}, ++{0x3818, 0x00}, ++{0x3819, 0x05}, ++{0x3820, 0x00}, ++{0x3821, 0x00}, ++{0x382b, 0x5a}, ++{0x382c, 0x0a}, ++{0x382d, 0xf8}, ++{0x3881, 0x44}, ++{0x3882, 0x02}, ++{0x3883, 0x8c}, ++{0x3885, 0x07}, ++{0x389d, 0x03}, ++{0x38a6, 0x00}, ++{0x38a7, 0x01}, ++{0x38b3, 0x07}, ++{0x38b1, 0x00}, ++{0x38e5, 0x02}, ++{0x38e7, 0x00}, ++{0x38e8, 0x00}, ++{0x3910, 0xff}, ++{0x3911, 0xff}, ++{0x3912, 0x08}, ++{0x3913, 0x00}, ++{0x3914, 0x00}, ++{0x3915, 0x00}, ++{0x391c, 0x00}, ++{0x3920, 0xff}, ++{0x3921, 0x80}, ++{0x3922, 0x00}, ++{0x3923, 0x00}, ++{0x3924, 0x05}, ++{0x3925, 0x00}, ++{0x3926, 0x00}, ++{0x3927, 0x00}, ++{0x3928, 0x1a}, ++{0x392d, 0x03}, ++{0x392e, 0xa8}, ++{0x392f, 0x08}, ++{0x4001, 0x00}, ++{0x4003, 0x40}, ++{0x4008, 0x04}, ++{0x4009, 0x1b}, ++{0x400c, 0x04}, ++{0x400d, 0x1b}, ++{0x4010, 0xf4}, ++{0x4011, 0x00}, ++{0x4016, 0x00}, ++{0x4017, 0x04}, ++{0x4042, 0x11}, ++{0x4043, 0x70}, ++{0x4045, 0x00}, ++{0x4409, 0x5f}, ++{0x4509, 0x00}, ++{0x450b, 0x00}, ++{0x4600, 0x00}, ++{0x4601, 0xa0}, ++{0x4708, 0x09}, ++{0x470c, 0x81}, ++{0x4710, 0x06}, ++{0x4711, 0x00}, ++{0x4800, 0x00}, ++{0x481f, 0x30}, ++{0x4837, 0x14}, ++{0x4f00, 0x00}, ++{0x4f07, 0x00}, ++{0x4f08, 0x03}, ++{0x4f09, 0x08}, ++{0x4f0c, 0x05}, ++{0x4f0d, 0xb4}, ++{0x4f10, 0x00}, ++{0x4f11, 0x00}, ++{0x4f12, 0x07}, ++{0x4f13, 0xe2}, ++{0x5000, 0x9f}, ++{0x5001, 0x20}, ++{0x5026, 0x00}, ++{0x5c00, 0x00}, ++{0x5c01, 0x2c}, ++{0x5c02, 0x00}, ++{0x5c03, 0x7f}, ++{0x5e00, 0x00}, ++{0x5e01, 0x41}, ++{0x38b1, 0x02}, ++{0x3880, 0x00}, ++ ++#if 1 /* Y8 mode */ ++{0x3016, 0xF1}, ++{0x0100, 0x01}, ++{0x4814, 0x6A}, //; dt_man en, both embed/image data type are 0x2A ++{0x3218, 0x32}, ++{0x3216, 0x01}, ++{0x3208, 0x04}, ++{0x3D81, 0x01}, ++{0x4605, 0x02}, ++{0x4816, 0x0A}, ++{0x3208, 0x14}, ++{0x3662, 0x67}, //; [1] raw8 ++{0x366F, 0x1A}, //; [6] MSB ++//{0x3674, 0x11}, //; [0] embed_en, add embed data before normal image ++{0x3674, 0x10}, //; [0] embed_dis, add embed data before normal image ++{0x3016, 0xF0}, ++#endif ++ ++{0x0100, 0x01}, ++}; +diff --git a/drivers/media/i2c/soc_camera/imagers/ov490.c b/drivers/media/i2c/soc_camera/imagers/ov490.c +new file mode 100644 +index 0000000..3c47398 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ov490.c +@@ -0,0 +1,1051 @@ ++/* ++ * OmniVision ov490-10640 sensor camera driver ++ * ++ * Copyright (C) 2016-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++#include "../gmsl/common.h" ++#include "ov490.h" ++ ++#define OV490_I2C_ADDR 0x24 ++ ++#define OV490_PID_REGA 0x300a ++#define OV490_PID_REGB 0x300b ++#define OV490_PID 0x0490 ++ ++#define OV490_ISP_HSIZE_LOW 0x60 ++#define OV490_ISP_HSIZE_HIGH 0x61 ++#define OV490_ISP_VSIZE_LOW 0x62 ++#define OV490_ISP_VSIZE_HIGH 0x63 ++ ++struct ov490_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int max_width; ++ int max_height; ++ int init_complete; ++ u8 id[6]; ++ int exposure; ++ int gain; ++ int autogain; ++ int red; ++ int green_r; ++ int green_b; ++ int blue; ++ int awb; ++ int dvp_order; ++ int group; ++ /* serializers */ ++ int ser_addr; ++ int des_addr; ++ int reset_gpio; ++ int active_low_resetb; ++}; ++ ++static int conf_link; ++module_param(conf_link, int, 0644); ++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); ++ ++static int group = 0; ++module_param(group, int, 0644); ++MODULE_PARM_DESC(group, " group number (0 - does not apply)"); ++ ++static int dvp_order = 0; ++module_param(dvp_order, int, 0644); ++MODULE_PARM_DESC(dvp_order, " DVP bus bits order"); ++ ++static int reset_gpio = 0; ++module_param(reset_gpio, int, 0644); ++MODULE_PARM_DESC(reset_gpio, " serializer gpio number on imager RESETB"); ++ ++static inline struct ov490_priv *to_ov490(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov490_priv, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov490_priv, hdl)->sd; ++} ++ ++static void ov490_reset(struct i2c_client *client) ++{ ++ struct ov490_priv *priv = to_ov490(client); ++ ++ switch (get_des_id(client)) { ++ case MAX9286_ID: ++ case MAX9288_ID: ++ case MAX9296A_ID: ++ case MAX96712_ID: ++ reg8_write_addr(client, priv->ser_addr, 0x0f, (0xfe & ~BIT(priv->reset_gpio))); /* set GPIOn value to reset */ ++ usleep_range(2000, 2500); ++ reg8_write_addr(client, priv->ser_addr, 0x0f, 0xfe | BIT(priv->reset_gpio)); /* set GPIOn value to un-reset */ ++ usleep_range(2000, 2500); ++ break; ++ case UB960_ID: ++ reg8_write_addr(client, get_des_addr(client), 0x6e, 0x8a); /* set GPIO1 value to reset */ ++ usleep_range(2000, 2500); ++ reg8_write_addr(client, get_des_addr(client), 0x6e, 0x9a); /* set GPIO1 value to un-reset */ ++ usleep_range(2000, 2500); ++ break; ++ } ++} ++ ++static int ov490_set_regs(struct i2c_client *client, ++ const struct ov490_reg *regs, int nr_regs) ++{ ++ int i; ++ ++ for (i = 0; i < nr_regs; i++) { ++ if (reg16_write(client, regs[i].reg, regs[i].val)) { ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, regs[i].reg, regs[i].val); ++ } ++ ++ if (regs[i].reg == 0xFFFE) ++ usleep_range(100, 150); /* wait 100 us */ ++ } ++ ++ return 0; ++} ++ ++static u8 ov490_ov10640_read(struct i2c_client *client, u16 addr) ++{ ++ u8 reg_val = 0; ++ ++ reg16_write(client, 0xFFFD, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x5000, 0x01); /* read operation */ ++ reg16_write(client, 0x5001, addr >> 8); ++ reg16_write(client, 0x5002, addr & 0xff); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x00C0, 0xc1); ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(1000, 1500); /* wait 1 ms */ ++ reg16_read(client, 0x5000, ®_val); ++ ++ return reg_val; ++} ++ ++static void ov490_ov10640_write(struct i2c_client *client, u16 addr, u8 val) ++{ ++ reg16_write(client, 0xFFFD, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x5000, 0x00); /* write operation */ ++ reg16_write(client, 0x5001, addr >> 8); ++ reg16_write(client, 0x5002, addr & 0xff); ++ reg16_write(client, 0x5003, val); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x00C0, 0xc1); ++} ++ ++static void ov490_otp_id_read(struct i2c_client *client) ++{ ++ struct ov490_priv *priv = to_ov490(client); ++ int i; ++ int otp_bank0_allzero = 1; ++#if 0 ++ /* read camera id from ov490 OTP memory */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x28); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0xE084, 0x40); /* manual mode, bank#0 */ ++ reg16_write(client, 0xE081, 1); /* start OTP read */ ++ ++ usleep_range(25000, 26000); /* wait 25 ms */ ++ ++ for (i = 0; i < 6; i++) ++ reg16_read(client, 0xe000 + i + 4, &priv->id[i]); ++#else ++ /* read camera id from ov10640 OTP memory */ ++ ov490_ov10640_write(client, 0x349C, 1); ++ usleep_range(25000, 25500); /* wait 25 ms */ ++ ++ for (i = 0; i < 6; i++) { ++ /* first 6 bytes are equal on all ov10640 */ ++ priv->id[i] = ov490_ov10640_read(client, 0x349e + i + 6); ++ if (priv->id[i]) ++ otp_bank0_allzero = 0; ++ } ++ ++ if (otp_bank0_allzero) { ++ ov490_ov10640_write(client, 0x3495, 0x41); /* bank#1 */ ++ ov490_ov10640_write(client, 0x349C, 1); ++ usleep_range(25000, 25500); /* wait 25 ms */ ++ ++ for (i = 0; i < 6; i++) ++ priv->id[i] = ov490_ov10640_read(client, 0x34ae + i); ++ } ++#endif ++} ++ ++static int ov490_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int ov490_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov490_priv *priv = to_ov490(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov490_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ ++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int ov490_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_YUYV8_2X8; ++ ++ return 0; ++} ++ ++static int ov490_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov490_priv *priv = to_ov490(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = OV490_PID >> 8; ++ edid->edid[9] = OV490_PID & 0xff; ++ ++ return 0; ++} ++ ++static int ov490_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov490_priv *priv = to_ov490(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > priv->max_width) || ++ (rect->top + rect->height > priv->max_height)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ return 0; ++} ++ ++static int ov490_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov490_priv *priv = to_ov490(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ov490_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov490_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ u8 val = 0; ++ ++ ret = reg16_read(client, (u16)reg->reg, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = sizeof(u16); ++ ++ return 0; ++} ++ ++static int ov490_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ ret = reg16_write(client, (u16)reg->reg, (u8)reg->val); ++ if ((u8)reg->reg == 0xFFFD) ++ usleep_range(100, 150); /* wait 100 us */ ++ if ((u8)reg->reg == 0xFFFE) ++ usleep_range(100, 150); /* wait 100 us */ ++ return ret; ++} ++#endif ++ ++static struct v4l2_subdev_core_ops ov490_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov490_g_register, ++ .s_register = ov490_s_register, ++#endif ++}; ++ ++static int ov490_s_gamma(int a, int ref) ++{ ++ if ((a + ref) > 0xff) ++ return 0xff; ++ ++ if ((a + ref) < 0) ++ return 0; ++ ++ return a + ref; ++} ++ ++static int ov490_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov490_priv *priv = to_ov490(client); ++ int ret = -EINVAL; ++ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ /* SDE (rough) brightness */ ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); ++ ret |= reg16_write(client, 0x5001, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xf1); ++ break; ++ case V4L2_CID_CONTRAST: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xfd); ++ break; ++ case V4L2_CID_SATURATION: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xf3); ++ break; ++ case V4L2_CID_HUE: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xf5); ++ break; ++ case V4L2_CID_GAMMA: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ov490_s_gamma(ctrl->val, 0x12)); ++ ret |= reg16_write(client, 0x5001, ov490_s_gamma(ctrl->val, 0x20)); ++ ret |= reg16_write(client, 0x5002, ov490_s_gamma(ctrl->val, 0x3b)); ++ ret |= reg16_write(client, 0x5003, ov490_s_gamma(ctrl->val, 0x5d)); ++ ret |= reg16_write(client, 0x5004, ov490_s_gamma(ctrl->val, 0x6a)); ++ ret |= reg16_write(client, 0x5005, ov490_s_gamma(ctrl->val, 0x76)); ++ ret |= reg16_write(client, 0x5006, ov490_s_gamma(ctrl->val, 0x81)); ++ ret |= reg16_write(client, 0x5007, ov490_s_gamma(ctrl->val, 0x8b)); ++ ret |= reg16_write(client, 0x5008, ov490_s_gamma(ctrl->val, 0x96)); ++ ret |= reg16_write(client, 0x5009, ov490_s_gamma(ctrl->val, 0x9e)); ++ ret |= reg16_write(client, 0x500a, ov490_s_gamma(ctrl->val, 0xae)); ++ ret |= reg16_write(client, 0x500b, ov490_s_gamma(ctrl->val, 0xbc)); ++ ret |= reg16_write(client, 0x500c, ov490_s_gamma(ctrl->val, 0xcf)); ++ ret |= reg16_write(client, 0x500d, ov490_s_gamma(ctrl->val, 0xde)); ++ ret |= reg16_write(client, 0x500e, ov490_s_gamma(ctrl->val, 0xec)); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xf9); ++ break; ++ case V4L2_CID_SHARPNESS: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xfb); ++ break; ++ case V4L2_CID_AUTOGAIN: ++ case V4L2_CID_GAIN: ++ case V4L2_CID_EXPOSURE: ++ if (ctrl->id == V4L2_CID_AUTOGAIN) ++ priv->autogain = ctrl->val; ++ if (ctrl->id == V4L2_CID_GAIN) ++ priv->gain = ctrl->val; ++ if (ctrl->id == V4L2_CID_EXPOSURE) ++ priv->exposure = ctrl->val; ++ ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, !priv->autogain); ++ ret |= reg16_write(client, 0x5001, priv->exposure >> 8); ++ ret |= reg16_write(client, 0x5002, priv->exposure & 0xff); ++ ret |= reg16_write(client, 0x5003, priv->exposure >> 8); ++ ret |= reg16_write(client, 0x5004, priv->exposure & 0xff); ++ ret |= reg16_write(client, 0x5005, priv->exposure >> 8); ++ ret |= reg16_write(client, 0x5006, priv->exposure & 0xff); ++ ret |= reg16_write(client, 0x5007, priv->gain >> 8); ++ ret |= reg16_write(client, 0x5008, priv->gain & 0xff); ++ ret |= reg16_write(client, 0x5009, priv->gain >> 8); ++ ret |= reg16_write(client, 0x500a, priv->gain & 0xff); ++ ret |= reg16_write(client, 0x500b, priv->gain >> 8); ++ ret |= reg16_write(client, 0x500c, priv->gain & 0xff); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xea); ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ case V4L2_CID_RED_BALANCE: ++ case V4L2_CID_BLUE_BALANCE: ++ if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE) ++ priv->awb = ctrl->val; ++ if (ctrl->id == V4L2_CID_RED_BALANCE) { ++ priv->red = ctrl->val; ++ priv->red <<= 8; ++ priv->green_r = priv->red / 2; ++ } ++ if (ctrl->id == V4L2_CID_BLUE_BALANCE) { ++ priv->blue = ctrl->val; ++ priv->blue <<= 8; ++ priv->green_b = priv->blue / 2; ++ } ++ ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, !priv->awb); ++ ret |= reg16_write(client, 0x5001, priv->red >> 8); ++ ret |= reg16_write(client, 0x5002, priv->red & 0xff); ++ ret |= reg16_write(client, 0x5003, priv->green_r >> 8); ++ ret |= reg16_write(client, 0x5004, priv->green_r & 0xff); ++ ret |= reg16_write(client, 0x5005, priv->green_b >> 8); ++ ret |= reg16_write(client, 0x5006, priv->green_b & 0xff); ++ ret |= reg16_write(client, 0x5007, priv->blue >> 8); ++ ret |= reg16_write(client, 0x5008, priv->blue & 0xff); ++ ret |= reg16_write(client, 0x5009, priv->red >> 8); ++ ret |= reg16_write(client, 0x500a, priv->red & 0xff); ++ ret |= reg16_write(client, 0x500b, priv->green_r >> 8); ++ ret |= reg16_write(client, 0x500c, priv->green_r & 0xff); ++ ret |= reg16_write(client, 0x500d, priv->green_b >> 8); ++ ret |= reg16_write(client, 0x500e, priv->green_b & 0xff); ++ ret |= reg16_write(client, 0x500f, priv->blue >> 8); ++ ret |= reg16_write(client, 0x5010, priv->blue & 0xff); ++ ret |= reg16_write(client, 0x5011, priv->red >> 8); ++ ret |= reg16_write(client, 0x5012, priv->red & 0xff); ++ ret |= reg16_write(client, 0x5013, priv->green_r >> 8); ++ ret |= reg16_write(client, 0x5014, priv->green_r & 0xff); ++ ret |= reg16_write(client, 0x5015, priv->green_b >> 8); ++ ret |= reg16_write(client, 0x5016, priv->green_b & 0xff); ++ ret |= reg16_write(client, 0x5017, priv->blue >> 8); ++ ret |= reg16_write(client, 0x5018, priv->blue & 0xff); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xeb); ++ break; ++ case V4L2_CID_HFLIP: ++#if 1 ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0x5001, 0x00); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xdc); ++#else ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3128 ++ ret |= reg16_write(client, 0x5001, 0x31); ++ ret |= reg16_write(client, 0x5002, 0x28); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 0); ++ val |= (ctrl->val << 0); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3128 ++ ret |= reg16_write(client, 0x5001, 0x31); ++ ret |= reg16_write(client, 0x5002, 0x28); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3291 ++ ret |= reg16_write(client, 0x5001, 0x32); ++ ret |= reg16_write(client, 0x5002, 0x91); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 1); ++ val |= (ctrl->val << 1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3291 ++ ret |= reg16_write(client, 0x5001, 0x32); ++ ret |= reg16_write(client, 0x5002, 0x91); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3090 ++ ret |= reg16_write(client, 0x5001, 0x30); ++ ret |= reg16_write(client, 0x5002, 0x90); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 2); ++ val |= (ctrl->val << 2); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3090 ++ ret |= reg16_write(client, 0x5001, 0x30); ++ ret |= reg16_write(client, 0x5002, 0x90); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++#endif ++ break; ++ case V4L2_CID_VFLIP: ++#if 1 ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0x5001, 0x01); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xdc); ++#else ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3128 ++ ret |= reg16_write(client, 0x5001, 0x31); ++ ret |= reg16_write(client, 0x5002, 0x28); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 1); ++ val |= (ctrl->val << 1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3128 ++ ret |= reg16_write(client, 0x5001, 0x31); ++ ret |= reg16_write(client, 0x5002, 0x28); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3291 ++ ret |= reg16_write(client, 0x5001, 0x32); ++ ret |= reg16_write(client, 0x5002, 0x91); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 2); ++ val |= (ctrl->val << 2); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3291 ++ ret |= reg16_write(client, 0x5001, 0x32); ++ ret |= reg16_write(client, 0x5002, 0x91); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3090 ++ ret |= reg16_write(client, 0x5001, 0x30); ++ ret |= reg16_write(client, 0x5002, 0x90); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 3); ++ val |= (ctrl->val << 3); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3090 ++ ret |= reg16_write(client, 0x5001, 0x30); ++ ret |= reg16_write(client, 0x5002, 0x90); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++#endif ++ break; ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ret = 0; ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov490_ctrl_ops = { ++ .s_ctrl = ov490_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops ov490_video_ops = { ++ .s_stream = ov490_s_stream, ++ .g_mbus_config = ov490_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov490_subdev_pad_ops = { ++ .get_edid = ov490_get_edid, ++ .enum_mbus_code = ov490_enum_mbus_code, ++ .get_selection = ov490_get_selection, ++ .set_selection = ov490_set_selection, ++ .get_fmt = ov490_get_fmt, ++ .set_fmt = ov490_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops ov490_subdev_ops = { ++ .core = &ov490_core_ops, ++ .video = &ov490_video_ops, ++ .pad = &ov490_subdev_pad_ops, ++}; ++ ++static ssize_t ov490_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov490_priv *priv = to_ov490(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_ov490, S_IRUGO, ov490_otp_id_show, NULL); ++ ++static int ov490_initialize(struct i2c_client *client) ++{ ++ struct ov490_priv *priv = to_ov490(client); ++ u8 val = 0; ++ u16 pid = 0; ++ int timeout, retry_timeout = 3; ++ ++ setup_i2c_translator(client, priv->ser_addr, OV490_I2C_ADDR, MODE_GMSL1); ++ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_read(client, OV490_PID_REGA, &val); ++ pid = val; ++ reg16_read(client, OV490_PID_REGB, &val); ++ pid = (pid << 8) | val; ++ ++ if (pid != OV490_PID) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ return -ENODEV; ++ } ++ ++ if (unlikely(conf_link)) ++ goto out; ++again: ++ /* Check if firmware booted by reading stream-on status */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x29); ++ usleep_range(100, 150); /* wait 100 us */ ++ for (timeout = 300; timeout > 0; timeout--) { ++ reg16_read(client, 0xd000, &val); ++ if (val == 0x0c) ++ break; ++ mdelay(1); ++ } ++ ++ /* wait firmware apps started by reading OV10640 ID */ ++ for (;timeout > 0; timeout--) { ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x5000, 0x01); ++ reg16_write(client, 0x5001, 0x30); ++ reg16_write(client, 0x5002, 0x0a); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0xC0, 0xc1); ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(1000, 1500); /* wait 1 ms */ ++ reg16_read(client, 0x5000, &val); ++ if (val == 0xa6) ++ break; ++ mdelay(1); ++ } ++ ++ if (!timeout) { ++ dev_err(&client->dev, "Timeout firmware boot wait, retrying\n"); ++ /* reset OV10640 using RESETB pin controlled by OV490 GPIO0 */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x0050, 0x01); ++ reg16_write(client, 0x0054, 0x01); ++ reg16_write(client, 0x0058, 0x00); ++ mdelay(10); ++ reg16_write(client, 0x0058, 0x01); ++ /* reset OV490 using RESETB pin controlled by serializer */ ++ ov490_reset(client); ++ if (retry_timeout--) ++ goto again; ++ } ++ ++ if (priv->group) { ++ /* switch to group# */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x5000, priv->group); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0xc0, 0x3f); ++ ++ mdelay(30); ++ } ++ ++ /* read resolution used by current firmware */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x82); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_read(client, OV490_ISP_HSIZE_HIGH, &val); ++ priv->max_width = val; ++ reg16_read(client, OV490_ISP_HSIZE_LOW, &val); ++ priv->max_width = (priv->max_width << 8) | val; ++ reg16_read(client, OV490_ISP_VSIZE_HIGH, &val); ++ priv->max_height = val; ++ reg16_read(client, OV490_ISP_VSIZE_LOW, &val); ++ priv->max_height = (priv->max_height << 8) | val; ++ /* Program wizard registers */ ++ ov490_set_regs(client, ov490_regs_wizard, ARRAY_SIZE(ov490_regs_wizard)); ++ /* Set DVP bit swap */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x28); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x6009, priv->dvp_order << 4); ++ /* Read OTP IDs */ ++ ov490_otp_id_read(client); ++ ++out: ++ dev_info(&client->dev, "ov490-10640 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ return 0; ++} ++ ++static const struct i2c_device_id ov490_id[] = { ++ { "ov490", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov490_id); ++ ++static const struct of_device_id ov490_of_ids[] = { ++ { .compatible = "ovti,ov490", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ov490_of_ids); ++ ++static int ov490_parse_dt(struct device_node *np, struct ov490_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ u32 addrs[2], naddrs; ++ ++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32)); ++ if (naddrs != 2) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ priv->ser_addr = addrs[1]; ++ ++ if (of_property_read_u32(np, "dvp-order", &priv->dvp_order)) ++ priv->dvp_order = 0; ++ if (of_property_read_u32(np, "reset-gpio", &priv->reset_gpio)) ++ priv->reset_gpio = 1; ++ if (of_property_read_u32(np, "group", &priv->group)) ++ priv->group = 0; ++ ++ /* module params override dts */ ++ if (dvp_order) ++ priv->dvp_order = dvp_order; ++ if (group) ++ priv->group = group; ++ ++ return 0; ++} ++ ++static int ov490_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov490_priv *priv; ++ struct v4l2_ctrl *ctrl; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &ov490_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ priv->exposure = 0x100; ++ priv->gain = 0x100; ++ priv->autogain = 1; ++ priv->red = 0x400; ++ priv->blue = 0x400; ++ priv->green_r = priv->red / 2; ++ priv->green_b = priv->blue / 2; ++ priv->awb = 1; ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, priv->autogain); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_RED_BALANCE, 2, 0xf, 1, priv->red >> 8); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_BLUE_BALANCE, 2, 0xf, 1, priv->blue >> 8); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 1); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); ++ if (ctrl) ++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = ov490_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = ov490_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = priv->max_width; ++ priv->rect.height = priv->max_height; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov490) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ return ret; ++} ++ ++static int ov490_remove(struct i2c_client *client) ++{ ++ struct ov490_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_ov490); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++static struct i2c_driver ov490_i2c_driver = { ++ .driver = { ++ .name = "ov490", ++ .of_match_table = ov490_of_ids, ++ }, ++ .probe = ov490_probe, ++ .remove = ov490_remove, ++ .id_table = ov490_id, ++}; ++ ++module_i2c_driver(ov490_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for OV490"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/imagers/ov490.h b/drivers/media/i2c/soc_camera/imagers/ov490.h +new file mode 100644 +index 0000000..6c39bdd +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ov490.h +@@ -0,0 +1,102 @@ ++/* ++ * OmniVision ov490-ov10640 sensor camera wizard 1280x1080@30/UYVY/BT601/8bit ++ * ++ * Copyright (C) 2016-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++//#define OV490_DISPLAY_PATTERN ++ ++struct ov490_reg { ++ u16 reg; ++ u8 val; ++}; ++ ++static const struct ov490_reg ov490_regs_wizard[] = { ++/* The following registers should match firmware */ ++{0xfffd, 0x80}, ++{0xfffe, 0x82}, ++{0x0071, 0x11}, ++{0x0075, 0x11}, ++{0xfffe, 0x29}, ++{0x6010, 0x01}, ++/* ov490 EMB line disable in YUV and RAW data, NOTE: EMB line is still used in ISP and sensor */ ++{0xe000, 0x14}, ++#if 0 /* do not disable EMB line in ISP! */ ++{0x4017, 0x00}, ++#endif ++{0xfffe, 0x28}, ++{0x6000, 0x04}, ++{0x6004, 0x00}, ++//{0x6008, 0x000}, // PCLK polarity - useless due to silicon bug -> use 0x808000bb register ++{0x6008, 0x02}, // PCLK polarity - useless due to silicon bug -> use 0x808000bb register ++{0xfffe, 0x80}, ++{0x0091, 0x00}, ++{0x00bb, 0x1d}, // bit[3]=0 - PCLK polarity workaround ++/* ov10640 EMB line disable */ ++#if 0 /* do not disable EMB line in sensor! */ ++{0xfffe, 0x19}, ++{0x5000, 0x00}, ++{0x5001, 0x30}, ++{0x5002, 0x91}, ++{0x5003, 0x08}, ++{0xfffe, 0x80}, ++{0x00c0, 0xc1}, ++#endif ++/* Ov490 FSIN: app_fsin_from_fsync */ ++{0xfffe, 0x85}, ++{0x0008, 0x00}, ++{0x0009, 0x01}, ++{0x000A, 0x05}, // fsin0 src ++{0x000B, 0x00}, ++{0x0030, 0x02}, // fsin0_delay ++{0x0031, 0x00}, ++{0x0032, 0x00}, ++{0x0033, 0x00}, ++{0x0038, 0x02}, // fsin1_delay ++{0x0039, 0x00}, ++{0x003A, 0x00}, ++{0x003B, 0x00}, ++{0x0070, 0x2C}, // fsin0_length ++{0x0071, 0x01}, ++{0x0072, 0x00}, ++{0x0073, 0x00}, ++{0x0074, 0x64}, // fsin1_length ++{0x0075, 0x00}, ++{0x0076, 0x00}, ++{0x0077, 0x00}, ++{0x0000, 0x14}, ++{0x0001, 0x00}, ++{0x0002, 0x00}, ++{0x0003, 0x00}, ++{0x0004, 0x32}, // load fsin0,load fsin1,load other, it will be cleared automatically. ++{0x0005, 0x00}, ++{0x0006, 0x00}, ++{0x0007, 0x00}, ++{0xfffe, 0x80}, ++{0x0081, 0x00}, // 03;SENSOR FSIN ++/* ov10640 FSIN */ ++{0xfffe, 0x19}, ++{0x5000, 0x00}, ++{0x5001, 0x30}, ++{0x5002, 0x8c}, ++{0x5003, 0xb2}, ++{0xfffe, 0x80}, ++{0x00c0, 0xc1}, ++/* ov10640 HFLIP=1 by default */ ++{0xfffe, 0x19}, ++{0x5000, 0x01}, ++{0x5001, 0x00}, ++{0xfffe, 0x80}, ++{0x00c0, 0xdc}, ++#ifdef OV490_DISPLAY_PATTERN ++{0xfffe, 0x19}, ++{0x5000, 0x02}, ++{0xfffe, 0x80}, ++{0x00c0, 0xd6}, ++#endif ++}; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0497-media-i2c-soc_camera-rcar_csi2-adjust-debugging.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0497-media-i2c-soc_camera-rcar_csi2-adjust-debugging.patch new file mode 100644 index 00000000..89bf7716 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0497-media-i2c-soc_camera-rcar_csi2-adjust-debugging.patch @@ -0,0 +1,165 @@ +From ae9686ecfbdb0af61975e1f501d83f9a488e2e7b Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 11:25:19 +0300 +Subject: [PATCH] media: i2c: soc_camera: rcar_csi2: adjust debugging + +This extends MIPI packets debugging. +This adds possibility to enable debuuggin runtime via sysfs + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/platform/soc_camera/rcar_csi2.c | 84 ++++++++++++++++++++++----- + 1 file changed, 69 insertions(+), 15 deletions(-) + +diff --git a/drivers/media/platform/soc_camera/rcar_csi2.c b/drivers/media/platform/soc_camera/rcar_csi2.c +index ca47ba3..1f1beb8 100644 +--- a/drivers/media/platform/soc_camera/rcar_csi2.c ++++ b/drivers/media/platform/soc_camera/rcar_csi2.c +@@ -293,10 +293,10 @@ MODULE_PARM_DESC(dump, " Dump CSI packets (default: disabled)"); + #define RCAR_CSI2_CRCECM 0x150 + #define RCAR_CSI2_LCNT(i) (0x160 + i * 0x04) + #define RCAR_CSI2_LCNTM(i) (0x168 + i * 0x04) +-#define RCAR_CSI2_FCNTM 0x170 +-#define RCAR_CSI2_FCNTM2 0x174 ++#define RCAR_CSI2_FCNTM(i) (0x170 + i * 0x04) + #define RCAR_CSI2_VINSM(i) (0x190 + i * 0x04) + #define RCAR_CSI2_PHM(i) (0x1C0 + i * 0x04) ++#define RCAR_CSI2_PPM(i) (0x1E0 + i * 0x04) + + #define RCAR_CSI2_INTSTATE_ALL 0x3FFFFCDD + +@@ -309,8 +309,28 @@ static void rcar_sci2_debug_show(struct rcar_csi2 *priv) + return; + + dev_info(&priv->pdev->dev, "Debug registers:\n"); +- printk("FCNTM : 0x%08x\n", ioread32(priv->base + RCAR_CSI2_FCNTM)); +- printk("FCNTM2: 0x%08x\n", ioread32(priv->base + RCAR_CSI2_FCNTM2)); ++ for (i = 0; i < 2; i++) { ++ reg0 = ioread32(priv->base + RCAR_CSI2_FCNTM(i)); ++ ++ printk("FCNTM%d: 0x%08x: " ++ "Ch%d: %d, Ch%d: %d\n", ++ i + 1, reg0, ++ i * 2, (reg0 >> 0) & 0xffff, i * 2 + 1, (reg0 >> 16) & 0xffff); ++ } ++ for (i = 0; i < 2; i++) { ++ reg0 = ioread32(priv->base + RCAR_CSI2_LCNTM(i)); ++ ++ printk("LCNTM%d: 0x%08x: " ++ "Ch%d: %d, Ch%d: %d\n", ++ i + 1, reg0, ++ i * 2, (reg0 >> 0) & 0xffff, i * 2 + 1, (reg0 >> 16) & 0xffff); ++ } ++ for (i = 0; i < 2; i++) { ++ reg0 = ioread32(priv->base + RCAR_CSI2_LCNT(i)); ++ ++ printk("LCNT%d: 0x%04x, 0x%04x\n", ++ i + 1, (reg0 >> 0) & 0xffff, (reg0 >> 16)); ++ } + + for (i = 0; i < 4; i++) { + reg0 = ioread32(priv->base + RCAR_CSI2_PHxM0(i)); +@@ -324,7 +344,7 @@ static void rcar_sci2_debug_show(struct rcar_csi2 *priv) + for (i = 0; i < 3; i++) { + reg0 = ioread32(priv->base + RCAR_CSI2_PHRM(i)); + +- printk("Packet header R %d dt: 0x%02x, vc: %d, wc: %d, ecc: 0x%02x\n", ++ printk("Packet Header R Monitor Register %d dt: 0x%02x, vc: %d, wc: %d, ecc: 0x%02x\n", + i, + reg0 & 0x3F, (reg0 >> 6) & 0x03, (reg0 >> 8) & 0xffff, + (reg0 >> 24) & 0xff); +@@ -332,21 +352,36 @@ static void rcar_sci2_debug_show(struct rcar_csi2 *priv) + for (i = 0; i < 2; i++) { + reg0 = ioread32(priv->base + RCAR_CSI2_PHCM(i)); + +- printk("Packet header C %d: dt: 0x%02x, vc: %d, wc: %d, cal_parity: 0x%02x\n", ++ printk("Packet Header C Monitor Register %d: dt: 0x%02x, vc: %d, wc: %d, cal_parity: 0x%02x\n", + i, + reg0 & 0x3F, (reg0 >> 6) & 0x03, (reg0 >> 8) & 0xffff, + (reg0 >> 24) & 0xff); + } + for (i = 0; i < 8; i++) { + reg0 = ioread32(priv->base + RCAR_CSI2_PHM(i)); ++ reg1 = ioread32(priv->base + RCAR_CSI2_PPM(i)); + +- printk("Packet header Monitor %d: dt: 0x%02x, vc: %d, wc: %d, ecc: 0x%02x\n", +- i + 1, ++ printk("Packet Header Monitor Register %d: dt: 0x%02x, vc: %d, wc: %d, ecc: 0x%02x (period = 0x%08x)\n", ++ i, + reg0 & 0x3F, (reg0 >> 6) & 0x03, (reg0 >> 8) & 0xffff, +- (reg0 >> 24) & 0xff); ++ (reg0 >> 24) & 0xff, ++ reg1); + } +- for (i = 0; i < 3; i++) +- printk("VINSM%d: 0x%08x\n", i, ioread32(priv->base + RCAR_CSI2_VINSM(i))); ++ for (i = 0; i < 2; i++) { ++ reg0 = ioread32(priv->base + RCAR_CSI2_VINSM(i)); ++ ++ printk("VINSM%d: 0x%08x: " ++ "HD%d: %d, VD%d: %d, HD%d: %d, VD%d: %d\n", ++ i, reg0, ++ 2 * i, (reg0 >> 0) & 0x0fff, 2* i, (reg0 >> 12) & 0x000f, ++ 2 * i + 1, (reg0 >> 16) & 0x0fff, 2 * i + 1, (reg0 >> 28) & 0x000f); ++ } ++ reg0 = ioread32(priv->base + RCAR_CSI2_VINSM(2)); ++ printk("VINSM3: 0x%08x: " ++ "PE: %d, PEB: %x, FLD: %x, TAG: %x, ERRC: %x, ERRE: %x\n", ++ reg0, ++ (reg0 >> 0) & 0x01, (reg0 >> 4) & 0x0f, (reg0 >> 8) & 0x0f, (reg0 >> 10) & 0x03, ++ (reg0 >> 14) & 0x01, (reg0 >> 15) & 0x01); + printk("SERCCNT: %d\n", + ioread32(priv->base + RCAR_CSI2_SERCCNT)); + printk("SSERCCNT: %d\n", +@@ -357,10 +392,6 @@ static void rcar_sci2_debug_show(struct rcar_csi2 *priv) + ioread32(priv->base + RCAR_CSI2_ECECM)); + printk("CRCECM: %d\n", + ioread32(priv->base + RCAR_CSI2_CRCECM)); +- for (i = 0; i < 2; i++) +- printk("LCNT%d: 0x%08x\n", i, ioread32(priv->base + RCAR_CSI2_LCNT(i))); +- for (i = 0; i < 2; i++) +- printk("LCNTM%d: 0x%08x\n", i, ioread32(priv->base + RCAR_CSI2_LCNTM(i))); + } + + static int rcar_csi2_set_phy_freq(struct rcar_csi2 *priv) +@@ -669,6 +700,26 @@ static struct v4l2_subdev_ops rcar_csi2_subdev_ops = { + .core = &rcar_csi2_subdev_core_ops, + }; + ++static ssize_t rcar_csi2_dump_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ u32 val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ dump = !!val; ++ ++ return count; ++} ++ ++static ssize_t rcar_csi2_dump_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ return snprintf(buf, 4, "%d\n", dump); ++} ++ ++static DEVICE_ATTR(dump, S_IRUGO|S_IWUSR, rcar_csi2_dump_show, rcar_csi2_dump_store); ++ + #ifdef CONFIG_OF + static const struct of_device_id rcar_csi2_of_table[] = { + { .compatible = "renesas,r8a77980-csi2", .data = (void *)RCAR_GEN3 }, +@@ -832,6 +883,9 @@ static int rcar_csi2_probe(struct platform_device *pdev) + + pm_runtime_enable(&pdev->dev); + ++ if (device_create_file(&pdev->dev, &dev_attr_dump) != 0) ++ dev_err(&pdev->dev, "sysfs dump entry creation failed\n"); ++ + dev_dbg(&pdev->dev, "CSI2 probed.\n"); + + return 0; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0498-media-platform-soc_camera-rcar_vin-add-max96712-max9.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0498-media-platform-soc_camera-rcar_vin-add-max96712-max9.patch new file mode 100644 index 00000000..b95f9cc6 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0498-media-platform-soc_camera-rcar_vin-add-max96712-max9.patch @@ -0,0 +1,135 @@ +From a7032bf42a9e8452ac2bc01a5bed0775ce80d4b3 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 11:33:26 +0300 +Subject: [PATCH] media: platform: soc_camera: rcar_vin: add max96712, max9296 + +This adds MAX96712 and MAX9296 deserializers in VIN binding + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/platform/soc_camera/rcar_vin.c | 75 ++++++++++------------------ + 1 file changed, 27 insertions(+), 48 deletions(-) + +diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c +index 93bc1e4..564c371 100644 +--- a/drivers/media/platform/soc_camera/rcar_vin.c ++++ b/drivers/media/platform/soc_camera/rcar_vin.c +@@ -880,6 +880,14 @@ enum rcar_vin_state { + STOPPING, + }; + ++static const char *deser_names[] = { ++ "max9286", ++ "ti9x4", ++ "max9288", ++ "max9296", ++ "max96712" ++}; ++ + struct rcar_vin_async_client { + struct v4l2_async_subdev *sensor; + struct v4l2_async_notifier notifier; +@@ -1571,23 +1579,15 @@ static struct v4l2_subdev *find_csi2(struct rcar_vin_priv *pcdev) + + static struct v4l2_subdev *find_deser(struct rcar_vin_priv *pcdev) + { ++ int i; + struct v4l2_subdev *sd; +- char name[] = "max9286"; +- char name2[] = "ti9x4"; +- char name3[] = "max9288"; + + v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev) { +- if (!strncmp(name, sd->name, sizeof(name) - 1)) { +- pcdev->deser_sd = sd; +- return sd; +- } +- if (!strncmp(name2, sd->name, sizeof(name2) - 1)) { +- pcdev->deser_sd = sd; +- return sd; +- } +- if (!strncmp(name3, sd->name, sizeof(name3) - 1)) { +- pcdev->deser_sd = sd; +- return sd; ++ for (i = 0; i < ARRAY_SIZE(deser_names); i++) { ++ if (!strncmp(deser_names[i], sd->name, strlen(deser_names[i]))) { ++ pcdev->deser_sd = sd; ++ return sd; ++ } + } + } + +@@ -3054,13 +3054,11 @@ static int rcar_vin_probe(struct platform_device *pdev) + unsigned int pdata_flags; + int irq, ret; + const char *str; +- unsigned int i; ++ unsigned int i, j; + struct device_node *epn = NULL, *ren = NULL; +- struct device_node *csi2_ren = NULL, *max9286_ren = NULL, *ti9x4_ren = NULL, *max9288_ren = NULL; ++ struct device_node *csi2_ren = NULL; ++ struct device_node *deser_ren[ARRAY_SIZE(deser_names)] = {NULL}; + bool csi_use = false; +- bool max9286_use = false; +- bool ti9x4_use = false; +- bool max9288_use = false; + + match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev); + +@@ -3092,19 +3090,10 @@ static int rcar_vin_probe(struct platform_device *pdev) + csi_use = true; + } + +- if (strcmp(ren->parent->name, "max9286") == 0) { +- max9286_ren = of_parse_phandle(epn, "remote-endpoint", 0); +- max9286_use = true; +- } +- +- if (strcmp(ren->parent->name, "ti9x4") == 0) { +- ti9x4_ren = of_parse_phandle(epn, "remote-endpoint", 0); +- ti9x4_use = true; +- } +- +- if (strcmp(ren->parent->name, "max9288") == 0) { +- max9288_ren = of_parse_phandle(epn, "remote-endpoint", 0); +- max9288_use = true; ++ for (j = 0; j < ARRAY_SIZE(deser_names); j++) { ++ if (strcmp(ren->parent->name, deser_names[j]) == 0) { ++ deser_ren[j] = of_parse_phandle(epn, "remote-endpoint", 0); ++ } + } + + of_node_put(ren); +@@ -3372,22 +3361,12 @@ static int rcar_vin_probe(struct platform_device *pdev) + goto cleanup; + } + +- if (max9286_use) { +- ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, max9286_ren); +- if (ret) +- goto cleanup; +- } +- +- if (ti9x4_use) { +- ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, ti9x4_ren); +- if (ret) +- goto cleanup; +- } +- +- if (max9288_use) { +- ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, max9288_ren); +- if (ret) +- goto cleanup; ++ for (j = 0; j < ARRAY_SIZE(deser_names); j++) { ++ if (deser_ren[j]) { ++ ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, deser_ren[j]); ++ if (ret) ++ goto cleanup; ++ } + } + + vin_debug = 0; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0499-regulator-add-MAX2008X-camera-protector.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0499-regulator-add-MAX2008X-camera-protector.patch new file mode 100644 index 00000000..6e1a3e8f --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0499-regulator-add-MAX2008X-camera-protector.patch @@ -0,0 +1,579 @@ +From 7cbcf44f887641e2d15b9b15c5aadd1850bc63ed Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 11:51:14 +0300 +Subject: [PATCH] regulator: add MAX2008X camera protector + +This adds MAX20086-MAX20089 camera protector regulator + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +--- + drivers/regulator/Kconfig | 6 + + drivers/regulator/Makefile | 1 + + drivers/regulator/max2008x-regulator.c | 526 +++++++++++++++++++++++++++++++++ + 3 files changed, 533 insertions(+) + create mode 100644 drivers/regulator/max2008x-regulator.c + +diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig +index 0fd6195..2ff9b57 100644 +--- a/drivers/regulator/Kconfig ++++ b/drivers/regulator/Kconfig +@@ -495,6 +495,12 @@ config REGULATOR_MAX8998 + via I2C bus. The provided regulator is suitable for S3C6410 + and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. + ++config REGULATOR_MAX2008X ++ tristate "Maxim 20086-20089 Dual/Quad Camera Power Protector reguator" ++ help ++ This driver controls MAX20086-MAX20089 dual/quad camera power ++ protector IC. ++ + config REGULATOR_MAX77686 + tristate "Maxim 77686 regulator" + depends on MFD_MAX77686 +diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile +index 80ffc57..eb05d35 100644 +--- a/drivers/regulator/Makefile ++++ b/drivers/regulator/Makefile +@@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o + obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o + obj-$(CONFIG_REGULATOR_MAX8997) += max8997-regulator.o + obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o ++obj-$(CONFIG_REGULATOR_MAX2008X) += max2008x-regulator.o + obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o + obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o + obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o +diff --git a/drivers/regulator/max2008x-regulator.c b/drivers/regulator/max2008x-regulator.c +new file mode 100644 +index 0000000..70f9fb3 +--- /dev/null ++++ b/drivers/regulator/max2008x-regulator.c +@@ -0,0 +1,526 @@ ++/* ++ * gpio-regulator.c ++ * ++ * Copyright 2019 Andrey Gusakov <andrey.gusakov@cogentembedded.com> ++ * ++ * based on gpio-regulator.c ++ * ++ * Copyright 2011 Heiko Stuebner <heiko@sntech.de> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This is useful for systems with mixed controllable and ++ * non-controllable regulators, as well as for allowing testing on ++ * systems with no controllable regulators. ++ */ ++ ++#include <linux/err.h> ++#include <linux/i2c.h> ++#include <linux/mutex.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/regulator/driver.h> ++#include <linux/regulator/machine.h> ++#include <linux/gpio.h> ++#include <linux/slab.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/iio/iio.h> ++#include <linux/regulator/of_regulator.h> ++#include <linux/regmap.h> ++ ++/* Register definitions */ ++#define REG_MASK 0x00 ++#define REG_CONFIG 0x01 ++#define REG_ID 0x02 ++#define REG_STAT1 0x03 ++/* 16 bit register: 0x04 + 0x05 */ ++#define REG_STAT2 0x04 ++/* ADC1..ADC4 */ ++#define REG_ADC(n) (0x06 + ((n) & 0x03)) ++ ++#define REG_CONFIG_ADC_MUX_CUR 0x00 ++#define REG_CONFIG_ADC_MUX_VOUT 0x40 ++#define REG_CONFIG_ADC_MUX_MISC 0x80 ++#define REG_CONFIG_ADC_MUX_MASK 0xc0 ++ ++struct max2008x_regulator_data { ++ int id; ++ const char *name; ++ struct regulator_init_data *init_data; ++ struct device_node *of_node; ++}; ++ ++struct max2008x_data { ++ struct regmap *regmap; ++ struct max2008x_regulator_data *regulators; ++ struct iio_dev *iio_dev; ++ ++ unsigned char id; ++ unsigned char rev; ++ unsigned char num_regulators; ++ ++ unsigned char adc_mux; ++}; ++ ++static int max2008x_set_adc_mux(struct max2008x_data *max, int mux) ++{ ++ int ret; ++ unsigned int reg; ++ ++ mux = mux & REG_CONFIG_ADC_MUX_MASK; ++ if (mux > REG_CONFIG_ADC_MUX_MISC) ++ return -EINVAL; ++ ++ /* do we need this? or we can relay on regmap? */ ++ if (mux == max->adc_mux) ++ return 0; ++ ++ ret = regmap_write_bits(max->regmap, REG_CONFIG, ++ REG_CONFIG_ADC_MUX_MASK, mux); ++ if (ret) ++ return ret; ++ ++ max->adc_mux = mux; ++ ++ /* Read ADC1 register to clear ACC bit in STAT1 register */ ++ ret = regmap_read(max->regmap, REG_ADC(0), ®); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int max2008x_read_adc(struct max2008x_data *max, int channel, int *value) ++{ ++ int ret; ++ int timeout = 100; ++ unsigned int reg; ++ ++ /* shift 3:2 bits to 7:6 */ ++ ret = max2008x_set_adc_mux(max, channel << 4); ++ if (ret) ++ return ret; ++ ++ do { ++ ret = regmap_read(max->regmap, REG_STAT1, ®); ++ if (ret) ++ return ret; ++ } while ((!(reg & BIT(4))) && (--timeout)); ++ ++ if (timeout <= 0) ++ return -ETIMEDOUT; ++ ++ ret = regmap_read(max->regmap, REG_ADC(channel & 0x03), ®); ++ if (ret) ++ return ret; ++ *value = reg; ++ ++ return 0; ++} ++ ++static int max2008x_get_voltage(struct regulator_dev *dev) ++{ ++ int ret; ++ int value = 0; ++ struct max2008x_data *max = rdev_get_drvdata(dev); ++ ++ /* voltage channels starts from 4 */ ++ ret = max2008x_read_adc(max, dev->desc->id + 4, &value); ++ if (ret) ++ return ret; ++ ++ /* in 70mV units */ ++ return (value * 70000); ++} ++ ++static struct regulator_ops max2008x_ops = { ++ .enable = regulator_enable_regmap, ++ .disable = regulator_disable_regmap, ++ .is_enabled = regulator_is_enabled_regmap, ++ .get_voltage = max2008x_get_voltage, ++}; ++ ++static struct of_regulator_match max2008x_matches[] = { ++ [0] = { .name = "SW0"}, ++ [1] = { .name = "SW1"}, ++ [2] = { .name = "SW2"}, ++ [3] = { .name = "SW3"}, ++}; ++ ++static int of_get_max2008x_pdata(struct device *dev, ++ struct max2008x_data *pdata) ++{ ++ int matched, i; ++ struct device_node *np; ++ struct max2008x_regulator_data *regulator; ++ ++ np = of_get_child_by_name(dev->of_node, "regulators"); ++ if (!np) { ++ dev_err(dev, "missing 'regulators' subnode in DT\n"); ++ return -EINVAL; ++ } ++ ++ matched = of_regulator_match(dev, np, max2008x_matches, ++ pdata->num_regulators); ++ of_node_put(np); ++ if (matched <= 0) ++ return matched; ++ ++ pdata->regulators = devm_kzalloc(dev, ++ sizeof(struct max2008x_regulator_data) * ++ pdata->num_regulators, GFP_KERNEL); ++ if (!pdata->regulators) ++ return -ENOMEM; ++ ++ regulator = pdata->regulators; ++ ++ for (i = 0; i < pdata->num_regulators; i++) { ++ regulator->id = i; ++ regulator->name = max2008x_matches[i].name; ++ regulator->init_data = max2008x_matches[i].init_data; ++ regulator->of_node = max2008x_matches[i].of_node; ++ regulator++; ++ } ++ ++ return 0; ++} ++ ++static struct max2008x_regulator_data *max2008x_get_regulator_data( ++ int id, struct max2008x_data *data) ++{ ++ int i; ++ ++ if (!data) ++ return NULL; ++ ++ for (i = 0; i < data->num_regulators; i++) { ++ if (data->regulators[i].id == id) ++ return &data->regulators[i]; ++ } ++ ++ return NULL; ++} ++ ++#define MAX2008X_REG(_name, _id, _supply) \ ++ { \ ++ .name = _name, \ ++ .supply_name = _supply, \ ++ .id = _id, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .ops = &max2008x_ops, \ ++ .enable_reg = REG_CONFIG, \ ++ .enable_mask = BIT(_id), \ ++ .owner = THIS_MODULE, \ ++ } ++ ++static const struct regulator_desc max2008x_regulators[] = { ++ MAX2008X_REG("SW0", 0, "out0"), ++ MAX2008X_REG("SW1", 1, "out1"), ++ MAX2008X_REG("SW2", 2, "out2"), ++ MAX2008X_REG("SW3", 3, "out3"), ++}; ++ ++static const char *max2008x_devnames[] = { ++ "max20089", ++ "max20088", ++ "max20087", ++ "max20086" ++}; ++ ++static int max2008x_adc_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ int *val, int *val2, long mask) ++{ ++ int ret; ++ struct max2008x_data *max = iio_device_get_drvdata(indio_dev); ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_RAW: ++ ret = iio_device_claim_direct_mode(indio_dev); ++ if (ret) ++ return ret; ++ ++ ret = max2008x_read_adc(max, chan->channel, val); ++ iio_device_release_direct_mode(indio_dev); ++ ++ if (ret) ++ return ret; ++ ++ return IIO_VAL_INT; ++ case IIO_CHAN_INFO_SCALE: ++ if (chan->type == IIO_VOLTAGE) { ++ /* Vout1..Vout4 and Vin */ ++ if (chan->channel <= 8) ++ *val = 70; ++ /* Vdd */ ++ else if (chan->channel == 9) ++ *val = 25; ++ /* Viset */ ++ else ++ *val = 5; ++ } else if (chan->type == IIO_CURRENT) { ++ *val = 3; ++ *val2 = 0; ++ } ++ ++ return IIO_VAL_INT; ++ } ++ ++ return 0; ++} ++ ++#define MAX2008X_ADC_C_CHAN(_chan, _addr, _name) { \ ++ .type = IIO_CURRENT, \ ++ .indexed = 1, \ ++ .address = _addr, \ ++ .channel = _chan, \ ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ ++ BIT(IIO_CHAN_INFO_SCALE), \ ++ .scan_index = _addr, \ ++ .scan_type = { \ ++ .sign = 'u', \ ++ .realbits = 8, \ ++ .storagebits = 8, \ ++ .endianness = IIO_CPU, \ ++ }, \ ++ .datasheet_name = _name, \ ++} ++ ++#define MAX2008X_ADC_V_CHAN(_chan, _addr, _name) { \ ++ .type = IIO_VOLTAGE, \ ++ .indexed = 1, \ ++ .address = _addr, \ ++ .channel = _chan, \ ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ ++ BIT(IIO_CHAN_INFO_SCALE), \ ++ .scan_index = _addr, \ ++ .scan_type = { \ ++ .sign = 'u', \ ++ .realbits = 8, \ ++ .storagebits = 8, \ ++ .endianness = IIO_CPU, \ ++ }, \ ++ .datasheet_name = _name, \ ++} ++ ++static const struct iio_chan_spec max2008x_adc_channels[] = ++{ ++ MAX2008X_ADC_C_CHAN( 0, 0, "out0"), ++ MAX2008X_ADC_C_CHAN( 1, 1, "out1"), ++ MAX2008X_ADC_C_CHAN( 2, 2, "out2"), ++ MAX2008X_ADC_C_CHAN( 3, 3, "out3"), ++ MAX2008X_ADC_V_CHAN( 4, 4, "out0"), ++ MAX2008X_ADC_V_CHAN( 5, 5, "out1"), ++ MAX2008X_ADC_V_CHAN( 6, 6, "out2"), ++ MAX2008X_ADC_V_CHAN( 7, 7, "out3"), ++ MAX2008X_ADC_V_CHAN( 8, 8, "Vin"), ++ MAX2008X_ADC_V_CHAN( 9, 9, "Vdd"), ++ MAX2008X_ADC_V_CHAN(10, 10, "Viset"), ++}; ++ ++static const struct iio_info max2008x_adc_info = { ++ .driver_module = THIS_MODULE, ++ .read_raw = max2008x_adc_read_raw, ++}; ++ ++#if defined(CONFIG_OF) ++static const struct of_device_id max2008x_of_match[] = { ++ { .compatible = "maxim,max2008x" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, max2008x_of_match); ++#endif ++ ++ ++static const struct regmap_range max2008x_reg_ranges[] = { ++ regmap_reg_range(REG_MASK, REG_ADC(3)), ++}; ++ ++static const struct regmap_range max2008x_reg_ro_ranges[] = { ++ regmap_reg_range(REG_ID, REG_ADC(3)), ++}; ++ ++static const struct regmap_range max2008x_reg_volatile_ranges[] = { ++ regmap_reg_range(REG_STAT1, REG_ADC(3)), ++}; ++ ++static const struct regmap_access_table max2008x_write_ranges_table = { ++ .yes_ranges = max2008x_reg_ranges, ++ .n_yes_ranges = ARRAY_SIZE(max2008x_reg_ranges), ++ .no_ranges = max2008x_reg_ro_ranges, ++ .n_no_ranges = ARRAY_SIZE(max2008x_reg_ro_ranges), ++}; ++ ++static const struct regmap_access_table max2008x_read_ranges_table = { ++ .yes_ranges = max2008x_reg_ranges, ++ .n_yes_ranges = ARRAY_SIZE(max2008x_reg_ranges), ++}; ++ ++static const struct regmap_access_table max2008x_volatile_ranges_table = { ++ .yes_ranges = max2008x_reg_volatile_ranges, ++ .n_yes_ranges = ARRAY_SIZE(max2008x_reg_volatile_ranges), ++}; ++ ++static const struct regmap_config max2008x_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = REG_ADC(3), ++ .wr_table = &max2008x_write_ranges_table, ++ .rd_table = &max2008x_read_ranges_table, ++ .volatile_table = &max2008x_volatile_ranges_table, ++}; ++ ++static int max2008x_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ struct device_node *np = dev->of_node; ++ struct max2008x_data *max; ++ struct gpio_desc *enable_gpio; ++ unsigned int reg; ++ int i, ret; ++ ++ max = devm_kzalloc(&client->dev, sizeof(struct max2008x_data), ++ GFP_KERNEL); ++ if (max == NULL) ++ return -ENOMEM; ++ ++ enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW); ++ ++ /* regmap */ ++ max->regmap = devm_regmap_init_i2c(client, &max2008x_regmap_config); ++ if (IS_ERR(max->regmap)) { ++ ret = PTR_ERR(max->regmap); ++ dev_err(&client->dev, ++ "regmap allocation failed with err %d\n", ret); ++ return ret; ++ } ++ i2c_set_clientdata(client, max); ++ ++ ret = regmap_read(max->regmap, REG_ID, ®); ++ if (ret) ++ return ret; ++ ++ max->id = (reg >> 4) & 0x03; ++ max->rev = reg & 0x0f; ++ /* MAX20086 and MAX20087 have 4 outputs */ ++ max->num_regulators = ((max->id == 0x2) || (max->id == 0x3)) ? 4 : 2; ++ ++ /* Disable all */ ++ ret = regmap_write_bits(max->regmap, REG_CONFIG, BIT(max->num_regulators) - 1, 0x00); ++ if (ret) ++ return ret; ++ ++ /* to update mux on first access */ ++ max->adc_mux = 0xff; ++ ++ /* set autoconvertion mode for ADC */ ++ ret = regmap_write_bits(max->regmap, REG_CONFIG, BIT(5), BIT(5)); ++ if (ret) ++ return ret; ++ ++ dev_info(&client->dev, "%s rev %d found (%d channels)\n", ++ max2008x_devnames[max->id], max->rev, max->num_regulators); ++ ++ if (np) { ++ ret = of_get_max2008x_pdata(&client->dev, max); ++ if (ret) { ++ dev_err(&client->dev, ++ "dt parse error %d\n", ret); ++ return ret; ++ } ++ } ++ ++ /* Finally register devices */ ++ for (i = 0; i < max->num_regulators; i++) { ++ const struct regulator_desc *desc = &max2008x_regulators[i]; ++ struct regulator_config config = { }; ++ struct max2008x_regulator_data *rdata; ++ struct regulator_dev *rdev; ++ ++ config.dev = dev; ++ config.driver_data = max; ++ config.regmap = max->regmap; ++ ++ rdata = max2008x_get_regulator_data(desc->id, max); ++ if (rdata) { ++ config.init_data = rdata->init_data; ++ config.of_node = rdata->of_node; ++ } ++ ++ rdev = devm_regulator_register(dev, desc, &config); ++ if (IS_ERR(rdev)) { ++ dev_err(dev, "failed to register %s\n", desc->name); ++ return PTR_ERR(rdev); ++ } ++ } ++ ++ /* IIO device */ ++ max->iio_dev = devm_iio_device_alloc(dev, 0); ++ if (!max->iio_dev) ++ return -ENOMEM; ++ ++ max->iio_dev->info = &max2008x_adc_info; ++ max->iio_dev->dev.parent = dev; ++ max->iio_dev->dev.of_node = dev->of_node; ++ max->iio_dev->name = "max2008x-adc"; ++ max->iio_dev->modes = INDIO_DIRECT_MODE; ++ ++ max->iio_dev->channels = max2008x_adc_channels; ++ /* only ASIL can measure voltages */ ++ if ((max->id == 0x00) || (max->id == 0x02)) ++ max->iio_dev->num_channels = ARRAY_SIZE(max2008x_adc_channels); ++ else ++ max->iio_dev->num_channels = 4; ++ ++ iio_device_set_drvdata(max->iio_dev, max); ++ ++ ret = iio_device_register(max->iio_dev); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed to register IIO device: %d\n", ret); ++ return ret; ++ } ++ ++ i2c_set_clientdata(client, max); ++ ++ if (!IS_ERR(enable_gpio)) ++ gpiod_set_value_cansleep(enable_gpio, 1); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id max2008x_id[] = { ++ { "maxim,max2008x" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max2008x_id); ++ ++static struct i2c_driver max2008x_driver = { ++ .driver = { ++ .name = "max2008x", ++ .of_match_table = of_match_ptr(max2008x_of_match), ++ }, ++ .probe = max2008x_probe, ++ .id_table = max2008x_id, ++}; ++ ++static int __init max2008x_init(void) ++{ ++ return i2c_add_driver(&max2008x_driver); ++} ++subsys_initcall(max2008x_init); ++ ++static void __exit max2008x_exit(void) ++{ ++ i2c_del_driver(&max2008x_driver); ++} ++module_exit(max2008x_exit); ++ ++MODULE_AUTHOR("Andrey Gusakov <andrey.gusakov@cogentembedded.com>"); ++MODULE_DESCRIPTION("max2008x Dual/Quad Camera Power Protector"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:max2008x"); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0500-arm64-dts-renesas-add-V3H-GMSL2-Videoboxes.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0500-arm64-dts-renesas-add-V3H-GMSL2-Videoboxes.patch new file mode 100644 index 00000000..4e58b2d8 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0500-arm64-dts-renesas-add-V3H-GMSL2-Videoboxes.patch @@ -0,0 +1,1445 @@ +From bcba64742b957d8a6f7303abf05c4e586522c89b Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 18:53:42 +0300 +Subject: [PATCH] arm64: dts: renesas: add V3H GMSL2 Videoboxes + +This adds Quad and Dual GMSL Videoboxes on V3H + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/Makefile | 2 + + .../dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts | 717 +++++++++++++++++++++ + .../boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts | 683 ++++++++++++++++++++ + 3 files changed, 1402 insertions(+) + create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts + create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts + +diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile +index 89da50c..a1373ba 100644 +--- a/arch/arm64/boot/dts/renesas/Makefile ++++ b/arch/arm64/boot/dts/renesas/Makefile +@@ -43,6 +43,8 @@ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v2.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-8ch.dtb r8a77980-v3hsk-vb-4ch.dtb ++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-2x2.dtb ++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-4.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl-8ch.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-4ch-hdmi.dtb r8a77980-v3hsk-vb-8ch-hdmi.dtb + +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts +new file mode 100644 +index 0000000..155b73f +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts +@@ -0,0 +1,717 @@ ++/* ++ * Device Tree Source for the V3HSK Videobox Mini board on r8a7798 ++ * ++ * Copyright (C) 2018 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "r8a77980-v3hsk.dts" ++#include <dt-bindings/gpio/gpio.h> ++/* FDPLink output */ ++//#include "vb-fdplink-output.dtsi" ++ ++#define COMPATIBLE_CAMERAS \ ++"onsemi,ar0140", \ ++"onsemi,ar0143", \ ++"onsemi,ar0147", \ ++"onsemi,ar0231", \ ++"onsemi,ar0233", \ ++"onsemi,ap0101", \ ++"onsemi,ap0201", \ ++"ovti,ov10635", \ ++"ovti,ov10640", \ ++"ovti,ov2311", \ ++"ovti,ov2775", \ ++"ovti,ov490", \ ++"ovti,ov495", \ ++"ovti,ox01d10", \ ++"ovti,ox03a", \ ++"sony,imx390", \ ++"sony,isx016", \ ++"sony,isx019", \ ++"dummy,camera" ++ ++/ { ++ model = "Renesas V3HSK 2x2ch GMSL2 Videobox board based on r8a7798"; ++ ++ aliases { ++ serial1 = &scif3; ++ ethernet1 = &avb; ++ }; ++ ++ cs2300_ref_clk: cs2300_ref_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <25000000>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led0 { ++ label = "board:status"; ++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "none"; ++ }; ++ }; ++ ++ mpcie_1v8: regulator2 { ++ compatible = "regulator-fixed"; ++ regulator-name = "mPCIe 1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ mpcie_3v3: regulator3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "mPCIe 3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ common_3v3: regulator4 { ++ compatible = "regulator-fixed"; ++ regulator-name = "main 3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ regulator_poc_0: regulator-poc-0 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "POC 0"; ++ regulator-min-microvolt = <9000000>; ++ regulator-max-microvolt = <9000000>; ++ startup-delay-us = <50>; ++ ++ gpio = <&gpio_exp_ch0 10 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ regulator_poc_1: regulator-poc-1 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "POC 1"; ++ regulator-min-microvolt = <9000000>; ++ regulator-max-microvolt = <9000000>; ++ startup-delay-us = <50>; ++ ++ gpio = <&gpio_exp_ch0 11 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ regulator_poc_2: regulator-poc-2 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "POC 2"; ++ regulator-min-microvolt = <9000000>; ++ regulator-max-microvolt = <9000000>; ++ startup-delay-us = <50>; ++ ++ gpio = <&gpio_exp_ch0 14 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ regulator_poc_3: regulator-poc-3 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "POC 3"; ++ regulator-min-microvolt = <9000000>; ++ regulator-max-microvolt = <9000000>; ++ startup-delay-us = <50>; ++ ++ gpio = <&gpio_exp_ch0 15 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++}; ++ ++&canfd { ++ pinctrl-0 = <&canfd0_pins &canfd1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ channel0 { ++ status = "okay"; ++ }; ++ ++ channel1 { ++ status = "okay"; ++ }; ++}; ++ ++&avb { ++ pinctrl-0 = <&avb_pins>; ++ pinctrl-names = "default"; ++ renesas,no-ether-link; ++ phy-handle = <&avb_phy0>; ++ status = "okay"; ++ phy-int-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>; ++ ++ avb_phy0: eavb-phy@0 { ++ rxc-skew-ps = <1500>; ++ rxdv-skew-ps = <420>; /* default */ ++ rxd0-skew-ps = <420>; /* default */ ++ rxd1-skew-ps = <420>; /* default */ ++ rxd2-skew-ps = <420>; /* default */ ++ rxd3-skew-ps = <420>; /* default */ ++ txc-skew-ps = <900>; /* default */ ++ txen-skew-ps = <420>; /* default */ ++ txd0-skew-ps = <420>; /* default */ ++ txd1-skew-ps = <420>; /* default */ ++ txd2-skew-ps = <420>; /* default */ ++ txd3-skew-ps = <420>; /* default */ ++ reg = <3>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>; ++ max-speed = <1000>; ++ }; ++}; ++ ++&csi40 { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi40_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <1200>; ++ }; ++ }; ++}; ++ ++&csi41 { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi41_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <1200>; ++ }; ++ }; ++}; ++ ++&i2c1 { ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ clock-frequency = <400000>; ++ ++ i2cswitch1: i2c-switch@74 { ++ compatible = "nxp,pca9548"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x74>; ++ reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; ++ ++ /* CCTRL_SDA and CCTRL_SCL */ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ gpio_exp_ch0: gpio_ch0@76 { ++ compatible = "nxp,pca9539"; ++ reg = <0x76>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ cmr_pwr_en { ++ gpio-hog; ++ gpios = <3 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CmrPEn"; ++ }; ++ }; ++ ++ /* CS2300 node @0x4e */ ++ cs2300: clk_multiplier@4e { ++ #clock-cells = <0>; ++ compatible = "cirrus,cs2300-cp"; ++ reg = <0x4e>; ++ clocks = <&cs2300_ref_clk>; ++ clock-names = "clk_in"; ++ ++ assigned-clocks = <&cs2300>; ++ assigned-clock-rates = <25000000>; ++ }; ++ ++ dac_vcam: dac_vcam@60 { ++ compatible = "microchip,mcp4725"; ++ reg = <0x60>; ++ vdd-supply = <&common_3v3>; ++ }; ++ }; ++ ++ /* DS0_SDA and DS0_SCL */ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ max9296@48 { ++ compatible = "maxim,max9296"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x48>; ++ clocks = <&cs2300>; ++ clock-names = "ref_clk"; ++ shutdown-gpios = <&gpio_exp_ch0 1 GPIO_ACTIVE_LOW>; ++ ++ maxim,link-mipi-map = <1 1>; ++ ++ poc0-supply = <®ulator_poc_0>; ++ poc1-supply = <®ulator_poc_1>; ++ ++ port@0 { ++ max9296_des0ep0: endpoint@0 { ++ ser-addr = <0x0c>; ++ remote-endpoint = <&camera_in0>; ++ }; ++ max9296_des0ep1: endpoint@1 { ++ ser-addr = <0x0d>; ++ remote-endpoint = <&camera_in1>; ++ }; ++ }; ++ ++ port@1 { ++ max9296_des0mipi1: endpoint { ++ csi-rate = <1200>; ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ camera@60 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x60 0x0c>; ++ ++ port@0 { ++ camera_in0: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin0ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max9296_des0ep0: endpoint@1 { ++ remote-endpoint = <&max9296_des0ep0>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ camera@61 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x61 0x0d>; ++ ++ port@0 { ++ camera_in1: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin1ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max9296_des0ep1: endpoint@1 { ++ remote-endpoint = <&max9296_des0ep1>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ /* DS1_SDA and DS1_SCL */ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ max9296@48 { ++ compatible = "maxim,max9296"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x48>; ++ clocks = <&cs2300>; ++ clock-names = "ref_clk"; ++ shutdown-gpios = <&gpio_exp_ch0 0 GPIO_ACTIVE_LOW>; ++ ++ maxim,link-mipi-map = <1 1>; ++ ++ poc0-supply = <®ulator_poc_2>; ++ poc1-supply = <®ulator_poc_3>; ++ ++ port@0 { ++ max9296_des1ep0: endpoint@0 { ++ ser-addr = <0x0c>; ++ remote-endpoint = <&camera_in2>; ++ }; ++ max9296_des1ep1: endpoint@1 { ++ ser-addr = <0x51>; ++ remote-endpoint = <&camera_in3>; ++ }; ++ }; ++ ++ port@1 { ++ max9296_des1mipi1: endpoint { ++ csi-rate = <1200>; ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ camera@60 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x60 0x0c>; ++ ++ port@0 { ++ camera_in2: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin4ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max9296_des1ep0: endpoint@1 { ++ remote-endpoint = <&max9296_des1ep0>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ camera@61 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x61 0x0c>; ++ ++ port@0 { ++ camera_in3: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin5ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max9296_des1ep1: endpoint@1 { ++ remote-endpoint = <&max9296_des1ep1>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ /* Disp_SDA and Disp_SCL */ ++ i2c@5 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <5>; ++ ++ /* fan node - lm96063 */ ++ fan_ctrl: lm96063@4c { ++ compatible = "lm96163"; ++ reg = <0x4c>; ++ }; ++ }; ++ ++ /* ESDA and ESCL */ ++ i2c@7 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <7>; ++ ++ /* ext connector nodes here */ ++ }; ++ }; ++}; ++ ++&gpio0 { ++ fpdl_shdn { ++ gpio-hog; ++ gpios = <1 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "FPDL_SHDN"; ++ }; ++ ++ cam_pwr_en { ++ gpio-hog; ++ gpios = <11 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "VIPWR_En"; ++ }; ++ ++ wake_pin_8 { ++ gpio-hog; ++ gpios = <0 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "WAKE INPUT PIN 8"; ++ }; ++}; ++ ++&gpio1 { ++ md_buf_en { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CPLD_If_En"; ++ }; ++}; ++ ++&gpio2 { ++ m2_rst { ++ gpio-hog; ++ gpios = <11 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "M.2 RST#"; ++ }; ++ ++ cctrl_rstn { ++ gpio-hog; ++ gpios = <16 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CCTRL_RSTn"; ++ }; ++ ++ can0_stby { ++ gpio-hog; ++ gpios = <27 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN0STBY"; ++ }; ++ ++ can1_load { ++ gpio-hog; ++ gpios = <29 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN1Loff"; ++ }; ++ ++ can1_stby { ++ gpio-hog; ++ gpios = <22 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN1STBY"; ++ }; ++ ++ wake_pin_7 { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "WAKE INPUT PIN 7"; ++ }; ++ ++ vi1_gpioext_rst { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "VIP1_RST"; ++ }; ++}; ++ ++&gpio3 { ++ vi0_gpioext_rst { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "VIP0_RST"; ++ }; ++}; ++ ++&pcie_bus_clk { ++ clock-frequency = <100000000>; ++ status = "okay"; ++}; ++ ++&pciec { ++ pcie3v3-supply = <&mpcie_3v3>; ++ pcie1v8-supply = <&mpcie_1v8>; ++ status = "okay"; ++}; ++ ++&pcie_phy { ++ status = "okay"; ++}; ++ ++&pfc { ++ canfd0_pins: canfd0 { ++ groups = "canfd0_data_a"; ++ function = "canfd0"; ++ }; ++ ++ canfd1_pins: canfd1 { ++ groups = "canfd1_data"; ++ function = "canfd1"; ++ }; ++ ++ avb_pins: avb { ++ groups = "avb_mdio", "avb_rgmii"; ++ function = "avb"; ++ }; ++ ++ i2c1_pins: i2c1 { ++ groups = "i2c1"; ++ function = "i2c1"; ++ }; ++ ++ scif3_pins: scif3 { ++ groups = "scif3_data"; ++ function = "scif3"; ++ }; ++}; ++ ++&scif3 { ++ pinctrl-0 = <&scif3_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&tpu { ++ status = "disabled"; ++}; ++ ++&vin0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin0ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in0>; ++ }; ++ }; ++ port@1 { ++ csi0ep0: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin0_max9296_des0ep0: endpoint@1 { ++ remote-endpoint = <&max9296_des0ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin1 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin1ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <1>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in1>; ++ }; ++ }; ++ port@1 { ++ csi0ep1: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin1_max9296_des0ep1: endpoint@1 { ++ remote-endpoint = <&max9296_des0ep1>; ++ }; ++ }; ++ }; ++}; ++ ++&vin4 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin4ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in2>; ++ }; ++ }; ++ port@1 { ++ csi1ep0: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin4_max9296_des1ep0: endpoint@1 { ++ remote-endpoint = <&max9296_des1ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin5 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin5ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <1>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in3>; ++ }; ++ }; ++ port@1 { ++ csi1ep1: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin5_max9296_des1ep1: endpoint@1 { ++ remote-endpoint = <&max9296_des1ep1>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts +new file mode 100644 +index 0000000..310061f +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts +@@ -0,0 +1,683 @@ ++/* ++ * Device Tree Source for the V3HSK GMSL2 Quad Videobox Mini board on r8a7798 ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "r8a77980-v3hsk.dts" ++#include <dt-bindings/gpio/gpio.h> ++/* FDPLink output */ ++//#include "vb-fdplink-output.dtsi" ++ ++#define COMPATIBLE_CAMERAS \ ++"onsemi,ar0140", \ ++"onsemi,ar0143", \ ++"onsemi,ar0147", \ ++"onsemi,ar0231", \ ++"onsemi,ar0233", \ ++"onsemi,ap0101", \ ++"onsemi,ap0201", \ ++"ovti,ov10635", \ ++"ovti,ov10640", \ ++"ovti,ov2311", \ ++"ovti,ov2775", \ ++"ovti,ov490", \ ++"ovti,ov495", \ ++"ovti,ox01d10", \ ++"ovti,ox03a", \ ++"sony,imx390", \ ++"sony,isx016", \ ++"sony,isx019", \ ++"dummy,camera" ++ ++/ { ++ model = "Renesas V3HSK 4ch GMSL2 Videobox board based on r8a77980"; ++ ++ aliases { ++ serial1 = &scif3; ++ ethernet1 = &avb; ++ }; ++ ++ cs2300_ref_clk: cs2300_ref_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <25000000>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led0 { ++ label = "board:status"; ++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "none"; ++ }; ++ }; ++ ++ mpcie_1v8: regulator2 { ++ compatible = "regulator-fixed"; ++ regulator-name = "mPCIe 1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ mpcie_3v3: regulator3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "mPCIe 3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ common_3v3: regulator4 { ++ compatible = "regulator-fixed"; ++ regulator-name = "main 3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ iio_hwmon: hwmon@1 { ++ compatible = "iio-hwmon"; ++ io-channels = ++ /* current */ ++ <&max2008x 0>, ++ <&max2008x 2>, ++ /* voltage */ ++ <&max2008x 4>, ++ <&max2008x 6>, ++ /* misc voltages */ ++ <&max2008x 8>, ++ <&max2008x 9>; ++ io-channel-names = ++ "camera-0-Iout", ++ "camera-1-Iout", ++ "camera-0-Vout", ++ "camera-1-Vout", ++ "cameras-Vregulator", ++ "cameras-3v3"; ++ }; ++}; ++ ++&canfd { ++ pinctrl-0 = <&canfd0_pins &canfd1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ channel0 { ++ status = "okay"; ++ }; ++ ++ channel1 { ++ status = "okay"; ++ }; ++}; ++ ++&avb { ++ pinctrl-0 = <&avb_pins>; ++ pinctrl-names = "default"; ++ renesas,no-ether-link; ++ phy-handle = <&avb_phy0>; ++ status = "okay"; ++ phy-int-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>; ++ ++ avb_phy0: eavb-phy@0 { ++ rxc-skew-ps = <1500>; ++ rxdv-skew-ps = <420>; /* default */ ++ rxd0-skew-ps = <420>; /* default */ ++ rxd1-skew-ps = <420>; /* default */ ++ rxd2-skew-ps = <420>; /* default */ ++ rxd3-skew-ps = <420>; /* default */ ++ txc-skew-ps = <900>; /* default */ ++ txen-skew-ps = <420>; /* default */ ++ txd0-skew-ps = <420>; /* default */ ++ txd1-skew-ps = <420>; /* default */ ++ txd2-skew-ps = <420>; /* default */ ++ txd3-skew-ps = <420>; /* default */ ++ reg = <3>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>; ++ max-speed = <1000>; ++ }; ++}; ++ ++&csi40 { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi40_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <1200>; ++ }; ++ }; ++}; ++ ++&i2c1 { ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ clock-frequency = <400000>; ++ ++ i2cswitch1: i2c-switch@74 { ++ compatible = "nxp,pca9548"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x74>; ++ reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; ++ ++ /* CCTRL_SDA and CCTRL_SCL */ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ gpio_exp_ch0: gpio_ch0@76 { ++ compatible = "nxp,pca9539"; ++ reg = <0x76>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ cmr_pwr_en { ++ gpio-hog; ++ gpios = <3 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CmrPEn"; ++ }; ++ }; ++ ++ cs2300: clk_multiplier@4e { ++ #clock-cells = <0>; ++ compatible = "cirrus,cs2300-cp"; ++ reg = <0x4e>; ++ clocks = <&cs2300_ref_clk>; ++ clock-names = "clk_in"; ++ ++ assigned-clocks = <&cs2300>; ++ assigned-clock-rates = <25000000>; ++ }; ++ ++ dac_vcam: dac_vcam@60 { ++ compatible = "microchip,mcp4725"; ++ reg = <0x60>; ++ vdd-supply = <&common_3v3>; ++ }; ++ ++ max2008x: vcam_switch@28 { ++ compatible = "maxim,max2008x"; ++ reg = <0x28>; ++ #io-channel-cells = <1>; ++ enable-gpios = <&gpio_exp_ch0 5 GPIO_ACTIVE_HIGH>; ++ ++ regulators { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ vdd_cam0: SW0 { ++ reg = <0>; ++ regulator-name = "Camera-0"; ++ }; ++ vdd_cam1: SW1 { ++ reg = <1>; ++ regulator-name = "Camera-1"; ++ }; ++ vdd_cam2: SW2 { ++ reg = <2>; ++ regulator-name = "Camera-2"; ++ }; ++ vdd_cam3: SW3 { ++ reg = <3>; ++ regulator-name = "Camera-3"; ++ }; ++ }; ++ }; ++ }; ++ ++ /* DS0_SDA and DS0_SCL */ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ max96712@29 { ++ compatible = "maxim,max96712"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x29>; ++ clocks = <&cs2300>; ++ clock-names = "ref_clk"; ++ shutdown-gpios = <&gpio_exp_ch0 1 GPIO_ACTIVE_LOW>; ++ ++ maxim,links-mipi-map = <2 2 2 2>; ++ ++ poc0-supply = <&vdd_cam3>; ++ poc1-supply = <&vdd_cam1>; ++ poc2-supply = <&vdd_cam0>; ++ poc3-supply = <&vdd_cam2>; ++ ++ port@0 { ++ max96712_des0ep0: endpoint@0 { ++ ser-addr = <0x0c>; ++ remote-endpoint = <&camera_in0>; ++ }; ++ max96712_des0ep1: endpoint@1 { ++ ser-addr = <0x0d>; ++ remote-endpoint = <&camera_in1>; ++ }; ++ max96712_des0ep2: endpoint@2 { ++ ser-addr = <0x0e>; ++ remote-endpoint = <&camera_in2>; ++ }; ++ max96712_des0ep3: endpoint@3 { ++ ser-addr = <0x0f>; ++ remote-endpoint = <&camera_in3>; ++ }; ++ }; ++ ++ port@1 { ++ max96712_mipi2: endpoint { ++ csi-rate = <1200>; ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ camera@60 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x60 0x0c>; ++ ++ port@0 { ++ camera_in0: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin0ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep0: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep0>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ camera@61 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x61 0x0d>; ++ ++ port@0 { ++ camera_in1: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin1ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep1: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep1>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ camera@62 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x62 0x0e>; ++ ++ port@0 { ++ camera_in2: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin2ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep2: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep2>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ camera@63 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x63 0x0f>; ++ ++ port@0 { ++ camera_in3: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin3ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep3: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep3>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ /* CTL0_SDA and CTL0_SCL */ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ }; ++ ++ /* Disp_SDA and Disp_SCL */ ++ i2c@5 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <5>; ++ ++ /* fan node - lm96063 */ ++ fan_ctrl: lm96063@4c { ++ compatible = "lm96163"; ++ reg = <0x4c>; ++ }; ++ }; ++ ++ /* ESDA and ESCL */ ++ i2c@7 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <7>; ++ ++ rtc: mcp79411@6f { ++ compatible = "microchip,mcp7941x"; ++ reg = <0x6f>; ++ }; ++ }; ++ }; ++}; ++ ++&gpio0 { ++ fpdl_shdn { ++ gpio-hog; ++ gpios = <1 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "FPDL_SHDN"; ++ }; ++ ++ cam_pwr_en { ++ gpio-hog; ++ gpios = <11 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "VIPWR_En"; ++ }; ++ ++ wake_pin_8 { ++ gpio-hog; ++ gpios = <0 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "WAKE INPUT PIN 8"; ++ }; ++}; ++ ++&gpio1 { ++ md_buf_en { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CPLD_If_En"; ++ }; ++}; ++ ++&gpio2 { ++ m2_rst { ++ gpio-hog; ++ gpios = <11 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "M.2 RST#"; ++ }; ++ ++ cctrl_rstn { ++ gpio-hog; ++ gpios = <16 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CCTRL_RSTn"; ++ }; ++ ++ can0_stby { ++ gpio-hog; ++ gpios = <27 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN0STBY"; ++ }; ++ ++ can1_load { ++ gpio-hog; ++ gpios = <29 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN1Loff"; ++ }; ++ ++ can1_stby { ++ gpio-hog; ++ gpios = <22 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN1STBY"; ++ }; ++ ++ wake_pin_7 { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "WAKE INPUT PIN 7"; ++ }; ++ ++ vi1_gpioext_rst { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "VIP1_RST"; ++ }; ++}; ++ ++&gpio3 { ++ vi0_gpioext_rst { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "VIP0_RST"; ++ }; ++}; ++ ++&pcie_bus_clk { ++ clock-frequency = <100000000>; ++ status = "okay"; ++}; ++ ++&pciec { ++ pcie3v3-supply = <&mpcie_3v3>; ++ pcie1v8-supply = <&mpcie_1v8>; ++ status = "okay"; ++}; ++ ++&pcie_phy { ++ status = "okay"; ++}; ++ ++&pfc { ++ canfd0_pins: canfd0 { ++ groups = "canfd0_data_a"; ++ function = "canfd0"; ++ }; ++ ++ canfd1_pins: canfd1 { ++ groups = "canfd1_data"; ++ function = "canfd1"; ++ }; ++ ++ avb_pins: avb { ++ groups = "avb_mdio", "avb_rgmii"; ++ function = "avb"; ++ }; ++ ++ i2c1_pins: i2c1 { ++ groups = "i2c1"; ++ function = "i2c1"; ++ }; ++ ++ scif3_pins: scif3 { ++ groups = "scif3_data"; ++ function = "scif3"; ++ }; ++}; ++ ++&scif3 { ++ pinctrl-0 = <&scif3_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&tpu { ++ status = "disabled"; ++}; ++ ++&vin0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin0ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in0>; ++ }; ++ }; ++ port@1 { ++ csi1ep0: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin0_max96712_des0ep0: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin1 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin1ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <1>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in1>; ++ }; ++ }; ++ port@1 { ++ csi1ep1: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin1_max96712_des0ep1: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep1>; ++ }; ++ }; ++ }; ++}; ++ ++&vin2 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin2ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <2>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in2>; ++ }; ++ }; ++ port@1 { ++ csi1ep2: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin2_max96712_des0ep2: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep2>; ++ }; ++ }; ++ }; ++}; ++ ++&vin3 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin3ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <3>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in3>; ++ }; ++ }; ++ port@1 { ++ csi1ep3: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin3_max96712_des0ep3: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep3>; ++ }; ++ }; ++ }; ++}; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0501-media-i2c-ap0101-fix-fsin-on-AP0102.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0501-media-i2c-ap0101-fix-fsin-on-AP0102.patch new file mode 100644 index 00000000..1d6af948 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0501-media-i2c-ap0101-fix-fsin-on-AP0102.patch @@ -0,0 +1,52 @@ +From 7bb14f5fe5ab6c00c48dc879767b3def79bcef17 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 27 Apr 2020 18:55:09 +0300 +Subject: [PATCH] media: i2c: ap0101: fix fsin on AP0102 + +AP0101 and AP0102 hav different FSIN setup + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/ap0101_ar014x.c | 9 ++++++++- + drivers/media/i2c/soc_camera/ap0101_ar014x.h | 8 ++++++++ + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/ap0101_ar014x.c +index 8a2d2a6..55cff3f 100644 +--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.c ++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.c +@@ -477,7 +477,14 @@ static int ap0101_initialize(struct i2c_client *client) + priv->max_height = AP0101_MAX_HEIGHT; + #endif + /* Program wizard registers */ +- ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard)); ++ switch (pid) { ++ case AP0101_VERSION_REG: ++ ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard)); ++ break; ++ case AP0102_VERSION_REG: ++ ap0101_set_regs(client, ap0102_regs_wizard, ARRAY_SIZE(ap0102_regs_wizard)); ++ break; ++ } + /* Read OTP IDs */ + ap0101_otp_id_read(client); + +diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.h b/drivers/media/i2c/soc_camera/ap0101_ar014x.h +index 16599a1..d72ebfe 100644 +--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.h ++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.h +@@ -26,3 +26,11 @@ static const struct ap0101_reg ap0101_regs_wizard[] = { + {0x0040, 0x8100}, + {AP0101_DELAY, 100}, + }; ++ ++static const struct ap0101_reg ap0102_regs_wizard[] = { ++/* enable FSIN */ ++{0xc890, 0x0303}, ++{0xfc00, 0x2800}, ++{0x0040, 0x8100}, ++{AP0101_DELAY, 100}, ++}; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0502-media-i2c-max96712-add-MIPI-GMSL2-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0502-media-i2c-max96712-add-MIPI-GMSL2-support.patch new file mode 100644 index 00000000..6f1d59e0 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0502-media-i2c-max96712-add-MIPI-GMSL2-support.patch @@ -0,0 +1,189 @@ +From 73714bd64b9beb6af9a4e00b85a4d2e6d8933143 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 29 Apr 2020 01:27:08 +0300 +Subject: [PATCH 1/3] media: i2c: max96712: add MIPI GMSL2 support + +This adds MIPI stream from serializer + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/gmsl/max9295.h | 10 ++++ + drivers/media/i2c/soc_camera/gmsl/max96712.c | 75 ++++++++++++++++------------ + drivers/media/i2c/soc_camera/gmsl/max96712.h | 6 +-- + 3 files changed, 57 insertions(+), 34 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9295.h b/drivers/media/i2c/soc_camera/gmsl/max9295.h +index cf12d3c..864c441 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max9295.h ++++ b/drivers/media/i2c/soc_camera/gmsl/max9295.h +@@ -27,3 +27,13 @@ + #define MAX9295_VIDEO_TX_BASE(n) (0x100 + (0x8 * n)) + #define MAX9295_VIDEO_TX0(n) (MAX9295_VIDEO_TX_BASE(n) + 0) + #define MAX9295_VIDEO_TX1(n) (MAX9295_VIDEO_TX_BASE(n) + 1) ++ ++#define MAX9295_FRONTTOP_0 0x308 ++#define MAX9295_FRONTTOP_9 0x311 ++#define MAX9295_FRONTTOP_12 0x314 ++#define MAX9295_FRONTTOP_13 0x315 ++ ++#define MAX9295_MIPI_RX0 0x330 ++#define MAX9295_MIPI_RX1 0x331 ++#define MAX9295_MIPI_RX2 0x332 ++#define MAX9295_MIPI_RX3 0x333 +\ No newline at end of file +diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c +index af5e1d7..02ccc38 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max96712.c ++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c +@@ -94,7 +94,7 @@ static int gmsl = MODE_GMSL2; + module_param(gmsl, int, 0644); + MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)"); + +-static char *mbus = "dvp"; ++static char *mbus = mbus_default; + module_param(mbus, charp, 0644); + MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)"); + +@@ -161,7 +161,7 @@ static void max96712_reset_oneshot(struct max96712_priv *priv, int mask) + if (!(reg & mask)) + break; + +- msleep(1); ++ mdelay(1); + } + + if (reg & mask) +@@ -741,9 +741,12 @@ static int max96712_gmsl2_reverse_channel_setup(struct max96712_priv *priv, int + des_write(MAX96712_REG6, 0xf0 | BIT(link_n)); /* GMSL2 mode, enable GMSL link# */ + max96712_reset_oneshot(priv, BIT(link_n)); + +- /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */ +- while ((!max96712_gmsl2_get_link_lock(priv, link_n)) && (--timeout)) +- msleep(1); ++ /* wait the link to be established, indicated when status bit LOCKED goes high */ ++ for (; timeout > 0; timeout--) { ++ if (max96712_gmsl2_get_link_lock(priv, link_n)) ++ break; ++ mdelay(1); ++ } + + if (!timeout) { + ret = -ETIMEDOUT; +@@ -781,36 +784,42 @@ static int max96712_gmsl2_link_serializer_setup(struct max96712_priv *priv, int + struct max96712_link *link = priv->link[link_n]; + int i; + +- //ser_write(MAX9295_CTRL0, 0x31); /* link reset */ +- //msleep(100); +- ser_write(MAX9295_REG2, 0x03); /* disable all pipes */ +- + if (strcmp(priv->mbus, "dvp") == 0) { +- ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */ ++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */ + (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */ + ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */ + ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */ +- } +- +- ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */ + +- switch (priv->dt) { +- case MIPI_DT_YUV8: +- case MIPI_DT_RAW12: +- /* setup crossbar: strait DVP mapping */ +- ser_write(MAX9295_CROSS(0), priv->cb[0]); +- ser_write(MAX9295_CROSS(1), priv->cb[1]); +- ser_write(MAX9295_CROSS(2), priv->cb[2]); +- ser_write(MAX9295_CROSS(3), priv->cb[3]); +- ser_write(MAX9295_CROSS(4), priv->cb[4]); +- ser_write(MAX9295_CROSS(5), priv->cb[5]); +- ser_write(MAX9295_CROSS(6), priv->cb[6]); +- ser_write(MAX9295_CROSS(7), priv->cb[7]); +- ser_write(MAX9295_CROSS(8), priv->cb[8]); +- ser_write(MAX9295_CROSS(9), priv->cb[9]); +- ser_write(MAX9295_CROSS(10), priv->cb[10]); +- ser_write(MAX9295_CROSS(11), priv->cb[11]); +- break; ++ switch (priv->dt) { ++ case MIPI_DT_YUV8: ++ case MIPI_DT_RAW12: ++ /* setup crossbar: strait DVP mapping */ ++ ser_write(MAX9295_CROSS(0), priv->cb[0]); ++ ser_write(MAX9295_CROSS(1), priv->cb[1]); ++ ser_write(MAX9295_CROSS(2), priv->cb[2]); ++ ser_write(MAX9295_CROSS(3), priv->cb[3]); ++ ser_write(MAX9295_CROSS(4), priv->cb[4]); ++ ser_write(MAX9295_CROSS(5), priv->cb[5]); ++ ser_write(MAX9295_CROSS(6), priv->cb[6]); ++ ser_write(MAX9295_CROSS(7), priv->cb[7]); ++ ser_write(MAX9295_CROSS(8), priv->cb[8]); ++ ser_write(MAX9295_CROSS(9), priv->cb[9]); ++ ser_write(MAX9295_CROSS(10), priv->cb[10]); ++ ser_write(MAX9295_CROSS(11), priv->cb[11]); ++ break; ++ } ++ } else { ++ /* defaults: ++ * REG2 - video enable Pipex X,Z ++ * MIPI_RX0 - 1x4 mode (1-port x 4-lanes) ++ * MIPI_RX1 - 4-lanes ++ * MIPI_RX2, MIPI_RX3 - merge PHY1,PHY2 to 1x4-mode ++ * FRONTTOP_9 - start Pipes X,Z from CSI_A,CSI_B ++ */ ++ ++ ser_write(MAX9295_FRONTTOP_0, 0x71); /* enable Pipe X from from CSI_A,CSI_B */ ++ ser_write(MAX9295_FRONTTOP_12, BIT(6) | priv->dt); /* primary DT for Pipe X */ ++ ser_write(MAX9295_FRONTTOP_13, BIT(6) | MIPI_DT_EMB); /* secondary DT for Pipe X */ + } + + for (i = 0; i < 11; i++) { +@@ -852,7 +861,9 @@ static struct { + } gmsl2_pipe_maps[] = { + {0x00, 0x00}, /* FS */ + {0x01, 0x01}, /* FE */ +- {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */ ++ {MIPI_DT_YUV8, MIPI_DT_YUV8}, /* payload data */ ++ {MIPI_DT_RAW8, MIPI_DT_RAW8}, ++ {MIPI_DT_RAW12, MIPI_DT_RAW12}, + }; + + static void max96712_gmsl2_pipe_set_source(struct max96712_priv *priv, int pipe, int phy, int in_pipe) +@@ -1193,6 +1204,8 @@ static int max96712_parse_dt(struct i2c_client *client) + priv->gpio[7] = gpio7; + if (gpio8 >= 0) + priv->gpio[8] = gpio8; ++ if (strcmp(mbus, "dvp")) ++ priv->mbus = mbus; + + /* parse serializer crossbar setup */ + for (i = 0; i < 16; i++) { +diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.h b/drivers/media/i2c/soc_camera/gmsl/max96712.h +index 2976027..b648bdc 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max96712.h ++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.h +@@ -236,11 +236,11 @@ static inline int max96712_ser_write(struct max96712_link *link, int reg, int va + return ret; + } + +-static inline int max96712_ser_read(struct max96712_link *link, int reg, u8 *val) ++static inline int max96712_ser_read(struct max96712_link *link, int reg, int *val) + { + int ret; + +- ret = regmap_read(link->regmap, reg, (int *)val); ++ ret = regmap_read(link->regmap, reg, val); + if (ret) + dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret); + +@@ -258,6 +258,6 @@ static inline int max96712_ser_update_bits(struct max96712_link *link, int reg, + return ret; + } + +-#define ser_read(reg, val) max96712_ser_read(link, reg, val) ++#define ser_read(reg, val) max96712_ser_read(link, reg, (int *)val) + #define ser_write(reg, val) max96712_ser_write(link, reg, val) + #define ser_update_bits(reg, mask, bits) max96712_ser_update_bits(link, reg, mask, bits) +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0503-media-i2c-ov2311-add-GMSL2-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0503-media-i2c-ov2311-add-GMSL2-support.patch new file mode 100644 index 00000000..478f36f2 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0503-media-i2c-ov2311-add-GMSL2-support.patch @@ -0,0 +1,83 @@ +From fa1d9aeccd9d3244d48ded2dc9e9405aab949513 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 29 Apr 2020 01:28:16 +0300 +Subject: [PATCH] media: i2c: ov2311: add GMSL2 support + +This add GMSL2 camera with this imager + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imagers/ov2311.c | 21 ++++++++++++++------- + drivers/media/i2c/soc_camera/imagers/ov2311.h | 2 +- + 2 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.c b/drivers/media/i2c/soc_camera/imagers/ov2311.c +index ce4999b..764c261 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ov2311.c ++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.c +@@ -1,7 +1,7 @@ + /* + * OmniVision ov2311 sensor camera driver + * +- * Copyright (C) 2015-2019 Cogent Embedded, Inc. ++ * Copyright (C) 2015-2020 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the +@@ -25,8 +25,8 @@ + + #define OV2311_I2C_ADDR 0x60 + +-#define OV2311_PID_REGA 0x300a +-#define OV2311_PID_REGB 0x300b ++#define OV2311_PIDA_REG 0x300a ++#define OV2311_PIDB_REG 0x300b + #define OV2311_REV_REG 0x300c + #define OV2311_PID 0x2311 + +@@ -397,9 +397,9 @@ static int ov2311_initialize(struct i2c_client *client) + + setup_i2c_translator(client, priv->ser_addr, OV2311_I2C_ADDR, MODE_GMSL2); + +- reg16_read(client, OV2311_PID_REGA, &val); ++ reg16_read(client, OV2311_PIDA_REG, &val); + pid = val; +- reg16_read(client, OV2311_PID_REGB, &val); ++ reg16_read(client, OV2311_PIDB_REG, &val); + pid = (pid << 8) | val; + + if (pid != OV2311_PID) { +@@ -407,8 +407,15 @@ static int ov2311_initialize(struct i2c_client *client) + return -ENODEV; + } + +- if (get_des_id(client) == UB960_ID) +- reg8_write_addr(client, priv->ser_addr, 0x02, 0x13); /* MIPI 2-lanes */ ++ switch (get_des_id(client)) { ++ case UB960_ID: ++ reg8_write_addr(client, priv->ser_addr, 0x02, 0x13); /* MIPI 2-lanes */ ++ break; ++ case MAX9296A_ID: ++ case MAX96712_ID: ++ reg16_write_addr(client, priv->ser_addr, MAX9295_MIPI_RX1, 0x11); /* MIPI 2-lanes */ ++ break; ++ } + + /* check revision */ + reg16_read(client, OV2311_REV_REG, &rev); +diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.h b/drivers/media/i2c/soc_camera/imagers/ov2311.h +index 3a56b0b..f76662a 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ov2311.h ++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.h +@@ -30,7 +30,7 @@ struct ov2311_reg { + u8 val; + }; + +-/* R1600x1300 RAW10 MIPI 60fps */ ++/* R1600x1300 RAW8 MIPI 60fps */ + static const struct ov2311_reg ov2311_regs_wizard_r1c[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0504-media-i2c-max9296-add-MIPI-GMSL2-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0504-media-i2c-max9296-add-MIPI-GMSL2-support.patch new file mode 100644 index 00000000..5301e0a3 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0504-media-i2c-max9296-add-MIPI-GMSL2-support.patch @@ -0,0 +1,169 @@ +From ebdaf5ec6d7040c1c7c9a3486ea16ea60f5f127f Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 29 Apr 2020 01:31:03 +0300 +Subject: [PATCH] media: i2c: max9296: add MIPI GMSL2 support + +This adds MIPI stream from serializer + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/gmsl/max9296.c | 75 +++++++++++++++++------------ + drivers/media/i2c/soc_camera/gmsl/max9296.h | 6 +-- + 2 files changed, 47 insertions(+), 34 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.c b/drivers/media/i2c/soc_camera/gmsl/max9296.c +index a6d286f..85b45ca 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max9296.c ++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.c +@@ -94,7 +94,7 @@ static int gmsl = MODE_GMSL2; + module_param(gmsl, int, 0644); + MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)"); + +-static char *mbus = "dvp"; ++static char *mbus = mbus_default; + module_param(mbus, charp, 0644); + MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)"); + +@@ -165,7 +165,7 @@ static void max9296_reset_oneshot(struct max9296_priv *priv) + if (!(reg & BIT(5))) + break; + +- msleep(1); ++ mdelay(1); + } + + if (reg & BIT(5)) +@@ -745,9 +745,12 @@ static int max9296_gmsl2_reverse_channel_setup(struct max9296_priv *priv, int li + des_update_bits(MAX9296_CTRL0, 0x13, BIT(link_n)); /* enable GMSL link# */ + max9296_reset_oneshot(priv); + +- /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */ +- while ((!max9296_gmsl2_get_link_lock(priv, link_n)) && (--timeout)) +- msleep(1); ++ /* wait the link to be established, indicated when status bit LOCKED goes high */ ++ for (; timeout > 0; timeout--) { ++ if (max9296_gmsl2_get_link_lock(priv, link_n)) ++ break; ++ mdelay(1); ++ } + + if (!timeout) { + ret = -ETIMEDOUT; +@@ -785,36 +788,42 @@ static int max9296_gmsl2_link_serializer_setup(struct max9296_priv *priv, int li + struct max9296_link *link = priv->link[link_n]; + int i; + +- //ser_write(MAX9295_CTRL0, 0x31); /* link reset */ +- //msleep(100); +- ser_write(MAX9295_REG2, 0x03); /* disable all pipes */ +- + if (strcmp(priv->mbus, "dvp") == 0) { +- ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */ ++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */ + (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */ + ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */ + ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */ +- } +- +- ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */ + +- switch (priv->dt) { +- case MIPI_DT_YUV8: +- case MIPI_DT_RAW12: +- /* setup crossbar: strait DVP mapping */ +- ser_write(MAX9295_CROSS(0), priv->cb[0]); +- ser_write(MAX9295_CROSS(1), priv->cb[1]); +- ser_write(MAX9295_CROSS(2), priv->cb[2]); +- ser_write(MAX9295_CROSS(3), priv->cb[3]); +- ser_write(MAX9295_CROSS(4), priv->cb[4]); +- ser_write(MAX9295_CROSS(5), priv->cb[5]); +- ser_write(MAX9295_CROSS(6), priv->cb[6]); +- ser_write(MAX9295_CROSS(7), priv->cb[7]); +- ser_write(MAX9295_CROSS(8), priv->cb[8]); +- ser_write(MAX9295_CROSS(9), priv->cb[9]); +- ser_write(MAX9295_CROSS(10), priv->cb[10]); +- ser_write(MAX9295_CROSS(11), priv->cb[11]); +- break; ++ switch (priv->dt) { ++ case MIPI_DT_YUV8: ++ case MIPI_DT_RAW12: ++ /* setup crossbar: strait DVP mapping */ ++ ser_write(MAX9295_CROSS(0), priv->cb[0]); ++ ser_write(MAX9295_CROSS(1), priv->cb[1]); ++ ser_write(MAX9295_CROSS(2), priv->cb[2]); ++ ser_write(MAX9295_CROSS(3), priv->cb[3]); ++ ser_write(MAX9295_CROSS(4), priv->cb[4]); ++ ser_write(MAX9295_CROSS(5), priv->cb[5]); ++ ser_write(MAX9295_CROSS(6), priv->cb[6]); ++ ser_write(MAX9295_CROSS(7), priv->cb[7]); ++ ser_write(MAX9295_CROSS(8), priv->cb[8]); ++ ser_write(MAX9295_CROSS(9), priv->cb[9]); ++ ser_write(MAX9295_CROSS(10), priv->cb[10]); ++ ser_write(MAX9295_CROSS(11), priv->cb[11]); ++ break; ++ } ++ } else { ++ /* defaults: ++ * REG2 - video enable Pipex X,Z ++ * MIPI_RX0 - 1x4 mode (1-port x 4-lanes) ++ * MIPI_RX1 - 4-lanes ++ * MIPI_RX2, MIPI_RX3 - merge PHY1,PHY2 to 1x4-mode ++ * FRONTTOP_9 - start Pipes X,Z from CSI_A,CSI_B ++ */ ++ ++ ser_write(MAX9295_FRONTTOP_0, 0x71); /* enable Pipe X from from CSI_A,CSI_B */ ++ ser_write(MAX9295_FRONTTOP_12, BIT(6) | priv->dt); /* primary DT for Pipe X */ ++ ser_write(MAX9295_FRONTTOP_13, BIT(6) | MIPI_DT_EMB); /* secondary DT for Pipe X */ + } + + for (i = 0; i < 11; i++) { +@@ -856,7 +865,9 @@ static struct { + } gmsl2_pipe_maps[] = { + {0x00, 0x00}, /* FS */ + {0x01, 0x01}, /* FE */ +- {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */ ++ {MIPI_DT_YUV8, MIPI_DT_YUV8}, /* payload data */ ++ {MIPI_DT_RAW8, MIPI_DT_RAW8}, ++ {MIPI_DT_RAW12, MIPI_DT_RAW12}, + }; + + static void max9296_gmsl2_pipe_set_source(struct max9296_priv *priv, int pipe, int phy, int in_pipe) +@@ -1193,6 +1204,8 @@ static int max9296_parse_dt(struct i2c_client *client) + priv->gpio[7] = gpio7; + if (gpio8 >= 0) + priv->gpio[8] = gpio8; ++ if (strcmp(mbus, "dvp")) ++ priv->mbus = mbus; + + /* parse serializer crossbar setup */ + for (i = 0; i < 16; i++) { +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.h b/drivers/media/i2c/soc_camera/gmsl/max9296.h +index 800df43..985b77e 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max9296.h ++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.h +@@ -254,11 +254,11 @@ static inline int max9296_ser_write(struct max9296_link *link, int reg, int val) + return ret; + } + +-static inline int max9296_ser_read(struct max9296_link *link, int reg, u8 *val) ++static inline int max9296_ser_read(struct max9296_link *link, int reg, int *val) + { + int ret; + +- ret = regmap_read(link->regmap, reg, (int *)val); ++ ret = regmap_read(link->regmap, reg, val); + if (ret) + dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret); + +@@ -276,6 +276,6 @@ static inline int max9296_ser_update_bits(struct max9296_link *link, int reg, in + return ret; + } + +-#define ser_read(reg, val) max9296_ser_read(link, reg, val) ++#define ser_read(reg, val) max9296_ser_read(link, reg, (int *)val) + #define ser_write(reg, val) max9296_ser_write(link, reg, val) + #define ser_update_bits(reg, mask, bits) max9296_ser_update_bits(link, reg, mask, bits) +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0505-media-i2c-gmsl-parse-gmsl_mode-from-deserializer.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0505-media-i2c-gmsl-parse-gmsl_mode-from-deserializer.patch new file mode 100644 index 00000000..21edaa0a --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0505-media-i2c-gmsl-parse-gmsl_mode-from-deserializer.patch @@ -0,0 +1,118 @@ +From afbb91288b32731dcf5249dcddeee019994364e2 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 29 Apr 2020 02:33:17 +0300 +Subject: [PATCH] media: i2c: gmsl: parse gmsl_mode from deserializer + +The gmsl1/2 mode needs to be parsed from deserizlier to +access 16 or 8 bit remote serializer. If not done then +imager may try to make 16 bit writes to 8 bit serizlier and +hence it will change it's address at reg=0 + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/gmsl/common.h | 13 +++++++++++-- + drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c | 2 +- + drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c | 2 +- + drivers/media/i2c/soc_camera/imagers/ov10635.c | 2 +- + drivers/media/i2c/soc_camera/imagers/ov2311.c | 2 +- + drivers/media/i2c/soc_camera/imagers/ov490.c | 2 +- + 6 files changed, 16 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/gmsl/common.h b/drivers/media/i2c/soc_camera/gmsl/common.h +index 98bb1c0..346db3ca 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/common.h ++++ b/drivers/media/i2c/soc_camera/gmsl/common.h +@@ -473,14 +473,23 @@ static inline int get_des_addr(struct i2c_client *client) + return to_i2c_client(mux_priv->muxc->dev)->addr; + } + +-static inline void setup_i2c_translator(struct i2c_client *client, int ser_addr, int sensor_addr, int gmsl_mode) ++static inline void setup_i2c_translator(struct i2c_client *client, int ser_addr, int sensor_addr) + { ++ int gmsl_mode = MODE_GMSL2; ++ + switch (get_des_id(client)) { + case MAX9286_ID: + case MAX9288_ID: +- case MAX9296A_ID: + case MAX96706_ID: ++ reg8_write_addr(client, ser_addr, 0x09, client->addr << 1); /* Sensor translated I2C address */ ++ reg8_write_addr(client, ser_addr, 0x0A, sensor_addr << 1); /* Sensor native I2C address */ ++ break; ++ case MAX9296A_ID: + case MAX96712_ID: ++ /* parse gmsl mode from deserializer */ ++ reg16_read_addr(client, get_des_addr(client), 6, &gmsl_mode); ++ gmsl_mode = !!(gmsl_mode & BIT(7)) + 1; ++ + if (gmsl_mode == MODE_GMSL1) { + reg8_write_addr(client, ser_addr, 0x09, client->addr << 1); /* Sensor translated I2C address */ + reg8_write_addr(client, ser_addr, 0x0A, sensor_addr << 1); /* Sensor native I2C address */ +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c +index 1df3f3b..d2a6ff9 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c ++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c +@@ -409,7 +409,7 @@ static int ap0101_initialize(struct i2c_client *client) + int i; + + for (i = 0; i < ARRAY_SIZE(ap0101_i2c_addr); i++) { +- setup_i2c_translator(client, priv->ser_addr, ap0101_i2c_addr[i], MODE_GMSL1); ++ setup_i2c_translator(client, priv->ser_addr, ap0101_i2c_addr[i]); + + /* check model ID */ + reg16_read16(client, AP0101_PID_REG, &pid); +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +index 35169b8..7b274ce 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c ++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +@@ -405,7 +405,7 @@ static int ap0201_initialize(struct i2c_client *client) + int i; + + for (i = 0; i < ARRAY_SIZE(ap0201_i2c_addr); i++) { +- setup_i2c_translator(client, priv->ser_addr, ap0201_i2c_addr[i], MODE_GMSL2); ++ setup_i2c_translator(client, priv->ser_addr, ap0201_i2c_addr[i]); + + /* check product ID */ + reg16_read16(client, AP0201_PID_REG, &pid); +diff --git a/drivers/media/i2c/soc_camera/imagers/ov10635.c b/drivers/media/i2c/soc_camera/imagers/ov10635.c +index b9813f7..d21d357 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ov10635.c ++++ b/drivers/media/i2c/soc_camera/imagers/ov10635.c +@@ -506,7 +506,7 @@ static int ov10635_initialize(struct i2c_client *client) + u8 val = 0; + u16 pid = 0; + +- setup_i2c_translator(client, priv->ser_addr, OV10635_I2C_ADDR, MODE_GMSL1); ++ setup_i2c_translator(client, priv->ser_addr, OV10635_I2C_ADDR); + udelay(100); + + reg16_read(client, OV10635_PID_REGA, &val); +diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.c b/drivers/media/i2c/soc_camera/imagers/ov2311.c +index 764c261..d49ca96 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ov2311.c ++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.c +@@ -395,7 +395,7 @@ static int ov2311_initialize(struct i2c_client *client) + u8 val = 0, rev = 0; + int ret = 0; + +- setup_i2c_translator(client, priv->ser_addr, OV2311_I2C_ADDR, MODE_GMSL2); ++ setup_i2c_translator(client, priv->ser_addr, OV2311_I2C_ADDR); + + reg16_read(client, OV2311_PIDA_REG, &val); + pid = val; +diff --git a/drivers/media/i2c/soc_camera/imagers/ov490.c b/drivers/media/i2c/soc_camera/imagers/ov490.c +index 3c47398..ff0d122 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ov490.c ++++ b/drivers/media/i2c/soc_camera/imagers/ov490.c +@@ -767,7 +767,7 @@ static int ov490_initialize(struct i2c_client *client) + u16 pid = 0; + int timeout, retry_timeout = 3; + +- setup_i2c_translator(client, priv->ser_addr, OV490_I2C_ADDR, MODE_GMSL1); ++ setup_i2c_translator(client, priv->ser_addr, OV490_I2C_ADDR); + + reg16_write(client, 0xFFFD, 0x80); + reg16_write(client, 0xFFFE, 0x80); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0506-media-i2c-imagers-add-AR0231-for-new-LVDS-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0506-media-i2c-imagers-add-AR0231-for-new-LVDS-support.patch new file mode 100644 index 00000000..c75293ae --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0506-media-i2c-imagers-add-AR0231-for-new-LVDS-support.patch @@ -0,0 +1,1843 @@ +From f113d62d104a24b6035d969bad8cb04af54d7534 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Apr 2020 10:54:49 +0300 +Subject: [PATCH] media: i2c: imagers: add AR0231 for new LVDS support + +This adds AR0231 into new LVDS drivers that support all enabled +serializers + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imagers/Makefile | 1 + + drivers/media/i2c/soc_camera/imagers/ar0231.c | 604 +++++++++++++++++++++ + drivers/media/i2c/soc_camera/imagers/ar0231.h | 35 ++ + drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h | 344 ++++++++++++ + drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h | 343 ++++++++++++ + drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h | 445 +++++++++++++++ + 5 files changed, 1771 insertions(+) + create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231.c + create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231.h + create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h + create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h + create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h + +diff --git a/drivers/media/i2c/soc_camera/imagers/Makefile b/drivers/media/i2c/soc_camera/imagers/Makefile +index 0d0ff32..eeb36fd 100644 +--- a/drivers/media/i2c/soc_camera/imagers/Makefile ++++ b/drivers/media/i2c/soc_camera/imagers/Makefile +@@ -1,7 +1,8 @@ + # SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0101_ar014x.o ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0201_ar023x.o ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ar0231.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov10635.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov2311.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov490.o +-obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0101_ar014x.o +-obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0201_ar023x.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += dummy.o +diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231.c b/drivers/media/i2c/soc_camera/imagers/ar0231.c +new file mode 100644 +index 0000000..fc08793 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ar0231.c +@@ -0,0 +1,604 @@ ++/* ++ * ON Semiconductor AR0231 sensor camera driver ++ * ++ * Copyright (C) 2018-220 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++#include "../gmsl/common.h" ++#include "ar0231.h" ++ ++static const int ar0231_i2c_addr[] = {0x10, 0x20}; ++ ++#define AR0231_PID_REG 0x3000 ++#define AR0231_REV_REG 0x31FE ++#define AR0231_PID 0x0354 ++ ++#define AR0231_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG12_1X12 ++ ++struct ar0231_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int init_complete; ++ u8 id[6]; ++ /* serializers */ ++ int ser_addr; ++ int trigger; ++}; ++ ++static int trigger = 0; ++module_param(trigger, int, 0644); ++MODULE_PARM_DESC(trigger, " Trigger gpio number (default: 0 - GPIO0) "); ++ ++static inline struct ar0231_priv *to_ar0231(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ar0231_priv, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ar0231_priv, hdl)->sd; ++} ++ ++static int ar0231_set_regs(struct i2c_client *client, ++ const struct ar0231_reg *regs, int nr_regs) ++{ ++ int i; ++ ++ for (i = 0; i < nr_regs; i++) { ++ if (regs[i].reg == AR0231_DELAY) { ++ mdelay(regs[i].val); ++ continue; ++ } ++ ++ reg16_write16(client, regs[i].reg, regs[i].val); ++ } ++ ++ return 0; ++} ++ ++static void ar0231_otp_id_read(struct i2c_client *client) ++{ ++ struct ar0231_priv *priv = to_ar0231(client); ++ int i; ++ u16 val = 0; ++ ++ /* read camera id from ar014x OTP memory */ ++ reg16_write16(client, 0x3054, 0x400); ++ reg16_write16(client, 0x304a, 0x110); ++ usleep_range(25000, 25500); /* wait 25 ms */ ++ ++ for (i = 0; i < 6; i += 2) { ++ /* first 4 bytes are equal on all ar014x */ ++ reg16_read16(client, 0x3800 + i + 4, &val); ++ priv->id[i] = val >> 8; ++ priv->id[i + 1] = val & 0xff; ++ } ++} ++ ++ ++static int ar0231_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int ar0231_set_window(struct v4l2_subdev *sd) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0231_priv *priv = to_ar0231(client); ++ ++ dev_dbg(&client->dev, "L=%d T=%d %dx%d\n", priv->rect.left, priv->rect.top, priv->rect.width, priv->rect.height); ++ ++ /* horiz crop start */ ++ reg16_write16(client, 0x3004, priv->rect.left + AR0231_X_START); ++ /* horiz crop end */ ++ reg16_write16(client, 0x3008, priv->rect.left + priv->rect.width - 1 + AR0231_X_START); ++ /* vert crop start */ ++ reg16_write16(client, 0x3002, priv->rect.top + AR0231_Y_START); ++ /* vert crop end */ ++ reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR0231_Y_START); ++ ++ return 0; ++}; ++ ++static int ar0231_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0231_priv *priv = to_ar0231(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = AR0231_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ar0231_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ ++ mf->code = AR0231_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int ar0231_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = AR0231_MEDIA_BUS_FMT; ++ ++ return 0; ++} ++ ++static int ar0231_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0231_priv *priv = to_ar0231(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = AR0231_PID >> 8; ++ edid->edid[9] = AR0231_PID & 0xff; ++ ++ return 0; ++} ++ ++static int ar0231_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0231_priv *priv = to_ar0231(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > AR0231_MAX_WIDTH) || ++ (rect->top + rect->height > AR0231_MAX_HEIGHT)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ ar0231_set_window(sd); ++ ++ return 0; ++} ++ ++static int ar0231_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0231_priv *priv = to_ar0231(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = AR0231_MAX_WIDTH; ++ sel->r.height = AR0231_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = AR0231_MAX_WIDTH; ++ sel->r.height = AR0231_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ar0231_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ar0231_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ __be64 be_val; ++ ++ if (!reg->size) ++ reg->size = sizeof(u16); ++ if (reg->size > sizeof(reg->val)) ++ reg->size = sizeof(reg->val); ++ ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size); ++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8); ++ reg->val = be64_to_cpu(be_val); ++ ++ return ret; ++} ++ ++static int ar0231_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 size = reg->size; ++ int ret; ++ __be64 be_val; ++ ++ if (!size) ++ size = sizeof(u16); ++ if (size > sizeof(reg->val)) ++ size = sizeof(reg->val); ++ ++ be_val = cpu_to_be64(reg->val); ++ be_val = be_val >> ((sizeof(be_val) - size) * 8); ++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size); ++ ++ return ret; ++} ++#endif ++ ++static struct v4l2_subdev_core_ops ar0231_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ar0231_g_register, ++ .s_register = ar0231_s_register, ++#endif ++}; ++ ++static int ar0231_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0231_priv *priv = to_ar0231(client); ++ int ret = -EINVAL; ++ u16 val = 0; ++ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ case V4L2_CID_SHARPNESS: ++ case V4L2_CID_AUTOGAIN: ++ break; ++ case V4L2_CID_GAIN: ++ /* Digital gain */ ++ ret = reg16_write16(client, 0x3308, ctrl->val); ++ break; ++ case V4L2_CID_ANALOGUE_GAIN: ++ /* Analog gain */ ++ ret = reg16_write16(client, 0x3366, (ctrl->val << 8) | (ctrl->val << 4) | ctrl->val); ++ break; ++ case V4L2_CID_EXPOSURE: ++ /* T1 exposure */ ++ ret = reg16_write16(client, 0x3012, ctrl->val); ++ break; ++ case V4L2_CID_HFLIP: ++ ret = reg16_read16(client, 0x3040, &val); ++ if (ctrl->val) ++ val |= (1 << 14); ++ else ++ val &= ~(1 << 14); ++ ret |= reg16_write16(client, 0x3040, val); ++ break; ++ case V4L2_CID_VFLIP: ++ ret = reg16_read16(client, 0x3040, &val); ++ if (ctrl->val) ++ val |= (1 << 15); ++ else ++ val &= ~(1 << 15); ++ ret |= reg16_write16(client, 0x3040, val); ++ break; ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ret = 0; ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ar0231_ctrl_ops = { ++ .s_ctrl = ar0231_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops ar0231_video_ops = { ++ .s_stream = ar0231_s_stream, ++ .g_mbus_config = ar0231_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops ar0231_subdev_pad_ops = { ++ .get_edid = ar0231_get_edid, ++ .enum_mbus_code = ar0231_enum_mbus_code, ++ .get_selection = ar0231_get_selection, ++ .set_selection = ar0231_set_selection, ++ .get_fmt = ar0231_get_fmt, ++ .set_fmt = ar0231_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops ar0231_subdev_ops = { ++ .core = &ar0231_core_ops, ++ .video = &ar0231_video_ops, ++ .pad = &ar0231_subdev_pad_ops, ++}; ++ ++static ssize_t ar0231_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0231_priv *priv = to_ar0231(client); ++ ++ ar0231_otp_id_read(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_ar0231, S_IRUGO, ar0231_otp_id_show, NULL); ++ ++static int ar0231_initialize(struct i2c_client *client) ++{ ++ struct ar0231_priv *priv = to_ar0231(client); ++ u16 val = 0, pid = 0, rev = 0; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ar0231_i2c_addr); i++) { ++ setup_i2c_translator(client, priv->ser_addr, ar0231_i2c_addr[i] << 1); ++ ++ /* check model ID */ ++ reg16_read16(client, AR0231_PID_REG, &pid); ++ if (pid == AR0231_PID) ++ break; ++ } ++ ++ if (pid != AR0231_PID) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ return -ENODEV; ++ } ++ ++ /* check revision */ ++ reg16_read16(client, AR0231_REV_REG, &rev); ++ /* Read OTP IDs */ ++ ar0231_otp_id_read(client); ++ /* Program wizard registers */ ++ switch (get_des_id(client)) { ++ case UB960_ID: ++ ar0231_set_regs(client, ar0231_regs_wizard_rev7, ARRAY_SIZE(ar0231_regs_wizard_rev7)); ++ break; ++ case MAX9286_ID: ++ case MAX9296A_ID: ++ case MAX96712_ID: ++ ar0231_set_regs(client, ar0231_regs_wizard_rev6_dvp, ARRAY_SIZE(ar0231_regs_wizard_rev6_dvp)); ++ break; ++ } ++ /* Enable trigger */ ++ if (priv->trigger >= 0 && priv->trigger < 4) { ++ reg16_write16(client, 0x340A, (~(BIT(priv->trigger) << 4)) & 0xf0);/* GPIO_CONTROL1: GPIOn input enable */ ++ reg16_write16(client, 0x340C, (0x2 << 2*priv->trigger)); /* GPIO_CONTROL2: GPIOn is trigger */ ++ reg16_write16(client, 0x30CE, 0x0120); /* TRIGGER_MODE */ ++ //reg16_write16(client, 0x30DC, 0x0120); /* TRIGGER_DELAY */ ++ } ++ /* Enable stream */ ++ reg16_read16(client, 0x301a, &val); ++ val |= (1 << 8); /* GPI pins enable */ ++ val |= (1 << 2); ++ reg16_write16(client, 0x301a, val); ++ ++ dev_info(&client->dev, "ar0231 PID %x (rev%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, rev & 0xf, AR0231_MAX_WIDTH, AR0231_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ return 0; ++} ++ ++static const struct i2c_device_id ar0231_id[] = { ++ { "ar0231", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ar0231_id); ++ ++static const struct of_device_id ar0231_of_ids[] = { ++ { .compatible = "onnn,ar0231", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ar0231_of_ids); ++ ++static int ar0231_parse_dt(struct device_node *np, struct ar0231_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ u32 addrs[2], naddrs; ++ ++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32)); ++ if (naddrs != 2) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ priv->ser_addr = addrs[1]; ++ ++ if (of_property_read_u32(np, "trigger", &priv->trigger)) ++ priv->trigger = 0; ++ ++ /* module params override dts */ ++ if (trigger) ++ priv->trigger = trigger; ++ ++ return 0; ++} ++ ++static int ar0231_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ar0231_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &ar0231_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_GAIN, 1, 0x7ff, 1, 0x200); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = ar0231_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = ar0231_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = AR0231_MAX_WIDTH; ++ priv->rect.height = AR0231_MAX_HEIGHT; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ar0231) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ return ret; ++} ++ ++static int ar0231_remove(struct i2c_client *client) ++{ ++ struct ar0231_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_ar0231); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++static struct i2c_driver ar0231_i2c_driver = { ++ .driver = { ++ .name = "ar0231", ++ .of_match_table = ar0231_of_ids, ++ }, ++ .probe = ar0231_probe, ++ .remove = ar0231_remove, ++ .id_table = ar0231_id, ++}; ++ ++module_i2c_driver(ar0231_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for AR0231"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231.h b/drivers/media/i2c/soc_camera/imagers/ar0231.h +new file mode 100644 +index 0000000..e455b38 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ar0231.h +@@ -0,0 +1,35 @@ ++/* ++ * ON Semiconductor AR0231 sensor camera wizard 1928x1208@30/BGGR/BT601 ++ * ++ * Copyright (C) 2018-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++//#define AR0231_DISPLAY_PATTERN_FIXED ++//#define AR0231_DISPLAY_PATTERN_COLOR_BAR ++ ++#define AR0231_MAX_WIDTH 1920 ++#define AR0231_MAX_HEIGHT 1200 ++ ++#define AR0231_DELAY 0xffff ++ ++#define AR0231_SENSOR_WIDTH 1928 ++#define AR0231_SENSOR_HEIGHT 1208 ++ ++#define AR0231_X_START ((AR0231_SENSOR_WIDTH - AR0231_MAX_WIDTH) / 2) ++#define AR0231_Y_START ((AR0231_SENSOR_HEIGHT - AR0231_MAX_HEIGHT) / 2) ++#define AR0231_X_END (AR0231_X_START + AR0231_MAX_WIDTH - 1) ++#define AR0231_Y_END (AR0231_Y_START + AR0231_MAX_HEIGHT - 1) ++ ++struct ar0231_reg { ++ u16 reg; ++ u16 val; ++}; ++ ++#include "ar0231_rev4.h" ++#include "ar0231_rev6.h" ++#include "ar0231_rev7.h" +diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h b/drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h +new file mode 100644 +index 0000000..e18b96d +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h +@@ -0,0 +1,344 @@ ++/* ++ * ON Semiconductor AR0231 sensor camera wizard 1920x1080@30/BGGR/MIPI ++ * ++ * Copyright (C) 2018-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++static const struct ar0231_reg ar0231_regs_wizard_rev4_dvp[] = { ++{0x301A, 0x0001}, // reset ++{0x301A, 0x10D8}, // Stream off and setup parallel ++{0x3070, 0x0000}, // 1: Solid color test pattern, ++ // 2: Full color bar test pattern, ++ // 3: Fade to grey color bar test pattern, ++ //256: Walking 1 test pattern (12 bit) ++{0x3072, 0x0123}, // R ++{0x3074, 0x0456}, // G(GR row) ++{0x3076, 0x0abc}, // B ++{0x3078, 0x0def}, // G(GB row) ++#ifdef AR0231_DISPLAY_PATTERN_FIXED ++{0x3070, 0x0001}, ++#endif ++#ifdef AR0231_DISPLAY_PATTERN_COLOR_BAR ++{0x3070, 0x0002}, ++#endif ++ ++//Recommended Settings ++{0x3366, 0x6666}, // ANALOG_GAIN ++{0x3056, 0x0080}, // GREEN1_GAIN ++{0x305C, 0x0080}, // GREEN2_GAIN ++{0x3058, 0x0080}, // BLUE_GAIN ++{0x305A, 0x0080}, // RED_GAIN ++{0x3044, 0x0400}, // DARK_CONTROL ++{0x30BA, 0x1021}, // DIGITAL_CTRL ++{0x318E, 0x0200}, // DLO_CONTROL0 ++{0x32EA, 0x3C0A}, // RESERVED_MFR_32EA ++{0x32EA, 0x3C0E}, // RESERVED_MFR_32EA ++{0x3362, 0x0000}, // DC_GAIN ++{0x3364, 0x0060}, // RESERVED_MFR_3364 ++{0x3370, 0x0231}, // DBLC_CONTROL ++{0x3372, 0x700F}, // RESERVED_MFR_3372 ++{0x3386, 0x0000}, // RESERVED_MFR_3386 ++{0x3C04, 0x0E80}, // RESERVED_MFR_3C04 ++{0x3F90, 0x06E1}, // TEMPVSENS0_TMG_CTRL ++{0x3F92, 0x06E1}, // TEMPVSENS1_TMG_CTRL ++{0x3502, 0x0808}, // RESERVED_MFR_3502 ++{0x3502, 0x0808}, // RESERVED_MFR_3502 ++{0x350E, 0xFF10}, // RESERVED_MFR_350E ++{0x3506, 0x4444}, // RESERVED_MFR_3506 ++{0x3508, 0x4444}, // RESERVED_MFR_3508 ++{0x350A, 0x4465}, // RESERVED_MFR_350A ++{0x350C, 0x055F}, // RESERVED_MFR_350C ++{0x3230, 0x0317}, // FINE_CORRECTION ++{0x3232, 0x0552}, // FINE_CORRECTION2 ++{0x3234, 0x078D}, // FINE_CORRECTION3 ++{0x3566, 0x9D38}, // RESERVED_MFR_3566 ++{0x3518, 0x1FFE}, // RESERVED_MFR_3518 ++{0x3520, 0xC688}, // RESERVED_MFR_3520 ++{0x3522, 0x88C0}, // RESERVED_MFR_3522 ++{0x3524, 0xC0C6}, // RESERVED_MFR_3524 ++{0x352C, 0xC6C6}, // RESERVED_MFR_352C ++{0x3528, 0x0900}, // RESERVED_MFR_3528 ++{0x3528, 0x9900}, // RESERVED_MFR_3528 ++{0x3528, 0x9909}, // RESERVED_MFR_3528 ++{0x3528, 0x9999}, // RESERVED_MFR_3528 ++{0x352A, 0x081F}, // RESERVED_MFR_352A ++{0x352E, 0x0001}, // RESERVED_MFR_352E ++{0x352E, 0x0011}, // RESERVED_MFR_352E ++{0x3530, 0x0400}, // RESERVED_MFR_3530 ++{0x3530, 0x4400}, // RESERVED_MFR_3530 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF02}, // RESERVED_MFR_3536 ++{0x3536, 0xFF06}, // RESERVED_MFR_3536 ++{0x3536, 0xFF06}, // RESERVED_MFR_3536 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x353A, 0x9000}, // RESERVED_MFR_353A ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x32EC, 0x72A1}, // RESERVED_MFR_32EC ++{0x3540, 0xC637}, // RESERVED_MFR_3540 ++{0x3540, 0xC637}, // RESERVED_MFR_3540 ++{0x3540, 0xC637}, // RESERVED_MFR_3540 ++{0x3542, 0x584B}, // RESERVED_MFR_3542 ++{0x3542, 0x464B}, // RESERVED_MFR_3542 ++{0x3544, 0x565A}, // RESERVED_MFR_3544 ++{0x3544, 0x4B5A}, // RESERVED_MFR_3544 ++{0x3546, 0x545A}, // RESERVED_MFR_3546 ++{0x3546, 0x5A5A}, // RESERVED_MFR_3546 ++{0x3548, 0x6430}, // RESERVED_MFR_3548 ++{0x3556, 0x101F}, // RESERVED_MFR_3556 ++{0x3566, 0x9D38}, // RESERVED_MFR_3566 ++{0x3566, 0x1D38}, // RESERVED_MFR_3566 ++{0x3566, 0x1D28}, // RESERVED_MFR_3566 ++{0x3566, 0x1128}, // RESERVED_MFR_3566 ++{0x3566, 0x1328}, // RESERVED_MFR_3566 ++{0x3566, 0x3328}, // RESERVED_MFR_3566 ++ ++//Sequencer Update ++{0x2512, 0x8000}, // SEQ_CTRL_PORT ++{0x2510, 0x0905}, // SEQ_DATA_PORT ++{0x2510, 0x3350}, // SEQ_DATA_PORT ++{0x2510, 0x2004}, // SEQ_DATA_PORT ++{0x2510, 0x1460}, // SEQ_DATA_PORT ++{0x2510, 0x1578}, // SEQ_DATA_PORT ++{0x2510, 0x1360}, // SEQ_DATA_PORT ++{0x2510, 0x7B24}, // SEQ_DATA_PORT ++{0x2510, 0xFF24}, // SEQ_DATA_PORT ++{0x2510, 0xFF24}, // SEQ_DATA_PORT ++{0x2510, 0xEA24}, // SEQ_DATA_PORT ++{0x2510, 0x1022}, // SEQ_DATA_PORT ++{0x2510, 0x2410}, // SEQ_DATA_PORT ++{0x2510, 0x155A}, // SEQ_DATA_PORT ++{0x2510, 0x1342}, // SEQ_DATA_PORT ++{0x2510, 0x1400}, // SEQ_DATA_PORT ++{0x2510, 0x24FF}, // SEQ_DATA_PORT ++{0x2510, 0x24FF}, // SEQ_DATA_PORT ++{0x2510, 0x24EA}, // SEQ_DATA_PORT ++{0x2510, 0x2324}, // SEQ_DATA_PORT ++{0x2510, 0x647A}, // SEQ_DATA_PORT ++{0x2510, 0x2404}, // SEQ_DATA_PORT ++{0x2510, 0x052C}, // SEQ_DATA_PORT ++{0x2510, 0x400A}, // SEQ_DATA_PORT ++{0x2510, 0xFF0A}, // SEQ_DATA_PORT ++{0x2510, 0xFF0A}, // SEQ_DATA_PORT ++{0x2510, 0x0408}, // SEQ_DATA_PORT ++{0x2510, 0x3851}, // SEQ_DATA_PORT ++{0x2510, 0x1440}, // SEQ_DATA_PORT ++{0x2510, 0x0004}, // SEQ_DATA_PORT ++{0x2510, 0x0801}, // SEQ_DATA_PORT ++{0x2510, 0x0408}, // SEQ_DATA_PORT ++{0x2510, 0x1180}, // SEQ_DATA_PORT ++{0x2510, 0x15DC}, // SEQ_DATA_PORT ++{0x2510, 0x134C}, // SEQ_DATA_PORT ++{0x2510, 0x1002}, // SEQ_DATA_PORT ++{0x2510, 0x1016}, // SEQ_DATA_PORT ++{0x2510, 0x1181}, // SEQ_DATA_PORT ++{0x2510, 0x1189}, // SEQ_DATA_PORT ++{0x2510, 0x1056}, // SEQ_DATA_PORT ++{0x2510, 0x1210}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x0D08}, // SEQ_DATA_PORT ++{0x2510, 0x0913}, // SEQ_DATA_PORT ++{0x2510, 0x13C8}, // SEQ_DATA_PORT ++{0x2510, 0x092B}, // SEQ_DATA_PORT ++{0x2510, 0x1588}, // SEQ_DATA_PORT ++{0x2510, 0x1388}, // SEQ_DATA_PORT ++{0x2510, 0x090B}, // SEQ_DATA_PORT ++{0x2510, 0x11D9}, // SEQ_DATA_PORT ++{0x2510, 0x091D}, // SEQ_DATA_PORT ++{0x2510, 0x1441}, // SEQ_DATA_PORT ++{0x2510, 0x0903}, // SEQ_DATA_PORT ++{0x2510, 0x1214}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x10D6}, // SEQ_DATA_PORT ++{0x2510, 0x1210}, // SEQ_DATA_PORT ++{0x2510, 0x1212}, // SEQ_DATA_PORT ++{0x2510, 0x1210}, // SEQ_DATA_PORT ++{0x2510, 0x11DD}, // SEQ_DATA_PORT ++{0x2510, 0x11D9}, // SEQ_DATA_PORT ++{0x2510, 0x1056}, // SEQ_DATA_PORT ++{0x2510, 0x090B}, // SEQ_DATA_PORT ++{0x2510, 0x11DB}, // SEQ_DATA_PORT ++{0x2510, 0x0915}, // SEQ_DATA_PORT ++{0x2510, 0x119B}, // SEQ_DATA_PORT ++{0x2510, 0x090F}, // SEQ_DATA_PORT ++{0x2510, 0x11BB}, // SEQ_DATA_PORT ++{0x2510, 0x121A}, // SEQ_DATA_PORT ++{0x2510, 0x1210}, // SEQ_DATA_PORT ++{0x2510, 0x1460}, // SEQ_DATA_PORT ++{0x2510, 0x1250}, // SEQ_DATA_PORT ++{0x2510, 0x1076}, // SEQ_DATA_PORT ++{0x2510, 0x10E6}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x15AB}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x13A8}, // SEQ_DATA_PORT ++{0x2510, 0x1240}, // SEQ_DATA_PORT ++{0x2510, 0x1260}, // SEQ_DATA_PORT ++{0x2510, 0x0923}, // SEQ_DATA_PORT ++{0x2510, 0x158D}, // SEQ_DATA_PORT ++{0x2510, 0x138D}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x0B09}, // SEQ_DATA_PORT ++{0x2510, 0x0108}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x1440}, // SEQ_DATA_PORT ++{0x2510, 0x091D}, // SEQ_DATA_PORT ++{0x2510, 0x1588}, // SEQ_DATA_PORT ++{0x2510, 0x1388}, // SEQ_DATA_PORT ++{0x2510, 0x092D}, // SEQ_DATA_PORT ++{0x2510, 0x1066}, // SEQ_DATA_PORT ++{0x2510, 0x0905}, // SEQ_DATA_PORT ++{0x2510, 0x0C08}, // SEQ_DATA_PORT ++{0x2510, 0x090B}, // SEQ_DATA_PORT ++{0x2510, 0x1441}, // SEQ_DATA_PORT ++{0x2510, 0x090D}, // SEQ_DATA_PORT ++{0x2510, 0x10E6}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x1262}, // SEQ_DATA_PORT ++{0x2510, 0x1260}, // SEQ_DATA_PORT ++{0x2510, 0x11BF}, // SEQ_DATA_PORT ++{0x2510, 0x11BB}, // SEQ_DATA_PORT ++{0x2510, 0x1066}, // SEQ_DATA_PORT ++{0x2510, 0x11FB}, // SEQ_DATA_PORT ++{0x2510, 0x0935}, // SEQ_DATA_PORT ++{0x2510, 0x11BB}, // SEQ_DATA_PORT ++{0x2510, 0x1263}, // SEQ_DATA_PORT ++{0x2510, 0x1260}, // SEQ_DATA_PORT ++{0x2510, 0x1400}, // SEQ_DATA_PORT ++{0x2510, 0x1510}, // SEQ_DATA_PORT ++{0x2510, 0x11B8}, // SEQ_DATA_PORT ++{0x2510, 0x12A0}, // SEQ_DATA_PORT ++{0x2510, 0x1200}, // SEQ_DATA_PORT ++{0x2510, 0x1026}, // SEQ_DATA_PORT ++{0x2510, 0x1000}, // SEQ_DATA_PORT ++{0x2510, 0x1342}, // SEQ_DATA_PORT ++{0x2510, 0x1100}, // SEQ_DATA_PORT ++{0x2510, 0x7A06}, // SEQ_DATA_PORT ++{0x2510, 0x0926}, // SEQ_DATA_PORT ++{0x2510, 0x0507}, // SEQ_DATA_PORT ++{0x2510, 0x0841}, // SEQ_DATA_PORT ++{0x2510, 0x3750}, // SEQ_DATA_PORT ++{0x2510, 0x2C2C}, // SEQ_DATA_PORT ++{0x2510, 0xFE02}, // SEQ_DATA_PORT ++{0x2510, 0xFE14}, // SEQ_DATA_PORT ++{0x3566, 0x3328}, // RESERVED_MFR_3566 ++{0x350C, 0x055F}, // RESERVED_MFR_350C ++{0x32D0, 0x3A02}, // RESERVED_MFR_32D0 ++{0x32D2, 0x3508}, // RESERVED_MFR_32D2 ++{0x32D4, 0x3702}, // RESERVED_MFR_32D4 ++{0x32D6, 0x3C04}, // RESERVED_MFR_32D6 ++{0x32DC, 0x370A}, // RESERVED_MFR_32DC ++ ++//Parallel Timing Setup ++{0x302A, 0x0009}, // VT_PIX_CLK_DIV ++{0x302C, 0x0001}, // VT_SYS_CLK_DIV ++{0x302E, 0x0003}, // PRE_PLL_CLK_DIV ++{0x3030, 0x0058}, // PLL_MULTIPLIER ++{0x3036, 0x0008}, // OP_WORD_CLK_DIV ++{0x3038, 0x0001}, // OP_SYS_CLK_DIV ++{0x30B0, 0x0A00}, // DIGITAL_TEST ++ ++//Readout Mode Configuration ++{0x30A2, 0x0001}, // X_ODD_INC_ ++{0x30A6, 0x0001}, // Y_ODD_INC_ ++{0x3040, 0x0000}, // READ_MODE ++{0x3044, 0x0400}, // DARK_CONTROL ++#ifdef AR0231_EMBEDDED_LINE ++{0x3064, 0x1982}, // SMIA_TEST ++#else ++{0x3064, 0x1802}, // SMIA_TEST ++#endif ++{0x33E0, 0x0880}, // RESERVED_MFR_33E0 ++{0x3180, 0x0080}, // RESERVED_MFR_3180 ++{0x33E4, 0x0080}, // RESERVED_MFR_33E4 ++ ++#if 1 ++{0x3004, AR0231_X_START}, // X_ADDR_START_ ++{0x3008, AR0231_X_END}, // X_ADDR_END_ ++{0x3002, AR0231_Y_START}, // Y_ADDR_START_ ++{0x3006, AR0231_Y_END}, // Y_ADDR_END_ ++{0x3402, 0x0000 | AR0231_MAX_WIDTH}, // X_OUTPUT_CONTROL ++{0x3404, 0x0000 | AR0231_MAX_HEIGHT}, // Y_OUTPUT_CONTROL ++#else ++{0x3004, 0}, // X_ADDR_START_ ++{0x3008, 0x0787}, // X_ADDR_END_ ++{0x3002, 0x0000}, // Y_ADDR_START_ ++{0x3006, 0x04B7}, // Y_ADDR_END_ ++{0x3402, 0x0788}, // RESERVED_MFR_3402 ++{0x3402, 0x0F10}, // RESERVED_MFR_3402 ++{0x3404, 0x0440}, // RESERVED_MFR_3404 ++{0x3404, 0x0970}, // RESERVED_MFR_3404 ++#endif ++{0x3032, 0x0000}, // SCALING_MODE ++{0x3400, 0x0010}, // RESERVED_MFR_3400 ++ ++//3exp Timing and Exposure ++{0x3082, 0x0008}, // OPERATION_MODE_CTRL ++{0x30BA, 0x11E2}, // DIGITAL_CTRL ++{0x300A, 0x05AF}, // FRAME_LENGTH_LINES_ ++{0x300C, 0x07BA}, // LINE_LENGTH_PCK_ ++{0x3042, 0x0000}, // EXTRA_DELAY ++{0x3238, 0x0222}, // EXPOSURE_RATIO ++{0x1008, 0x0374}, // FINE_INTEGRATION_TIME_MIN ++{0x100C, 0x05AF}, // FINE_INTEGRATION_TIME2_MIN ++{0x100E, 0x07EA}, // FINE_INTEGRATION_TIME3_MIN ++{0x1010, 0x0139}, // FINE_INTEGRATION_TIME4_MIN ++{0x3012, 0x0163}, // COARSE_INTEGRATION_TIME_ ++{0x3014, 0x06A6}, // FINE_INTEGRATION_TIME_ ++{0x321E, 0x06A6}, // FINE_INTEGRATION_TIME2 ++{0x3222, 0x06A6}, // FINE_INTEGRATION_TIME3 ++{0x30B0, 0x0B02}, // DIGITAL_TEST ++{0x32EA, 0x3C0E}, // RESERVED_MFR_32EA ++{0x32EC, 0x72A1}, // RESERVED_MFR_32EC ++ ++//Parallel HDR 12 bit Output ++{0x31D0, 0x0001}, // COMPANDING ++{0x31AE, 0x0001}, // SERIAL_FORMAT ++{0x31AC, 0x140C}, // DATA_FORMAT_BITS ++ ++#if 0 // no need for front only camera ++/* Enable trigger input */ ++{0x340A, 0x00E0}, // GPIO_CONTROL1: GPIO1 is trigger ++{0x340C, 0x0002}, // GPIO_CONTROL2: GPIO1 is trigger ++{0x30CE, 0x0120}, // TRIGGER_MODE ++//{0x30DC, 0x0120}, // TRIGGER_DELAY ++{0x301A, 0x01D8}, // GPI pins enable ++#endif ++ ++{0x301A, 0x01DC}, // RESET_REGISTER - stream on ++ ++#if 1 ++{0x300A, AR0231_SENSOR_HEIGHT + 225}, // FRAME_LENGTH_LINES_ ++{0x300C, AR0231_SENSOR_WIDTH + 120}, // LINE_LENGTH_PCK_ ++/* the sequence must be updated to use following timings, now it is a hack */ ++{0x1008, 0x0fff}, // FINE_INTEGRATION_TIME_MIN ++{0x100C, 0x0fff}, // FINE_INTEGRATION_TIME2_MIN ++{0x100E, 0x0fff}, // FINE_INTEGRATION_TIME3_MIN ++{0x1010, 0x0fff}, // FINE_INTEGRATION_TIME4_MIN ++#endif ++}; +diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h b/drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h +new file mode 100644 +index 0000000..b5b8cb2 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h +@@ -0,0 +1,343 @@ ++/* ++ * ON Semiconductor AR0231 sensor camera wizard 1920x1080@30/BGGR/MIPI ++ * ++ * Copyright (C) 2018-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++/* Parallel Timing Setup 27MHz In 88 MHz Out */ ++static const struct ar0231_reg ar0231_regs_wizard_rev6_dvp[] = { ++{0x301A, 0x0001}, // reset ++{0x301A, 0x10D8}, // Stream off and setup parallel ++{0x3070, 0x0000}, // 1: Solid color test pattern, ++ // 2: Full color bar test pattern, ++ // 3: Fade to grey color bar test pattern, ++ //256: Walking 1 test pattern (12 bit) ++{0x3072, 0x0123}, // R ++{0x3074, 0x0456}, // G(GR row) ++{0x3076, 0x0abc}, // B ++{0x3078, 0x0def}, // G(GB row) ++#ifdef AR0231_DISPLAY_PATTERN_FIXED ++{0x3070, 0x0001}, ++#endif ++#ifdef AR0231_DISPLAY_PATTERN_COLOR_BAR ++{0x3070, 0x0002}, ++#endif ++ ++//Recommended Settings ++{0x3056, 0x0080}, // GREEN1_GAIN ++{0x305C, 0x0080}, // GREEN2_GAIN ++{0x3058, 0x0080}, // BLUE_GAIN ++{0x305A, 0x0080}, // RED_GAIN ++{0x3138, 0x000B}, // OTPM_TCFG_OPT ++{0x3372, 0xF54F}, // RESERVED_MFR_3372 ++{0x337A, 0x0D70}, // RESERVED_MFR_337A ++{0x337E, 0x1FFD}, // RESERVED_MFR_337E ++{0x3382, 0x00C0}, // RESERVED_MFR_3382 ++{0x3C04, 0x0E80}, // RESERVED_MFR_3C04 ++{0x3F90, 0x06E1}, // RESERVED_MFR_3F90 ++{0x3F92, 0x06E1}, // RESERVED_MFR_3F92 ++{0x350E, 0x1F14}, // RESERVED_MFR_350E ++{0x350E, 0xFF10}, // RESERVED_MFR_350E ++{0x3506, 0x4444}, // RESERVED_MFR_3506 ++{0x3508, 0x4444}, // RESERVED_MFR_3508 ++{0x350A, 0x4465}, // RESERVED_MFR_350A ++{0x350C, 0x055F}, // RESERVED_MFR_350C ++{0x3566, 0x9D38}, // RESERVED_MFR_3566 ++{0x3518, 0x1FFE}, // RESERVED_MFR_3518 ++{0x3520, 0xC688}, // RESERVED_MFR_3520 ++{0x3522, 0x88C0}, // RESERVED_MFR_3522 ++{0x3524, 0xC0C6}, // RESERVED_MFR_3524 ++{0x352C, 0xC6C6}, // RESERVED_MFR_352C ++{0x3528, 0x0900}, // RESERVED_MFR_3528 ++{0x3528, 0x9900}, // RESERVED_MFR_3528 ++{0x3528, 0x9909}, // RESERVED_MFR_3528 ++{0x3528, 0x9999}, // RESERVED_MFR_3528 ++{0x352A, 0x089F}, // RESERVED_MFR_352A ++{0x352E, 0x0001}, // RESERVED_MFR_352E ++{0x352E, 0x0011}, // RESERVED_MFR_352E ++{0x3530, 0x0400}, // RESERVED_MFR_3530 ++{0x3530, 0x4400}, // RESERVED_MFR_3530 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF00}, // RESERVED_MFR_3536 ++{0x3536, 0xFF02}, // RESERVED_MFR_3536 ++{0x3536, 0xFF06}, // RESERVED_MFR_3536 ++{0x3536, 0xFF06}, // RESERVED_MFR_3536 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x3538, 0xFFFF}, // RESERVED_MFR_3538 ++{0x353A, 0x9000}, // RESERVED_MFR_353A ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x353C, 0x3F00}, // RESERVED_MFR_353C ++{0x32EC, 0x72A1}, // RESERVED_MFR_32EC ++{0x3540, 0xC637}, // RESERVED_MFR_3540 ++{0x3540, 0xC637}, // RESERVED_MFR_3540 ++{0x3540, 0xC637}, // RESERVED_MFR_3540 ++{0x3542, 0x584B}, // RESERVED_MFR_3542 ++{0x3542, 0x464B}, // RESERVED_MFR_3542 ++{0x3544, 0x565A}, // RESERVED_MFR_3544 ++{0x3544, 0x4B5A}, // RESERVED_MFR_3544 ++{0x3546, 0x545A}, // RESERVED_MFR_3546 ++{0x3546, 0x5A5A}, // RESERVED_MFR_3546 ++{0x3548, 0x6400}, // RESERVED_MFR_3548 ++{0x3556, 0x101F}, // RESERVED_MFR_3556 ++{0x3566, 0x9D38}, // RESERVED_MFR_3566 ++{0x3566, 0x1D38}, // RESERVED_MFR_3566 ++{0x3566, 0x1D28}, // RESERVED_MFR_3566 ++{0x3566, 0x1128}, // RESERVED_MFR_3566 ++{0x3566, 0x1328}, // RESERVED_MFR_3566 ++{0x3566, 0x3328}, // RESERVED_MFR_3566 ++{0x3528, 0xDDDD}, // RESERVED_MFR_3528 ++ ++//Sequencer Update ++{0x2512, 0x8000}, // SEQ_CTRL_PORT ++{0x2510, 0x0905}, // SEQ_DATA_PORT ++{0x2510, 0x3350}, // SEQ_DATA_PORT ++{0x2510, 0x2004}, // SEQ_DATA_PORT ++{0x2510, 0x1460}, // SEQ_DATA_PORT ++{0x2510, 0x1578}, // SEQ_DATA_PORT ++{0x2510, 0x1360}, // SEQ_DATA_PORT ++{0x2510, 0x7B24}, // SEQ_DATA_PORT ++{0x2510, 0xFF24}, // SEQ_DATA_PORT ++{0x2510, 0xFF24}, // SEQ_DATA_PORT ++{0x2510, 0xEA24}, // SEQ_DATA_PORT ++{0x2510, 0x1022}, // SEQ_DATA_PORT ++{0x2510, 0x2410}, // SEQ_DATA_PORT ++{0x2510, 0x155A}, // SEQ_DATA_PORT ++{0x2510, 0x1342}, // SEQ_DATA_PORT ++{0x2510, 0x1400}, // SEQ_DATA_PORT ++{0x2510, 0x24FF}, // SEQ_DATA_PORT ++{0x2510, 0x24FF}, // SEQ_DATA_PORT ++{0x2510, 0x24EA}, // SEQ_DATA_PORT ++{0x2510, 0x2324}, // SEQ_DATA_PORT ++{0x2510, 0x647A}, // SEQ_DATA_PORT ++{0x2510, 0x2404}, // SEQ_DATA_PORT ++{0x2510, 0x052C}, // SEQ_DATA_PORT ++{0x2510, 0x400A}, // SEQ_DATA_PORT ++{0x2510, 0xFF0A}, // SEQ_DATA_PORT ++{0x2510, 0xFF0A}, // SEQ_DATA_PORT ++{0x2510, 0x1808}, // SEQ_DATA_PORT ++{0x2510, 0x3851}, // SEQ_DATA_PORT ++{0x2510, 0x1440}, // SEQ_DATA_PORT ++{0x2510, 0x0004}, // SEQ_DATA_PORT ++{0x2510, 0x0801}, // SEQ_DATA_PORT ++{0x2510, 0x0408}, // SEQ_DATA_PORT ++{0x2510, 0x1180}, // SEQ_DATA_PORT ++{0x2510, 0x15DC}, // SEQ_DATA_PORT ++{0x2510, 0x134C}, // SEQ_DATA_PORT ++{0x2510, 0x1002}, // SEQ_DATA_PORT ++{0x2510, 0x1016}, // SEQ_DATA_PORT ++{0x2510, 0x1181}, // SEQ_DATA_PORT ++{0x2510, 0x1189}, // SEQ_DATA_PORT ++{0x2510, 0x1056}, // SEQ_DATA_PORT ++{0x2510, 0x1210}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x0D08}, // SEQ_DATA_PORT ++{0x2510, 0x0913}, // SEQ_DATA_PORT ++{0x2510, 0x13C8}, // SEQ_DATA_PORT ++{0x2510, 0x092B}, // SEQ_DATA_PORT ++{0x2510, 0x1588}, // SEQ_DATA_PORT ++{0x2510, 0x1388}, // SEQ_DATA_PORT ++{0x2510, 0x090B}, // SEQ_DATA_PORT ++{0x2510, 0x11D9}, // SEQ_DATA_PORT ++{0x2510, 0x091D}, // SEQ_DATA_PORT ++{0x2510, 0x1441}, // SEQ_DATA_PORT ++{0x2510, 0x0903}, // SEQ_DATA_PORT ++{0x2510, 0x1214}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x10D6}, // SEQ_DATA_PORT ++{0x2510, 0x1210}, // SEQ_DATA_PORT ++{0x2510, 0x1212}, // SEQ_DATA_PORT ++{0x2510, 0x1210}, // SEQ_DATA_PORT ++{0x2510, 0x11DD}, // SEQ_DATA_PORT ++{0x2510, 0x11D9}, // SEQ_DATA_PORT ++{0x2510, 0x1056}, // SEQ_DATA_PORT ++{0x2510, 0x090B}, // SEQ_DATA_PORT ++{0x2510, 0x11DB}, // SEQ_DATA_PORT ++{0x2510, 0x0915}, // SEQ_DATA_PORT ++{0x2510, 0x119B}, // SEQ_DATA_PORT ++{0x2510, 0x090F}, // SEQ_DATA_PORT ++{0x2510, 0x11BB}, // SEQ_DATA_PORT ++{0x2510, 0x121A}, // SEQ_DATA_PORT ++{0x2510, 0x1210}, // SEQ_DATA_PORT ++{0x2510, 0x1460}, // SEQ_DATA_PORT ++{0x2510, 0x1250}, // SEQ_DATA_PORT ++{0x2510, 0x1076}, // SEQ_DATA_PORT ++{0x2510, 0x10E6}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x15AB}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x13A8}, // SEQ_DATA_PORT ++{0x2510, 0x1240}, // SEQ_DATA_PORT ++{0x2510, 0x1260}, // SEQ_DATA_PORT ++{0x2510, 0x0923}, // SEQ_DATA_PORT ++{0x2510, 0x158D}, // SEQ_DATA_PORT ++{0x2510, 0x138D}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x0B09}, // SEQ_DATA_PORT ++{0x2510, 0x0108}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x1440}, // SEQ_DATA_PORT ++{0x2510, 0x091D}, // SEQ_DATA_PORT ++{0x2510, 0x1588}, // SEQ_DATA_PORT ++{0x2510, 0x1388}, // SEQ_DATA_PORT ++{0x2510, 0x092D}, // SEQ_DATA_PORT ++{0x2510, 0x1066}, // SEQ_DATA_PORT ++{0x2510, 0x0905}, // SEQ_DATA_PORT ++{0x2510, 0x0C08}, // SEQ_DATA_PORT ++{0x2510, 0x090B}, // SEQ_DATA_PORT ++{0x2510, 0x1441}, // SEQ_DATA_PORT ++{0x2510, 0x090D}, // SEQ_DATA_PORT ++{0x2510, 0x10E6}, // SEQ_DATA_PORT ++{0x2510, 0x0901}, // SEQ_DATA_PORT ++{0x2510, 0x1262}, // SEQ_DATA_PORT ++{0x2510, 0x1260}, // SEQ_DATA_PORT ++{0x2510, 0x11BF}, // SEQ_DATA_PORT ++{0x2510, 0x11BB}, // SEQ_DATA_PORT ++{0x2510, 0x1066}, // SEQ_DATA_PORT ++{0x2510, 0x11FB}, // SEQ_DATA_PORT ++{0x2510, 0x0935}, // SEQ_DATA_PORT ++{0x2510, 0x11BB}, // SEQ_DATA_PORT ++{0x2510, 0x1263}, // SEQ_DATA_PORT ++{0x2510, 0x1260}, // SEQ_DATA_PORT ++{0x2510, 0x1400}, // SEQ_DATA_PORT ++{0x2510, 0x1510}, // SEQ_DATA_PORT ++{0x2510, 0x11B8}, // SEQ_DATA_PORT ++{0x2510, 0x12A0}, // SEQ_DATA_PORT ++{0x2510, 0x1200}, // SEQ_DATA_PORT ++{0x2510, 0x1026}, // SEQ_DATA_PORT ++{0x2510, 0x1000}, // SEQ_DATA_PORT ++{0x2510, 0x1342}, // SEQ_DATA_PORT ++{0x2510, 0x1100}, // SEQ_DATA_PORT ++{0x2510, 0x7A06}, // SEQ_DATA_PORT ++{0x2510, 0x0915}, // SEQ_DATA_PORT ++{0x2510, 0x0507}, // SEQ_DATA_PORT ++{0x2510, 0x0841}, // SEQ_DATA_PORT ++{0x2510, 0x3750}, // SEQ_DATA_PORT ++{0x2510, 0x2C2C}, // SEQ_DATA_PORT ++{0x2510, 0xFE05}, // SEQ_DATA_PORT ++{0x2510, 0xFE13}, // SEQ_DATA_PORT ++{0x1008, 0x0361}, // FINE_INTEGRATION_TIME_MIN ++{0x100C, 0x0589}, // FINE_INTEGRATION_TIME2_MIN ++{0x100E, 0x07B1}, // FINE_INTEGRATION_TIME3_MIN ++{0x1010, 0x0139}, // FINE_INTEGRATION_TIME4_MIN ++{0x3230, 0x0304}, // FINE_CORRECTION ++{0x3232, 0x052C}, // FINE_CORRECTION2 ++{0x3234, 0x0754}, // FINE_CORRECTION3 ++{0x3236, 0x00DC}, // FINE_CORRECTION4 ++{0x3566, 0x3328}, // RESERVED_MFR_3566 ++{0x350C, 0x055F}, // RESERVED_MFR_350C ++{0x32D0, 0x3A02}, // RESERVED_MFR_32D0 ++{0x32D2, 0x3508}, // RESERVED_MFR_32D2 ++{0x32D4, 0x3702}, // RESERVED_MFR_32D4 ++{0x32D6, 0x3C04}, // RESERVED_MFR_32D6 ++{0x32DC, 0x370A}, // RESERVED_MFR_32DC ++ ++//Parallel Timing Setup 27MHz In 88 MHz Out ++{0x302A, 0x0009}, // VT_PIX_CLK_DIV ++{0x302C, 0x0001}, // VT_SYS_CLK_DIV ++{0x302E, 0x0003}, // PRE_PLL_CLK_DIV ++{0x3030, 0x0058}, // PLL_MULTIPLIER ++{0x3036, 0x0008}, // OP_WORD_CLK_DIV ++{0x3038, 0x0001}, // OP_SYS_CLK_DIV ++{0x30B0, 0x0B02}, // DIGITAL_TEST ++ ++//Readout Mode Configuration ++{0x30A2, 0x0001}, // X_ODD_INC_ ++{0x30A6, 0x0001}, // Y_ODD_INC_ ++{0x3040, 0x0000}, // READ_MODE ++{0x3082, 0x0008}, // OPERATION_MODE_CTRL ++{0x30BA, 0x11E2}, // DIGITAL_CTRL ++{0x3044, 0x0400}, // DARK_CONTROL ++#ifdef AR0231_EMBEDDED_LINE ++{0x3064, 0x1982}, // SMIA_TEST ++#else ++{0x3064, 0x1802}, // SMIA_TEST ++#endif ++{0x33E0, 0x0880}, // RESERVED_MFR_33E0 ++{0x3180, 0x0080}, // RESERVED_MFR_3180 ++{0x33E4, 0x0080}, // RESERVED_MFR_33E4 ++{0x33E0, 0x0C80}, // RESERVED_MFR_33E0 ++ ++#if 1 ++{0x3004, AR0231_X_START}, // X_ADDR_START_ ++{0x3008, AR0231_X_END}, // X_ADDR_END_ ++{0x3002, AR0231_Y_START}, // Y_ADDR_START_ ++{0x3006, AR0231_Y_END}, // Y_ADDR_END_ ++{0x3402, 0x0000 | AR0231_MAX_WIDTH}, // X_OUTPUT_CONTROL ++{0x3404, 0x0000 | AR0231_MAX_HEIGHT}, // Y_OUTPUT_CONTROL ++#else ++{0x3004, 0}, // X_ADDR_START_ ++{0x3008, 0x0787}, // X_ADDR_END_ ++{0x3002, 0x0000}, // Y_ADDR_START_ ++{0x3006, 0x04B7}, // Y_ADDR_END_ ++{0x3402, 0x0788}, // RESERVED_MFR_3402 ++{0x3402, 0x0F10}, // RESERVED_MFR_3402 ++{0x3404, 0x0440}, // RESERVED_MFR_3404 ++{0x3404, 0x0970}, // RESERVED_MFR_3404 ++#endif ++{0x3032, 0x0000}, // SCALING_MODE ++{0x3400, 0x0010}, // RESERVED_MFR_3400 ++ ++//3exp Timing and Exposure ++{0x3082, 0x0008}, // OPERATION_MODE_CTRL ++{0x30BA, 0x11E2}, // DIGITAL_CTRL ++{0x300A, 0x05CA}, // FRAME_LENGTH_LINES_ ++{0x300C, 0x07BA}, // LINE_LENGTH_PCK_ ++{0x3042, 0x0000}, // EXTRA_DELAY ++{0x3238, 0x0222}, // EXPOSURE_RATIO ++{0x3012, 0x0163}, // COARSE_INTEGRATION_TIME_ ++{0x3014, 0x08CC}, // FINE_INTEGRATION_TIME_ ++{0x321E, 0x08CC}, // FINE_INTEGRATION_TIME2 ++{0x3222, 0x0254}, // FINE_INTEGRATION_TIME3 ++{0x30B0, 0x0A00}, // DIGITAL_TEST ++{0x32EA, 0x3C0E}, // RESERVED_MFR_32EA ++{0x32EC, 0x72A1}, // RESERVED_MFR_32EC ++ ++//Parallel HDR 12 bit Output ++{0x31D0, 0x0001}, // COMPANDING ++{0x31AE, 0x0001}, // SERIAL_FORMAT ++{0x31AC, 0x140C}, // DATA_FORMAT_BITS ++ ++#if 0 // no need for front only camera ++/* Enable trigger input */ ++{0x340A, 0x00E0}, // GPIO_CONTROL1: GPIO1 is trigger ++{0x340C, 0x0002}, // GPIO_CONTROL2: GPIO1 is trigger ++{0x30CE, 0x0120}, // TRIGGER_MODE ++//{0x30DC, 0x0120}, // TRIGGER_DELAY ++{0x301A, 0x01D8}, // GPI pins enable ++#endif ++ ++{0x301A, 0x01DC}, // RESET_REGISTER - stream on ++ ++#if 1 ++{0x300A, AR0231_SENSOR_HEIGHT + 225}, // FRAME_LENGTH_LINES_ ++{0x300C, AR0231_SENSOR_WIDTH + 120}, // LINE_LENGTH_PCK_ ++/* the sequence must be updated to use following timings, now it is a hack */ ++{0x1008, 0x0fff}, // FINE_INTEGRATION_TIME_MIN ++{0x100C, 0x0fff}, // FINE_INTEGRATION_TIME2_MIN ++{0x100E, 0x0fff}, // FINE_INTEGRATION_TIME3_MIN ++{0x1010, 0x0fff}, // FINE_INTEGRATION_TIME4_MIN ++#endif ++}; +diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h b/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h +new file mode 100644 +index 0000000..f3485f5 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h +@@ -0,0 +1,445 @@ ++/* ++ * ON Semiconductor AR0231 sensor camera wizard 1928x1208@30/BGGR/MIPI ++ * ++ * Copyright (C) 2018-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++/* 3Exp HDR Full Resolution Mode MIPI 4lane 12bit 30FPS, XCLK=27MHz */ ++static const struct ar0231_reg ar0231_regs_wizard_rev7[] = { ++{0x301A, 0x18}, // MIPI, stream OFF ++{AR0231_DELAY, 200}, // Wait 200ms ++ ++{0x3070, 0x0000}, // 1: Solid color test pattern, ++ // 2: Full color bar test pattern, ++ // 3: Fade to grey color bar test pattern, ++ //256: Walking 1 test pattern (12 bit) ++{0x3072, 0x0123}, // R ++{0x3074, 0x0456}, // G(GR row) ++{0x3076, 0x0abc}, // B ++{0x3078, 0x0def}, // G(GB row) ++#ifdef AR0231_DISPLAY_PATTERN_FIXED ++{0x3070, 0x0001}, ++#endif ++#ifdef AR0231_DISPLAY_PATTERN_COLOR_BAR ++{0x3070, 0x0002}, ++#endif ++{AR0231_DELAY, 100}, // Wait 100ms ++ ++#if 1 /* Sensor Setup */ ++#if 1 /* Recommended Settings */ ++{0x3092, 0x0C24}, ++{0x337A, 0x0C80}, ++{0x3520, 0x1288}, ++{0x3522, 0x880C}, ++{0x3524, 0x0C12}, ++{0x352C, 0x1212}, ++{0x354A, 0x007F}, ++{0x350C, 0x055C}, ++{0x3506, 0x3333}, ++{0x3508, 0x3333}, ++{0x3100, 0x4000}, ++{0x3280, 0x0FA0}, ++{0x3282, 0x0FA0}, ++{0x3284, 0x0FA0}, ++{0x3286, 0x0FA0}, ++{0x3288, 0x0FA0}, ++{0x328A, 0x0FA0}, ++{0x328C, 0x0FA0}, ++{0x328E, 0x0FA0}, ++{0x3290, 0x0FA0}, ++{0x3292, 0x0FA0}, ++{0x3294, 0x0FA0}, ++{0x3296, 0x0FA0}, ++{0x3298, 0x0FA0}, ++{0x329A, 0x0FA0}, ++{0x329C, 0x0FA0}, ++{0x329E, 0x0FA0}, ++#endif /* Recommended Settings */ ++ ++#if 1 /* Sequencer Update */ ++{0x2512, 0x8000}, ++{0x2510, 0x0905}, ++{0x2510, 0x3350}, ++{0x2510, 0x2004}, ++{0x2510, 0x1460}, ++{0x2510, 0x1578}, ++{0x2510, 0x0901}, ++{0x2510, 0x7B24}, ++{0x2510, 0xFF24}, ++{0x2510, 0xFF24}, ++{0x2510, 0xEA24}, ++{0x2510, 0x1022}, ++{0x2510, 0x2410}, ++{0x2510, 0x155A}, ++{0x2510, 0x0901}, ++{0x2510, 0x1400}, ++{0x2510, 0x24FF}, ++{0x2510, 0x24FF}, ++{0x2510, 0x24EA}, ++{0x2510, 0x2324}, ++{0x2510, 0x647A}, ++{0x2510, 0x2404}, ++{0x2510, 0x052C}, ++{0x2510, 0x400A}, ++{0x2510, 0xFF0A}, ++{0x2510, 0xFF0A}, ++{0x2510, 0x1008}, ++{0x2510, 0x3851}, ++{0x2510, 0x1440}, ++{0x2510, 0x0004}, ++{0x2510, 0x0801}, ++{0x2510, 0x0408}, ++{0x2510, 0x1180}, ++{0x2510, 0x2652}, ++{0x2510, 0x1518}, ++{0x2510, 0x0906}, ++{0x2510, 0x1348}, ++{0x2510, 0x1002}, ++{0x2510, 0x1016}, ++{0x2510, 0x1181}, ++{0x2510, 0x1189}, ++{0x2510, 0x1056}, ++{0x2510, 0x1210}, ++{0x2510, 0x0901}, ++{0x2510, 0x0D09}, ++{0x2510, 0x1413}, ++{0x2510, 0x8809}, ++{0x2510, 0x2B15}, ++{0x2510, 0x8809}, ++{0x2510, 0x0311}, ++{0x2510, 0xD909}, ++{0x2510, 0x1214}, ++{0x2510, 0x4109}, ++{0x2510, 0x0312}, ++{0x2510, 0x1409}, ++{0x2510, 0x0110}, ++{0x2510, 0xD612}, ++{0x2510, 0x1012}, ++{0x2510, 0x1212}, ++{0x2510, 0x1011}, ++{0x2510, 0xDD11}, ++{0x2510, 0xD910}, ++{0x2510, 0x5609}, ++{0x2510, 0x1511}, ++{0x2510, 0xDB09}, ++{0x2510, 0x1511}, ++{0x2510, 0x9B09}, ++{0x2510, 0x0F11}, ++{0x2510, 0xBB12}, ++{0x2510, 0x1A12}, ++{0x2510, 0x1014}, ++{0x2510, 0x6012}, ++{0x2510, 0x5010}, ++{0x2510, 0x7610}, ++{0x2510, 0xE609}, ++{0x2510, 0x0812}, ++{0x2510, 0x4012}, ++{0x2510, 0x6009}, ++{0x2510, 0x290B}, ++{0x2510, 0x0904}, ++{0x2510, 0x1440}, ++{0x2510, 0x0923}, ++{0x2510, 0x15C8}, ++{0x2510, 0x13C8}, ++{0x2510, 0x092C}, ++{0x2510, 0x1588}, ++{0x2510, 0x1388}, ++{0x2510, 0x0C09}, ++{0x2510, 0x0C14}, ++{0x2510, 0x4109}, ++{0x2510, 0x1112}, ++{0x2510, 0x6212}, ++{0x2510, 0x6011}, ++{0x2510, 0xBF11}, ++{0x2510, 0xBB10}, ++{0x2510, 0x6611}, ++{0x2510, 0xFB09}, ++{0x2510, 0x3511}, ++{0x2510, 0xBB12}, ++{0x2510, 0x6312}, ++{0x2510, 0x6014}, ++{0x2510, 0x0015}, ++{0x2510, 0x0011}, ++{0x2510, 0xB812}, ++{0x2510, 0xA012}, ++{0x2510, 0x0010}, ++{0x2510, 0x2610}, ++{0x2510, 0x0013}, ++{0x2510, 0x0011}, ++{0x2510, 0x0008}, ++{0x2510, 0x3053}, ++{0x2510, 0x4215}, ++{0x2510, 0x4013}, ++{0x2510, 0x4010}, ++{0x2510, 0x0210}, ++{0x2510, 0x1611}, ++{0x2510, 0x8111}, ++{0x2510, 0x8910}, ++{0x2510, 0x5612}, ++{0x2510, 0x1009}, ++{0x2510, 0x010D}, ++{0x2510, 0x0815}, ++{0x2510, 0xC015}, ++{0x2510, 0xD013}, ++{0x2510, 0x5009}, ++{0x2510, 0x1313}, ++{0x2510, 0xD009}, ++{0x2510, 0x0215}, ++{0x2510, 0xC015}, ++{0x2510, 0xC813}, ++{0x2510, 0xC009}, ++{0x2510, 0x0515}, ++{0x2510, 0x8813}, ++{0x2510, 0x8009}, ++{0x2510, 0x0213}, ++{0x2510, 0x8809}, ++{0x2510, 0x0411}, ++{0x2510, 0xC909}, ++{0x2510, 0x0814}, ++{0x2510, 0x0109}, ++{0x2510, 0x0B11}, ++{0x2510, 0xD908}, ++{0x2510, 0x1400}, ++{0x2510, 0x091A}, ++{0x2510, 0x1440}, ++{0x2510, 0x0903}, ++{0x2510, 0x1214}, ++{0x2510, 0x0901}, ++{0x2510, 0x10D6}, ++{0x2510, 0x1210}, ++{0x2510, 0x1212}, ++{0x2510, 0x1210}, ++{0x2510, 0x11DD}, ++{0x2510, 0x11D9}, ++{0x2510, 0x1056}, ++{0x2510, 0x0917}, ++{0x2510, 0x11DB}, ++{0x2510, 0x0913}, ++{0x2510, 0x11FB}, ++{0x2510, 0x0905}, ++{0x2510, 0x11BB}, ++{0x2510, 0x121A}, ++{0x2510, 0x1210}, ++{0x2510, 0x1460}, ++{0x2510, 0x1250}, ++{0x2510, 0x1076}, ++{0x2510, 0x10E6}, ++{0x2510, 0x0901}, ++{0x2510, 0x15A8}, ++{0x2510, 0x0901}, ++{0x2510, 0x13A8}, ++{0x2510, 0x1240}, ++{0x2510, 0x1260}, ++{0x2510, 0x0925}, ++{0x2510, 0x13AD}, ++{0x2510, 0x0902}, ++{0x2510, 0x0907}, ++{0x2510, 0x1588}, ++{0x2510, 0x0901}, ++{0x2510, 0x138D}, ++{0x2510, 0x0B09}, ++{0x2510, 0x0914}, ++{0x2510, 0x4009}, ++{0x2510, 0x0B13}, ++{0x2510, 0x8809}, ++{0x2510, 0x1C0C}, ++{0x2510, 0x0920}, ++{0x2510, 0x1262}, ++{0x2510, 0x1260}, ++{0x2510, 0x11BF}, ++{0x2510, 0x11BB}, ++{0x2510, 0x1066}, ++{0x2510, 0x090A}, ++{0x2510, 0x11FB}, ++{0x2510, 0x093B}, ++{0x2510, 0x11BB}, ++{0x2510, 0x1263}, ++{0x2510, 0x1260}, ++{0x2510, 0x1400}, ++{0x2510, 0x1508}, ++{0x2510, 0x11B8}, ++{0x2510, 0x12A0}, ++{0x2510, 0x1200}, ++{0x2510, 0x1026}, ++{0x2510, 0x1000}, ++{0x2510, 0x1300}, ++{0x2510, 0x1100}, ++{0x2510, 0x437A}, ++{0x2510, 0x0609}, ++{0x2510, 0x0B05}, ++{0x2510, 0x0708}, ++{0x2510, 0x4137}, ++{0x2510, 0x502C}, ++{0x2510, 0x2CFE}, ++{0x2510, 0x15FE}, ++{0x2510, 0x0C2C}, ++ ++{0x32e6, 0xe0}, ++{0x1008, 0x36f}, ++{0x100c, 0x58f}, ++{0x100e, 0x7af}, ++{0x1010, 0x14f}, ++ ++{0x3230, 0x312}, ++{0x3232, 0x532}, ++{0x3234, 0x752}, ++{0x3236, 0xf2}, ++#endif /* Sequencer Update */ ++ ++//{0x3566, 0x3328}, // clear bit6 ++{0x32D0, 0x3A02}, ++{0x32D2, 0x3508}, ++{0x32D4, 0x3702}, ++{0x32D6, 0x3C04}, ++{0x32DC, 0x370A}, ++{0x30B0, 0x800}, // clear bit9 ++#endif /* Sensor Setup */ ++ ++#if 1 /* Serial 12-bit Timing Setup */ ++/* PCLK=24Mhz/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ ++/* PCLK=24Mhz/2 *44/1/12 *2= 88Mhz - TI serializers */ ++{0x302E, 2}, // pre_pll_clk_div ++{0x3030, 44}, // pll_multiplier ++{0x302C, 1}, // vt_sys_clk_div (P1 divider) ++{0x302A, 6}, // vt_pix_clk_div (P2 divider) ++{0x3038, 1}, // op_sys_clk_div (P3 divider) ++{0x3036, 12}, // op_word_clk_div (P4 divider) ++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 ++#endif /* Serial 12-bit Timing Setup */ ++ ++#if 1 /* Readout Mode Configuration */ ++{0x30A2, 1}, // x_odd_inc_ ++{0x30A6, 1}, // y_odd_inc_ ++{0x3040, 0}, // read_mode ++//{0x3082, 0x8}, // operation_mode_ctrl ++//{0x30BA, 0x11E2}, // digital_ctrl ++{0x3044, 0x400}, // dark_control ++#ifdef AR0231_EMBEDDED_LINE ++{0x3064, 0x1982}, // SMIA_TEST ++#else ++{0x3064, 0x1802}, // SMIA_TEST ++#endif ++//{0x33E0, 0xC80}, ++//{0x3180, 0x80}, ++//{0x33E4, 0x80}, ++#endif /* Readout Mode Configuration */ ++ ++#if 1 /* Full Res FOV */ ++{0x3004, AR0231_X_START}, // X_ADDR_START_ ++{0x3008, AR0231_X_END}, // X_ADDR_END_ ++{0x3002, AR0231_Y_START}, // Y_ADDR_START_ ++{0x3006, AR0231_Y_END}, // Y_ADDR_END_ ++{0x3032, 0x0}, // scaling_mode ++{0x3400, 0x10}, ++{0x3402, 0x0000 | AR0231_MAX_WIDTH}, // X_OUTPUT_CONTROL ++{0x3404, 0x0000 | AR0231_MAX_HEIGHT}, // Y_OUTPUT_CONTROL ++#endif /* Full Res FOV */ ++ ++#if 1 /* 3exp Timing and Exposure */ ++{0x3082, 0x8}, // operation_mode_ctrl ++{0x30BA, 0x11E2}, // digital_ctrl: num_exp_max=2 ++ ++/* Row and Pixel Timing */ ++{0x300C, 1674}, // line_length_pck_ ++{0x300A, 1314}, // frame_length_lines_ ++{0x3042, 0}, // extra_delay ++ ++/* Exposure Settings */ ++//{0x3238, 0x222}, // exposure_ratio ++{0x3012, 355}, // coarse_integration_time_ ++{0x3014, 1874}, // fine_integration_time_ ++{0x321E, 1874}, // fine_integration_time2 ++{0x3222, 1874}, // fine_integration_time3 ++{0x30B0, 0x800}, // digital_test: set bit11 ++{0x32EA, 0x3C0E}, ++{0x32EC, 0x72A1}, ++#endif /* 3exp Timing and Exposure - Serial */ ++ ++#if 1 /* HDR 12 bit Output */ ++{0x31D0, 1}, // companding ++{0x31AC, 0x140C}, // data_format_bits: RAW20, OUT12 ++#endif /* HDR 12 bit Output */ ++ ++#if 1 /* MIPI 12 bit Settings */ ++{0x31AE, 0x204}, // serial_format: MIPI 4 lanes ++{0x3342, 0x2c2c}, // default, DT=0x12, DT=0x2C ++{0x3346, 0x2c2c}, // default, DT=0x12, DT=0x2C ++{0x334A, 0x2c2c}, // default, DT=0x12, DT=0x2C ++{0x334E, 0x2c2c}, // default, DT=0x12, DT=0x2C ++//{0x3344, 0x0011}, // default, VC=0 ++//{0x3348, 0x0111}, // default, VC=1 ++//{0x334C, 0x0211}, // default, VC=2 ++//{0x3350, 0x0311}, // default, VC=3 ++//{0x31B0, 0x49}, // frame_preamble ++//{0x31B2, 0x33}, // line_preamble ++{0x31B4, 0x2185}, ++{0x31B6, 0x1146}, ++{0x31B8, 0x3047}, ++{0x31BA, 0x186}, ++{0x31BC, 0x805}, ++#endif /* MIPI 12 bit Settings */ ++ ++/* FPS = 105MHz / reg0x300A / reg0x300C * (DES_XTAL/27MHz), DES_XTAL=23.5MHz */ ++{0x300A, AR0231_SENSOR_HEIGHT + 100}, // Frame_length_Lines ++{0x300C, AR0231_SENSOR_WIDTH + 550}, // Line_length_pck ++{0x3012, 0x144}, //Integration_time ++ ++#if 0 /* Enable trigger input */ ++{0x340A, 0x00E0}, // GPIO_CONTROL1: GPIO0 is trigger ++{0x340C, 0x0002}, // GPIO_CONTROL2: GPIO0 is trigger ++{0x30CE, 0x0120}, // TRIGGER_MODE ++//{0x30DC, 0x0120}, // TRIGGER_DELAY ++{0x301A, 0x0118}, // GPI pins enable ++#endif ++}; ++ ++/* 3Exp HDR Full Resolution Mode Parallel 12bit 30FPS, XCLK=24MHz */ ++static const struct ar0231_reg ar0231_regs_wizard_rev7_dvp[] = { ++#if 1 /* Parallel Timing Setup */ ++/* PCLK=24Mhz/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 */ ++/* PCLK=24Mhz/3 *88/1/8 = 88Mhz - TI serializers */ ++{0x302A, 8}, // vt_pix_clk_div (P2 divider) ++{0x302C, 1}, // vt_sys_clk_div (P1 divider) ++{0x302E, 3}, // pre_pll_clk_div ++{0x3030, 88}, // pll_multiplier ++{0x3036, 8}, // op_word_clk_div (P4 divider) ++{0x3038, 1}, // op_sys_clk_div (P3 divider) ++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0 ++#endif ++ ++#if 1 /* 3exp Timing and Exposure - Parallel */ ++{0x3082, 0x8}, // operation_mode_ctrl ++{0x30BA, 0x11E2}, // digital_ctrl: num_exp_max=2 ++ ++/* Row and Pixel Timing */ ++#if 1 ++{0x300A, AR0231_SENSOR_HEIGHT + 225}, // frame_length_lines_ ++{0x300C, AR0231_SENSOR_WIDTH + 120}, // line_length_pck_ ++#else ++{0x300C, 1978}, // line_length_pck_ ++{0x300A, 1482}, // frame_length_lines_ ++#endif ++{0x3042, 0}, // extra_delay ++ ++/* Exposure Settings */ ++//{0x3238, 0x222}, // exposure_ratio ++//{0x3012, 355}, // coarse_integration_time_ ++{0x3014, 2178}, // fine_integration_time_ ++{0x321E, 2178}, // fine_integration_time2 ++{0x3222, 2178}, // fine_integration_time3 ++{0x30B0, 0x800}, // digital_test: set bit11 ++{0x32EA, 0x3C0E}, ++{0x32EC, 0x72A1}, ++#endif /* 3exp Timing and Exposure - Parallel */ ++ ++#if 1 /* Parallel HDR 12 bit Output */ ++{0x31AE, 0x001}, // serial_format: ++#endif ++ ++{0x301A, 0x01d8}, // RESET_REGISTER parallel pins enable ++}; +-- +2.7.4 + + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0507-media-i2c-ap0101-ap0201-fix-vendor-name-fsin-fix-on-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0507-media-i2c-ap0101-ap0201-fix-vendor-name-fsin-fix-on-.patch new file mode 100644 index 00000000..45b07d44 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0507-media-i2c-ap0101-ap0201-fix-vendor-name-fsin-fix-on-.patch @@ -0,0 +1,97 @@ +From 9d8155ae4fbf9f480c993447f6f4753ec2f9c3bf Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Apr 2020 11:03:16 +0300 +Subject: [PATCH] media: i2c: ap0101,ap0201: fix vendor name, fsin fix on ap0102 + +This fixes vendor name, fix fsync on ap0102 + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c | 14 ++++++++++++-- + drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h | 8 ++++++++ + drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c | 6 ++++-- + 3 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c +index d2a6ff9..526d4ea 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c ++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c +@@ -27,7 +27,9 @@ static const int ap0101_i2c_addr[] = {0x5d, 0x48}; + + #define AP0101_PID_REG 0x0000 + #define AP0101_REV_REG 0x0058 ++#define AP0100_PID 0x0062 + #define AP0101_PID 0x0160 ++#define AP0102_PID 0x0064 + + #define AP0101_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8 + +@@ -434,7 +436,15 @@ static int ap0101_initialize(struct i2c_client *client) + priv->max_height = AP0101_MAX_HEIGHT; + #endif + /* Program wizard registers */ +- ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard)); ++ switch (pid) { ++ case AP0100_PID: ++ case AP0101_PID: ++ ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard)); ++ break; ++ case AP0102_PID: ++ ap0101_set_regs(client, ap0102_regs_wizard, ARRAY_SIZE(ap0102_regs_wizard)); ++ break; ++ } + /* Read OTP IDs */ + ap0101_otp_id_read(client); + +@@ -471,7 +481,7 @@ static const struct i2c_device_id ap0101_id[] = { + MODULE_DEVICE_TABLE(i2c, ap0101_id); + + static const struct of_device_id ap0101_of_ids[] = { +- { .compatible = "onsemi,ap0101", }, ++ { .compatible = "onnn,ap0101", }, + { } + }; + MODULE_DEVICE_TABLE(of, ap0101_of_ids); +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h +index d0d6205..5755b87 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h ++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h +@@ -26,3 +26,11 @@ static const struct ap0101_reg ap0101_regs_wizard[] = { + {0x0040, 0x8100}, + {AP0101_DELAY, 100}, + }; ++ ++static const struct ap0101_reg ap0102_regs_wizard[] = { ++/* enable FSIN */ ++{0xc890, 0x0303}, ++{0xfc00, 0x2800}, ++{0x0040, 0x8100}, ++{AP0101_DELAY, 100}, ++}; +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +index 7b274ce..10bf6f7 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c ++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +@@ -27,7 +27,9 @@ static const int ap0201_i2c_addr[] = {0x5d, 0x48}; + + #define AP0201_PID_REG 0x0000 + #define AP0201_REV_REG 0x0058 +-#define AP0201_PID 0x0064 ++#define AP0200_PID 0x0062 ++#define AP0201_PID 0x0160 ++#define AP0202_PID 0x0064 + + #define AP0201_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8 + +@@ -446,7 +448,7 @@ static const struct i2c_device_id ap0201_id[] = { + MODULE_DEVICE_TABLE(i2c, ap0201_id); + + static const struct of_device_id ap0201_of_ids[] = { +- { .compatible = "onsemi,ap0201", }, ++ { .compatible = "onnn,ap0201", }, + { } + }; + MODULE_DEVICE_TABLE(of, ap0201_of_ids); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0508-media-i2c-fix-indentation.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0508-media-i2c-fix-indentation.patch new file mode 100644 index 00000000..98a00d29 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0508-media-i2c-fix-indentation.patch @@ -0,0 +1,46 @@ +From b6a59d9176b872d7247b5829f5d3112376fc4877 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Apr 2020 11:05:05 +0300 +Subject: [PATCH] media: i2c: fix indentation + +Indentation fixes + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/fpdlink/ti9x4.c | 2 +- + drivers/media/i2c/soc_camera/gmsl/max96712.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c +index a50201d..56b5ed8a 100644 +--- a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c ++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c +@@ -218,7 +218,7 @@ static void ti9x4_initial_setup(struct i2c_client *client) + #else + reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */ + reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */ +- reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */ ++ reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */ + reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */ + reg8_write(client, 0x18, 0x00); /* Disable FrameSync - must be enabled after all cameras are set up */ + #endif +diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c +index 02ccc38..c4cdf0e 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max96712.c ++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c +@@ -494,9 +494,9 @@ static int max96712_gmsl1_link_serializer_setup(struct max96712_priv *priv, int + /* GMSL setup */ + ser_write(0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ + ser_write(0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */ +- (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */ +- (0x80) | /* DBL=1 in serializer */ +- (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */ ++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */ ++ (0x80) | /* DBL=1 in serializer */ ++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */ + usleep_range(2000, 2500); + ser_write(0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */ + usleep_range(2000, 2500); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0509-media-i2c-fix-broken-old-LVDS-imagers.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0509-media-i2c-fix-broken-old-LVDS-imagers.patch new file mode 100644 index 00000000..4bd48b82 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0509-media-i2c-fix-broken-old-LVDS-imagers.patch @@ -0,0 +1,33 @@ +From e24f11423cea901af73faaacbd3c1614f4be2954 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Apr 2020 11:06:12 +0300 +Subject: [PATCH] media: i2c: fix broken old LVDS imagers + +This fixes broken old LVDS imagers from support. +We temporary need to support these + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/Makefile | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile +index 5e08254..8640bac 100644 +--- a/drivers/media/i2c/soc_camera/Makefile ++++ b/drivers/media/i2c/soc_camera/Makefile +@@ -11,10 +11,11 @@ obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o + obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o + obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o + obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o +-obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov106xx.o + obj-$(CONFIG_SOC_CAMERA_IMX219) += imx219.o + + obj-$(CONFIG_SOC_CAMERA_AR0147) += ar0147.o + obj-y += imagers/ + obj-y += gmsl/ + obj-y += fpdlink/ ++ ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov106xx.o +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0510-arm64-dts-renesas-add-camera-dtsi-file.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0510-arm64-dts-renesas-add-camera-dtsi-file.patch new file mode 100644 index 00000000..eda17d66 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0510-arm64-dts-renesas-add-camera-dtsi-file.patch @@ -0,0 +1,120 @@ +From 048fcef8ad30f5a5158b3f3d2c2cf1c63fe51b90 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Apr 2020 11:15:37 +0300 +Subject: [PATCH] arm64: dts: renesas: add camera dtsi file + +This adds camera dtsi file for common data + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/camera.dtsi | 30 ++++++++++++++++++++++ + .../dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts | 22 +--------------- + .../boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts | 22 +--------------- + 3 files changed, 32 insertions(+), 42 deletions(-) + create mode 100644 arch/arm64/boot/dts/renesas/camera.dtsi + +diff --git a/arch/arm64/boot/dts/renesas/camera.dtsi b/arch/arm64/boot/dts/renesas/camera.dtsi +new file mode 100644 +index 0000000..0216327 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/camera.dtsi +@@ -0,0 +1,30 @@ ++/* ++ * Device Tree Source for the LVDS cameras ++ * ++ * Copyright (C) 2020 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#define COMPATIBLE_CAMERAS \ ++ "onnn,ar0140", \ ++ "onnn,ar0143", \ ++ "onnn,ar0147", \ ++ "onnn,ar0231", \ ++ "onnn,ar0233", \ ++ "onnn,ap0101", \ ++ "onnn,ap0201", \ ++ "ovti,ov10635", \ ++ "ovti,ov10640", \ ++ "ovti,ov2311", \ ++ "ovti,ov2775", \ ++ "ovti,ov490", \ ++ "ovti,ov495", \ ++ "ovti,ox01d10", \ ++ "ovti,ox03a", \ ++ "sony,imx390", \ ++ "sony,isx016", \ ++ "sony,isx019", \ ++ "dummy,camera" +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts +index 155b73f..4d284b1 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts +@@ -12,27 +12,7 @@ + #include <dt-bindings/gpio/gpio.h> + /* FDPLink output */ + //#include "vb-fdplink-output.dtsi" +- +-#define COMPATIBLE_CAMERAS \ +-"onsemi,ar0140", \ +-"onsemi,ar0143", \ +-"onsemi,ar0147", \ +-"onsemi,ar0231", \ +-"onsemi,ar0233", \ +-"onsemi,ap0101", \ +-"onsemi,ap0201", \ +-"ovti,ov10635", \ +-"ovti,ov10640", \ +-"ovti,ov2311", \ +-"ovti,ov2775", \ +-"ovti,ov490", \ +-"ovti,ov495", \ +-"ovti,ox01d10", \ +-"ovti,ox03a", \ +-"sony,imx390", \ +-"sony,isx016", \ +-"sony,isx019", \ +-"dummy,camera" ++#include "camera.dtsi" + + / { + model = "Renesas V3HSK 2x2ch GMSL2 Videobox board based on r8a7798"; +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts +index 310061f..ac2d825 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts +@@ -12,27 +12,7 @@ + #include <dt-bindings/gpio/gpio.h> + /* FDPLink output */ + //#include "vb-fdplink-output.dtsi" +- +-#define COMPATIBLE_CAMERAS \ +-"onsemi,ar0140", \ +-"onsemi,ar0143", \ +-"onsemi,ar0147", \ +-"onsemi,ar0231", \ +-"onsemi,ar0233", \ +-"onsemi,ap0101", \ +-"onsemi,ap0201", \ +-"ovti,ov10635", \ +-"ovti,ov10640", \ +-"ovti,ov2311", \ +-"ovti,ov2775", \ +-"ovti,ov490", \ +-"ovti,ov495", \ +-"ovti,ox01d10", \ +-"ovti,ox03a", \ +-"sony,imx390", \ +-"sony,isx016", \ +-"sony,isx019", \ +-"dummy,camera" ++#include "camera.dtsi" + + / { + model = "Renesas V3HSK 4ch GMSL2 Videobox board based on r8a77980"; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0511-media-i2c-ap0201-detect-AP0200-AP0202.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0511-media-i2c-ap0201-detect-AP0200-AP0202.patch new file mode 100644 index 00000000..dccf8c03 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0511-media-i2c-ap0201-detect-AP0200-AP0202.patch @@ -0,0 +1,85 @@ +From bc27eaaaddb5ebc94daa3a7f91d753162de944b9 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Apr 2020 16:33:49 +0300 +Subject: [PATCH 1/2] media: i2c: ap0201: detect AP0200, AP0202 + +This allows to detect AP0200 and AP0202 imagers + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + .../media/i2c/soc_camera/imagers/ap0201_ar023x.c | 6 +++--- + drivers/media/i2c/soc_camera/imagers/dummy.c | 24 +++++++++++----------- + 2 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +index 10bf6f7..ad18e2e 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c ++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +@@ -411,11 +411,11 @@ static int ap0201_initialize(struct i2c_client *client) + + /* check product ID */ + reg16_read16(client, AP0201_PID_REG, &pid); +- if (pid == AP0201_PID) ++ if (pid == AP0200_PID || pid == AP0201_PID || pid == AP0202_PID) + break; + } + +- if (pid != AP0201_PID) { ++ if (pid != AP0200_PID && pid != AP0201_PID && pid != AP0202_PID) { + dev_dbg(&client->dev, "Product ID error %x\n", pid); + return -ENODEV; + } +@@ -436,7 +436,7 @@ static int ap0201_initialize(struct i2c_client *client) + /* Read OTP IDs */ + ap0201_otp_id_read(client); + +- dev_info(&client->dev, "ap0201 PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ dev_info(&client->dev, "ap020X PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", + pid, rev, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + return 0; + } +diff --git a/drivers/media/i2c/soc_camera/imagers/dummy.c b/drivers/media/i2c/soc_camera/imagers/dummy.c +index d213fff..e4070fc 100644 +--- a/drivers/media/i2c/soc_camera/imagers/dummy.c ++++ b/drivers/media/i2c/soc_camera/imagers/dummy.c +@@ -343,6 +343,18 @@ static int dummy_initialize(struct i2c_client *client) + return 0; + } + ++static const struct i2c_device_id dummy_id[] = { ++ { "dummy-camera", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, dummy_id); ++ ++static const struct of_device_id dummy_of_ids[] = { ++ { .compatible = "dummy,camera", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, dummy_of_ids); ++ + static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv) + { + if (of_property_read_u32(np, "dummy,width", &priv->max_width)) +@@ -463,18 +475,6 @@ static int dummy_remove(struct i2c_client *client) + return 0; + } + +-static const struct i2c_device_id dummy_id[] = { +- { "dummy-camera", 0 }, +- { } +-}; +-MODULE_DEVICE_TABLE(i2c, dummy_id); +- +-static const struct of_device_id dummy_of_ids[] = { +- { .compatible = "dummy-camera", }, +- { } +-}; +-MODULE_DEVICE_TABLE(of, dummy_of_ids); +- + static struct i2c_driver dummy_i2c_driver = { + .driver = { + .name = "dummy-camera", +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0512-arm64-dts-renesas-add-H3-GMSL2-Videobox.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0512-arm64-dts-renesas-add-H3-GMSL2-Videobox.patch new file mode 100644 index 00000000..198d1daf --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0512-arm64-dts-renesas-add-H3-GMSL2-Videobox.patch @@ -0,0 +1,1949 @@ +From fabd912331128d45339dd6f9282aa623c1b92bb1 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 30 Apr 2020 16:34:44 +0300 +Subject: [PATCH 2/2] arm64: dts: renesas: add H3 GMSL2 Videobox + +This is GMSL2 RCAR H3 Videobox 2.1 support +This is interim support since all serializers soon will +be integrated to PnP. + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/Makefile | 1 + + .../renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts | 68 + + .../dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts | 68 + + arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi | 1662 ++++++++++++++++++++ + arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi | 90 ++ + 5 files changed, 1889 insertions(+) + create mode 100644 arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts + create mode 100644 arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts + create mode 100644 arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi + create mode 100644 arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi + +diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile +index f18c742..cd53aaf 100644 +--- a/arch/arm64/boot/dts/renesas/Makefile ++++ b/arch/arm64/boot/dts/renesas/Makefile +@@ -26,6 +26,7 @@ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-kf.dtb r8a7795-h3ulcb-4x2g-kf.dtb r + dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vb.dtb r8a7795-es1-h3ulcb-vb.dtb r8a7795-h3ulcb-4x2g-vb.dtb + dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vb2.dtb r8a7795-es1-h3ulcb-vb2.dtb r8a7795-h3ulcb-4x2g-vb2.dtb + dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vb2.1.dtb r8a7795-h3ulcb-4x2g-vb2.1.dtb ++dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vb2.1-gmsl2.dtb r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dtb + dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vbm.dtb r8a7795-es1-h3ulcb-vbm.dtb r8a7795-h3ulcb-4x2g-vbm.dtb + dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-m3nulcb-kf.dtb + dtb-$(CONFIG_ARCH_R8A77970) += r8a77970-eagle-function.dtb +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts +new file mode 100644 +index 0000000..54170c9 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts +@@ -0,0 +1,68 @@ ++/* ++ * Device Tree Source for the 8GB H3ULCB Videobox board V2.1 on r8a7795 ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "r8a7795-h3ulcb-4x2g.dts" ++#include "ulcb-vb2.1-gmsl2.dtsi" ++ ++/ { ++ model = "Renesas H3ULCB Videobox V2.1 board based on r8a7795 with 8GiB (4 x 2 GiB)"; ++ ++ hdmi1-out { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi1_con: endpoint { ++ remote-endpoint = <&rcar_dw_hdmi1_out>; ++ }; ++ }; ++ }; ++}; ++ ++&du { ++ ports { ++ port@2 { ++ endpoint { ++ remote-endpoint = <&rcar_dw_hdmi1_in>; ++ }; ++ }; ++ port@3 { ++ endpoint { ++ remote-endpoint = <&lvds_in>; ++ }; ++ }; ++ }; ++}; ++ ++&hdmi1 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ rcar_dw_hdmi1_in: endpoint { ++ remote-endpoint = <&du_out_hdmi1>; ++ }; ++ }; ++ port@1 { ++ reg = <1>; ++ rcar_dw_hdmi1_out: endpoint { ++ remote-endpoint = <&hdmi1_con>; ++ }; ++ }; ++ }; ++}; ++ ++&hsusb { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts +new file mode 100644 +index 0000000..144b035 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts +@@ -0,0 +1,68 @@ ++/* ++ * Device Tree Source for the H3ULCB Videobox board V2.1 on r8a7795 ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "r8a7795-h3ulcb.dts" ++#include "ulcb-vb2.1-gmsl2.dtsi" ++ ++/ { ++ model = "Renesas H3ULCB Videobox V2.1 board based on r8a7795"; ++ ++ hdmi1-out { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi1_con: endpoint { ++ remote-endpoint = <&rcar_dw_hdmi1_out>; ++ }; ++ }; ++ }; ++}; ++ ++&du { ++ ports { ++ port@2 { ++ endpoint { ++ remote-endpoint = <&rcar_dw_hdmi1_in>; ++ }; ++ }; ++ port@3 { ++ endpoint { ++ remote-endpoint = <&lvds_in>; ++ }; ++ }; ++ }; ++}; ++ ++&hdmi1 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ rcar_dw_hdmi1_in: endpoint { ++ remote-endpoint = <&du_out_hdmi1>; ++ }; ++ }; ++ port@1 { ++ reg = <1>; ++ rcar_dw_hdmi1_out: endpoint { ++ remote-endpoint = <&hdmi1_con>; ++ }; ++ }; ++ }; ++}; ++ ++&hsusb { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi +new file mode 100644 +index 0000000..64f54f5 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi +@@ -0,0 +1,1662 @@ ++/* ++ * Device Tree Source for the ULCB Videobox V2 board ++ * ++ * Copyright (C) 2018 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "camera.dtsi" ++ ++/ { ++ cs2300_ref_clk: cs2300_ref_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <25000000>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led5 { ++ gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>; ++ }; ++ led6 { ++ gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>; ++ }; ++ /* D13 - status 0 */ ++ led_ext00 { ++ gpios = <&gpio_ext_led 0 GPIO_ACTIVE_LOW>; ++ /* linux,default-trigger = "heartbeat"; */ ++ }; ++ /* D14 - status 1 */ ++ led_ext01 { ++ gpios = <&gpio_ext_led 1 GPIO_ACTIVE_LOW>; ++ /* linux,default-trigger = "mmc1"; */ ++ }; ++ /* D16 - HDMI0 */ ++ led_ext02 { ++ gpios = <&gpio_ext_led 2 GPIO_ACTIVE_LOW>; ++ }; ++ /* D18 - HDMI1 */ ++ led_ext03 { ++ gpios = <&gpio_ext_led 3 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ vcc_sdhi3: regulator-vcc-sdhi3 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "SDHI3 Vcc"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ ++ gpio = <&gpio4 17 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ vccq_sdhi3: regulator-vccq-sdhi3 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "SDHI3 VccQ"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ fpdlink_switch: regulator@8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "fpdlink_on"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio1 20 0>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ can2_power: regulator@9 { ++ compatible = "regulator-fixed"; ++ regulator-name = "can2_power"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio_ext_pwr 8 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ can3_power: regulator@10 { ++ compatible = "regulator-fixed"; ++ regulator-name = "can3_power"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio_ext_pwr 9 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ lvds { ++ compatible = "panel-lvds"; ++ ++ width-mm = <210>; ++ height-mm = <158>; ++ ++ data-mapping = "jeida-24"; ++ ++ panel-timing { ++ /* 1280x800 @60Hz */ ++ clock-frequency = <65000000>; ++ hactive = <1280>; ++ vactive = <800>; ++ hsync-len = <40>; ++ hfront-porch = <80>; ++ hback-porch = <40>; ++ vfront-porch = <14>; ++ vback-porch = <14>; ++ vsync-len = <4>; ++ }; ++ ++ port { ++ lvds_in: endpoint { ++ remote-endpoint = <&du_out_lvds0>; ++ }; ++ }; ++ }; ++ ++ excan_ref_clk: excan-ref-clock { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <16000000>; ++ }; ++ ++ spi_gpio_sw { ++ compatible = "spi-gpio"; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ gpio-sck = <&gpio0 8 GPIO_ACTIVE_HIGH>; ++ gpio-miso = <&gpio0 10 GPIO_ACTIVE_HIGH>; ++ gpio-mosi = <&gpio0 11 GPIO_ACTIVE_HIGH>; ++ cs-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; ++ num-chipselects = <1>; ++ ++ spidev: spidev@0 { ++ compatible = "spidev", "spi-gpio"; ++ reg = <0>; ++ spi-max-frequency = <25000000>; ++ spi-cpha; ++ spi-cpol; ++ }; ++ }; ++ ++ spi_gpio_can { ++ compatible = "spi-gpio"; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ gpio-sck = <&gpio1 2 GPIO_ACTIVE_HIGH>; ++ gpio-miso = <&gpio1 3 GPIO_ACTIVE_HIGH>; ++ gpio-mosi = <&gpio1 1 GPIO_ACTIVE_HIGH>; ++ cs-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH ++ &gpio1 4 GPIO_ACTIVE_HIGH>; ++ num-chipselects = <2>; ++ ++ spican0: spidev@0 { ++ compatible = "microchip,mcp2515"; ++ reg = <0>; ++ clocks = <&excan_ref_clk>; ++ interrupt-parent = <&gpio0>; ++ interrupts = <15 GPIO_ACTIVE_LOW>; ++ spi-max-frequency = <10000000>; ++ vdd-supply = <&can2_power>; ++ }; ++ spican1: spidev@1 { ++ compatible = "microchip,mcp2515"; ++ reg = <1>; ++ clocks = <&excan_ref_clk>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <5 GPIO_ACTIVE_LOW>; ++ spi-max-frequency = <10000000>; ++ vdd-supply = <&can3_power>; ++ }; ++ }; ++ ++ /* camera slot A */ ++ iio_hwmon_a: hwmon_a@1 { ++ compatible = "iio-hwmon"; ++ io-channels = ++ /* current */ ++ <&max2008x_a 0>, ++ <&max2008x_a 2>, ++ /* voltage */ ++ <&max2008x_a 4>, ++ <&max2008x_a 6>, ++ /* misc voltages */ ++ <&max2008x_a 8>, ++ <&max2008x_a 9>; ++ io-channel-names = ++ "camera-A-0-Iout", ++ "camera-A-1-Iout", ++ "camera-A-0-Vout", ++ "camera-A-1-Vout", ++ "cameras-A-Vregulator", ++ "cameras-A-3v3"; ++ }; ++}; ++ ++&pfc { ++ hscif4_pins: hscif4 { ++ groups = "hscif4_data_a", "hscif4_ctrl"; ++ function = "hscif4"; ++ }; ++ ++ usb0_pins: usb0 { ++ groups = "usb0"; ++ function = "usb0"; ++ }; ++ ++ usb2_pins: usb2 { ++ groups = "usb2"; ++ function = "usb2"; ++ }; ++ ++ usb30_pins: usb30 { ++ groups = "usb30"; ++ function = "usb30"; ++ }; ++ ++ can0_pins: can0 { ++ groups = "can0_data_a"; ++ function = "can0"; ++ }; ++ ++ can1_pins: can1 { ++ groups = "can1_data"; ++ function = "can1"; ++ }; ++ ++ canfd0_pins: canfd0 { ++ groups = "canfd0_data_a"; ++ function = "canfd0"; ++ }; ++ ++ canfd1_pins: canfd1 { ++ groups = "canfd1_data"; ++ function = "canfd1"; ++ }; ++ ++ sdhi3_pins: sd3 { ++ groups = "sdhi3_data4", "sdhi3_ctrl"; ++ function = "sdhi3"; ++ power-source = <3300>; ++ }; ++ ++ sdhi3_pins_uhs: sd3_uhs { ++ groups = "sdhi3_data4", "sdhi3_ctrl"; ++ function = "sdhi3"; ++ power-source = <1800>; ++ }; ++}; ++ ++&gpio0 { ++ video_a_irq { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-A irq"; ++ }; ++ ++ video_b_irq { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-B irq"; ++ }; ++ ++ video_c_irq { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-C irq"; ++ }; ++ can2_irq { ++ gpio-hog; ++ gpios = <15 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "CAN2 irq"; ++ }; ++}; ++ ++&gpio1 { ++ can3_irq { ++ gpio-hog; ++ gpios = <5 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "CAN3 irq"; ++ }; ++ gpioext_4_22_irq { ++ gpio-hog; ++ gpios = <25 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "0x22@i2c4 irq"; ++ }; ++ m2_0_sleep { ++ gpio-hog; ++ gpios = <6 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "M2 0 SLEEP#"; ++ }; ++ m2_1_sleep { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "M2 1 SLEEP#"; ++ }; ++ m2_0_pcie_det { ++ gpio-hog; ++ gpios = <18 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "M.2 0 PCIe/SATA"; ++ }; ++ m2_1_pcie_det { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "M.2 1 PCIe/SATA"; ++ }; ++ m2_1_rst { ++ gpio-hog; ++ gpios = <11 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "M.2 1 RST#"; ++ }; ++ switch_ext_phy_reset { ++ gpio-hog; ++ gpios = <16 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "BR ext phy reset"; ++ }; ++ switch_sw_reset { ++ gpio-hog; ++ gpios = <17 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "BR switch reset"; ++ }; ++ switch_1v2_en { ++ gpio-hog; ++ gpios = <27 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "BR 1.2V en"; ++ }; ++}; ++ ++&gpio2 { ++ m2_0_wake { ++ gpio-hog; ++ gpios = <1 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "M.2 0 WAKE#"; ++ }; ++ m2_0_clkreq { ++ gpio-hog; ++ gpios = <5 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "M.2 0 CLKREQ#"; ++ }; ++ switch_3v3_en { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "BR 3.3V en"; ++ }; ++}; ++ ++&gpio3 { ++ switch_int_phy_reset { ++ gpio-hog; ++ gpios = <15 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "BR int phy reset"; ++ }; ++}; ++ ++&gpio5 { ++ switch_2v5_en { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "BR 2.5V en"; ++ }; ++ switch_25mhz_en { ++ gpio-hog; ++ gpios = <8 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "BR 25MHz clk en"; ++ }; ++}; ++ ++&gpio6 { ++ m2_1_wake { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "M.2 1 WAKE#"; ++ }; ++ m2_1_clkreq { ++ gpio-hog; ++ gpios = <10 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "M.2 1 CLKREQ#"; ++ }; ++ ++ m2_0_rst { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "M.2 0 RST#"; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <400000>; ++ ++ i2cswitch2: pca9548@74 { ++ compatible = "nxp,pca9548"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x74>; ++ reset-gpios = <&gpio6 5 GPIO_ACTIVE_LOW>; ++ ++ i2c@4 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <4>; ++ /* USB3.0 HUB node(s) */ ++ tusb8041_44@44 { ++ compatible = "ti,tusb8041"; ++ reg = <0x44>; ++ reset-gpios = <&gpio5 5 0>; ++ ti,registers = /bits/ 8 < ++ 0x05 0x10 ++ 0x06 0x0f ++ 0x07 0x8f ++ 0x08 0x0f ++ 0x0a 0x20 ++ 0x0b 0x80>; ++ }; ++ tusb8041_45@45 { ++ compatible = "ti,tusb8041"; ++ reg = <0x45>; ++ reset-gpios = <&gpio5 5 0>; ++ ti,registers = /bits/ 8 < ++ 0x05 0x10 ++ 0x06 0x0f ++ 0x07 0x8f ++ 0x08 0x0f ++ 0x0a 0x20 ++ 0x0b 0x80>; ++ }; ++ }; ++ ++ /* Slot A (CN10) */ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ max96712@29 { ++ compatible = "maxim,max96712"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x29>; ++ clocks = <&cs2300_a>; ++ clock-names = "ref_clk"; ++ shutdown-gpios = <&gpio_exp_a_5c 13 GPIO_ACTIVE_LOW>; ++ ++ maxim,link-mipi-map = <1 1 1 1>; ++ ++ poc0-supply = <&vdd_cam_a_0>; ++ poc1-supply = <&vdd_cam_a_1>; ++ poc2-supply = <&vdd_cam_a_2>; ++ poc3-supply = <&vdd_cam_a_3>; ++ ++ port@0 { ++ reg = <4>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ max96712_des0ep0: endpoint@0 { ++ ser-addr = <0x0c>; ++ remote-endpoint = <&camera_in0>; ++ }; ++ max96712_des0ep1: endpoint@1 { ++ ser-addr = <0x0d>; ++ remote-endpoint = <&camera_in1>; ++ }; ++ max96712_des0ep2: endpoint@2 { ++ ser-addr = <0x0e>; ++ remote-endpoint = <&camera_in2>; ++ }; ++ max96712_des0ep3: endpoint@3 { ++ ser-addr = <0x0f>; ++ remote-endpoint = <&camera_in3>; ++ }; ++ }; ++ ++ port@1 { ++ max96712_des0csi0ep0: endpoint { ++ csi-rate = <1200>; ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ ++ ++ i2c_des@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ camera@0 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x60 0x0c>; ++ ++ port@0 { ++ camera_in0: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin0ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep0: endpoint { ++ remote-endpoint = <&max96712_des0ep0>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c_des@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ camera@1 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x61 0x0d>; ++ ++ port@0 { ++ camera_in1: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin1ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep1: endpoint { ++ remote-endpoint = <&max96712_des0ep1>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c_des@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ camera@2 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x62 0x0e>; ++ ++ port@0 { ++ camera_in2: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin2ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep2: endpoint { ++ remote-endpoint = <&max96712_des0ep2>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c_des@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ camera@3 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x63 0x0f>; ++ ++ port@0 { ++ camera_in3: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin3ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep3: endpoint { ++ remote-endpoint = <&max96712_des0ep3>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ /* Slot B (CN11) */ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ max96712@29 { ++ compatible = "maxim,max96712_XX"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x29>; ++ clocks = <&cs2300_b>; ++ clock-names = "ref_clk"; ++ shutdown-gpios = <&gpio_exp_b_5c 13 GPIO_ACTIVE_LOW>; ++ ++ maxim,link-mipi-map = <1 1 1 1>; ++ ++ poc0-supply = <&vdd_cam_b_0>; ++ poc1-supply = <&vdd_cam_b_1>; ++ poc2-supply = <&vdd_cam_b_2>; ++ poc3-supply = <&vdd_cam_b_3>; ++ ++ port@0 { ++ reg = <4>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ max96712_des1ep0: endpoint@0 { ++ ser-addr = <0x1c>; ++ remote-endpoint = <&camera_in4>; ++ }; ++ max96712_des1ep1: endpoint@1 { ++ ser-addr = <0x1d>; ++ remote-endpoint = <&camera_in5>; ++ }; ++ max96712_des1ep2: endpoint@2 { ++ ser-addr = <0x1e>; ++ remote-endpoint = <&camera_in6>; ++ }; ++ max96712_des1ep3: endpoint@3 { ++ ser-addr = <0x1f>; ++ remote-endpoint = <&camera_in7>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <5>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ max96712_des1csi0ep0: endpoint { ++ csi-rate = <1200>; ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ ++ i2c_des@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ camera@0 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x64 0x1c>; ++ ++ port@0 { ++ camera_in4: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin4ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des1ep0: endpoint { ++ remote-endpoint = <&max96712_des1ep0>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c_des@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ camera@1 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x65 0x1d>; ++ ++ port@0 { ++ camera_in5: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin5ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des1ep1: endpoint { ++ remote-endpoint = <&max96712_des1ep1>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c_des@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ camera@2 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x66 0x1e>; ++ ++ port@0 { ++ camera_in6: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin6ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des1ep2: endpoint { ++ remote-endpoint = <&max96712_des1ep2>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c_des@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ camera@3 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x67 0x1f>; ++ ++ port@0 { ++ camera_in7: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin7ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des1ep3: endpoint { ++ remote-endpoint = <&max96712_des1ep3>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ /* Slot A (CN10) */ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ /* PCA9535 is a redundant/deprecated card */ ++ gpio_exp_a_26: gpio@26 { ++ compatible = "nxp,pca9535"; ++ reg = <0x26>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ video_a_pwr_shdn { ++ gpio-hog; ++ gpios = <3 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-A PWR_SHDN"; ++ }; ++ video_a_cam_pwr0 { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-A PWR0"; ++ }; ++ video_a_cam_pwr1 { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-A PWR1"; ++ }; ++ video_a_cam_pwr2 { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-A PWR2"; ++ }; ++ video_a_cam_pwr3 { ++ gpio-hog; ++ gpios = <15 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-A PWR3"; ++ }; ++ video_a_des_shdn { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-A DES_SHDN"; ++ }; ++ video_a_des_led { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "Video-A led"; ++ }; ++ }; ++ ++ gpio_exp_a_5c: gpio@5c { ++ compatible = "maxim,max7325"; ++ reg = <0x5c>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ video_a_des_cfg0 { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-A cfg0"; ++ }; ++ video_a_pwr_shdn { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-A PWR_SHDN"; ++ }; ++/* ++ video_a_des_shdn { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-A DES_SHDN"; ++ }; ++*/ ++ video_a_led { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "Video-A LED"; ++ }; ++ }; ++ ++ cs2300_a: clk_multiplier_a@4e { ++ #clock-cells = <0>; ++ compatible = "cirrus,cs2300-cp"; ++ reg = <0x4e>; ++ clocks = <&cs2300_ref_clk>; ++ clock-names = "clk_in"; ++ ++ assigned-clocks = <&cs2300_a>; ++ assigned-clock-rates = <25000000>; ++ }; ++ ++ dac_vcam_a: dac_vcam_a@60 { ++ compatible = "microchip,mcp4725"; ++ reg = <0x60>; ++ }; ++ ++ max2008x_a: vcam_switch_a@28 { ++ compatible = "maxim,max2008x"; ++ reg = <0x28>; ++ #io-channel-cells = <1>; ++ ++ regulators { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ vdd_cam_a_0: SW0 { ++ reg = <0>; ++ regulator-name = "Camera-A-0"; ++ }; ++ vdd_cam_a_3: SW1 { ++ reg = <1>; ++ regulator-name = "Camera-A-3"; ++ }; ++ vdd_cam_a_1: SW2 { ++ reg = <2>; ++ regulator-name = "Camera-A-1"; ++ }; ++ vdd_cam_a_2: SW3 { ++ reg = <3>; ++ regulator-name = "Camera-A-2"; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ /* Slot B (CN11) */ ++ ++ /* PCA9535 is a redundant/deprecated card */ ++ gpio_exp_b_26: gpio@26 { ++ compatible = "nxp,pca9535"; ++ reg = <0x26>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ video_b_des_cfg1 { ++ gpio-hog; ++ gpios = <5 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-B cfg1"; ++ }; ++ video_b_des_cfg0 { ++ gpio-hog; ++ gpios = <6 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-B cfg0"; ++ }; ++ video_b_pwr_shdn { ++ gpio-hog; ++ gpios = <3 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-B PWR_SHDN"; ++ }; ++ video_b_cam_pwr0 { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-B PWR0"; ++ }; ++ video_b_cam_pwr1 { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-B PWR1"; ++ }; ++ video_b_cam_pwr2 { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-B PWR2"; ++ }; ++ video_b_cam_pwr3 { ++ gpio-hog; ++ gpios = <15 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-B PWR3"; ++ }; ++ video_b_des_shdn { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-B DES_SHDN"; ++ }; ++ video_b_des_led { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "Video-B led"; ++ }; ++ }; ++ ++ gpio_exp_b_5c: gpio@5c { ++ compatible = "maxim,max7325"; ++ reg = <0x5c>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ video_b_des_cfg0 { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-B cfg0"; ++ }; ++ video_b_pwr_shdn { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-B PWR_SHDN"; ++ }; ++/* ++ video_b_des_shdn { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-B DES_SHDN"; ++ }; ++*/ ++ video_b_led { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "Video-B LED"; ++ }; ++ }; ++ ++ cs2300_b: clk_multiplier_b@4e { ++ #clock-cells = <0>; ++ compatible = "cirrus,cs2300-cp"; ++ reg = <0x4e>; ++ clocks = <&cs2300_ref_clk>; ++ clock-names = "clk_in"; ++ ++ assigned-clocks = <&cs2300_b>; ++ assigned-clock-rates = <25000000>; ++ }; ++ ++ dac_vcam_b: dac_vcam_b@60 { ++ compatible = "microchip,mcp4725"; ++ reg = <0x60>; ++ }; ++ ++ max2008x_b: vcam_switch_b@28 { ++ compatible = "maxim,max2008x"; ++ reg = <0x28>; ++ #io-channel-cells = <1>; ++ ++ regulators { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ vdd_cam_b_0: SW0 { ++ reg = <0>; ++ regulator-name = "Camera-B-0"; ++ }; ++ vdd_cam_b_3: SW1 { ++ reg = <1>; ++ regulator-name = "Camera-B-3"; ++ }; ++ vdd_cam_b_1: SW2 { ++ reg = <2>; ++ regulator-name = "Camera-B-1"; ++ }; ++ vdd_cam_b_2: SW3 { ++ reg = <3>; ++ regulator-name = "Camera-B-2"; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@5 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <5>; ++ /* Slot C (CN12) */ ++ ++ gpio_exp_c_5c: gpio@5c { ++ compatible = "maxim,max7325"; ++ reg = <0x5c>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ video_c_des_cfg0 { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "Video-C cfg0"; ++ }; ++ video_c_pwr_shdn { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C PWR_SHDN"; ++ }; ++/* ++ video_c_des_shdn { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "Video-C DES_SHDN"; ++ }; ++*/ ++ video_c_led { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "Video-C LED"; ++ }; ++ }; ++ ++ cs2300_c: clk_multiplier_c@4e { ++ #clock-cells = <0>; ++ compatible = "cirrus,cs2300-cp"; ++ reg = <0x4e>; ++ clocks = <&cs2300_ref_clk>; ++ clock-names = "clk_in"; ++ ++ assigned-clocks = <&cs2300_c>; ++ assigned-clock-rates = <25000000>; ++ }; ++ ++ dac_vcam_c: dac_vcam_c@60 { ++ compatible = "microchip,mcp4725"; ++ reg = <0x60>; ++ }; ++ ++ max2008x_c: vcam_switch_c@28 { ++ compatible = "maxim,max2008x"; ++ reg = <0x28>; ++ #io-channel-cells = <1>; ++ ++ regulators { ++ vdd_cam_c_0: SW0 { ++ regulator-name = "Camera-C-0"; ++ }; ++ vdd_cam_c_1: SW2 { ++ regulator-name = "Camera-C-1"; ++ }; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&i2c4 { ++ i2cswitch4: pca9548@74 { ++ compatible = "nxp,pca9548"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x74>; ++ reset-gpios= <&gpio5 15 GPIO_ACTIVE_LOW>; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ /* FAN1 node - lm96063 */ ++ fan_ctrl_1:lm96063-1@4c { ++ compatible = "lm96163"; ++ reg = <0x4c>; ++ }; ++ }; ++ ++ i2c@6 { ++ /* FAN2 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <6>; ++ /* FAN2 node - lm96063 */ ++ fan_ctrl_2:lm96063-2@4c { ++ compatible = "lm96163"; ++ reg = <0x4c>; ++ }; ++ }; ++ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ /* Power nodes - 2 x TPS544x20 */ ++ tps_5v: tps544c20@0x2a { ++ compatible = "tps544c20"; ++ reg = <0x2c>; ++ status = "disabled"; ++ }; ++ tps_3v3: tps544c20@0x22 { ++ compatible = "tps544c20"; ++ reg = <0x24>; ++ status = "disabled"; ++ }; ++ }; ++ ++ i2c_power: i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ /* CAN and power board nodes */ ++ ++ gpio_ext_pwr: pca9535@22 { ++ compatible = "nxp,pca9535"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ interrupt-parent = <&gpio1>; ++ interrupts = <25 IRQ_TYPE_EDGE_FALLING>; ++ ++ /* enable input DCDC after wake-up signal released */ ++ pwr_hold { ++ gpio-hog; ++ gpios = <11 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "pwr_hold"; ++ }; ++ pwr_5v_out { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "pwr_5v_out"; ++ }; ++ pwr_5v_oc { ++ gpio-hog; ++ gpios = <15 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "pwr_5v_oc"; ++ }; ++ pwr_wake8 { ++ gpio-hog; ++ gpios = <12 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "wake8"; ++ }; ++ pwr_wake7 { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "wake7"; ++ }; ++ ++ /* CAN0 */ ++ can0_stby { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "can0_stby"; ++ }; ++ can0_load { ++ gpio-hog; ++ gpios = <0 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "can0_120R_load"; ++ }; ++ /* CAN1 */ ++ can1_stby { ++ gpio-hog; ++ gpios = <5 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "can1_stby"; ++ }; ++ can1_load { ++ gpio-hog; ++ gpios = <1 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "can1_120R_load"; ++ }; ++ /* CAN2 */ ++ can2_stby { ++ gpio-hog; ++ gpios = <6 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "can2_stby"; ++ }; ++ can2_load { ++ gpio-hog; ++ gpios = <2 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "can2_120R_load"; ++ }; ++ /* CAN3 */ ++ can3_stby { ++ gpio-hog; ++ gpios = <7 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "can3_stby"; ++ }; ++ can3_load { ++ gpio-hog; ++ gpios = <3 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "can3_120R_load"; ++ }; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ /* FPDLink output node - DS90UH947 */ ++ }; ++ ++ i2c@4 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <4>; ++ /* BCM switch node */ ++ }; ++ ++ i2c@5 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <5>; ++ /* LED board node(s) */ ++ ++ gpio_ext_led: pca9535@22 { ++ compatible = "nxp,pca9535"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ /* gpios 0..7 are used for indication LEDs, low-active */ ++ }; ++ rtc: mcp79411@6f { ++ compatible = "microchip,mcp7941x"; ++ reg = <0x6f>; ++ }; ++ }; ++ ++ /* port 7 is not used */ ++ }; ++}; ++ ++&pcie_bus_clk { ++ clock-frequency = <100000000>; ++ status = "okay"; ++}; ++ ++&pciec0 { ++ status = "okay"; ++}; ++ ++&pciec1 { ++ status = "okay"; ++}; ++ ++&vin0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin0ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in0>; ++ }; ++ }; ++ port@1 { ++ csi40ep0: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin0_mmax96712_des0ep0: endpoint { ++ remote-endpoint = <&max96712_des0ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin1 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin1ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <1>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in1>; ++ }; ++ }; ++ port@1 { ++ csi40ep1: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin1_max96712_des0ep1: endpoint { ++ remote-endpoint = <&max96712_des0ep1>; ++ }; ++ }; ++ }; ++}; ++ ++&vin2 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin2ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <2>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in2>; ++ }; ++ }; ++ port@1 { ++ csi40ep2: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin2_max96712_des0ep2: endpoint { ++ remote-endpoint = <&max96712_des0ep2>; ++ }; ++ }; ++ }; ++}; ++ ++&vin3 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin3ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <3>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in3>; ++ }; ++ }; ++ port@1 { ++ csi40ep3: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin3_max96712_des0ep3: endpoint { ++ remote-endpoint = <&max96712_des0ep3>; ++ }; ++ }; ++ }; ++}; ++ ++&vin4 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin4ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <0>; ++ remote-endpoint = <&camera_in4>; ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ port@1 { ++ csi41ep0: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin4_max96712_des0ep1: endpoint { ++ remote-endpoint = <&max96712_des1ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin5 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin5ep0: endpoint@0 { ++ csi,select = "csi41"; ++ virtual,channel = <1>; ++ remote-endpoint = <&camera_in5>; ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ port@1 { ++ csi41ep1: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin5_max96712_des0ep1: endpoint { ++ remote-endpoint = <&max96712_des1ep1>; ++ }; ++ }; ++ }; ++}; ++ ++&vin6 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin6ep0: endpoint@0 { ++ csi,select = "csi41"; ++ virtual,channel = <2>; ++ remote-endpoint = <&camera_in6>; ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ port@1 { ++ csi41ep2: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin6_max96712_des2ep2: endpoint { ++ remote-endpoint = <&max96712_des1ep2>; ++ }; ++ }; ++ }; ++}; ++ ++&vin7 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin7ep0: endpoint@0 { ++ csi,select = "csi41"; ++ virtual,channel = <3>; ++ remote-endpoint = <&camera_in7>; ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ port@1 { ++ csi41ep3: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin7_max96712_des2ep3: endpoint { ++ remote-endpoint = <&max96712_des1ep3>; ++ }; ++ }; ++ }; ++}; ++ ++&csi40 { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi40_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <300>; ++ }; ++ }; ++}; ++ ++&csi41 { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi41_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <300>; ++ }; ++ }; ++}; ++ ++&ssi1 { ++ /delete-property/shared-pin; ++}; ++ ++&sdhi3 { ++ pinctrl-0 = <&sdhi3_pins>; ++ pinctrl-1 = <&sdhi3_pins_uhs>; ++ pinctrl-names = "default", "state_uhs"; ++ ++ vmmc-supply = <&vcc_sdhi3>; ++ vqmmc-supply = <&vccq_sdhi3>; ++ cd-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; ++ wp-gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>; ++ bus-width = <4>; ++ sd-uhs-sdr50; ++ status = "okay"; ++}; ++ ++&msiof1 { ++ status = "disabled"; ++}; ++ ++&usb2_phy0 { ++ pinctrl-0 = <&usb0_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&usb2_phy2 { ++ pinctrl-0 = <&usb2_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&xhci0 { ++ pinctrl-0 = <&usb30_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&ehci0 { ++ status = "okay"; ++}; ++ ++&ehci2 { ++ status = "okay"; ++}; ++ ++&ohci0 { ++ status = "okay"; ++}; ++ ++&ohci2 { ++ status = "okay"; ++}; ++ ++&can0 { ++ pinctrl-0 = <&can0_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++}; ++ ++&can1 { ++ pinctrl-0 = <&can1_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++}; ++ ++&canfd { ++ pinctrl-0 = <&canfd0_pins &canfd1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ channel0 { ++ status = "okay"; ++ }; ++ ++ channel1 { ++ status = "okay"; ++ }; ++}; ++ ++/* uncomment to enable CN12 on VIN4-7 */ ++//#include "ulcb-vb2-cn12.dtsi" +diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi +new file mode 100644 +index 0000000..7334a5e +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi +@@ -0,0 +1,90 @@ ++/* ++ * Device Tree Source for the ULCB Videobox V2.1 board ++ * ++ * Copyright (C) 2019 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "ulcb-vb2-gmsl2.dtsi" ++ ++/{ ++ leds { ++ led_button { ++ gpios = <&gpio_ext_led 9 GPIO_ACTIVE_LOW>; ++ linux,default-trigger = "cpu"; ++ }; ++ }; ++ ++ gpio_keys_polled { ++ compatible = "gpio-keys-polled"; ++ poll-interval = <100>; ++ autorepeat; ++ ++ button_pwr { ++ label = "GPIO Key POWER"; ++ linux,code = <116>; ++ gpios = <&gpio_ext_led 8 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++}; ++ ++&i2c_power { ++ adc@48 { ++ reg = <0x48>; ++ compatible = "ti,ads1115"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ wake7_voltage: channel@4 { ++ /* single endded AIN0 */ ++ reg = <4>; ++ }; ++ wake8_voltage: channel@5 { ++ /* single endded AIN1 */ ++ reg = <5>; ++ }; ++ dc_prot_voltage: channel@6 { ++ /* single endded AIN2 */ ++ reg = <6>; ++ }; ++ dcdc_voltage: channel@7 { ++ /* single endded AIN3 */ ++ reg = <7>; ++ }; ++ }; ++}; ++ ++&gpio6 { ++ /delete-node/m2_0_rst; ++ ++ m2_0_rst { ++ gpio-hog; ++ gpios = <6 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "M.2 0 RST#"; ++ }; ++}; ++ ++&pfc { ++ usb1_pins: usb1 { ++ groups = "usb1"; ++ function = "usb1"; ++ }; ++}; ++ ++&usb2_phy1 { ++ pinctrl-0 = <&usb1_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&ehci1 { ++ status = "okay"; ++}; ++ ++&ohci1 { ++ status = "okay"; ++}; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0513-MTD-renesas-rpc-fix-dummy-cycles.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0513-MTD-renesas-rpc-fix-dummy-cycles.patch new file mode 100644 index 00000000..fe348084 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0513-MTD-renesas-rpc-fix-dummy-cycles.patch @@ -0,0 +1,30 @@ +From 09381afbd95859e22aad7d0647b202eba7bb2cae Mon Sep 17 00:00:00 2001 +From: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +Date: Thu, 5 Dec 2019 17:30:15 +0300 +Subject: [PATCH] MTD: renesas-rpc: fix dummy cycles + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +--- + drivers/mtd/spi-nor/renesas-rpc-qspi.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/renesas-rpc-qspi.c b/drivers/mtd/spi-nor/renesas-rpc-qspi.c +index 3d2d5dbe03e0..f4abdac10670 100644 +--- a/drivers/mtd/spi-nor/renesas-rpc-qspi.c ++++ b/drivers/mtd/spi-nor/renesas-rpc-qspi.c +@@ -458,7 +458,11 @@ static ssize_t rpc_read_flash(struct spi_nor *nor, loff_t from, size_t len, + + /* ...setup read sequence */ + val = rpc_readl(rpc, RPC_DRENR); +- val |= RPC_DRENR_DME | RPC_DRENR_CDE; ++ if (nor->read_dummy) ++ val |= RPC_DRENR_DME; ++ else ++ val &= ~RPC_DRENR_DME; ++ val |= RPC_DRENR_CDE; + rpc_writel(rpc, RPC_DRENR, val); + + rpc_do_read_flash(rpc, from, len, buf, nor->addr_width > 3); +-- +2.17.1 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0514-media-i2c-gmsl2-add-fsync-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0514-media-i2c-gmsl2-add-fsync-support.patch new file mode 100644 index 00000000..49b66489 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0514-media-i2c-gmsl2-add-fsync-support.patch @@ -0,0 +1,102 @@ +From 848b902979b3d10b6104bdae5a73285351b98a3a Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Tue, 5 May 2020 00:31:31 +0300 +Subject: [PATCH 1/3] media: i2c: gmsl2: add fsync support + +This add FSYNC support on GMSL2 serializers + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/gmsl/max9296.c | 12 ++++++++++-- + drivers/media/i2c/soc_camera/gmsl/max9296.h | 1 + + drivers/media/i2c/soc_camera/gmsl/max96712.c | 12 ++++++++++-- + drivers/media/i2c/soc_camera/gmsl/max96712.h | 1 + + 4 files changed, 22 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.c b/drivers/media/i2c/soc_camera/gmsl/max9296.c +index 85b45ca..daa2201 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max9296.c ++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.c +@@ -840,7 +840,7 @@ static int max9296_gmsl2_link_serializer_setup(struct max9296_priv *priv, int li + if (priv->gpio[i] == 2) { + /* GPIO FSIN */ + ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */ +- ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */ ++ ser_write(MAX9295_GPIO_C(i), 0x08); /* pull-none, GPIO ID=8 assosiated with FSYNC transmission */ + } + if (priv->gpio[i] == 3) { + /* GPIO Interrupt */ +@@ -919,7 +919,15 @@ static void max9296_gmsl2_link_crossbar_setup(struct max9296_priv *priv, int lin + + static void max9296_gmsl2_fsync_setup(struct max9296_priv *priv) + { +- /* TODO */ ++ des_write(MAX9296_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */ ++ des_write(MAX9296_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */ ++ des_write(MAX9296_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */ ++ des_write(MAX9296_FSYNC_10, 0x00); /* Disable Overlap */ ++ des_write(MAX9296_FSYNC_11, 0x00); ++ ++ des_write(MAX9296_FSYNC_0, 0x00); /* Manual method, Internal GMSL2 generator mode */ ++ des_write(MAX9296_FSYNC_15, 0x9f); /* GMSL2 Type Fsync, Enable all pipes */ ++ des_write(MAX9296_FSYNC_17, 8 << 3); /* GPIO ID=8 assosiated with FSYNC transmission */ + } + + /* ----------------------------------------------------------------------------- +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.h b/drivers/media/i2c/soc_camera/gmsl/max9296.h +index 985b77e..87fa05ee 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max9296.h ++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.h +@@ -153,6 +153,7 @@ struct max9296_priv { + #define MAX9296_FSYNC_10 0x3aa + #define MAX9296_FSYNC_11 0x3ab + #define MAX9296_FSYNC_15 0x3af ++#define MAX9296_FSYNC_17 0x3b1 + + #define MAX_MIPI_PHY_BASE 0x8a0 + #define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00) +diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c +index c4cdf0e..17eed0b 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max96712.c ++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c +@@ -836,7 +836,7 @@ static int max96712_gmsl2_link_serializer_setup(struct max96712_priv *priv, int + if (priv->gpio[i] == 2) { + /* GPIO FSIN */ + ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */ +- ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */ ++ ser_write(MAX9295_GPIO_C(i), 0x08); /* pull-none, GPIO ID=8 assosiated with FSYNC transmission */ + } + if (priv->gpio[i] == 3) { + /* GPIO Interrupt */ +@@ -918,7 +918,15 @@ static void max96712_gmsl2_link_crossbar_setup(struct max96712_priv *priv, int l + + static void max96712_gmsl2_fsync_setup(struct max96712_priv *priv) + { +- /* TODO */ ++ des_write(MAX96712_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */ ++ des_write(MAX96712_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */ ++ des_write(MAX96712_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */ ++ des_write(MAX96712_FSYNC_10, 0x00); /* Disable Overlap */ ++ des_write(MAX96712_FSYNC_11, 0x00); ++ ++ des_write(MAX96712_FSYNC_0, 0x00); /* Manual method, Internal GMSL2 generator mode */ ++ des_write(MAX96712_FSYNC_15, 0x9f); /* GMSL2 Type Fsync, Enable all pipes */ ++ des_write(MAX96712_FSYNC_17, 8 << 3); /* GPIO ID=8 assosiated with FSYNC transmission */ + } + + /* ----------------------------------------------------------------------------- +diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.h b/drivers/media/i2c/soc_camera/gmsl/max96712.h +index b648bdc..609da2f 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max96712.h ++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.h +@@ -135,6 +135,7 @@ struct max96712_priv { + #define MAX96712_FSYNC_10 0x4aa + #define MAX96712_FSYNC_11 0x4ab + #define MAX96712_FSYNC_15 0x4af ++#define MAX96712_FSYNC_17 0x4b1 + + #define MAX_MIPI_PHY_BASE 0x8a0 + #define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00) +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0515-media-i2c-ap020x-add-fsync-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0515-media-i2c-ap020x-add-fsync-support.patch new file mode 100644 index 00000000..84088d7c --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0515-media-i2c-ap020x-add-fsync-support.patch @@ -0,0 +1,74 @@ +From e5c437ef218ca86640a3c80c5e6a75602748ae5e Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Tue, 5 May 2020 00:35:42 +0300 +Subject: [PATCH 2/3] media: i2c: ap020x: add fsync support + +This adds fsync support + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c | 19 +++++++++++++------ + drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h | 12 ++++++++++++ + 2 files changed, 25 insertions(+), 6 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +index ad18e2e..8dfad4a 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c ++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c +@@ -421,6 +421,18 @@ static int ap0201_initialize(struct i2c_client *client) + } + + reg16_read16(client, AP0201_REV_REG, &rev); ++ /* Program wizard registers */ ++ switch (pid) { ++ case AP0200_PID: ++ case AP0201_PID: ++ ap0201_set_regs(client, ap0201_regs_wizard, ARRAY_SIZE(ap0201_regs_wizard)); ++ break; ++ case AP0202_PID: ++ ap0201_set_regs(client, ap0202_regs_wizard, ARRAY_SIZE(ap0202_regs_wizard)); ++ break; ++ } ++ /* Read OTP IDs */ ++ ap0201_otp_id_read(client); + #if 1 + /* read resolution used by current firmware */ + reg16_read16(client, 0xcae4, &val); +@@ -431,12 +443,7 @@ static int ap0201_initialize(struct i2c_client *client) + priv->max_width = AP0201_MAX_WIDTH; + priv->max_height = AP0201_MAX_HEIGHT; + #endif +- /* Program wizard registers */ +- ap0201_set_regs(client, ap0201_regs_wizard, ARRAY_SIZE(ap0201_regs_wizard)); +- /* Read OTP IDs */ +- ap0201_otp_id_read(client); +- +- dev_info(&client->dev, "ap020X PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ dev_info(&client->dev, "ap020X PID %x (rev%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", + pid, rev, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); + return 0; + } +diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h +index c857edc..daf6bd6 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h ++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h +@@ -21,4 +21,16 @@ struct ap0201_reg { + + static const struct ap0201_reg ap0201_regs_wizard[] = { + /* enable FSIN */ ++{0xc88c, 0x0303}, ++{0xfc00, 0x2800}, ++{0x0040, 0x8100}, ++{AP0201_DELAY, 100}, ++}; ++ ++static const struct ap0201_reg ap0202_regs_wizard[] = { ++/* enable FSIN */ ++{0xc890, 0x0303}, ++{0xfc00, 0x2800}, ++{0x0040, 0x8100}, ++{AP0201_DELAY, 100}, + }; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0516-media-i2c-ar0231-fix-translator.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0516-media-i2c-ar0231-fix-translator.patch new file mode 100644 index 00000000..3c276931 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0516-media-i2c-ar0231-fix-translator.patch @@ -0,0 +1,37 @@ +From 104e7ee4ee011b6050dc9b55b993c811e3efc959 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Tue, 5 May 2020 00:36:27 +0300 +Subject: [PATCH 3/3] media: i2c: ar0231: fix translator + +This fixes translator imager address + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imagers/ar0231.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231.c b/drivers/media/i2c/soc_camera/imagers/ar0231.c +index fc08793..42f125c 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ar0231.c ++++ b/drivers/media/i2c/soc_camera/imagers/ar0231.c +@@ -27,7 +27,7 @@ static const int ar0231_i2c_addr[] = {0x10, 0x20}; + + #define AR0231_PID_REG 0x3000 + #define AR0231_REV_REG 0x31FE +-#define AR0231_PID 0x0354 ++#define AR0231_PID 0x0354 + + #define AR0231_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG12_1X12 + +@@ -403,7 +403,7 @@ static int ar0231_initialize(struct i2c_client *client) + int i; + + for (i = 0; i < ARRAY_SIZE(ar0231_i2c_addr); i++) { +- setup_i2c_translator(client, priv->ser_addr, ar0231_i2c_addr[i] << 1); ++ setup_i2c_translator(client, priv->ser_addr, ar0231_i2c_addr[i]); + + /* check model ID */ + reg16_read16(client, AR0231_PID_REG, &pid); +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0517-media-i2c-gmsl2-fix-fsync-in-manual-mode.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0517-media-i2c-gmsl2-fix-fsync-in-manual-mode.patch new file mode 100644 index 00000000..b9c0b8e1 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0517-media-i2c-gmsl2-fix-fsync-in-manual-mode.patch @@ -0,0 +1,43 @@ +From bc3d7daebf2a0e35d859d847bbe3f9e648cb1c71 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Tue, 5 May 2020 00:52:41 +0300 +Subject: [PATCH] media: i2c: gmsl2: fix fsync in manual mode + +disable back control from pipes, since this is needed only for +automatic mode, that we do not use + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/gmsl/max9296.c | 2 +- + drivers/media/i2c/soc_camera/gmsl/max96712.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.c b/drivers/media/i2c/soc_camera/gmsl/max9296.c +index daa2201..a2a30ef 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max9296.c ++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.c +@@ -926,7 +926,7 @@ static void max9296_gmsl2_fsync_setup(struct max9296_priv *priv) + des_write(MAX9296_FSYNC_11, 0x00); + + des_write(MAX9296_FSYNC_0, 0x00); /* Manual method, Internal GMSL2 generator mode */ +- des_write(MAX9296_FSYNC_15, 0x9f); /* GMSL2 Type Fsync, Enable all pipes */ ++ des_write(MAX9296_FSYNC_15, 0x80); /* GMSL2 Type Fsync, Disable all pipes for manual mode */ + des_write(MAX9296_FSYNC_17, 8 << 3); /* GPIO ID=8 assosiated with FSYNC transmission */ + } + +diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c +index 17eed0b..80e26d0 100644 +--- a/drivers/media/i2c/soc_camera/gmsl/max96712.c ++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c +@@ -925,7 +925,7 @@ static void max96712_gmsl2_fsync_setup(struct max96712_priv *priv) + des_write(MAX96712_FSYNC_11, 0x00); + + des_write(MAX96712_FSYNC_0, 0x00); /* Manual method, Internal GMSL2 generator mode */ +- des_write(MAX96712_FSYNC_15, 0x9f); /* GMSL2 Type Fsync, Enable all pipes */ ++ des_write(MAX96712_FSYNC_15, 0x80); /* GMSL2 Type Fsync, Disable all pipes for manual mode */ + des_write(MAX96712_FSYNC_17, 8 << 3); /* GPIO ID=8 assosiated with FSYNC transmission */ + } + +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0518-media-i2c-imagers-ar0231-fix-GMSL2.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0518-media-i2c-imagers-ar0231-fix-GMSL2.patch new file mode 100644 index 00000000..e6aab0b5 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0518-media-i2c-imagers-ar0231-fix-GMSL2.patch @@ -0,0 +1,55 @@ +From 92c2f541b19b139a4457383c634b142457ca3df3 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 6 May 2020 17:19:02 +0300 +Subject: [PATCH 1/2] media: i2c: imagers: ar0231: fix GMSL2 + +This fixes imager MIPI setup over GMSL2 + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imagers/ar0231.c | 4 ++-- + drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h | 3 ++- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231.c b/drivers/media/i2c/soc_camera/imagers/ar0231.c +index 42f125c..fd8fe94 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ar0231.c ++++ b/drivers/media/i2c/soc_camera/imagers/ar0231.c +@@ -423,11 +423,11 @@ static int ar0231_initialize(struct i2c_client *client) + /* Program wizard registers */ + switch (get_des_id(client)) { + case UB960_ID: ++ case MAX9296A_ID: ++ case MAX96712_ID: + ar0231_set_regs(client, ar0231_regs_wizard_rev7, ARRAY_SIZE(ar0231_regs_wizard_rev7)); + break; + case MAX9286_ID: +- case MAX9296A_ID: +- case MAX96712_ID: + ar0231_set_regs(client, ar0231_regs_wizard_rev6_dvp, ARRAY_SIZE(ar0231_regs_wizard_rev6_dvp)); + break; + } +diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h b/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h +index f3485f5..96dd2c4 100644 +--- a/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h ++++ b/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h +@@ -303,6 +303,7 @@ static const struct ar0231_reg ar0231_regs_wizard_rev7[] = { + #if 1 /* Serial 12-bit Timing Setup */ + /* PCLK=24Mhz/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */ + /* PCLK=24Mhz/2 *44/1/12 *2= 88Mhz - TI serializers */ ++/* MIPI 528MBPS */ + {0x302E, 2}, // pre_pll_clk_div + {0x3030, 44}, // pll_multiplier + {0x302C, 1}, // vt_sys_clk_div (P1 divider) +@@ -381,7 +382,7 @@ static const struct ar0231_reg ar0231_regs_wizard_rev7[] = { + {0x31B6, 0x1146}, + {0x31B8, 0x3047}, + {0x31BA, 0x186}, +-{0x31BC, 0x805}, ++{0x31BC, 0x805 | BIT(15)}, + #endif /* MIPI 12 bit Settings */ + + /* FPS = 105MHz / reg0x300A / reg0x300C * (DES_XTAL/27MHz), DES_XTAL=23.5MHz */ +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0519-media-i2c-imagers-add-IMX390-for-new-LVDS-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0519-media-i2c-imagers-add-IMX390-for-new-LVDS-support.patch new file mode 100644 index 00000000..b4e8848e --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0519-media-i2c-imagers-add-IMX390-for-new-LVDS-support.patch @@ -0,0 +1,4377 @@ +From f901052c8130b621fa1a94facb375ac9a5bc8a2e Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 27 May 2020 12:34:28 +0300 +Subject: [PATCH] media: i2c: imagers: add IMX390 for new LVDS support + +This adds IMX390 into new LVDS drivers that support all enabled +serializers + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +media: i2c: imagers: add IMX390 for new LVDS support + +This adds IMX390 into new LVDS drivers that support all enabled +serializers + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/imagers/Makefile | 1 + + drivers/media/i2c/soc_camera/imagers/imx390.c | 655 +++++ + drivers/media/i2c/soc_camera/imagers/imx390.h | 3672 +++++++++++++++++++++++++ + 3 files changed, 4328 insertions(+) + create mode 100644 drivers/media/i2c/soc_camera/imagers/imx390.c + create mode 100644 drivers/media/i2c/soc_camera/imagers/imx390.h + +diff --git a/drivers/media/i2c/soc_camera/imagers/Makefile b/drivers/media/i2c/soc_camera/imagers/Makefile +index eeb36fd..66c9237 100644 +--- a/drivers/media/i2c/soc_camera/imagers/Makefile ++++ b/drivers/media/i2c/soc_camera/imagers/Makefile +@@ -2,6 +2,7 @@ + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0101_ar014x.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0201_ar023x.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ar0231.o ++obj-$(CONFIG_SOC_CAMERA_OV106XX) += imx390.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov10635.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov2311.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov490.o +diff --git a/drivers/media/i2c/soc_camera/imagers/imx390.c b/drivers/media/i2c/soc_camera/imagers/imx390.c +new file mode 100644 +index 0000000..c326aa6 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/imx390.c +@@ -0,0 +1,655 @@ ++/* ++ * Sony IMX390 sensor camera driver ++ * ++ * Copyright (C) 2018-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++#include "../gmsl/common.h" ++#include "imx390.h" ++ ++static const int imx390_i2c_addr[] = {0x21, 0x1a}; ++ ++#define IMX390_PID_REG 0x0330 ++#define IMX390_PID 0x0015 ++ ++#define IMX390_MEDIA_BUS_FMT MEDIA_BUS_FMT_SRGGB12_1X12 ++ ++struct imx390_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int fps_denominator; ++ int fps_numerator; ++ int init_complete; ++ u8 id[6]; ++ int exposure; ++ int gain; ++ int autogain; ++ /* serializers */ ++ int ser_addr; ++ int vts; ++}; ++ ++static inline struct imx390_priv *to_imx390(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct imx390_priv, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct imx390_priv, hdl)->sd; ++} ++ ++static int imx390_set_regs(struct i2c_client *client, ++ const struct imx390_reg *regs, int nr_regs) ++{ ++ int i; ++ ++ for (i = 0; i < nr_regs; i++) { ++ if (regs[i].reg == IMX390_DELAY) { ++ mdelay(regs[i].val); ++ continue; ++ } ++ ++ reg16_write(client, regs[i].reg, regs[i].val); ++ } ++ ++ return 0; ++} ++ ++static void imx390_otp_id_read(struct i2c_client *client) ++{ ++ struct imx390_priv *priv = to_imx390(client); ++ int i; ++ u8 val = 0; ++ ++ /* read camera id from imx390 OTP memory */ ++ for (i = 0; i < 6; i++) { ++ reg16_read(client, 0x3050 + i, &val); ++ priv->id[i] = val; ++ } ++} ++ ++static int imx390_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int imx390_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = IMX390_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int imx390_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ ++ mf->code = IMX390_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int imx390_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = IMX390_MEDIA_BUS_FMT; ++ ++ return 0; ++} ++ ++static int imx390_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = IMX390_PID >> 8; ++ edid->edid[9] = IMX390_PID & 0xff; ++ ++ return 0; ++} ++ ++static int imx390_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > IMX390_MAX_WIDTH) || ++ (rect->top + rect->height > IMX390_MAX_HEIGHT)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ return 0; ++} ++ ++static int imx390_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = IMX390_MAX_WIDTH; ++ sel->r.height = IMX390_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = IMX390_MAX_WIDTH; ++ sel->r.height = IMX390_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int imx390_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++static int imx390_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ memset(cp, 0, sizeof(struct v4l2_captureparm)); ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = priv->fps_numerator; ++ cp->timeperframe.denominator = priv->fps_denominator; ++ ++ return 0; ++} ++ ++static int imx390_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ int ret = 0, timeout; ++ u8 val; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (priv->fps_denominator != cp->timeperframe.denominator || ++ priv->fps_numerator != cp->timeperframe.numerator) { ++ priv->vts = (IMX390_SENSOR_HEIGHT + 29) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; ++ ++ reg16_write(client, 0x0, 1); ++ for (timeout = 100; timeout > 0; timeout--) { ++ reg16_read(client, 0x5001, &val); ++ if (val == 1) ++ break; ++ mdelay(1); ++ } ++ if (!timeout) ++ dev_err(&client->dev, "timeout enter standby\n"); ++ ++ reg16_write(client, 0x2008, priv->vts & 0xff); ++ reg16_write(client, 0x2009, (priv->vts >> 8) & 0xff); ++ reg16_write(client, 0x200A, priv->vts >> 16); ++ ret = reg16_write(client, 0x0, 0); ++ ++ priv->fps_numerator = cp->timeperframe.numerator; ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int imx390_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 s = reg->size; ++ int ret; ++ ++ if (!s) ++ s = 1; ++ if (s > sizeof(reg->val)) ++ s = sizeof(reg->val); ++ ++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)®->val, s); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int imx390_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u32 s = reg->size; ++ ++ if (!s) ++ s = 1; ++ if (s > sizeof(reg->val)) ++ s = sizeof(reg->val); ++ ++ return reg16_write_n(client, (u16)reg->reg, (u8*)®->val, s); ++} ++#endif ++ ++static struct v4l2_subdev_core_ops imx390_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = imx390_g_register, ++ .s_register = imx390_s_register, ++#endif ++}; ++ ++static int imx390_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ int ret = -EINVAL; ++ int val; ++ uint8_t val8 = 0; ++ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ case V4L2_CID_SHARPNESS: ++ case V4L2_CID_AUTOGAIN: ++ break; ++ case V4L2_CID_GAIN: ++ /* Digital gain */ ++ /* Set PGA_GAIN_SP1H as Normal SP1 HCG mode is configured in wizard */ ++ val8 = ctrl->val & 0xff; ++ ret = reg16_write(client, 0x24, val8); ++#if 0 // stubs for other normal modes and HDR ++ /* Set PGA_GAIN_SP1L as Normal SP1 LCG mode is configured in wizard */ ++ val8 = ctrl->val & 0xff; ++ ret = reg16_write(client, 0x26, val8); ++ ++ /* Set PGA_GAIN_SP2 as Normal SP2 mode is configured in wizard */ ++ val8 = ctrl->val & 0xff; ++ ret = reg16_write(client, 0x28, val8); ++#endif ++ break; ++ case V4L2_CID_ANALOGUE_GAIN: ++ /* Analog gain */ ++ /* Set AGAIN_SP1H as Normal SP1 HCG mode is configured in wizard */ ++ val8 = ctrl->val & 0xff; ++ ret = reg16_write(client, 0x18, val8); ++#if 0 // stubs for other normal modes and HDR ++ /* Set AGAIN_SP1L as Normal SP1 LCG mode is configured in wizard */ ++ val8 = ctrl->val & 0xff; ++ ret = reg16_write(client, 0x1A, val8); ++#endif ++ break; ++ case V4L2_CID_EXPOSURE: ++ val = 0xfff - ctrl->val; ++ reg16_write(client, 0x0c, val); /* LSB */ ++ reg16_write(client, 0x0d, val >> 8); ++ ret = reg16_write(client, 0x0e, val >> 16); /* MSB */ ++ break; ++ case V4L2_CID_HFLIP: ++ /* hflip */ ++ ret = reg16_read(client, 0x74, &val8); ++ if (ctrl->val) ++ val8 |= (1 << 1); ++ else ++ val8 &= ~(1 << 1); ++ ret |= reg16_write(client, 0x74, val8); ++ ++ /* hflip app lock */ ++ ret = reg16_read(client, 0x3c0, &val8); ++ if (ctrl->val) ++ val8 |= (1 << 3); ++ else ++ val8 &= ~(1 << 3); ++ ret |= reg16_write(client, 0x3c0, val8); ++ break; ++ case V4L2_CID_VFLIP: ++ /* vflip */ ++ ret = reg16_read(client, 0x74, &val8); ++ if (ctrl->val) ++ val8 |= (1 << 0); ++ else ++ val8 &= ~(1 << 0); ++ ret |= reg16_write(client, 0x74, val8); ++ ++ /* vflip app lock */ ++ ret = reg16_read(client, 0x3c0, &val8); ++ if (ctrl->val) ++ val8 |= (1 << 2); ++ else ++ val8 &= ~(1 << 2); ++ ret |= reg16_write(client, 0x3c0, val8); ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops imx390_ctrl_ops = { ++ .s_ctrl = imx390_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops imx390_video_ops = { ++ .s_stream = imx390_s_stream, ++ .g_mbus_config = imx390_g_mbus_config, ++ .g_parm = imx390_g_parm, ++ .s_parm = imx390_s_parm, ++}; ++ ++static const struct v4l2_subdev_pad_ops imx390_subdev_pad_ops = { ++ .get_edid = imx390_get_edid, ++ .enum_mbus_code = imx390_enum_mbus_code, ++ .get_selection = imx390_get_selection, ++ .set_selection = imx390_set_selection, ++ .get_fmt = imx390_get_fmt, ++ .set_fmt = imx390_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops imx390_subdev_ops = { ++ .core = &imx390_core_ops, ++ .video = &imx390_video_ops, ++ .pad = &imx390_subdev_pad_ops, ++}; ++ ++static ssize_t imx390_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct imx390_priv *priv = to_imx390(client); ++ ++ imx390_otp_id_read(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_imx390, S_IRUGO, imx390_otp_id_show, NULL); ++ ++static int imx390_initialize(struct i2c_client *client) ++{ ++ struct imx390_priv *priv = to_imx390(client); ++ u8 pid = 0; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(imx390_i2c_addr); i++) { ++ setup_i2c_translator(client, priv->ser_addr, imx390_i2c_addr[i]); ++ ++ /* check model ID */ ++ reg16_read(client, IMX390_PID_REG, &pid); ++ if (pid == IMX390_PID) ++ break; ++ } ++ ++ if (pid != IMX390_PID) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ return -ENODEV; ++ } ++ ++ switch (get_des_id(client)) { ++ case UB960_ID: ++ /* Setup XCLK: ++ * CLK_OUT=23MHz*160*M/N/CLKDIV ++ * CLK_OUT=24MHz (desired), CLKDIV=4, M=6, N=230 ++ * 23*160/4*6/230 = 24MHz = CLK_OUT ++ */ ++ reg8_write_addr(client, priv->ser_addr, 0x06, 0x46); /* Set CLKDIV and M */ ++ reg8_write_addr(client, priv->ser_addr, 0x07, 0xe6); /* Set N */ ++ break; ++ case MAX9296A_ID: ++ case MAX96712_ID: ++// reg16_write_addr(client, priv->ser_addr, MAX9295_MIPI_RX1, 0x11); /* MIPI 2-lanes */ ++ break; ++ } ++ ++ /* Read OTP IDs */ ++ imx390_otp_id_read(client); ++ /* Program wizard registers */ ++ imx390_set_regs(client, imx390_regs_wizard, ARRAY_SIZE(imx390_regs_wizard)); ++ ++ dev_info(&client->dev, "imx390 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, IMX390_MAX_WIDTH, IMX390_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ return 0; ++} ++ ++static const struct i2c_device_id imx390_id[] = { ++ { "imx390", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, imx390_id); ++ ++static const struct of_device_id imx390_of_ids[] = { ++ { .compatible = "sony,imx390", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, imx390_of_ids); ++ ++static int imx390_parse_dt(struct device_node *np, struct imx390_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ u32 addrs[2], naddrs; ++ ++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32)); ++ if (naddrs != 2) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) { ++ dev_err(&client->dev, "Invalid DT reg property\n"); ++ return -EINVAL; ++ } ++ ++ priv->ser_addr = addrs[1]; ++ ++ return 0; ++} ++ ++static int imx390_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct imx390_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &imx390_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ priv->fps_numerator = 1; ++ priv->fps_denominator = 30; ++ ++ priv->exposure = 0x100; ++ priv->gain = 0; ++ priv->autogain = 1; ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_GAIN, 0, 140, 1, priv->gain); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0x15); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 0xff0, 1, 0xfff - 0x2f2); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = imx390_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = imx390_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = IMX390_MAX_WIDTH; ++ priv->rect.height = IMX390_MAX_HEIGHT; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_imx390) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ return ret; ++} ++ ++static int imx390_remove(struct i2c_client *client) ++{ ++ struct imx390_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_imx390); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++static struct i2c_driver imx390_i2c_driver = { ++ .driver = { ++ .name = "imx390", ++ .of_match_table = imx390_of_ids, ++ }, ++ .probe = imx390_probe, ++ .remove = imx390_remove, ++ .id_table = imx390_id, ++}; ++ ++module_i2c_driver(imx390_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for IMX390"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/imagers/imx390.h b/drivers/media/i2c/soc_camera/imagers/imx390.h +new file mode 100644 +index 0000000..8f27447 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/imagers/imx390.h +@@ -0,0 +1,3672 @@ ++/* ++ * Sony IMX390 sensor camera wizard 1920x1080@30/BGGR/MIPI ++ * ++ * Copyright (C) 2018-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++//#define IMX390_DISPLAY_PATTERN_COLOR_BAR ++ ++#define IMX390_MAX_WIDTH 1920 ++#define IMX390_MAX_HEIGHT 1080 ++ ++#define IMX390_SENSOR_WIDTH 1936 ++#define IMX390_SENSOR_HEIGHT 1096 ++ ++#define IMX390_DELAY 0xffff ++#define IMX390_DT 0x2c /* MIPI Data Type RAW12 */ ++ ++struct imx390_reg { ++ u16 reg; ++ u8 val; ++}; ++ ++/* wizard: MIPI 1920x1080 RAW12 Linear 30fps 700Mbps */ ++static const struct imx390_reg imx390_regs_wizard[] = { ++{0x000C, 0xF2}, ++{0x000D, 0x02}, ++{0x000E, 0x00}, ++{0x0010, 0xF2}, ++{0x0011, 0x02}, ++{0x0012, 0x00}, ++{0x0018, 0x15}, ++{0x0019, 0x00}, ++{0x001A, 0x0C}, ++{0x001B, 0x00}, ++{0x0038, 0x00}, ++{0x003C, 0x00}, ++{0x003D, 0x00}, ++{0x003E, 0x00}, ++{0x0040, 0x00}, ++{0x0041, 0x00}, ++{0x0042, 0x00}, ++{0x0044, 0x00}, ++{0x0045, 0x00}, ++{0x0046, 0x00}, ++{0x0048, 0x00}, ++{0x0049, 0x00}, ++{0x004A, 0x00}, ++{0x004C, 0x00}, ++{0x004D, 0x00}, ++{0x004E, 0x00}, ++{0x0050, 0x00}, ++{0x0051, 0x00}, ++{0x0052, 0x00}, ++{0x0054, 0x00}, ++{0x0055, 0x00}, ++{0x0056, 0x00}, ++{0x0058, 0x00}, ++{0x0059, 0x00}, ++{0x005A, 0x00}, ++{0x005C, 0x00}, ++{0x005D, 0x00}, ++{0x005E, 0x00}, ++{0x0060, 0x00}, ++{0x0061, 0x00}, ++{0x0062, 0x00}, ++{0x0064, 0x00}, ++{0x0065, 0x00}, ++{0x0066, 0x00}, ++{0x0068, 0x00}, ++{0x0069, 0x00}, ++{0x006A, 0x00}, ++{0x0078, 0x00}, ++{0x007C, 0x00}, ++{0x007D, 0x00}, ++{0x0080, 0x00}, ++{0x0081, 0x00}, ++{0x00F4, 0x1C}, ++{0x00F5, 0xF8}, ++{0x00F6, 0x01}, ++{0x00F8, 0x03}, ++{0x00F9, 0x00}, // non-HDR ++//{0x00F9, 0x01}, // HDR ++{0x00FA, 0x00}, ++{0x00FB, 0x00}, ++{0x0114, 0x00}, ++{0x0115, 0x01}, ++{0x0118, 0x20}, ++{0x0119, 0x03}, ++{0x011A, 0x00}, ++{0x011B, 0x41}, ++{0x011C, 0x80}, ++{0x011D, 0x00}, ++{0x0120, 0x20}, ++{0x0121, 0x00}, ++{0x0122, 0x00}, ++{0x0123, 0x44}, ++{0x0124, 0x00}, ++{0x0125, 0x01}, ++{0x0128, 0xAC}, ++{0x0129, 0x0D}, ++{0x012A, 0x00}, ++{0x012B, 0xA4}, ++{0x012C, 0x00}, ++{0x012D, 0x01}, ++{0x0130, 0xC4}, ++{0x0131, 0x09}, ++{0x0132, 0x00}, ++{0x0133, 0xDA}, ++{0x013B, 0x01}, ++{0x01C4, 0x00}, ++{0x01C5, 0x00}, ++{0x01CC, 0x01}, ++{0x01D0, 0x09}, ++{0x01D4, 0x01}, ++{0x0232, 0x7E}, ++{0x0233, 0x00}, ++{0x0390, 0x00}, ++{0x0391, 0x00}, ++{0x0392, 0x00}, ++#ifdef IMX390_DISPLAY_PATTERN_COLOR_BAR ++{0x01DB, 0x32}, ++{0x03C0, 0x02}, ++#else ++{0x03C0, 0x00}, ++#endif ++{0x2000, 0x55}, ++{0x2001, 0x55}, ++{0x2002, 0x55}, ++{0x2003, 0x05}, ++{0x2004, 0x02}, ++{0x2008, (IMX390_SENSOR_HEIGHT + 29) & 0xff}, ++{0x2009, ((IMX390_SENSOR_HEIGHT + 29) >> 8) & 0xff}, ++{0x200A, (IMX390_SENSOR_HEIGHT + 29) >> 16}, ++{0x200C, 0x30}, ++{0x200D, 0x11}, ++{0x2010, 0x04}, ++{0x2014, 0x01}, ++{0x2018, 0x02}, ++{0x2019, 0x04}, ++{0x201A, 0x00}, ++{0x201C, 0x21}, ++{0x201D, 0x11}, ++{0x201E, 0x00}, ++{0x201F, 0x00}, ++{0x2020, 0xBC}, ++{0x2021, 0x00}, ++{0x2022, 0x7F}, ++{0x2023, 0x00}, ++{0x2024, 0xBA}, ++{0x2025, 0x00}, ++{0x2026, 0x81}, ++{0x2027, 0x00}, ++{0x2028, 0x7D}, ++{0x2029, 0x90}, ++{0x202A, 0x05}, ++{0x202C, 0xFC}, ++{0x202D, 0x02}, ++{0x202E, 0x25}, ++{0x202F, 0x03}, ++{0x2030, 0x05}, ++{0x2031, 0x02}, ++{0x2032, 0xCA}, ++{0x2033, 0x02}, ++{0x2034, 0xFC}, ++{0x2035, 0x02}, ++{0x2036, 0x25}, ++{0x2037, 0x03}, ++{0x2038, 0x25}, ++{0x2039, 0x97}, ++{0x203A, 0xEC}, ++{0x203B, 0x01}, ++{0x203C, 0xF5}, ++{0x203D, 0x8E}, ++{0x203E, 0x0C}, ++{0x203F, 0x2D}, ++{0x2040, 0x69}, ++{0x2041, 0x01}, ++{0x2042, 0x8E}, ++{0x2043, 0x01}, ++{0x2044, 0x0C}, ++{0x2045, 0x02}, ++{0x2046, 0x31}, ++{0x2047, 0x02}, ++{0x2048, 0x6A}, ++{0x2049, 0x01}, ++{0x204A, 0x8E}, ++{0x204B, 0x01}, ++{0x204C, 0x0D}, ++{0x204D, 0x02}, ++{0x204E, 0x31}, ++{0x204F, 0x02}, ++{0x2050, 0x7B}, ++{0x2051, 0x00}, ++{0x2052, 0x7D}, ++{0x2053, 0x00}, ++{0x2054, 0x95}, ++{0x2055, 0x00}, ++{0x2056, 0x97}, ++{0x2057, 0x00}, ++{0x2058, 0xAD}, ++{0x2059, 0x00}, ++{0x205A, 0xAF}, ++{0x205B, 0x00}, ++{0x205C, 0x92}, ++{0x205D, 0x00}, ++{0x205E, 0x94}, ++{0x205F, 0x00}, ++{0x2060, 0x8E}, ++{0x2061, 0x00}, ++{0x2062, 0x90}, ++{0x2063, 0x00}, ++{0x2064, 0xB1}, ++{0x2065, 0x00}, ++{0x2066, 0xB3}, ++{0x2067, 0x00}, ++{0x2068, 0x08}, ++{0x2069, 0x00}, ++{0x206A, 0x04}, ++{0x206B, 0x00}, ++{0x206C, 0x84}, ++{0x206D, 0x00}, ++{0x206E, 0x80}, ++{0x206F, 0x00}, ++{0x2070, 0x04}, ++{0x2071, 0x00}, ++{0x2072, 0x46}, ++{0x2073, 0x00}, ++{0x2074, 0xE9}, ++{0x2075, 0x01}, ++{0x2076, 0x74}, ++{0x2077, 0x02}, ++{0x2078, 0x80}, ++{0x2079, 0x00}, ++{0x207A, 0xC1}, ++{0x207B, 0x00}, ++{0x207C, 0xFF}, ++{0x207D, 0x03}, ++{0x207E, 0xFF}, ++{0x207F, 0x03}, ++{0x2080, 0x78}, ++{0x2081, 0x00}, ++{0x2082, 0x6A}, ++{0x2083, 0x01}, ++{0x2084, 0xE4}, ++{0x2085, 0x01}, ++{0x2086, 0x2B}, ++{0x2087, 0x03}, ++{0x2088, 0x00}, ++{0x2089, 0x00}, ++{0x208A, 0xFF}, ++{0x208B, 0x03}, ++{0x208C, 0xFF}, ++{0x208D, 0x03}, ++{0x208E, 0xFF}, ++{0x208F, 0x03}, ++{0x2090, 0x7D}, ++{0x2091, 0x00}, ++{0x2092, 0x62}, ++{0x2093, 0x01}, ++{0x2094, 0xE9}, ++{0x2095, 0x01}, ++{0x2096, 0x00}, ++{0x2097, 0x00}, ++{0x2098, 0x7C}, ++{0x2099, 0x00}, ++{0x209A, 0x21}, ++{0x209B, 0x03}, ++{0x209C, 0xE9}, ++{0x209D, 0x01}, ++{0x209E, 0x21}, ++{0x209F, 0x03}, ++{0x20A0, 0xFF}, ++{0x20A1, 0x03}, ++{0x20A2, 0xFF}, ++{0x20A3, 0x03}, ++{0x20A4, 0xFF}, ++{0x20A5, 0x03}, ++{0x20A6, 0xFF}, ++{0x20A7, 0x03}, ++{0x20A8, 0xFF}, ++{0x20A9, 0x03}, ++{0x20AA, 0xFF}, ++{0x20AB, 0x03}, ++{0x20AC, 0xFF}, ++{0x20AD, 0x03}, ++{0x20AE, 0xFF}, ++{0x20AF, 0x03}, ++{0x20B0, 0xFF}, ++{0x20B1, 0x03}, ++{0x20B2, 0xFF}, ++{0x20B3, 0x03}, ++{0x20B4, 0x87}, ++{0x20B5, 0xCC}, ++{0x20B6, 0x87}, ++{0x20B7, 0x08}, ++{0x20B8, 0xF4}, ++{0x20B9, 0xA5}, ++{0x20BA, 0x07}, ++{0x20BC, 0x1F}, ++{0x20BD, 0x01}, ++{0x20BE, 0xF6}, ++{0x20BF, 0x00}, ++{0x20C0, 0x90}, ++{0x20C1, 0x01}, ++{0x20C2, 0x67}, ++{0x20C3, 0x01}, ++{0x20C4, 0xFF}, ++{0x20C5, 0x03}, ++{0x20C6, 0xFF}, ++{0x20C7, 0x03}, ++{0x20C8, 0x33}, ++{0x20C9, 0x02}, ++{0x20CA, 0x0A}, ++{0x20CB, 0x02}, ++{0x20CC, 0x7F}, ++{0x20CD, 0x00}, ++{0x20CE, 0xD2}, ++{0x20CF, 0x00}, ++{0x20D0, 0x81}, ++{0x20D1, 0x00}, ++{0x20D2, 0x87}, ++{0x20D3, 0x00}, ++{0x20D4, 0x09}, ++{0x20D5, 0x00}, ++{0x20D8, 0x7F}, ++{0x20D9, 0x00}, ++{0x20DA, 0x62}, ++{0x20DB, 0x01}, ++{0x20DC, 0x7F}, ++{0x20DD, 0x00}, ++{0x20DE, 0x62}, ++{0x20DF, 0x01}, ++{0x20E0, 0x65}, ++{0x20E1, 0x00}, ++{0x20E2, 0x75}, ++{0x20E3, 0x00}, ++{0x20E4, 0xE0}, ++{0x20E5, 0x00}, ++{0x20E6, 0xF0}, ++{0x20E7, 0x00}, ++{0x20E8, 0x4C}, ++{0x20E9, 0x01}, ++{0x20EA, 0x5C}, ++{0x20EB, 0x01}, ++{0x20EC, 0xD1}, ++{0x20ED, 0x01}, ++{0x20EE, 0xE1}, ++{0x20EF, 0x01}, ++{0x20F0, 0x93}, ++{0x20F1, 0x02}, ++{0x20F2, 0xA3}, ++{0x20F3, 0x02}, ++{0x20F4, 0x0D}, ++{0x20F5, 0x03}, ++{0x20F6, 0x1D}, ++{0x20F7, 0x03}, ++{0x20F8, 0x57}, ++{0x20F9, 0x00}, ++{0x20FA, 0x7B}, ++{0x20FB, 0x00}, ++{0x20FC, 0xD2}, ++{0x20FD, 0x00}, ++{0x20FE, 0xF6}, ++{0x20FF, 0x00}, ++{0x2100, 0x3E}, ++{0x2101, 0x01}, ++{0x2102, 0x60}, ++{0x2103, 0x01}, ++{0x2104, 0xC3}, ++{0x2105, 0x01}, ++{0x2106, 0xE5}, ++{0x2107, 0x01}, ++{0x2108, 0x85}, ++{0x2109, 0x02}, ++{0x210A, 0xA9}, ++{0x210B, 0x02}, ++{0x210C, 0xFF}, ++{0x210D, 0x02}, ++{0x210E, 0x21}, ++{0x210F, 0x03}, ++{0x2110, 0xFF}, ++{0x2111, 0x03}, ++{0x2112, 0x00}, ++{0x2113, 0x00}, ++{0x2114, 0xFF}, ++{0x2115, 0x03}, ++{0x2116, 0xFF}, ++{0x2117, 0x03}, ++{0x2118, 0xFF}, ++{0x2119, 0x03}, ++{0x211A, 0xFF}, ++{0x211B, 0x03}, ++{0x211C, 0xFF}, ++{0x211D, 0x03}, ++{0x211E, 0xFF}, ++{0x211F, 0x03}, ++{0x2120, 0xFF}, ++{0x2121, 0x03}, ++{0x2122, 0xFF}, ++{0x2123, 0x03}, ++{0x2124, 0xFF}, ++{0x2125, 0x03}, ++{0x2126, 0xFF}, ++{0x2127, 0x03}, ++{0x2128, 0x7D}, ++{0x2129, 0x90}, ++{0x212A, 0xD5}, ++{0x212B, 0x07}, ++{0x212C, 0x64}, ++{0x212D, 0x01}, ++{0x2130, 0x5F}, ++{0x2131, 0x7D}, ++{0x2132, 0x05}, ++{0x2134, 0x78}, ++{0x2135, 0x00}, ++{0x2136, 0x76}, ++{0x2137, 0x00}, ++{0x2138, 0xF3}, ++{0x2139, 0x00}, ++{0x213A, 0xF1}, ++{0x213B, 0x00}, ++{0x213C, 0xA6}, ++{0x213D, 0x02}, ++{0x213E, 0xA4}, ++{0x213F, 0x02}, ++{0x2140, 0x7D}, ++{0x2141, 0x00}, ++{0x2142, 0x8D}, ++{0x2143, 0x00}, ++{0x2144, 0xA1}, ++{0x2145, 0x01}, ++{0x2146, 0xB1}, ++{0x2147, 0x01}, ++{0x2148, 0xAB}, ++{0x2149, 0x02}, ++{0x214A, 0xBB}, ++{0x214B, 0x02}, ++{0x214C, 0x17}, ++{0x214D, 0x5C}, ++{0x214E, 0x00}, ++{0x2150, 0x00}, ++{0x2151, 0x00}, ++{0x2152, 0xF8}, ++{0x2153, 0x00}, ++{0x2154, 0xBE}, ++{0x2155, 0x00}, ++{0x2156, 0x7D}, ++{0x2157, 0x00}, ++{0x2158, 0x25}, ++{0x2159, 0x00}, ++{0x215A, 0x7D}, ++{0x215B, 0x00}, ++{0x215C, 0x62}, ++{0x215D, 0x01}, ++{0x215E, 0xFF}, ++{0x215F, 0x03}, ++{0x2160, 0x26}, ++{0x2161, 0x00}, ++{0x2162, 0x7D}, ++{0x2163, 0x00}, ++{0x2164, 0x63}, ++{0x2165, 0x01}, ++{0x2166, 0xFF}, ++{0x2167, 0x03}, ++{0x2168, 0xCB}, ++{0x2169, 0x02}, ++{0x216A, 0xCF}, ++{0x216B, 0x02}, ++{0x216C, 0xFF}, ++{0x216D, 0x03}, ++{0x216E, 0xFF}, ++{0x216F, 0x03}, ++{0x2170, 0xFF}, ++{0x2171, 0x03}, ++{0x2172, 0xFF}, ++{0x2173, 0x03}, ++{0x2174, 0xFF}, ++{0x2175, 0x03}, ++{0x2176, 0xFF}, ++{0x2177, 0x03}, ++{0x2178, 0x7E}, ++{0x2179, 0x00}, ++{0x217A, 0xBD}, ++{0x217B, 0x00}, ++{0x217C, 0xEC}, ++{0x217D, 0x01}, ++{0x217E, 0x7B}, ++{0x217F, 0x02}, ++{0x2180, 0xD1}, ++{0x2181, 0x02}, ++{0x2182, 0x25}, ++{0x2183, 0x03}, ++{0x2184, 0x7F}, ++{0x2185, 0x00}, ++{0x2186, 0xBD}, ++{0x2187, 0x00}, ++{0x2188, 0xED}, ++{0x2189, 0x01}, ++{0x218A, 0x7B}, ++{0x218B, 0x02}, ++{0x218C, 0xD2}, ++{0x218D, 0x02}, ++{0x218E, 0x25}, ++{0x218F, 0x03}, ++{0x2190, 0xFF}, ++{0x2191, 0x03}, ++{0x2192, 0xFF}, ++{0x2193, 0x03}, ++{0x2194, 0xE9}, ++{0x2195, 0x01}, ++{0x2196, 0x21}, ++{0x2197, 0x03}, ++{0x2198, 0x17}, ++{0x2199, 0xFC}, ++{0x219A, 0x7F}, ++{0x219B, 0x01}, ++{0x219C, 0xFF}, ++{0x219D, 0x03}, ++{0x21A0, 0x1B}, ++{0x21A1, 0x1B}, ++{0x21A2, 0x1B}, ++{0x21A3, 0x1B}, ++{0x21A4, 0x2E}, ++{0x21A5, 0x80}, ++{0x21A6, 0x00}, ++{0x21A8, 0x04}, ++{0x21A9, 0x98}, ++{0x21AA, 0x60}, ++{0x21AB, 0x03}, ++{0x21AC, 0x7F}, ++{0x21AD, 0x80}, ++{0x21AE, 0x09}, ++{0x21B0, 0x1C}, ++{0x21B1, 0x00}, ++{0x21B2, 0xA0}, ++{0x21B3, 0x00}, ++{0x21B4, 0x0C}, ++{0x21B5, 0x00}, ++{0x21B6, 0x2D}, ++{0x21B7, 0x00}, ++{0x21B8, 0x20}, ++{0x21B9, 0x00}, ++{0x21BA, 0x02}, ++{0x21BB, 0x00}, ++{0x21BC, 0xCC}, ++{0x21BD, 0x00}, ++{0x21BE, 0x4A}, ++{0x21BF, 0x00}, ++{0x21C0, 0xD0}, ++{0x21C1, 0x00}, ++{0x21C2, 0x44}, ++{0x21C3, 0x00}, ++{0x21C4, 0x00}, ++{0x21C5, 0xE0}, ++{0x21C6, 0x00}, ++{0x21C8, 0x11}, ++{0x21C9, 0x00}, ++{0x21CA, 0x02}, ++{0x21CC, 0x08}, ++{0x21CD, 0xC0}, ++{0x21CE, 0x0C}, ++{0x21D0, 0x44}, ++{0x21D1, 0x00}, ++{0x21D2, 0x02}, ++{0x21D4, 0x02}, ++{0x21D5, 0x20}, ++{0x21D6, 0x2C}, ++{0x21D8, 0xFE}, ++{0x21D9, 0x9D}, ++{0x21DA, 0xDF}, ++{0x21DB, 0x03}, ++{0x21DC, 0x62}, ++{0x21DD, 0x01}, ++{0x21DE, 0x7F}, ++{0x21DF, 0x00}, ++{0x21E0, 0xB7}, ++{0x21E1, 0x01}, ++{0x21E2, 0xB5}, ++{0x21E3, 0x01}, ++{0x21E4, 0xC1}, ++{0x21E5, 0x02}, ++{0x21E6, 0xBF}, ++{0x21E7, 0x02}, ++{0x21E8, 0xB3}, ++{0x21E9, 0x0D}, ++{0x21EA, 0x00}, ++{0x21EB, 0x04}, ++#if 1 ++{0x21EC, 0x90}, ++{0x21ED, 0x07}, ++{0x21EE, 0x58}, ++{0x21EF, 0x04}, ++#else ++{0x21EC, 0x80}, ++{0x21ED, 0x07}, ++{0x21EE, 0x38}, ++{0x21EF, 0x04}, ++#endif ++{0x21F0, 0x54}, ++{0x21F1, 0x04}, ++{0x21F4, 0x02}, ++{0x21F5, 0x00}, ++{0x21F6, 0x00}, ++{0x21F8, 0x3C}, ++{0x21F9, 0x00}, ++{0x21FC, 0x28}, ++{0x21FD, 0x00}, ++{0x21FE, 0x3C}, ++{0x21FF, 0x00}, ++{0x2200, 0x00}, ++{0x2204, 0x4C}, ++{0x2205, 0x04}, ++{0x2206, 0x65}, ++{0x2207, 0x04}, ++{0x2208, 0x0A}, ++{0x2209, 0x00}, ++{0x220C, 0x47}, ++{0x220D, 0x00}, ++{0x220E, 0x1F}, ++{0x220F, 0x00}, ++{0x2210, 0x17}, ++{0x2211, 0x00}, ++{0x2212, 0x0F}, ++{0x2213, 0x00}, ++{0x2214, 0x17}, ++{0x2215, 0x00}, ++{0x2216, 0x47}, ++{0x2217, 0x00}, ++{0x2218, 0x0F}, ++{0x2219, 0x00}, ++{0x221A, 0x0F}, ++{0x221B, 0x00}, ++{0x221C, 0x03}, ++{0x2220, 0x20}, ++{0x2221, 0x20}, ++{0x2222, 0x22}, ++{0x2223, 0x02}, ++{0x2224, 0xA7}, ++{0x2225, 0xAA}, ++{0x2226, 0x80}, ++{0x2227, 0x08}, ++{0x2228, 0x01}, ++{0x22B2, 0x92}, ++{0x22B4, 0x20}, ++{0x22B5, 0x00}, ++{0x22B6, 0x20}, ++{0x22B7, 0x00}, ++{0x22B8, 0x20}, ++{0x22B9, 0x00}, ++{0x22BA, 0x20}, ++{0x22BB, 0x00}, ++{0x22BC, 0x20}, ++{0x22BD, 0x00}, ++{0x22BE, 0x20}, ++{0x22BF, 0x00}, ++{0x22C0, 0x20}, ++{0x22C1, 0x00}, ++{0x22C2, 0x20}, ++{0x22C3, 0x00}, ++{0x22C4, 0x20}, ++{0x22C5, 0x00}, ++{0x22C6, 0x20}, ++{0x22C7, 0x00}, ++{0x22C8, 0x20}, ++{0x22C9, 0x00}, ++{0x22CA, 0x20}, ++{0x22CB, 0x00}, ++{0x22CC, 0x20}, ++{0x22CD, 0x00}, ++{0x22CE, 0x20}, ++{0x22CF, 0x00}, ++{0x22DA, 0x00}, ++{0x2308, 0x01}, ++{0x2311, 0x09}, ++{0x2318, 0x40}, ++{0x2319, 0xCD}, ++{0x231A, 0x54}, ++{0x2324, 0x20}, ++{0x2325, 0x00}, ++{0x2328, 0x00}, ++{0x2354, 0x0C}, ++{0x23C0, 0x5D}, ++{0x244C, 0x00}, ++{0x244D, 0x02}, ++{0x244E, 0x54}, ++{0x244F, 0x02}, ++{0x24A0, 0x00}, ++{0x24DA, 0x6F}, ++{0x24DB, 0x00}, ++{0x24DC, 0x62}, ++{0x24DD, 0x01}, ++{0x24EA, 0x32}, ++{0x24EB, 0x00}, ++{0x24EC, 0xDC}, ++{0x24ED, 0x00}, ++{0x24FA, 0x32}, ++{0x24FB, 0x00}, ++{0x24FC, 0xDD}, ++{0x24FD, 0x00}, ++{0x254A, 0x15}, ++{0x254B, 0x01}, ++{0x255A, 0x15}, ++{0x255B, 0x01}, ++{0x2560, 0x01}, ++{0x2561, 0x00}, ++{0x2562, 0x2A}, ++{0x2563, 0x00}, ++{0x2564, 0xF8}, ++{0x2565, 0x00}, ++{0x2566, 0x15}, ++{0x2567, 0x01}, ++{0x2568, 0x0C}, ++{0x2569, 0x02}, ++{0x256A, 0x31}, ++{0x256B, 0x02}, ++{0x2578, 0x90}, ++{0x2579, 0x01}, ++{0x257A, 0x92}, ++{0x257B, 0x01}, ++{0x257C, 0xB8}, ++{0x257D, 0x02}, ++{0x257E, 0xBA}, ++{0x257F, 0x02}, ++{0x2584, 0x90}, ++{0x2585, 0x01}, ++{0x2586, 0x92}, ++{0x2587, 0x01}, ++{0x2588, 0xB8}, ++{0x2589, 0x02}, ++{0x258A, 0xBA}, ++{0x258B, 0x02}, ++{0x26B8, 0x10}, ++{0x26B9, 0x00}, ++{0x26BA, 0x33}, ++{0x26BB, 0x00}, ++{0x26BC, 0x89}, ++{0x26BD, 0x00}, ++{0x26BE, 0xB0}, ++{0x26BF, 0x00}, ++{0x26C4, 0x4E}, ++{0x26C5, 0x00}, ++{0x26C8, 0xC9}, ++{0x26C9, 0x00}, ++{0x26CC, 0x35}, ++{0x26CD, 0x01}, ++{0x26D0, 0xBA}, ++{0x26D1, 0x01}, ++{0x26D4, 0x7C}, ++{0x26D5, 0x02}, ++{0x26D8, 0xF6}, ++{0x26D9, 0x02}, ++{0x26DE, 0x51}, ++{0x26DF, 0x00}, ++{0x26E0, 0x7F}, ++{0x26E1, 0x00}, ++{0x26E2, 0xCC}, ++{0x26E3, 0x00}, ++{0x26E4, 0xF8}, ++{0x26E5, 0x00}, ++{0x26E6, 0x38}, ++{0x26E7, 0x01}, ++{0x26E8, 0x65}, ++{0x26E9, 0x01}, ++{0x26EA, 0xBD}, ++{0x26EB, 0x01}, ++{0x26EE, 0x7F}, ++{0x26EF, 0x02}, ++{0x26F0, 0xAB}, ++{0x26F1, 0x02}, ++{0x26F2, 0xF9}, ++{0x26F3, 0x02}, ++{0x2722, 0x59}, ++{0x2723, 0x02}, ++{0x2938, 0x55}, ++{0x2939, 0x00}, ++{0x293A, 0x17}, ++{0x293B, 0x00}, ++{0x293C, 0xD0}, ++{0x293D, 0x00}, ++{0x293E, 0x91}, ++{0x293F, 0x00}, ++{0x2940, 0x3C}, ++{0x2941, 0x01}, ++{0x2942, 0x0C}, ++{0x2943, 0x01}, ++{0x2944, 0xC1}, ++{0x2945, 0x01}, ++{0x2946, 0x76}, ++{0x2947, 0x01}, ++{0x2948, 0x83}, ++{0x2949, 0x02}, ++{0x294A, 0xFB}, ++{0x294B, 0x01}, ++{0x294C, 0xFD}, ++{0x294D, 0x02}, ++{0x294E, 0xBF}, ++{0x294F, 0x02}, ++{0x2A06, 0xFF}, ++{0x2A07, 0x03}, ++{0x2A20, 0x00}, ++{0x2A21, 0x00}, ++{0x2A22, 0x7D}, ++{0x2A23, 0x00}, ++{0x2B11, 0x19}, ++{0x2B13, 0x15}, ++{0x2B14, 0x14}, ++{0x2B15, 0x13}, ++{0x2B16, 0x12}, ++{0x2B17, 0x11}, ++{0x2B18, 0x10}, ++{0x2B19, 0x0F}, ++{0x2B1A, 0x0E}, ++{0x2B1B, 0x0D}, ++{0x2B1C, 0x0C}, ++{0x2B1D, 0x0B}, ++{0x2B1E, 0x0A}, ++{0x2B1F, 0x09}, ++{0x2B20, 0x08}, ++{0x2B21, 0x07}, ++{0x2B22, 0x06}, ++{0x2B23, 0x05}, ++{0x2B24, 0x04}, ++{0x2B25, 0x03}, ++{0x2B26, 0x03}, ++{0x2B38, 0x01}, ++{0x2B45, 0xE3}, ++{0x2B50, 0x01}, ++{0x2B51, 0x00}, ++{0x2B6D, 0x47}, ++{0x2B70, 0x02}, ++{0x2B71, 0x02}, ++{0x2B72, 0x02}, ++{0x2B7F, 0x7F}, ++{0x2B80, 0x94}, ++{0x2B81, 0x06}, ++{0x2B87, 0x1B}, ++{0x2B88, 0x1B}, ++{0x2B89, 0x17}, ++{0x2B8A, 0x12}, ++{0x2B8B, 0x12}, ++{0x2B8D, 0x2B}, ++{0x2B8E, 0x2B}, ++{0x2B8F, 0x2B}, ++{0x2B90, 0x7F}, ++{0x2B91, 0x1F}, ++{0x2B94, 0x7F}, ++{0x2B95, 0x27}, ++{0x2B98, 0x7F}, ++{0x2B99, 0x57}, ++{0x2BA8, 0xBC}, ++{0x2BA9, 0x62}, ++{0x2BC1, 0x70}, ++{0x2BC5, 0x80}, ++{0x2BD5, 0x30}, ++{0x2BD6, 0xF0}, ++{0x2BD8, 0xDB}, ++{0x2BD9, 0xF6}, ++{0x2BDA, 0x63}, ++{0x2BDB, 0x0C}, ++{0x2BDC, 0x5C}, ++{0x2C98, 0xE1}, ++{0x2C99, 0x2E}, ++{0x2C9B, 0x86}, ++{0x2CA9, 0x80}, ++{0x2CAA, 0x01}, ++{0x2D39, 0x0E}, ++{0x2D54, 0x00}, ++{0x2D5B, 0x58}, ++{0x3000, 0x00}, ++{0x3001, 0x40}, ++{0x3002, 0x23}, ++{0x3003, 0xA1}, ++{0x3004, 0x00}, ++{0x3005, 0x20}, ++{0x3006, 0x94}, ++{0x3007, 0x00}, ++{0x3008, 0x06}, ++{0x3009, 0xB4}, ++{0x300A, 0x1F}, ++{0x300B, 0x28}, ++{0x300C, 0x00}, ++{0x300D, 0x18}, ++{0x300E, 0x90}, ++{0x300F, 0x97}, ++{0x3010, 0x00}, ++{0x3011, 0x40}, ++{0x3012, 0x21}, ++{0x3013, 0x21}, ++{0x3014, 0x00}, ++{0x3015, 0x20}, ++{0x3016, 0x94}, ++{0x3017, 0x00}, ++{0x3018, 0x00}, ++{0x3019, 0x09}, ++{0x301A, 0x46}, ++{0x301B, 0x28}, ++{0x3070, 0xC1}, ++{0x3071, 0x81}, ++{0x3072, 0x29}, ++{0x3073, 0x81}, ++#if 1 ++{0x3410, 0x90}, ++{0x3411, 0x07}, ++{0x3418, 0x48}, ++{0x3419, 0x04}, ++#else ++{0x3410, 0x80}, ++{0x3411, 0x07}, ++{0x3418, 0x38}, ++{0x3419, 0x04}, ++#endif ++{0x3584, 0x00}, ++{0x3586, 0x00}, ++{0x3587, 0x01}, ++{0x3588, 0xE6}, ++{0x3589, 0x00}, ++{0x3590, 0x00}, ++{0x3591, 0x00}, ++{0x3594, 0x40}, ++{0x3598, 0x03}, ++{0x3599, 0x00}, ++{0x359A, 0x80}, ++{0x359B, 0x00}, ++{0x359C, 0x00}, ++{0x359D, 0x01}, ++{0x359E, 0x00}, ++{0x359F, 0x02}, ++{0x35A0, 0x00}, ++{0x35A1, 0x04}, ++{0x35A2, 0x20}, ++{0x35A3, 0x00}, ++{0x35A4, 0x40}, ++{0x35A5, 0x00}, ++{0x35A6, 0x80}, ++{0x35A7, 0x00}, ++{0x35A8, 0x00}, ++{0x35A9, 0x01}, ++{0x35AA, 0x3A}, ++{0x35AB, 0x00}, ++{0x35AC, 0x80}, ++{0x35AD, 0x00}, ++{0x35AE, 0x00}, ++{0x35AF, 0x01}, ++{0x35B0, 0x00}, ++{0x35B1, 0x02}, ++{0x35B2, 0x00}, ++{0x35B3, 0x04}, ++{0x35B4, 0x02}, ++{0x35B5, 0x00}, ++{0x35B6, 0x04}, ++{0x35B7, 0x00}, ++{0x35B8, 0x08}, ++{0x35B9, 0x00}, ++{0x35BA, 0x10}, ++{0x35BB, 0x00}, ++{0x35BC, 0x03}, ++{0x35BD, 0x00}, ++{0x35C8, 0x00}, ++{0x35C9, 0x01}, ++{0x35CA, 0x00}, ++{0x35CB, 0x04}, ++{0x35CC, 0x00}, ++{0x35CD, 0x10}, ++{0x35CE, 0x00}, ++{0x35CF, 0x40}, ++{0x35D0, 0x00}, ++{0x35D1, 0x0C}, ++{0x35D2, 0x00}, ++{0x35D3, 0x0C}, ++{0x35D4, 0x00}, ++{0x35D5, 0x0C}, ++{0x35D6, 0x00}, ++{0x35D7, 0x0C}, ++{0x35D8, 0x00}, ++{0x35D9, 0x00}, ++{0x35DA, 0x08}, ++{0x35DB, 0x00}, ++{0x35DC, 0xD8}, ++{0x35DD, 0x0E}, ++{0x35F0, 0x00}, ++{0x35F1, 0x10}, ++{0x35F2, 0x00}, ++{0x35F3, 0x10}, ++{0x35F4, 0x00}, ++{0x35F5, 0x10}, ++{0x35F6, 0x00}, ++{0x35F7, 0x03}, ++{0x35F8, 0x00}, ++{0x35F9, 0x01}, ++{0x35FA, 0x38}, ++{0x35FB, 0x00}, ++{0x35FC, 0xB3}, ++{0x35FD, 0x01}, ++{0x35FE, 0x00}, ++{0x35FF, 0x00}, ++{0x3600, 0x04}, ++{0x3601, 0x06}, ++{0x3604, 0x03}, ++{0x3605, 0x00}, ++{0x3608, 0x03}, ++{0x3609, 0x00}, ++{0x360C, 0x00}, ++{0x360D, 0x00}, ++{0x3610, 0x10}, ++{0x3611, 0x01}, ++{0x3612, 0x00}, ++{0x3613, 0x00}, ++{0x3614, 0x00}, ++{0x3615, 0x00}, ++{0x361C, 0x00}, ++{0x361D, 0x01}, ++{0x361E, 0x00}, ++{0x361F, 0x01}, ++{0x3620, 0x01}, ++{0x3621, 0x00}, ++{0x3622, 0xB0}, ++{0x3623, 0x04}, ++{0x3624, 0xDC}, ++{0x3625, 0x05}, ++{0x3626, 0x00}, ++{0x3627, 0x01}, ++{0x3628, 0xFF}, ++{0x3629, 0x0F}, ++{0x362A, 0x00}, ++{0x362B, 0x10}, ++{0x362C, 0x00}, ++{0x362D, 0x01}, ++{0x36C4, 0x99}, ++{0x36C5, 0x09}, ++{0x36C6, 0x18}, ++{0x36C7, 0x07}, ++{0x36C8, 0x65}, ++{0x36C9, 0x0E}, ++{0x36CC, 0x99}, ++{0x36CD, 0x01}, ++{0x36CE, 0x47}, ++{0x36CF, 0x00}, ++{0x36D0, 0x04}, ++{0x36D1, 0x00}, ++{0x36D4, 0x65}, ++{0x36D5, 0x0E}, ++{0x36D6, 0xA4}, ++{0x36D7, 0x0A}, ++{0x36D8, 0x65}, ++{0x36D9, 0x0E}, ++{0x36DC, 0x65}, ++{0x36DD, 0x0E}, ++{0x36DE, 0xA4}, ++{0x36DF, 0x0A}, ++{0x36E0, 0x65}, ++{0x36E1, 0x0E}, ++{0x36E4, 0x65}, ++{0x36E5, 0x0E}, ++{0x36E6, 0xA4}, ++{0x36E7, 0x0A}, ++{0x36E8, 0x65}, ++{0x36E9, 0x0E}, ++{0x36EE, 0x00}, ++{0x36EF, 0x00}, ++{0x36F0, 0x00}, ++{0x36F1, 0x80}, ++{0x36F8, 0x00}, ++{0x3702, 0x03}, ++{0x3703, 0x04}, ++{0x3704, 0x08}, ++{0x370E, 0x0E}, ++{0x3718, 0x62}, ++{0x3719, 0x4A}, ++{0x371A, 0x38}, ++{0x371B, 0x20}, ++{0x371C, 0x64}, ++{0x371D, 0x42}, ++{0x371E, 0x32}, ++{0x371F, 0x1B}, ++{0x3720, 0x98}, ++{0x3721, 0xA0}, ++{0x3722, 0xA8}, ++{0x3723, 0xB0}, ++{0x3748, 0xA5}, ++{0x3749, 0x9B}, ++{0x374A, 0x91}, ++{0x374B, 0x7D}, ++{0x37C0, 0x00}, ++{0x37C1, 0x00}, ++{0x37C2, 0x00}, ++{0x37C4, 0x00}, ++{0x37C5, 0x00}, ++{0x37C6, 0x00}, ++{0x37C8, 0x00}, ++{0x37C9, 0x00}, ++{0x37CA, 0x00}, ++{0x37CC, 0x00}, ++{0x37CD, 0x00}, ++{0x37CE, 0x00}, ++{0x37D0, 0x00}, ++{0x37D1, 0x00}, ++{0x37D2, 0x00}, ++{0x37D4, 0x00}, ++{0x37D5, 0x00}, ++{0x37D6, 0x00}, ++{0x37D8, 0x00}, ++{0x37D9, 0x00}, ++{0x37DA, 0x00}, ++{0x37DC, 0x00}, ++{0x37DD, 0x00}, ++{0x37DE, 0x00}, ++{0x37E0, 0x00}, ++{0x37E1, 0x00}, ++{0x37E2, 0x00}, ++{0x37E4, 0x00}, ++{0x37E5, 0x00}, ++{0x37E6, 0x00}, ++{0x37E8, 0x00}, ++{0x37E9, 0x00}, ++{0x37EA, 0x00}, ++{0x37EC, 0x00}, ++{0x37ED, 0x00}, ++{0x37EE, 0x00}, ++{0x37F0, 0x00}, ++{0x37F4, 0x00}, ++{0x37F5, 0x1E}, ++{0x37F6, 0x34}, ++{0x37F7, 0x00}, ++{0x37F8, 0xFF}, ++{0x37F9, 0xFF}, ++{0x37FA, 0x03}, ++{0x37FC, 0x00}, ++{0x37FD, 0x00}, ++{0x37FE, 0x04}, ++{0x3800, 0xFF}, ++{0x3801, 0xFF}, ++{0x3802, 0x03}, ++{0x3804, 0x00}, ++{0x3805, 0x00}, ++{0x3806, 0x04}, ++{0x3808, 0x00}, ++{0x3809, 0x00}, ++{0x380A, 0x00}, ++{0x380C, 0x00}, ++{0x380D, 0x00}, ++{0x380E, 0x00}, ++{0x3810, 0x00}, ++{0x3811, 0x00}, ++{0x3812, 0x00}, ++{0x3814, 0x00}, ++{0x3815, 0x00}, ++{0x3816, 0x00}, ++{0x3818, 0x00}, ++{0x3819, 0x00}, ++{0x381A, 0x00}, ++{0x381C, 0x00}, ++{0x381D, 0x00}, ++{0x381E, 0x00}, ++{0x3820, 0x00}, ++{0x3821, 0x00}, ++{0x3822, 0x00}, ++{0x3824, 0x00}, ++{0x3825, 0x00}, ++{0x3826, 0x00}, ++{0x3828, 0x00}, ++{0x3829, 0x00}, ++{0x382A, 0x00}, ++{0x382C, 0x00}, ++{0x382D, 0x00}, ++{0x382E, 0x00}, ++{0x3830, 0x00}, ++{0x3831, 0x00}, ++{0x3832, 0x00}, ++{0x3834, 0x00}, ++{0x3835, 0x00}, ++{0x3836, 0x00}, ++{0x3838, 0x22}, ++{0x3839, 0x00}, ++{0x383A, 0x25}, ++{0x383B, 0x00}, ++{0x383C, 0x1A}, ++{0x383D, 0x00}, ++{0x383E, 0x26}, ++{0x383F, 0x00}, ++{0x3840, 0x07}, ++{0x3841, 0x00}, ++{0x3842, 0x06}, ++{0x3843, 0x00}, ++{0x3844, 0x03}, ++{0x3845, 0x00}, ++{0x3846, 0x02}, ++{0x3847, 0x00}, ++{0x3848, 0xFB}, ++{0x3849, 0xFF}, ++{0x384A, 0xFF}, ++{0x384B, 0xFF}, ++{0x384C, 0xF3}, ++{0x384D, 0xFF}, ++{0x384E, 0xF2}, ++{0x384F, 0xFF}, ++{0x3850, 0xFF}, ++{0x3851, 0x0F}, ++{0x3852, 0x00}, ++{0x3853, 0x10}, ++{0x3854, 0xFF}, ++{0x3855, 0x0F}, ++{0x3856, 0x00}, ++{0x3857, 0x10}, ++{0x3858, 0xFF}, ++{0x3859, 0x0F}, ++{0x385A, 0x00}, ++{0x385B, 0x10}, ++{0x385C, 0x02}, ++{0x385D, 0x00}, ++{0x385E, 0x06}, ++{0x385F, 0x00}, ++{0x3860, 0x06}, ++{0x3861, 0x00}, ++{0x3862, 0x08}, ++{0x3863, 0x00}, ++{0x3864, 0x02}, ++{0x3865, 0x00}, ++{0x38A0, 0x01}, ++{0x38A1, 0x01}, ++{0x38A2, 0x00}, ++{0x38A3, 0x01}, ++{0x38A4, 0x07}, ++{0x38A5, 0x00}, ++{0x38A6, 0x04}, ++{0x38A7, 0x05}, ++{0x38A8, 0x00}, ++{0x38A9, 0x00}, ++{0x38AC, 0x00}, ++{0x38AD, 0x00}, ++{0x38AE, 0x01}, ++{0x38B0, 0x02}, ++{0x38B2, 0x22}, ++{0x38B3, 0x00}, ++{0x38B4, 0x17}, ++{0x38B5, 0x00}, ++{0x38B6, 0x11}, ++{0x38B7, 0x00}, ++{0x38B8, 0x0E}, ++{0x38B9, 0x00}, ++{0x38BA, 0x2A}, ++{0x38BB, 0x00}, ++{0x38BC, 0x1C}, ++{0x38BD, 0x00}, ++{0x38BE, 0x14}, ++{0x38BF, 0x00}, ++{0x38C0, 0x10}, ++{0x38C1, 0x00}, ++{0x38C2, 0x31}, ++{0x38C3, 0x00}, ++{0x38C4, 0x21}, ++{0x38C5, 0x00}, ++{0x38C6, 0x18}, ++{0x38C7, 0x00}, ++{0x38C8, 0x12}, ++{0x38C9, 0x00}, ++{0x38CA, 0x3C}, ++{0x38CB, 0x00}, ++{0x38CC, 0x29}, ++{0x38CD, 0x00}, ++{0x38CE, 0x1D}, ++{0x38CF, 0x00}, ++{0x38D0, 0x15}, ++{0x38D1, 0x00}, ++{0x38D2, 0x4E}, ++{0x38D3, 0x00}, ++{0x38D4, 0x35}, ++{0x38D5, 0x00}, ++{0x38D6, 0x26}, ++{0x38D7, 0x00}, ++{0x38D8, 0x1A}, ++{0x38D9, 0x00}, ++{0x38DA, 0x69}, ++{0x38DB, 0x00}, ++{0x38DC, 0x48}, ++{0x38DD, 0x00}, ++{0x38DE, 0x33}, ++{0x38DF, 0x00}, ++{0x38E0, 0x22}, ++{0x38E1, 0x00}, ++{0x38E2, 0x93}, ++{0x38E3, 0x00}, ++{0x38E4, 0x64}, ++{0x38E5, 0x00}, ++{0x38E6, 0x48}, ++{0x38E7, 0x00}, ++{0x38E8, 0x30}, ++{0x38E9, 0x00}, ++{0x38EA, 0xD3}, ++{0x38EB, 0x00}, ++{0x38EC, 0x90}, ++{0x38ED, 0x00}, ++{0x38EE, 0x69}, ++{0x38EF, 0x00}, ++{0x38F0, 0x49}, ++{0x38F1, 0x00}, ++{0x38F2, 0x39}, ++{0x38F3, 0x01}, ++{0x38F4, 0xD5}, ++{0x38F5, 0x00}, ++{0x38F6, 0x9F}, ++{0x38F7, 0x00}, ++{0x38F8, 0x75}, ++{0x38F9, 0x00}, ++{0x38FA, 0x00}, ++{0x38FB, 0x01}, ++{0x38FC, 0x00}, ++{0x38FD, 0x01}, ++{0x38FE, 0x00}, ++{0x38FF, 0x01}, ++{0x3900, 0x00}, ++{0x3901, 0x01}, ++{0x3902, 0x60}, ++{0x3903, 0x00}, ++{0x3904, 0x25}, ++{0x3905, 0x00}, ++{0x3906, 0x18}, ++{0x3907, 0x00}, ++{0x3908, 0x10}, ++{0x3909, 0x00}, ++{0x390A, 0xFF}, ++{0x390B, 0x00}, ++{0x390C, 0xD5}, ++{0x390D, 0x00}, ++{0x390E, 0xAA}, ++{0x390F, 0x00}, ++{0x3910, 0x85}, ++{0x3911, 0x00}, ++{0x3912, 0xFF}, ++{0x3913, 0x00}, ++{0x3914, 0xD5}, ++{0x3915, 0x00}, ++{0x3916, 0xAA}, ++{0x3917, 0x00}, ++{0x3918, 0x85}, ++{0x3919, 0x00}, ++{0x391A, 0xFF}, ++{0x391B, 0x00}, ++{0x391C, 0xD5}, ++{0x391D, 0x00}, ++{0x391E, 0xAA}, ++{0x391F, 0x00}, ++{0x3920, 0x85}, ++{0x3921, 0x00}, ++{0x3922, 0x40}, ++{0x3923, 0x00}, ++{0x3924, 0x40}, ++{0x3925, 0x00}, ++{0x3926, 0x40}, ++{0x3927, 0x00}, ++{0x3928, 0x40}, ++{0x3929, 0x00}, ++{0x392A, 0x80}, ++{0x392B, 0x00}, ++{0x392C, 0x80}, ++{0x392D, 0x00}, ++{0x392E, 0x80}, ++{0x392F, 0x00}, ++{0x3930, 0x80}, ++{0x3931, 0x00}, ++{0x3932, 0x4C}, ++{0x3933, 0x4C}, ++{0x3934, 0x4C}, ++{0x3940, 0x01}, ++{0x3941, 0x01}, ++{0x3942, 0x00}, ++{0x3943, 0x01}, ++{0x3944, 0x07}, ++{0x3945, 0x00}, ++{0x3946, 0x04}, ++{0x3947, 0x05}, ++{0x3948, 0x00}, ++{0x3949, 0x00}, ++{0x394C, 0x00}, ++{0x394D, 0x00}, ++{0x394E, 0x01}, ++{0x3950, 0x03}, ++{0x3952, 0x14}, ++{0x3953, 0x00}, ++{0x3954, 0x0F}, ++{0x3955, 0x00}, ++{0x3956, 0x0E}, ++{0x3957, 0x00}, ++{0x3958, 0x0E}, ++{0x3959, 0x00}, ++{0x395A, 0x19}, ++{0x395B, 0x00}, ++{0x395C, 0x11}, ++{0x395D, 0x00}, ++{0x395E, 0x0F}, ++{0x395F, 0x00}, ++{0x3960, 0x0E}, ++{0x3961, 0x00}, ++{0x3962, 0x1C}, ++{0x3963, 0x00}, ++{0x3964, 0x13}, ++{0x3965, 0x00}, ++{0x3966, 0x0F}, ++{0x3967, 0x00}, ++{0x3968, 0x0E}, ++{0x3969, 0x00}, ++{0x396A, 0x23}, ++{0x396B, 0x00}, ++{0x396C, 0x15}, ++{0x396D, 0x00}, ++{0x396E, 0x11}, ++{0x396F, 0x00}, ++{0x3970, 0x0E}, ++{0x3971, 0x00}, ++{0x3972, 0x2E}, ++{0x3973, 0x00}, ++{0x3974, 0x1A}, ++{0x3975, 0x00}, ++{0x3976, 0x14}, ++{0x3977, 0x00}, ++{0x3978, 0x0F}, ++{0x3979, 0x00}, ++{0x397A, 0x3E}, ++{0x397B, 0x00}, ++{0x397C, 0x23}, ++{0x397D, 0x00}, ++{0x397E, 0x1A}, ++{0x397F, 0x00}, ++{0x3980, 0x12}, ++{0x3981, 0x00}, ++{0x3982, 0x56}, ++{0x3983, 0x00}, ++{0x3984, 0x31}, ++{0x3985, 0x00}, ++{0x3986, 0x25}, ++{0x3987, 0x00}, ++{0x3988, 0x1A}, ++{0x3989, 0x00}, ++{0x398A, 0x7B}, ++{0x398B, 0x00}, ++{0x398C, 0x49}, ++{0x398D, 0x00}, ++{0x398E, 0x39}, ++{0x398F, 0x00}, ++{0x3990, 0x2C}, ++{0x3991, 0x00}, ++{0x3992, 0xB4}, ++{0x3993, 0x00}, ++{0x3994, 0x75}, ++{0x3995, 0x00}, ++{0x3996, 0x61}, ++{0x3997, 0x00}, ++{0x3998, 0x53}, ++{0x3999, 0x00}, ++{0x399A, 0x00}, ++{0x399B, 0x01}, ++{0x399C, 0x00}, ++{0x399D, 0x01}, ++{0x399E, 0x00}, ++{0x399F, 0x01}, ++{0x39A0, 0x00}, ++{0x39A1, 0x01}, ++{0x39A2, 0x60}, ++{0x39A3, 0x00}, ++{0x39A4, 0x20}, ++{0x39A5, 0x00}, ++{0x39A6, 0x15}, ++{0x39A7, 0x00}, ++{0x39A8, 0x10}, ++{0x39A9, 0x00}, ++{0x39AA, 0xFF}, ++{0x39AB, 0x00}, ++{0x39AC, 0xD5}, ++{0x39AD, 0x00}, ++{0x39AE, 0xAA}, ++{0x39AF, 0x00}, ++{0x39B0, 0x85}, ++{0x39B1, 0x00}, ++{0x39B2, 0xFF}, ++{0x39B3, 0x00}, ++{0x39B4, 0xD5}, ++{0x39B5, 0x00}, ++{0x39B6, 0xAA}, ++{0x39B7, 0x00}, ++{0x39B8, 0x85}, ++{0x39B9, 0x00}, ++{0x39BA, 0xFF}, ++{0x39BB, 0x00}, ++{0x39BC, 0xD5}, ++{0x39BD, 0x00}, ++{0x39BE, 0xAA}, ++{0x39BF, 0x00}, ++{0x39C0, 0x85}, ++{0x39C1, 0x00}, ++{0x39C2, 0x40}, ++{0x39C3, 0x00}, ++{0x39C4, 0x40}, ++{0x39C5, 0x00}, ++{0x39C6, 0x40}, ++{0x39C7, 0x00}, ++{0x39C8, 0x40}, ++{0x39C9, 0x00}, ++{0x39CA, 0x80}, ++{0x39CB, 0x00}, ++{0x39CC, 0x80}, ++{0x39CD, 0x00}, ++{0x39CE, 0x80}, ++{0x39CF, 0x00}, ++{0x39D0, 0x80}, ++{0x39D1, 0x00}, ++{0x39D2, 0x4C}, ++{0x39D3, 0x4C}, ++{0x39D4, 0x4C}, ++{0x39E0, 0x01}, ++{0x39E1, 0x00}, ++{0x39E4, 0x40}, ++{0x39E5, 0x01}, ++{0x39E6, 0x01}, ++{0x39E8, 0x00}, ++{0x39E9, 0x01}, ++{0x39EA, 0x00}, ++{0x39EB, 0x00}, ++{0x39EC, 0x01}, ++{0x39ED, 0x00}, ++{0x39EE, 0x01}, ++{0x39F0, 0x03}, ++{0x39F1, 0x04}, ++{0x39F2, 0x0E}, ++{0x39F4, 0x1C}, ++{0x39F5, 0x00}, ++{0x39F6, 0x13}, ++{0x39F7, 0x00}, ++{0x39F8, 0x0D}, ++{0x39F9, 0x00}, ++{0x39FA, 0x07}, ++{0x39FB, 0x00}, ++{0x39FC, 0x38}, ++{0x39FD, 0x00}, ++{0x39FE, 0x1C}, ++{0x39FF, 0x00}, ++{0x3A00, 0x11}, ++{0x3A01, 0x00}, ++{0x3A02, 0x08}, ++{0x3A03, 0x00}, ++{0x3A04, 0x4A}, ++{0x3A05, 0x00}, ++{0x3A06, 0x23}, ++{0x3A07, 0x00}, ++{0x3A08, 0x15}, ++{0x3A09, 0x00}, ++{0x3A0A, 0x09}, ++{0x3A0B, 0x00}, ++{0x3A0C, 0x65}, ++{0x3A0D, 0x00}, ++{0x3A0E, 0x2D}, ++{0x3A0F, 0x00}, ++{0x3A10, 0x1A}, ++{0x3A11, 0x00}, ++{0x3A12, 0x0B}, ++{0x3A13, 0x00}, ++{0x3A14, 0x8D}, ++{0x3A15, 0x00}, ++{0x3A16, 0x3D}, ++{0x3A17, 0x00}, ++{0x3A18, 0x23}, ++{0x3A19, 0x00}, ++{0x3A1A, 0x0E}, ++{0x3A1B, 0x00}, ++{0x3A1C, 0xC5}, ++{0x3A1D, 0x00}, ++{0x3A1E, 0x55}, ++{0x3A1F, 0x00}, ++{0x3A20, 0x30}, ++{0x3A21, 0x00}, ++{0x3A22, 0x13}, ++{0x3A23, 0x00}, ++{0x3A24, 0x16}, ++{0x3A25, 0x01}, ++{0x3A26, 0x76}, ++{0x3A27, 0x00}, ++{0x3A28, 0x42}, ++{0x3A29, 0x00}, ++{0x3A2A, 0x1A}, ++{0x3A2B, 0x00}, ++{0x3A2C, 0x88}, ++{0x3A2D, 0x01}, ++{0x3A2E, 0xA7}, ++{0x3A2F, 0x00}, ++{0x3A30, 0x5D}, ++{0x3A31, 0x00}, ++{0x3A32, 0x24}, ++{0x3A33, 0x00}, ++{0x3A34, 0x2A}, ++{0x3A35, 0x02}, ++{0x3A36, 0xEB}, ++{0x3A37, 0x00}, ++{0x3A38, 0x83}, ++{0x3A39, 0x00}, ++{0x3A3A, 0x32}, ++{0x3A3B, 0x00}, ++{0x3A3C, 0x00}, ++{0x3A3D, 0x01}, ++{0x3A3E, 0x00}, ++{0x3A3F, 0x01}, ++{0x3A40, 0x00}, ++{0x3A41, 0x01}, ++{0x3A42, 0x00}, ++{0x3A43, 0x01}, ++{0x3A44, 0x70}, ++{0x3A45, 0x00}, ++{0x3A46, 0x25}, ++{0x3A47, 0x00}, ++{0x3A48, 0x18}, ++{0x3A49, 0x00}, ++{0x3A4A, 0x10}, ++{0x3A4B, 0x00}, ++{0x3A4C, 0xFF}, ++{0x3A4D, 0x00}, ++{0x3A4E, 0xD5}, ++{0x3A4F, 0x00}, ++{0x3A50, 0xAA}, ++{0x3A51, 0x00}, ++{0x3A52, 0x85}, ++{0x3A53, 0x00}, ++{0x3A54, 0xFF}, ++{0x3A55, 0x00}, ++{0x3A56, 0xD5}, ++{0x3A57, 0x00}, ++{0x3A58, 0xAA}, ++{0x3A59, 0x00}, ++{0x3A5A, 0x85}, ++{0x3A5B, 0x00}, ++{0x3A5C, 0xFF}, ++{0x3A5D, 0x00}, ++{0x3A5E, 0xD5}, ++{0x3A5F, 0x00}, ++{0x3A60, 0xAA}, ++{0x3A61, 0x00}, ++{0x3A62, 0x85}, ++{0x3A63, 0x00}, ++{0x3A64, 0x1C}, ++{0x3A65, 0x00}, ++{0x3A66, 0x13}, ++{0x3A67, 0x00}, ++{0x3A68, 0x0D}, ++{0x3A69, 0x00}, ++{0x3A6A, 0x07}, ++{0x3A6B, 0x00}, ++{0x3A6C, 0x0D}, ++{0x3A6D, 0x00}, ++{0x3A6E, 0x0B}, ++{0x3A6F, 0x00}, ++{0x3A70, 0x06}, ++{0x3A71, 0x00}, ++{0x3A72, 0x05}, ++{0x3A73, 0x00}, ++{0x3A74, 0x19}, ++{0x3A75, 0x00}, ++{0x3A76, 0x14}, ++{0x3A77, 0x00}, ++{0x3A78, 0x0F}, ++{0x3A79, 0x00}, ++{0x3A7A, 0x0A}, ++{0x3A7B, 0x00}, ++{0x3A7C, 0x80}, ++{0x3A7D, 0x00}, ++{0x3A7E, 0x80}, ++{0x3A7F, 0x00}, ++{0x3A80, 0x80}, ++{0x3A81, 0x00}, ++{0x3A82, 0x80}, ++{0x3A83, 0x00}, ++{0x3A84, 0x08}, ++{0x3A85, 0x00}, ++{0x3A86, 0x05}, ++{0x3A87, 0x00}, ++{0x3A88, 0x04}, ++{0x3A89, 0x00}, ++{0x3A8A, 0x03}, ++{0x3A8B, 0x00}, ++{0x3A8C, 0xCD}, ++{0x3A8D, 0x00}, ++{0x3A8E, 0xAA}, ++{0x3A8F, 0x00}, ++{0x3A90, 0x8C}, ++{0x3A91, 0x00}, ++{0x3A92, 0x64}, ++{0x3A93, 0x00}, ++{0x3A94, 0xCD}, ++{0x3A95, 0x00}, ++{0x3A96, 0xAA}, ++{0x3A97, 0x00}, ++{0x3A98, 0x8C}, ++{0x3A99, 0x00}, ++{0x3A9A, 0x64}, ++{0x3A9B, 0x00}, ++{0x3A9C, 0x08}, ++{0x3A9D, 0x10}, ++{0x3A9E, 0x4C}, ++{0x3A9F, 0x4C}, ++{0x3AA0, 0x4C}, ++{0x3AA1, 0x04}, ++{0x3AA2, 0x05}, ++{0x3AC0, 0x01}, ++{0x3AC4, 0x81}, ++{0x3AC5, 0x00}, ++{0x3AC6, 0x00}, ++{0x3AC7, 0x00}, ++{0x3AC8, 0x00}, ++{0x3AC9, 0x00}, ++{0x3ACA, 0x00}, ++{0x3ACB, 0x00}, ++{0x3ACC, 0x02}, ++{0x3ACD, 0x00}, ++{0x3ACE, 0x81}, ++{0x3ACF, 0x00}, ++{0x3AD0, 0x00}, ++{0x3AD1, 0x00}, ++{0x3AD2, 0xFD}, ++{0x3AD3, 0x03}, ++{0x3AD4, 0x02}, ++{0x3AD5, 0x00}, ++{0x3AD6, 0x00}, ++{0x3AD7, 0x00}, ++{0x3AD8, 0x81}, ++{0x3AD9, 0x00}, ++{0x3ADA, 0xFD}, ++{0x3ADB, 0x03}, ++{0x3ADC, 0xFF}, ++{0x3ADD, 0x03}, ++{0x3ADE, 0x01}, ++{0x3ADF, 0x00}, ++{0x3AE0, 0x01}, ++{0x3AE1, 0x00}, ++{0x3AE2, 0x7E}, ++{0x3AE3, 0x00}, ++{0x3AF4, 0x00}, ++{0x3AF6, 0x40}, ++{0x3AF7, 0x1E}, ++{0x3AF8, 0x01}, ++{0x3AFA, 0x63}, ++{0x3AFB, 0x09}, ++{0x3AFC, 0x11}, ++{0x3AFD, 0x09}, ++{0x3AFE, 0x00}, ++{0x3AFF, 0x00}, ++{0x3B00, 0x00}, ++{0x3B01, 0x00}, ++{0x3B02, 0x84}, ++{0x3B03, 0x06}, ++{0x3B04, 0x30}, ++{0x3B05, 0x06}, ++{0x3B06, 0x00}, ++{0x3B07, 0x00}, ++{0x3B08, 0x00}, ++{0x3B09, 0x00}, ++{0x3B0A, 0x00}, ++{0x3B0B, 0x00}, ++{0x3B0C, 0x00}, ++{0x3B0D, 0x00}, ++{0x3B0E, 0x00}, ++{0x3B0F, 0x00}, ++{0x3B10, 0x00}, ++{0x3B11, 0x00}, ++{0x3B12, 0x00}, ++{0x3B13, 0x00}, ++{0x3B14, 0x00}, ++{0x3B15, 0x00}, ++{0x3B16, 0x00}, ++{0x3B17, 0x00}, ++{0x3B18, 0x00}, ++{0x3B19, 0x00}, ++{0x3B1A, 0x00}, ++{0x3B1B, 0x00}, ++{0x3B1C, 0x00}, ++{0x3B1D, 0x00}, ++{0x3B1E, 0x00}, ++{0x3B1F, 0x00}, ++{0x3B20, 0x00}, ++{0x3B21, 0x00}, ++{0x3B22, 0x00}, ++{0x3B23, 0x00}, ++{0x3B24, 0x00}, ++{0x3B25, 0x00}, ++{0x3B26, 0x00}, ++{0x3B27, 0x00}, ++{0x3B28, 0x00}, ++{0x3B29, 0x00}, ++{0x3B2A, 0x00}, ++{0x3B2C, 0x00}, ++{0x3B2E, 0x00}, ++{0x3B30, 0x00}, ++{0x3B32, 0x0C}, ++{0x4000, 0xD1}, ++{0x4001, 0xC0}, ++{0x4002, 0xC0}, ++{0x4003, 0xB8}, ++{0x4004, 0xC0}, ++{0x4005, 0xB8}, ++{0x4006, 0xB9}, ++{0x4007, 0xB7}, ++{0x4008, 0xB0}, ++{0x4009, 0xAB}, ++{0x400A, 0xAC}, ++{0x400B, 0xAB}, ++{0x400C, 0xA8}, ++{0x400D, 0xA6}, ++{0x400E, 0xA6}, ++{0x400F, 0xA5}, ++{0x4010, 0xA2}, ++{0x4011, 0xA0}, ++{0x4012, 0xA0}, ++{0x4013, 0x9F}, ++{0x4014, 0xA4}, ++{0x4015, 0xA2}, ++{0x4016, 0xA2}, ++{0x4017, 0x9C}, ++{0x4018, 0xA8}, ++{0x4019, 0xA6}, ++{0x401A, 0xA8}, ++{0x401B, 0xAA}, ++{0x401C, 0xB0}, ++{0x401D, 0xAE}, ++{0x401E, 0xAE}, ++{0x401F, 0xAE}, ++{0x4020, 0xBA}, ++{0x4021, 0xAE}, ++{0x4022, 0xAF}, ++{0x4023, 0xAE}, ++{0x4024, 0xC6}, ++{0x4025, 0xBD}, ++{0x4026, 0xBD}, ++{0x4027, 0xBA}, ++{0x4028, 0xB0}, ++{0x4029, 0xA9}, ++{0x402A, 0xAA}, ++{0x402B, 0xA8}, ++{0x402C, 0x9F}, ++{0x402D, 0x9C}, ++{0x402E, 0x9C}, ++{0x402F, 0x9B}, ++{0x4030, 0x93}, ++{0x4031, 0x91}, ++{0x4032, 0x92}, ++{0x4033, 0x91}, ++{0x4034, 0x8D}, ++{0x4035, 0x8C}, ++{0x4036, 0x8C}, ++{0x4037, 0x8C}, ++{0x4038, 0x8F}, ++{0x4039, 0x8E}, ++{0x403A, 0x8E}, ++{0x403B, 0x8E}, ++{0x403C, 0x98}, ++{0x403D, 0x96}, ++{0x403E, 0x96}, ++{0x403F, 0x95}, ++{0x4040, 0xA4}, ++{0x4041, 0xA0}, ++{0x4042, 0xA0}, ++{0x4043, 0x9E}, ++{0x4044, 0xB3}, ++{0x4045, 0xAE}, ++{0x4046, 0xAF}, ++{0x4047, 0xAB}, ++{0x4048, 0xC2}, ++{0x4049, 0xB7}, ++{0x404A, 0xB8}, ++{0x404B, 0xB5}, ++{0x404C, 0xAB}, ++{0x404D, 0xA4}, ++{0x404E, 0xA5}, ++{0x404F, 0xA3}, ++{0x4050, 0x99}, ++{0x4051, 0x96}, ++{0x4052, 0x96}, ++{0x4053, 0x96}, ++{0x4054, 0x8B}, ++{0x4055, 0x8A}, ++{0x4056, 0x8A}, ++{0x4057, 0x8A}, ++{0x4058, 0x82}, ++{0x4059, 0x81}, ++{0x405A, 0x81}, ++{0x405B, 0x81}, ++{0x405C, 0x85}, ++{0x405D, 0x86}, ++{0x405E, 0x85}, ++{0x405F, 0x85}, ++{0x4060, 0x90}, ++{0x4061, 0x90}, ++{0x4062, 0x8F}, ++{0x4063, 0x8F}, ++{0x4064, 0x9D}, ++{0x4065, 0x9B}, ++{0x4066, 0x9B}, ++{0x4067, 0x9A}, ++{0x4068, 0xAF}, ++{0x4069, 0xAA}, ++{0x406A, 0xAC}, ++{0x406B, 0xAA}, ++{0x406C, 0xC2}, ++{0x406D, 0xB7}, ++{0x406E, 0xB8}, ++{0x406F, 0xB5}, ++{0x4070, 0xAB}, ++{0x4071, 0xA4}, ++{0x4072, 0xA4}, ++{0x4073, 0xA3}, ++{0x4074, 0x99}, ++{0x4075, 0x96}, ++{0x4076, 0x96}, ++{0x4077, 0x96}, ++{0x4078, 0x8B}, ++{0x4079, 0x8A}, ++{0x407A, 0x8A}, ++{0x407B, 0x8A}, ++{0x407C, 0x82}, ++{0x407D, 0x82}, ++{0x407E, 0x82}, ++{0x407F, 0x82}, ++{0x4080, 0x85}, ++{0x4081, 0x86}, ++{0x4082, 0x86}, ++{0x4083, 0x86}, ++{0x4084, 0x90}, ++{0x4085, 0x90}, ++{0x4086, 0x8F}, ++{0x4087, 0x8F}, ++{0x4088, 0x9D}, ++{0x4089, 0x9B}, ++{0x408A, 0x9B}, ++{0x408B, 0x99}, ++{0x408C, 0xAE}, ++{0x408D, 0xAA}, ++{0x408E, 0xAA}, ++{0x408F, 0xA7}, ++{0x4090, 0xC7}, ++{0x4091, 0xBA}, ++{0x4092, 0xBC}, ++{0x4093, 0xB9}, ++{0x4094, 0xB1}, ++{0x4095, 0xA8}, ++{0x4096, 0xA8}, ++{0x4097, 0xA7}, ++{0x4098, 0x9F}, ++{0x4099, 0x9B}, ++{0x409A, 0x9B}, ++{0x409B, 0x9B}, ++{0x409C, 0x93}, ++{0x409D, 0x91}, ++{0x409E, 0x91}, ++{0x409F, 0x91}, ++{0x40A0, 0x8D}, ++{0x40A1, 0x8C}, ++{0x40A2, 0x8C}, ++{0x40A3, 0x8C}, ++{0x40A4, 0x8E}, ++{0x40A5, 0x8E}, ++{0x40A6, 0x8D}, ++{0x40A7, 0x8D}, ++{0x40A8, 0x96}, ++{0x40A9, 0x95}, ++{0x40AA, 0x95}, ++{0x40AB, 0x94}, ++{0x40AC, 0xA2}, ++{0x40AD, 0x9F}, ++{0x40AE, 0x9F}, ++{0x40AF, 0x9D}, ++{0x40B0, 0xB1}, ++{0x40B1, 0xAC}, ++{0x40B2, 0xAB}, ++{0x40B3, 0xAA}, ++{0x40B4, 0xD3}, ++{0x40B5, 0xBC}, ++{0x40B6, 0xBD}, ++{0x40B7, 0xBC}, ++{0x40B8, 0xC1}, ++{0x40B9, 0xB7}, ++{0x40BA, 0xB7}, ++{0x40BB, 0xB5}, ++{0x40BC, 0xB0}, ++{0x40BD, 0xAA}, ++{0x40BE, 0xAA}, ++{0x40BF, 0xAA}, ++{0x40C0, 0xA8}, ++{0x40C1, 0xA4}, ++{0x40C2, 0xA4}, ++{0x40C3, 0xA4}, ++{0x40C4, 0xA2}, ++{0x40C5, 0x9F}, ++{0x40C6, 0x9F}, ++{0x40C7, 0x9F}, ++{0x40C8, 0xA3}, ++{0x40C9, 0xA0}, ++{0x40CA, 0xA0}, ++{0x40CB, 0xA0}, ++{0x40CC, 0xA6}, ++{0x40CD, 0xA3}, ++{0x40CE, 0xA3}, ++{0x40CF, 0xA2}, ++{0x40D0, 0xAF}, ++{0x40D1, 0xAB}, ++{0x40D2, 0xAA}, ++{0x40D3, 0xA8}, ++{0x40D4, 0xBA}, ++{0x40D5, 0xAE}, ++{0x40D6, 0xAE}, ++{0x40D7, 0xAB}, ++{0x4100, 0xBD}, ++{0x4101, 0xBA}, ++{0x4102, 0xBD}, ++{0x4103, 0xB7}, ++{0x4104, 0xB7}, ++{0x4105, 0xB7}, ++{0x4106, 0xB8}, ++{0x4107, 0xB5}, ++{0x4108, 0xAB}, ++{0x4109, 0xAA}, ++{0x410A, 0xAC}, ++{0x410B, 0xAB}, ++{0x410C, 0xA4}, ++{0x410D, 0xA5}, ++{0x410E, 0xA5}, ++{0x410F, 0xA4}, ++{0x4110, 0x9F}, ++{0x4111, 0xA0}, ++{0x4112, 0xA0}, ++{0x4113, 0x9F}, ++{0x4114, 0xA0}, ++{0x4115, 0xA0}, ++{0x4116, 0xA0}, ++{0x4117, 0x9F}, ++{0x4118, 0xA1}, ++{0x4119, 0xA1}, ++{0x411A, 0xA1}, ++{0x411B, 0xA0}, ++{0x411C, 0xA7}, ++{0x411D, 0xA6}, ++{0x411E, 0xA6}, ++{0x411F, 0xA6}, ++{0x4120, 0xA7}, ++{0x4121, 0xA6}, ++{0x4122, 0xA6}, ++{0x4123, 0xA3}, ++{0x4124, 0xB9}, ++{0x4125, 0xB9}, ++{0x4126, 0xBA}, ++{0x4127, 0xB8}, ++{0x4128, 0xA6}, ++{0x4129, 0xA7}, ++{0x412A, 0xA7}, ++{0x412B, 0xA6}, ++{0x412C, 0x9B}, ++{0x412D, 0x9B}, ++{0x412E, 0x9B}, ++{0x412F, 0x9B}, ++{0x4130, 0x91}, ++{0x4131, 0x92}, ++{0x4132, 0x92}, ++{0x4133, 0x91}, ++{0x4134, 0x8C}, ++{0x4135, 0x8C}, ++{0x4136, 0x8C}, ++{0x4137, 0x8C}, ++{0x4138, 0x8D}, ++{0x4139, 0x8D}, ++{0x413A, 0x8D}, ++{0x413B, 0x8D}, ++{0x413C, 0x93}, ++{0x413D, 0x93}, ++{0x413E, 0x93}, ++{0x413F, 0x92}, ++{0x4140, 0x9A}, ++{0x4141, 0x9A}, ++{0x4142, 0x9A}, ++{0x4143, 0x99}, ++{0x4144, 0xA7}, ++{0x4145, 0xA5}, ++{0x4146, 0xA6}, ++{0x4147, 0xA6}, ++{0x4148, 0xB8}, ++{0x4149, 0xB4}, ++{0x414A, 0xB4}, ++{0x414B, 0xB3}, ++{0x414C, 0xA3}, ++{0x414D, 0xA2}, ++{0x414E, 0xA3}, ++{0x414F, 0xA2}, ++{0x4150, 0x96}, ++{0x4151, 0x96}, ++{0x4152, 0x96}, ++{0x4153, 0x96}, ++{0x4154, 0x8A}, ++{0x4155, 0x8A}, ++{0x4156, 0x8A}, ++{0x4157, 0x8A}, ++{0x4158, 0x82}, ++{0x4159, 0x82}, ++{0x415A, 0x82}, ++{0x415B, 0x82}, ++{0x415C, 0x84}, ++{0x415D, 0x85}, ++{0x415E, 0x84}, ++{0x415F, 0x84}, ++{0x4160, 0x8D}, ++{0x4161, 0x8D}, ++{0x4162, 0x8D}, ++{0x4163, 0x8D}, ++{0x4164, 0x96}, ++{0x4165, 0x96}, ++{0x4166, 0x96}, ++{0x4167, 0x95}, ++{0x4168, 0xA5}, ++{0x4169, 0xA2}, ++{0x416A, 0xA3}, ++{0x416B, 0xA2}, ++{0x416C, 0xB7}, ++{0x416D, 0xB3}, ++{0x416E, 0xB5}, ++{0x416F, 0xB4}, ++{0x4170, 0xA4}, ++{0x4171, 0xA2}, ++{0x4172, 0xA3}, ++{0x4173, 0xA2}, ++{0x4174, 0x97}, ++{0x4175, 0x96}, ++{0x4176, 0x96}, ++{0x4177, 0x96}, ++{0x4178, 0x8B}, ++{0x4179, 0x8A}, ++{0x417A, 0x8A}, ++{0x417B, 0x8A}, ++{0x417C, 0x81}, ++{0x417D, 0x81}, ++{0x417E, 0x81}, ++{0x417F, 0x81}, ++{0x4180, 0x84}, ++{0x4181, 0x84}, ++{0x4182, 0x84}, ++{0x4183, 0x84}, ++{0x4184, 0x8C}, ++{0x4185, 0x8D}, ++{0x4186, 0x8D}, ++{0x4187, 0x8D}, ++{0x4188, 0x95}, ++{0x4189, 0x96}, ++{0x418A, 0x96}, ++{0x418B, 0x95}, ++{0x418C, 0xA1}, ++{0x418D, 0xA1}, ++{0x418E, 0xA1}, ++{0x418F, 0xA0}, ++{0x4190, 0xBC}, ++{0x4191, 0xB8}, ++{0x4192, 0xB8}, ++{0x4193, 0xB9}, ++{0x4194, 0xA8}, ++{0x4195, 0xA5}, ++{0x4196, 0xA6}, ++{0x4197, 0xA5}, ++{0x4198, 0x9C}, ++{0x4199, 0x9A}, ++{0x419A, 0x9A}, ++{0x419B, 0x9A}, ++{0x419C, 0x91}, ++{0x419D, 0x91}, ++{0x419E, 0x91}, ++{0x419F, 0x91}, ++{0x41A0, 0x8B}, ++{0x41A1, 0x8B}, ++{0x41A2, 0x8B}, ++{0x41A3, 0x8B}, ++{0x41A4, 0x8C}, ++{0x41A5, 0x8C}, ++{0x41A6, 0x8C}, ++{0x41A7, 0x8C}, ++{0x41A8, 0x91}, ++{0x41A9, 0x92}, ++{0x41AA, 0x91}, ++{0x41AB, 0x91}, ++{0x41AC, 0x98}, ++{0x41AD, 0x99}, ++{0x41AE, 0x99}, ++{0x41AF, 0x98}, ++{0x41B0, 0xA3}, ++{0x41B1, 0xA3}, ++{0x41B2, 0xA3}, ++{0x41B3, 0xA2}, ++{0x41B4, 0xC1}, ++{0x41B5, 0xB8}, ++{0x41B6, 0xB9}, ++{0x41B7, 0xBA}, ++{0x41B8, 0xB8}, ++{0x41B9, 0xB4}, ++{0x41BA, 0xB4}, ++{0x41BB, 0xB4}, ++{0x41BC, 0xAA}, ++{0x41BD, 0xA7}, ++{0x41BE, 0xA7}, ++{0x41BF, 0xA8}, ++{0x41C0, 0xA4}, ++{0x41C1, 0xA2}, ++{0x41C2, 0xA2}, ++{0x41C3, 0xA3}, ++{0x41C4, 0x9E}, ++{0x41C5, 0x9D}, ++{0x41C6, 0x9D}, ++{0x41C7, 0x9D}, ++{0x41C8, 0x9E}, ++{0x41C9, 0x9D}, ++{0x41CA, 0x9D}, ++{0x41CB, 0x9D}, ++{0x41CC, 0x9E}, ++{0x41CD, 0x9E}, ++{0x41CE, 0x9E}, ++{0x41CF, 0x9E}, ++{0x41D0, 0xA3}, ++{0x41D1, 0xA3}, ++{0x41D2, 0xA2}, ++{0x41D3, 0xA1}, ++{0x41D4, 0xA7}, ++{0x41D5, 0xA7}, ++{0x41D6, 0xA7}, ++{0x41D7, 0xA3}, ++{0x4200, 0xCE}, ++{0x4201, 0xC0}, ++{0x4202, 0xC1}, ++{0x4203, 0xB9}, ++{0x4204, 0xC3}, ++{0x4205, 0xB9}, ++{0x4206, 0xBC}, ++{0x4207, 0xBD}, ++{0x4208, 0xB3}, ++{0x4209, 0xAE}, ++{0x420A, 0xAF}, ++{0x420B, 0xAE}, ++{0x420C, 0xAA}, ++{0x420D, 0xA8}, ++{0x420E, 0xA8}, ++{0x420F, 0xA6}, ++{0x4210, 0xA4}, ++{0x4211, 0xA2}, ++{0x4212, 0xA2}, ++{0x4213, 0xA0}, ++{0x4214, 0xA4}, ++{0x4215, 0xA3}, ++{0x4216, 0xA2}, ++{0x4217, 0xA0}, ++{0x4218, 0xA7}, ++{0x4219, 0xA5}, ++{0x421A, 0xA3}, ++{0x421B, 0xA1}, ++{0x421C, 0xB0}, ++{0x421D, 0xA8}, ++{0x421E, 0xA8}, ++{0x421F, 0xA6}, ++{0x4220, 0xB4}, ++{0x4221, 0xAA}, ++{0x4222, 0xA5}, ++{0x4223, 0xA3}, ++{0x4224, 0xC7}, ++{0x4225, 0xBC}, ++{0x4226, 0xBE}, ++{0x4227, 0xBC}, ++{0x4228, 0xB0}, ++{0x4229, 0xA9}, ++{0x422A, 0xA9}, ++{0x422B, 0xA8}, ++{0x422C, 0xA0}, ++{0x422D, 0x9D}, ++{0x422E, 0x9D}, ++{0x422F, 0x9C}, ++{0x4230, 0x94}, ++{0x4231, 0x93}, ++{0x4232, 0x93}, ++{0x4233, 0x92}, ++{0x4234, 0x8E}, ++{0x4235, 0x8D}, ++{0x4236, 0x8D}, ++{0x4237, 0x8C}, ++{0x4238, 0x8F}, ++{0x4239, 0x8E}, ++{0x423A, 0x8E}, ++{0x423B, 0x8D}, ++{0x423C, 0x96}, ++{0x423D, 0x94}, ++{0x423E, 0x94}, ++{0x423F, 0x92}, ++{0x4240, 0xA1}, ++{0x4241, 0x9C}, ++{0x4242, 0x9C}, ++{0x4243, 0x99}, ++{0x4244, 0xB0}, ++{0x4245, 0xA8}, ++{0x4246, 0xAB}, ++{0x4247, 0xA7}, ++{0x4248, 0xC3}, ++{0x4249, 0xB7}, ++{0x424A, 0xB7}, ++{0x424B, 0xBC}, ++{0x424C, 0xAB}, ++{0x424D, 0xA4}, ++{0x424E, 0xA5}, ++{0x424F, 0xA5}, ++{0x4250, 0x9A}, ++{0x4251, 0x97}, ++{0x4252, 0x97}, ++{0x4253, 0x98}, ++{0x4254, 0x8C}, ++{0x4255, 0x8B}, ++{0x4256, 0x8B}, ++{0x4257, 0x8B}, ++{0x4258, 0x82}, ++{0x4259, 0x82}, ++{0x425A, 0x82}, ++{0x425B, 0x82}, ++{0x425C, 0x85}, ++{0x425D, 0x85}, ++{0x425E, 0x85}, ++{0x425F, 0x84}, ++{0x4260, 0x8F}, ++{0x4261, 0x8E}, ++{0x4262, 0x8E}, ++{0x4263, 0x8D}, ++{0x4264, 0x9B}, ++{0x4265, 0x98}, ++{0x4266, 0x98}, ++{0x4267, 0x95}, ++{0x4268, 0xAE}, ++{0x4269, 0xA5}, ++{0x426A, 0xA7}, ++{0x426B, 0xA2}, ++{0x426C, 0xC2}, ++{0x426D, 0xB7}, ++{0x426E, 0xB8}, ++{0x426F, 0xB9}, ++{0x4270, 0xAA}, ++{0x4271, 0xA4}, ++{0x4272, 0xA4}, ++{0x4273, 0xA5}, ++{0x4274, 0x99}, ++{0x4275, 0x96}, ++{0x4276, 0x97}, ++{0x4277, 0x98}, ++{0x4278, 0x8B}, ++{0x4279, 0x8A}, ++{0x427A, 0x8A}, ++{0x427B, 0x8B}, ++{0x427C, 0x81}, ++{0x427D, 0x81}, ++{0x427E, 0x81}, ++{0x427F, 0x82}, ++{0x4280, 0x84}, ++{0x4281, 0x84}, ++{0x4282, 0x84}, ++{0x4283, 0x84}, ++{0x4284, 0x8E}, ++{0x4285, 0x8E}, ++{0x4286, 0x8D}, ++{0x4287, 0x8C}, ++{0x4288, 0x9A}, ++{0x4289, 0x97}, ++{0x428A, 0x97}, ++{0x428B, 0x95}, ++{0x428C, 0xAA}, ++{0x428D, 0xA3}, ++{0x428E, 0xA3}, ++{0x428F, 0xA2}, ++{0x4290, 0xC7}, ++{0x4291, 0xBA}, ++{0x4292, 0xC0}, ++{0x4293, 0xC3}, ++{0x4294, 0xB0}, ++{0x4295, 0xA7}, ++{0x4296, 0xA7}, ++{0x4297, 0xA9}, ++{0x4298, 0x9F}, ++{0x4299, 0x9B}, ++{0x429A, 0x9B}, ++{0x429B, 0x9D}, ++{0x429C, 0x93}, ++{0x429D, 0x91}, ++{0x429E, 0x91}, ++{0x429F, 0x92}, ++{0x42A0, 0x8C}, ++{0x42A1, 0x8B}, ++{0x42A2, 0x8B}, ++{0x42A3, 0x8C}, ++{0x42A4, 0x8D}, ++{0x42A5, 0x8C}, ++{0x42A6, 0x8C}, ++{0x42A7, 0x8C}, ++{0x42A8, 0x94}, ++{0x42A9, 0x93}, ++{0x42AA, 0x92}, ++{0x42AB, 0x91}, ++{0x42AC, 0x9E}, ++{0x42AD, 0x9B}, ++{0x42AE, 0x9B}, ++{0x42AF, 0x98}, ++{0x42B0, 0xAC}, ++{0x42B1, 0xA6}, ++{0x42B2, 0xA6}, ++{0x42B3, 0xA2}, ++{0x42B4, 0xCE}, ++{0x42B5, 0xBA}, ++{0x42B6, 0xBC}, ++{0x42B7, 0xB7}, ++{0x42B8, 0xC5}, ++{0x42B9, 0xB5}, ++{0x42BA, 0xBA}, ++{0x42BB, 0xC0}, ++{0x42BC, 0xB1}, ++{0x42BD, 0xA8}, ++{0x42BE, 0xAE}, ++{0x42BF, 0xAF}, ++{0x42C0, 0xA7}, ++{0x42C1, 0xA3}, ++{0x42C2, 0xA3}, ++{0x42C3, 0xA5}, ++{0x42C4, 0xA0}, ++{0x42C5, 0x9D}, ++{0x42C6, 0x9D}, ++{0x42C7, 0x9F}, ++{0x42C8, 0xA0}, ++{0x42C9, 0x9E}, ++{0x42CA, 0x9E}, ++{0x42CB, 0x9F}, ++{0x42CC, 0xA2}, ++{0x42CD, 0xA0}, ++{0x42CE, 0xA0}, ++{0x42CF, 0xA0}, ++{0x42D0, 0xA8}, ++{0x42D1, 0xA5}, ++{0x42D2, 0xA5}, ++{0x42D3, 0xA2}, ++{0x42D4, 0xB3}, ++{0x42D5, 0xAA}, ++{0x42D6, 0xAB}, ++{0x42D7, 0xA3}, ++{0x42D8, 0x00}, ++{0x42D9, 0x00}, ++{0x4300, 0xA2}, ++{0x4301, 0xAE}, ++{0x4302, 0xAD}, ++{0x4303, 0xB5}, ++{0x4304, 0x95}, ++{0x4305, 0x9A}, ++{0x4306, 0x98}, ++{0x4307, 0x9B}, ++{0x4308, 0x8D}, ++{0x4309, 0x90}, ++{0x430A, 0x8F}, ++{0x430B, 0x91}, ++{0x430C, 0x86}, ++{0x430D, 0x88}, ++{0x430E, 0x87}, ++{0x430F, 0x89}, ++{0x4310, 0x86}, ++{0x4311, 0x87}, ++{0x4312, 0x86}, ++{0x4313, 0x88}, ++{0x4314, 0x89}, ++{0x4315, 0x88}, ++{0x4316, 0x88}, ++{0x4317, 0x8E}, ++{0x4318, 0x90}, ++{0x4319, 0x8F}, ++{0x431A, 0x8C}, ++{0x431B, 0x8C}, ++{0x431C, 0x9C}, ++{0x431D, 0x99}, ++{0x431E, 0x98}, ++{0x431F, 0x99}, ++{0x4320, 0xAB}, ++{0x4321, 0xB0}, ++{0x4322, 0xAD}, ++{0x4323, 0xAF}, ++{0x4324, 0x9B}, ++{0x4325, 0x9F}, ++{0x4326, 0x9E}, ++{0x4327, 0xA1}, ++{0x4328, 0x8E}, ++{0x4329, 0x91}, ++{0x432A, 0x90}, ++{0x432B, 0x93}, ++{0x432C, 0x86}, ++{0x432D, 0x88}, ++{0x432E, 0x87}, ++{0x432F, 0x89}, ++{0x4330, 0x82}, ++{0x4331, 0x84}, ++{0x4332, 0x83}, ++{0x4333, 0x84}, ++{0x4334, 0x82}, ++{0x4335, 0x82}, ++{0x4336, 0x82}, ++{0x4337, 0x83}, ++{0x4338, 0x85}, ++{0x4339, 0x84}, ++{0x433A, 0x84}, ++{0x433B, 0x85}, ++{0x433C, 0x8A}, ++{0x433D, 0x89}, ++{0x433E, 0x88}, ++{0x433F, 0x89}, ++{0x4340, 0x93}, ++{0x4341, 0x91}, ++{0x4342, 0x91}, ++{0x4343, 0x93}, ++{0x4344, 0xA0}, ++{0x4345, 0x9E}, ++{0x4346, 0x9D}, ++{0x4347, 0xA1}, ++{0x4348, 0x95}, ++{0x4349, 0x9B}, ++{0x434A, 0x9A}, ++{0x434B, 0x9C}, ++{0x434C, 0x8A}, ++{0x434D, 0x8D}, ++{0x434E, 0x8C}, ++{0x434F, 0x8D}, ++{0x4350, 0x83}, ++{0x4351, 0x85}, ++{0x4352, 0x84}, ++{0x4353, 0x85}, ++{0x4354, 0x80}, ++{0x4355, 0x81}, ++{0x4356, 0x81}, ++{0x4357, 0x81}, ++{0x4358, 0x80}, ++{0x4359, 0x80}, ++{0x435A, 0x80}, ++{0x435B, 0x80}, ++{0x435C, 0x82}, ++{0x435D, 0x81}, ++{0x435E, 0x81}, ++{0x435F, 0x81}, ++{0x4360, 0x85}, ++{0x4361, 0x84}, ++{0x4362, 0x84}, ++{0x4363, 0x85}, ++{0x4364, 0x8D}, ++{0x4365, 0x8B}, ++{0x4366, 0x8B}, ++{0x4367, 0x8D}, ++{0x4368, 0x98}, ++{0x4369, 0x98}, ++{0x436A, 0x95}, ++{0x436B, 0x98}, ++{0x436C, 0x95}, ++{0x436D, 0x9A}, ++{0x436E, 0x99}, ++{0x436F, 0x9A}, ++{0x4370, 0x8A}, ++{0x4371, 0x8D}, ++{0x4372, 0x8C}, ++{0x4373, 0x8C}, ++{0x4374, 0x83}, ++{0x4375, 0x85}, ++{0x4376, 0x84}, ++{0x4377, 0x84}, ++{0x4378, 0x80}, ++{0x4379, 0x80}, ++{0x437A, 0x80}, ++{0x437B, 0x80}, ++{0x437C, 0x7F}, ++{0x437D, 0x7F}, ++{0x437E, 0x7F}, ++{0x437F, 0x7F}, ++{0x4380, 0x81}, ++{0x4381, 0x80}, ++{0x4382, 0x80}, ++{0x4383, 0x81}, ++{0x4384, 0x84}, ++{0x4385, 0x83}, ++{0x4386, 0x83}, ++{0x4387, 0x84}, ++{0x4388, 0x8B}, ++{0x4389, 0x8A}, ++{0x438A, 0x8A}, ++{0x438B, 0x8C}, ++{0x438C, 0x97}, ++{0x438D, 0x96}, ++{0x438E, 0x96}, ++{0x438F, 0x99}, ++{0x4390, 0x99}, ++{0x4391, 0x9F}, ++{0x4392, 0x9E}, ++{0x4393, 0x9D}, ++{0x4394, 0x8D}, ++{0x4395, 0x90}, ++{0x4396, 0x90}, ++{0x4397, 0x8F}, ++{0x4398, 0x85}, ++{0x4399, 0x87}, ++{0x439A, 0x87}, ++{0x439B, 0x86}, ++{0x439C, 0x81}, ++{0x439D, 0x83}, ++{0x439E, 0x82}, ++{0x439F, 0x82}, ++{0x43A0, 0x80}, ++{0x43A1, 0x81}, ++{0x43A2, 0x81}, ++{0x43A3, 0x81}, ++{0x43A4, 0x82}, ++{0x43A5, 0x82}, ++{0x43A6, 0x82}, ++{0x43A7, 0x82}, ++{0x43A8, 0x86}, ++{0x43A9, 0x85}, ++{0x43AA, 0x85}, ++{0x43AB, 0x87}, ++{0x43AC, 0x8D}, ++{0x43AD, 0x8D}, ++{0x43AE, 0x8D}, ++{0x43AF, 0x90}, ++{0x43B0, 0x9A}, ++{0x43B1, 0x9A}, ++{0x43B2, 0x9B}, ++{0x43B3, 0x9D}, ++{0x43B4, 0xA0}, ++{0x43B5, 0xAD}, ++{0x43B6, 0xAC}, ++{0x43B7, 0xAA}, ++{0x43B8, 0x93}, ++{0x43B9, 0x97}, ++{0x43BA, 0x97}, ++{0x43BB, 0x96}, ++{0x43BC, 0x8B}, ++{0x43BD, 0x8E}, ++{0x43BE, 0x8E}, ++{0x43BF, 0x8C}, ++{0x43C0, 0x83}, ++{0x43C1, 0x85}, ++{0x43C2, 0x85}, ++{0x43C3, 0x84}, ++{0x43C4, 0x82}, ++{0x43C5, 0x84}, ++{0x43C6, 0x83}, ++{0x43C7, 0x83}, ++{0x43C8, 0x83}, ++{0x43C9, 0x84}, ++{0x43CA, 0x84}, ++{0x43CB, 0x85}, ++{0x43CC, 0x8A}, ++{0x43CD, 0x8A}, ++{0x43CE, 0x8A}, ++{0x43CF, 0x8C}, ++{0x43D0, 0x92}, ++{0x43D1, 0x93}, ++{0x43D2, 0x93}, ++{0x43D3, 0x96}, ++{0x43D4, 0x9F}, ++{0x43D5, 0xA6}, ++{0x43D6, 0xA5}, ++{0x43D7, 0xAA}, ++{0x4400, 0xA1}, ++{0x4401, 0xAB}, ++{0x4402, 0xA7}, ++{0x4403, 0xB0}, ++{0x4404, 0x91}, ++{0x4405, 0x96}, ++{0x4406, 0x94}, ++{0x4407, 0x99}, ++{0x4408, 0x8A}, ++{0x4409, 0x8E}, ++{0x440A, 0x8C}, ++{0x440B, 0x8F}, ++{0x440C, 0x85}, ++{0x440D, 0x86}, ++{0x440E, 0x86}, ++{0x440F, 0x88}, ++{0x4410, 0x85}, ++{0x4411, 0x86}, ++{0x4412, 0x85}, ++{0x4413, 0x87}, ++{0x4414, 0x88}, ++{0x4415, 0x87}, ++{0x4416, 0x87}, ++{0x4417, 0x89}, ++{0x4418, 0x91}, ++{0x4419, 0x8F}, ++{0x441A, 0x8F}, ++{0x441B, 0x90}, ++{0x441C, 0x9C}, ++{0x441D, 0x9B}, ++{0x441E, 0x9A}, ++{0x441F, 0x9A}, ++{0x4420, 0xB3}, ++{0x4421, 0xB1}, ++{0x4422, 0xB0}, ++{0x4423, 0xB2}, ++{0x4424, 0x96}, ++{0x4425, 0x9C}, ++{0x4426, 0x9A}, ++{0x4427, 0x9E}, ++{0x4428, 0x8B}, ++{0x4429, 0x8F}, ++{0x442A, 0x8E}, ++{0x442B, 0x91}, ++{0x442C, 0x84}, ++{0x442D, 0x87}, ++{0x442E, 0x86}, ++{0x442F, 0x88}, ++{0x4430, 0x82}, ++{0x4431, 0x83}, ++{0x4432, 0x82}, ++{0x4433, 0x84}, ++{0x4434, 0x82}, ++{0x4435, 0x82}, ++{0x4436, 0x82}, ++{0x4437, 0x83}, ++{0x4438, 0x84}, ++{0x4439, 0x84}, ++{0x443A, 0x84}, ++{0x443B, 0x84}, ++{0x443C, 0x8B}, ++{0x443D, 0x89}, ++{0x443E, 0x89}, ++{0x443F, 0x89}, ++{0x4440, 0x95}, ++{0x4441, 0x93}, ++{0x4442, 0x93}, ++{0x4443, 0x93}, ++{0x4444, 0xA2}, ++{0x4445, 0xA2}, ++{0x4446, 0xA1}, ++{0x4447, 0xA0}, ++{0x4448, 0x8F}, ++{0x4449, 0x97}, ++{0x444A, 0x97}, ++{0x444B, 0x98}, ++{0x444C, 0x87}, ++{0x444D, 0x8B}, ++{0x444E, 0x8A}, ++{0x444F, 0x8B}, ++{0x4450, 0x81}, ++{0x4451, 0x83}, ++{0x4452, 0x83}, ++{0x4453, 0x84}, ++{0x4454, 0x7F}, ++{0x4455, 0x80}, ++{0x4456, 0x80}, ++{0x4457, 0x81}, ++{0x4458, 0x80}, ++{0x4459, 0x80}, ++{0x445A, 0x80}, ++{0x445B, 0x80}, ++{0x445C, 0x82}, ++{0x445D, 0x81}, ++{0x445E, 0x81}, ++{0x445F, 0x81}, ++{0x4460, 0x87}, ++{0x4461, 0x85}, ++{0x4462, 0x85}, ++{0x4463, 0x86}, ++{0x4464, 0x90}, ++{0x4465, 0x8E}, ++{0x4466, 0x8E}, ++{0x4467, 0x8E}, ++{0x4468, 0x9B}, ++{0x4469, 0x9C}, ++{0x446A, 0x9A}, ++{0x446B, 0x9A}, ++{0x446C, 0x91}, ++{0x446D, 0x97}, ++{0x446E, 0x95}, ++{0x446F, 0x95}, ++{0x4470, 0x87}, ++{0x4471, 0x8A}, ++{0x4472, 0x8A}, ++{0x4473, 0x89}, ++{0x4474, 0x81}, ++{0x4475, 0x83}, ++{0x4476, 0x83}, ++{0x4477, 0x83}, ++{0x4478, 0x7F}, ++{0x4479, 0x80}, ++{0x447A, 0x80}, ++{0x447B, 0x80}, ++{0x447C, 0x80}, ++{0x447D, 0x80}, ++{0x447E, 0x80}, ++{0x447F, 0x7F}, ++{0x4480, 0x81}, ++{0x4481, 0x81}, ++{0x4482, 0x81}, ++{0x4483, 0x81}, ++{0x4484, 0x85}, ++{0x4485, 0x85}, ++{0x4486, 0x85}, ++{0x4487, 0x85}, ++{0x4488, 0x8E}, ++{0x4489, 0x8D}, ++{0x448A, 0x8D}, ++{0x448B, 0x8E}, ++{0x448C, 0x9D}, ++{0x448D, 0x9C}, ++{0x448E, 0x9C}, ++{0x448F, 0x9C}, ++{0x4490, 0x94}, ++{0x4491, 0x9B}, ++{0x4492, 0x9A}, ++{0x4493, 0x97}, ++{0x4494, 0x8A}, ++{0x4495, 0x8E}, ++{0x4496, 0x8E}, ++{0x4497, 0x8C}, ++{0x4498, 0x84}, ++{0x4499, 0x86}, ++{0x449A, 0x86}, ++{0x449B, 0x84}, ++{0x449C, 0x81}, ++{0x449D, 0x83}, ++{0x449E, 0x83}, ++{0x449F, 0x81}, ++{0x44A0, 0x81}, ++{0x44A1, 0x82}, ++{0x44A2, 0x82}, ++{0x44A3, 0x81}, ++{0x44A4, 0x83}, ++{0x44A5, 0x83}, ++{0x44A6, 0x83}, ++{0x44A7, 0x83}, ++{0x44A8, 0x88}, ++{0x44A9, 0x88}, ++{0x44AA, 0x88}, ++{0x44AB, 0x88}, ++{0x44AC, 0x91}, ++{0x44AD, 0x91}, ++{0x44AE, 0x91}, ++{0x44AF, 0x92}, ++{0x44B0, 0xA0}, ++{0x44B1, 0xA0}, ++{0x44B2, 0xA0}, ++{0x44B3, 0xA0}, ++{0x44B4, 0x9E}, ++{0x44B5, 0xA9}, ++{0x44B6, 0xA8}, ++{0x44B7, 0xA3}, ++{0x44B8, 0x90}, ++{0x44B9, 0x95}, ++{0x44BA, 0x95}, ++{0x44BB, 0x92}, ++{0x44BC, 0x8A}, ++{0x44BD, 0x8E}, ++{0x44BE, 0x8E}, ++{0x44BF, 0x8B}, ++{0x44C0, 0x84}, ++{0x44C1, 0x86}, ++{0x44C2, 0x86}, ++{0x44C3, 0x84}, ++{0x44C4, 0x84}, ++{0x44C5, 0x85}, ++{0x44C6, 0x85}, ++{0x44C7, 0x84}, ++{0x44C8, 0x86}, ++{0x44C9, 0x87}, ++{0x44CA, 0x87}, ++{0x44CB, 0x86}, ++{0x44CC, 0x8D}, ++{0x44CD, 0x8E}, ++{0x44CE, 0x8E}, ++{0x44CF, 0x8D}, ++{0x44D0, 0x98}, ++{0x44D1, 0x98}, ++{0x44D2, 0x99}, ++{0x44D3, 0x9A}, ++{0x44D4, 0xA9}, ++{0x44D5, 0xAA}, ++{0x44D6, 0xAA}, ++{0x44D7, 0xAD}, ++{0x4500, 0x9F}, ++{0x4501, 0xA8}, ++{0x4502, 0xA5}, ++{0x4503, 0xAF}, ++{0x4504, 0x8F}, ++{0x4505, 0x96}, ++{0x4506, 0x92}, ++{0x4507, 0x94}, ++{0x4508, 0x89}, ++{0x4509, 0x8D}, ++{0x450A, 0x8A}, ++{0x450B, 0x8E}, ++{0x450C, 0x84}, ++{0x450D, 0x85}, ++{0x450E, 0x84}, ++{0x450F, 0x87}, ++{0x4510, 0x84}, ++{0x4511, 0x85}, ++{0x4512, 0x84}, ++{0x4513, 0x86}, ++{0x4514, 0x87}, ++{0x4515, 0x86}, ++{0x4516, 0x86}, ++{0x4517, 0x88}, ++{0x4518, 0x8F}, ++{0x4519, 0x8D}, ++{0x451A, 0x8D}, ++{0x451B, 0x8F}, ++{0x451C, 0x9A}, ++{0x451D, 0x9A}, ++{0x451E, 0x98}, ++{0x451F, 0x9A}, ++{0x4520, 0xAF}, ++{0x4521, 0xAF}, ++{0x4522, 0xB2}, ++{0x4523, 0xB1}, ++{0x4524, 0x95}, ++{0x4525, 0x9B}, ++{0x4526, 0x97}, ++{0x4527, 0x9C}, ++{0x4528, 0x8A}, ++{0x4529, 0x8E}, ++{0x452A, 0x8D}, ++{0x452B, 0x90}, ++{0x452C, 0x84}, ++{0x452D, 0x86}, ++{0x452E, 0x85}, ++{0x452F, 0x87}, ++{0x4530, 0x81}, ++{0x4531, 0x82}, ++{0x4532, 0x82}, ++{0x4533, 0x83}, ++{0x4534, 0x81}, ++{0x4535, 0x81}, ++{0x4536, 0x81}, ++{0x4537, 0x82}, ++{0x4538, 0x84}, ++{0x4539, 0x83}, ++{0x453A, 0x83}, ++{0x453B, 0x84}, ++{0x453C, 0x8A}, ++{0x453D, 0x88}, ++{0x453E, 0x88}, ++{0x453F, 0x89}, ++{0x4540, 0x94}, ++{0x4541, 0x92}, ++{0x4542, 0x91}, ++{0x4543, 0x92}, ++{0x4544, 0xA1}, ++{0x4545, 0xA0}, ++{0x4546, 0x9C}, ++{0x4547, 0x9D}, ++{0x4548, 0x8F}, ++{0x4549, 0x96}, ++{0x454A, 0x95}, ++{0x454B, 0x92}, ++{0x454C, 0x87}, ++{0x454D, 0x8A}, ++{0x454E, 0x89}, ++{0x454F, 0x8A}, ++{0x4550, 0x81}, ++{0x4551, 0x83}, ++{0x4552, 0x82}, ++{0x4553, 0x83}, ++{0x4554, 0x7F}, ++{0x4555, 0x80}, ++{0x4556, 0x80}, ++{0x4557, 0x81}, ++{0x4558, 0x7F}, ++{0x4559, 0x80}, ++{0x455A, 0x7F}, ++{0x455B, 0x80}, ++{0x455C, 0x81}, ++{0x455D, 0x81}, ++{0x455E, 0x81}, ++{0x455F, 0x81}, ++{0x4560, 0x86}, ++{0x4561, 0x85}, ++{0x4562, 0x85}, ++{0x4563, 0x85}, ++{0x4564, 0x8F}, ++{0x4565, 0x8D}, ++{0x4566, 0x8D}, ++{0x4567, 0x8D}, ++{0x4568, 0x99}, ++{0x4569, 0x9A}, ++{0x456A, 0x97}, ++{0x456B, 0x99}, ++{0x456C, 0x90}, ++{0x456D, 0x95}, ++{0x456E, 0x93}, ++{0x456F, 0x92}, ++{0x4570, 0x87}, ++{0x4571, 0x8A}, ++{0x4572, 0x88}, ++{0x4573, 0x87}, ++{0x4574, 0x81}, ++{0x4575, 0x83}, ++{0x4576, 0x82}, ++{0x4577, 0x82}, ++{0x4578, 0x7F}, ++{0x4579, 0x80}, ++{0x457A, 0x80}, ++{0x457B, 0x80}, ++{0x457C, 0x80}, ++{0x457D, 0x80}, ++{0x457E, 0x80}, ++{0x457F, 0x80}, ++{0x4580, 0x81}, ++{0x4581, 0x81}, ++{0x4582, 0x81}, ++{0x4583, 0x81}, ++{0x4584, 0x85}, ++{0x4585, 0x85}, ++{0x4586, 0x84}, ++{0x4587, 0x85}, ++{0x4588, 0x8E}, ++{0x4589, 0x8D}, ++{0x458A, 0x8C}, ++{0x458B, 0x8D}, ++{0x458C, 0x9B}, ++{0x458D, 0x9B}, ++{0x458E, 0x9A}, ++{0x458F, 0x98}, ++{0x4590, 0x94}, ++{0x4591, 0x9A}, ++{0x4592, 0x94}, ++{0x4593, 0x90}, ++{0x4594, 0x8A}, ++{0x4595, 0x8D}, ++{0x4596, 0x8C}, ++{0x4597, 0x89}, ++{0x4598, 0x84}, ++{0x4599, 0x86}, ++{0x459A, 0x85}, ++{0x459B, 0x83}, ++{0x459C, 0x82}, ++{0x459D, 0x83}, ++{0x459E, 0x82}, ++{0x459F, 0x80}, ++{0x45A0, 0x81}, ++{0x45A1, 0x82}, ++{0x45A2, 0x81}, ++{0x45A3, 0x80}, ++{0x45A4, 0x83}, ++{0x45A5, 0x83}, ++{0x45A6, 0x83}, ++{0x45A7, 0x83}, ++{0x45A8, 0x88}, ++{0x45A9, 0x87}, ++{0x45AA, 0x87}, ++{0x45AB, 0x88}, ++{0x45AC, 0x91}, ++{0x45AD, 0x90}, ++{0x45AE, 0x90}, ++{0x45AF, 0x91}, ++{0x45B0, 0x9F}, ++{0x45B1, 0x9F}, ++{0x45B2, 0x9E}, ++{0x45B3, 0x9F}, ++{0x45B4, 0x9F}, ++{0x45B5, 0xA8}, ++{0x45B6, 0xA6}, ++{0x45B7, 0xA7}, ++{0x45B8, 0x8D}, ++{0x45B9, 0x95}, ++{0x45BA, 0x90}, ++{0x45BB, 0x8A}, ++{0x45BC, 0x89}, ++{0x45BD, 0x8D}, ++{0x45BE, 0x88}, ++{0x45BF, 0x86}, ++{0x45C0, 0x84}, ++{0x45C1, 0x86}, ++{0x45C2, 0x85}, ++{0x45C3, 0x82}, ++{0x45C4, 0x84}, ++{0x45C5, 0x85}, ++{0x45C6, 0x85}, ++{0x45C7, 0x83}, ++{0x45C8, 0x86}, ++{0x45C9, 0x86}, ++{0x45CA, 0x86}, ++{0x45CB, 0x85}, ++{0x45CC, 0x8E}, ++{0x45CD, 0x8D}, ++{0x45CE, 0x8D}, ++{0x45CF, 0x8C}, ++{0x45D0, 0x99}, ++{0x45D1, 0x98}, ++{0x45D2, 0x98}, ++{0x45D3, 0x98}, ++{0x45D4, 0xA6}, ++{0x45D5, 0xA9}, ++{0x45D6, 0xA7}, ++{0x45D7, 0xAC}, ++{0x7000, 0xAB}, ++{0x7001, 0xBA}, ++{0x7002, 0x40}, ++{0x7003, 0x02}, ++{0x7004, 0x00}, ++{0x7005, 0x00}, ++{0x7006, 0x00}, ++{0x7007, 0x00}, ++{0x7008, 0x00}, ++{0x7009, 0x00}, ++{0x700A, 0x00}, ++{0x700B, 0x00}, ++{0x700C, 0x00}, ++{0x700D, 0x00}, ++{0x700E, 0x00}, ++{0x700F, 0x00}, ++{0x7010, 0x55}, ++{0x7011, 0x88}, ++{0x7012, 0x40}, ++{0x7013, 0x01}, ++{0x7014, 0x72}, ++{0x7015, 0xF1}, ++{0x7016, 0x02}, ++{0x7017, 0xF8}, ++{0x7018, 0x00}, ++{0x7019, 0x00}, ++{0x701A, 0x00}, ++{0x701B, 0x00}, ++{0x701C, 0x00}, ++{0x701D, 0x00}, ++{0x701E, 0x00}, ++{0x701F, 0x00}, ++{0x7020, 0x00}, ++{0x7021, 0x00}, ++{0x7022, 0x00}, ++{0x7023, 0x00}, ++{0x7024, 0x00}, ++{0x7025, 0x00}, ++{0x7026, 0x00}, ++{0x7027, 0x00}, ++{0x7028, 0x00}, ++{0x7029, 0x00}, ++{0x702A, 0x00}, ++{0x702B, 0x00}, ++{0x702C, 0x00}, ++{0x702D, 0x00}, ++{0x702E, 0x00}, ++{0x702F, 0x00}, ++{0x7030, 0x00}, ++{0x7031, 0x00}, ++{0x7032, 0x00}, ++{0x7033, 0x00}, ++{0x7034, 0x00}, ++{0x7035, 0x00}, ++{0x7036, 0x00}, ++{0x7037, 0x00}, ++{0x7038, 0x00}, ++{0x7039, 0x00}, ++{0x703A, 0x00}, ++{0x703B, 0x00}, ++{0x703C, 0x00}, ++{0x703D, 0x00}, ++{0x703E, 0x00}, ++{0x703F, 0x00}, ++{0x7040, 0x00}, ++{0x7041, 0x00}, ++{0x7042, 0x00}, ++{0x7043, 0x00}, ++{0x7044, 0x00}, ++{0x7045, 0x00}, ++{0x7046, 0x00}, ++{0x7047, 0x00}, ++{0x7048, 0x00}, ++{0x7049, 0x00}, ++{0x704A, 0x00}, ++{0x704B, 0x00}, ++{0x704C, 0x00}, ++{0x704D, 0x00}, ++{0x704E, 0x00}, ++{0x704F, 0x00}, ++{0x7050, 0x00}, ++{0x7051, 0x00}, ++{0x7052, 0x00}, ++{0x7053, 0x00}, ++{0x7054, 0x00}, ++{0x7055, 0x00}, ++{0x7056, 0x00}, ++{0x7057, 0x00}, ++{0x7058, 0x00}, ++{0x7059, 0x00}, ++{0x705A, 0x00}, ++{0x705B, 0x00}, ++{0x705C, 0x00}, ++{0x705D, 0x00}, ++{0x705E, 0x00}, ++{0x705F, 0x00}, ++{0x7060, 0x00}, ++{0x7061, 0x00}, ++{0x7062, 0x00}, ++{0x7063, 0x00}, ++{0x7064, 0x00}, ++{0x7065, 0x00}, ++{0x7066, 0x00}, ++{0x7067, 0x00}, ++{0x7068, 0x00}, ++{0x7069, 0x00}, ++{0x706A, 0x00}, ++{0x706B, 0x00}, ++{0x706C, 0x00}, ++{0x706D, 0x00}, ++{0x706E, 0x00}, ++{0x706F, 0x00}, ++{0x7070, 0x00}, ++{0x7071, 0x00}, ++{0x7072, 0x00}, ++{0x7073, 0x00}, ++{0x7074, 0x00}, ++{0x7075, 0x00}, ++{0x7076, 0x00}, ++{0x7077, 0x00}, ++{0x7078, 0x00}, ++{0x7079, 0x00}, ++{0x707A, 0x00}, ++{0x707B, 0x00}, ++{0x707C, 0x00}, ++{0x707D, 0x00}, ++{0x707E, 0x00}, ++{0x707F, 0x00}, ++{0x7080, 0x00}, ++{0x7081, 0x00}, ++{0x7082, 0x00}, ++{0x7083, 0x00}, ++{0x7084, 0x00}, ++{0x7085, 0x00}, ++{0x7086, 0x00}, ++{0x7087, 0x00}, ++{0x7088, 0x00}, ++{0x7089, 0x00}, ++{0x708A, 0x00}, ++{0x708B, 0x00}, ++{0x708C, 0x00}, ++{0x708D, 0x00}, ++{0x708E, 0x00}, ++{0x708F, 0x00}, ++{0x7090, 0x00}, ++{0x7091, 0xF0}, ++{0x7092, 0x02}, ++{0x7093, 0xF8}, ++{0x7094, 0x8D}, ++{0x7095, 0xF6}, ++{0x7096, 0xFA}, ++{0x7097, 0xFF}, ++{0x7098, 0xF0}, ++{0x7099, 0xB5}, ++{0x709A, 0x04}, ++{0x709B, 0x46}, ++{0x709C, 0x8F}, ++{0x709D, 0xB0}, ++{0x709E, 0x5F}, ++{0x709F, 0x48}, ++{0x70A0, 0x0C}, ++{0x70A1, 0x90}, ++{0x70A2, 0x5F}, ++{0x70A3, 0x48}, ++{0x70A4, 0x06}, ++{0x70A5, 0x90}, ++{0x70A6, 0x20}, ++{0x70A7, 0x46}, ++{0x70A8, 0x34}, ++{0x70A9, 0x30}, ++{0x70AA, 0x0B}, ++{0x70AB, 0x90}, ++{0x70AC, 0x5B}, ++{0x70AD, 0x48}, ++{0x70AE, 0x5A}, ++{0x70AF, 0x49}, ++{0x70B0, 0x26}, ++{0x70B1, 0x46}, ++{0x70B2, 0x66}, ++{0x70B3, 0x30}, ++{0x70B4, 0x3A}, ++{0x70B5, 0x31}, ++{0x70B6, 0x3C}, ++{0x70B7, 0x36}, ++{0x70B8, 0x05}, ++{0x70B9, 0x90}, ++{0x70BA, 0x0A}, ++{0x70BB, 0x30}, ++{0x70BC, 0x04}, ++{0x70BD, 0x90}, ++{0x70BE, 0x59}, ++{0x70BF, 0x48}, ++{0x70C0, 0x55}, ++{0x70C1, 0x4A}, ++{0x70C2, 0x40}, ++{0x70C3, 0x6E}, ++{0x70C4, 0xC0}, ++{0x70C5, 0x07}, ++{0x70C6, 0x7D}, ++{0x70C7, 0xD1}, ++{0x70C8, 0x17}, ++{0x70C9, 0x88}, ++{0x70CA, 0x0A}, ++{0x70CB, 0x5E}, ++{0x70CC, 0x0D}, ++{0x70CD, 0x92}, ++{0x70CE, 0x53}, ++{0x70CF, 0x49}, ++{0x70D0, 0x55}, ++{0x70D1, 0x48}, ++{0x70D2, 0x94}, ++{0x70D3, 0x31}, ++{0x70D4, 0x89}, ++{0x70D5, 0x6B}, ++{0x70D6, 0x80}, ++{0x70D7, 0x68}, ++{0x70D8, 0x09}, ++{0x70D9, 0x02}, ++{0x70DA, 0x00}, ++{0x70DB, 0x03}, ++{0x70DC, 0x09}, ++{0x70DD, 0x0E}, ++{0x70DE, 0x00}, ++{0x70DF, 0x0B}, ++{0x70E0, 0x49}, ++{0x70E1, 0x1C}, ++{0x70E2, 0x48}, ++{0x70E3, 0x43}, ++{0x70E4, 0x4D}, ++{0x70E5, 0x49}, ++{0x70E6, 0x6C}, ++{0x70E7, 0x39}, ++{0x70E8, 0x8A}, ++{0x70E9, 0x6A}, ++{0x70EA, 0x07}, ++{0x70EB, 0x92}, ++{0x70EC, 0xCA}, ++{0x70ED, 0x6A}, ++{0x70EE, 0x00}, ++{0x70EF, 0x21}, ++{0x70F0, 0xC9}, ++{0x70F1, 0x43}, ++{0x70F2, 0x03}, ++{0x70F3, 0x92}, ++{0x70F4, 0x00}, ++{0x70F5, 0x22}, ++{0x70F6, 0x00}, ++{0x70F7, 0x91}, ++{0x70F8, 0x01}, ++{0x70F9, 0x92}, ++{0x70FA, 0x39}, ++{0x70FB, 0x46}, ++{0x70FC, 0x8F}, ++{0x70FD, 0xF6}, ++{0x70FE, 0xCE}, ++{0x70FF, 0xFB}, ++{0x7100, 0x01}, ++{0x7101, 0x22}, ++{0x7102, 0x00}, ++{0x7103, 0x23}, ++{0x7104, 0x8C}, ++{0x7105, 0xF6}, ++{0x7106, 0x02}, ++{0x7107, 0xFA}, ++{0x7108, 0x00}, ++{0x7109, 0x21}, ++{0x710A, 0x05}, ++{0x710B, 0x46}, ++{0x710C, 0x01}, ++{0x710D, 0x91}, ++{0x710E, 0x00}, ++{0x710F, 0x90}, ++{0x7110, 0x39}, ++{0x7111, 0x46}, ++{0x7112, 0x07}, ++{0x7113, 0x98}, ++{0x7114, 0x8F}, ++{0x7115, 0xF6}, ++{0x7116, 0xC2}, ++{0x7117, 0xFB}, ++{0x7118, 0x0D}, ++{0x7119, 0x9A}, ++{0x711A, 0xD3}, ++{0x711B, 0x17}, ++{0x711C, 0x80}, ++{0x711D, 0x18}, ++{0x711E, 0x59}, ++{0x711F, 0x41}, ++{0x7120, 0x01}, ++{0x7121, 0x22}, ++{0x7122, 0x00}, ++{0x7123, 0x23}, ++{0x7124, 0x8C}, ++{0x7125, 0xF6}, ++{0x7126, 0xCD}, ++{0x7127, 0xF9}, ++{0x7128, 0x07}, ++{0x7129, 0x90}, ++{0x712A, 0x00}, ++{0x712B, 0x20}, ++{0x712C, 0x01}, ++{0x712D, 0x90}, ++{0x712E, 0x00}, ++{0x712F, 0x95}, ++{0x7130, 0x39}, ++{0x7131, 0x46}, ++{0x7132, 0x03}, ++{0x7133, 0x98}, ++{0x7134, 0x8F}, ++{0x7135, 0xF6}, ++{0x7136, 0xB2}, ++{0x7137, 0xFB}, ++{0x7138, 0x01}, ++{0x7139, 0x22}, ++{0x713A, 0x00}, ++{0x713B, 0x23}, ++{0x713C, 0x8C}, ++{0x713D, 0xF6}, ++{0x713E, 0xE6}, ++{0x713F, 0xF9}, ++{0x7140, 0x02}, ++{0x7141, 0x46}, ++{0x7142, 0x07}, ++{0x7143, 0x98}, ++{0x7144, 0x00}, ++{0x7145, 0x23}, ++{0x7146, 0x81}, ++{0x7147, 0x0B}, ++{0x7148, 0x80}, ++{0x7149, 0x04}, ++{0x714A, 0x7A}, ++{0x714B, 0xF6}, ++{0x714C, 0x54}, ++{0x714D, 0xF8}, ++{0x714E, 0x37}, ++{0x714F, 0x4A}, ++{0x7150, 0x00}, ++{0x7151, 0x23}, ++{0x7152, 0x00}, ++{0x7153, 0x92}, ++{0x7154, 0x01}, ++{0x7155, 0x93}, ++{0x7156, 0x01}, ++{0x7157, 0x22}, ++{0x7158, 0x8C}, ++{0x7159, 0xF6}, ++{0x715A, 0xD8}, ++{0x715B, 0xF9}, ++{0x715C, 0x05}, ++{0x715D, 0x46}, ++{0x715E, 0x60}, ++{0x715F, 0x68}, ++{0x7160, 0x00}, ++{0x7161, 0x23}, ++{0x7162, 0x01}, ++{0x7163, 0x0C}, ++{0x7164, 0x00}, ++{0x7165, 0x04}, ++{0x7166, 0xE2}, ++{0x7167, 0x68}, ++{0x7168, 0x7A}, ++{0x7169, 0xF6}, ++{0x716A, 0x45}, ++{0x716B, 0xF8}, ++{0x716C, 0x00}, ++{0x716D, 0x22}, ++{0x716E, 0xD2}, ++{0x716F, 0x43}, ++{0x7170, 0x00}, ++{0x7171, 0x23}, ++{0x7172, 0x00}, ++{0x7173, 0x92}, ++{0x7174, 0x01}, ++{0x7175, 0x93}, ++{0x7176, 0x1A}, ++{0x7177, 0x46}, ++{0x7178, 0x8C}, ++{0x7179, 0xF6}, ++{0x717A, 0xC8}, ++{0x717B, 0xF9}, ++{0x717C, 0x29}, ++{0x717D, 0x46}, ++{0x717E, 0x8F}, ++{0x717F, 0xF6}, ++{0x7180, 0x8D}, ++{0x7181, 0xFB}, ++{0x7182, 0x8A}, ++{0x7183, 0x03}, ++{0x7184, 0x80}, ++{0x7185, 0x0C}, ++{0x7186, 0x10}, ++{0x7187, 0x43}, ++{0x7188, 0x00}, ++{0x7189, 0x22}, ++{0x718A, 0xD2}, ++{0x718B, 0x43}, ++{0x718C, 0x00}, ++{0x718D, 0x23}, ++{0x718E, 0x00}, ++{0x718F, 0x92}, ++{0x7190, 0x89}, ++{0x7191, 0x0C}, ++{0x7192, 0x01}, ++{0x7193, 0x93}, ++{0x7194, 0x1A}, ++{0x7195, 0x46}, ++{0x7196, 0x8C}, ++{0x7197, 0xF6}, ++{0x7198, 0xB9}, ++{0x7199, 0xF9}, ++{0x719A, 0x00}, ++{0x719B, 0x24}, ++{0x719C, 0x03}, ++{0x719D, 0x90}, ++{0x719E, 0x0C}, ++{0x719F, 0x98}, ++{0x71A0, 0x61}, ++{0x71A1, 0x00}, ++{0x71A2, 0x45}, ++{0x71A3, 0x5A}, ++{0x71A4, 0x06}, ++{0x71A5, 0x98}, ++{0x71A6, 0x22}, ++{0x71A7, 0x4A}, ++{0x71A8, 0x40}, ++{0x71A9, 0x5A}, ++{0x71AA, 0x00}, ++{0x71AB, 0x21}, ++{0x71AC, 0x8C}, ++{0x71AD, 0xF6}, ++{0x71AE, 0xBE}, ++{0x71AF, 0xF9}, ++{0x71B0, 0x07}, ++{0x71B1, 0x46}, ++{0x71B2, 0x28}, ++{0x71B3, 0x46}, ++{0x71B4, 0x03}, ++{0x71B5, 0x99}, ++{0x71B6, 0x8F}, ++{0x71B7, 0xF6}, ++{0x71B8, 0x71}, ++{0x71B9, 0xFB}, ++{0x71BA, 0x3A}, ++{0x71BB, 0x46}, ++{0x71BC, 0x00}, ++{0x71BD, 0x23}, ++{0x71BE, 0x79}, ++{0x71BF, 0xF6}, ++{0x71C0, 0xCA}, ++{0x71C1, 0xFF}, ++{0x71C2, 0x00}, ++{0x71C3, 0xE0}, ++{0x71C4, 0x0F}, ++{0x71C5, 0xE0}, ++{0x71C6, 0x8A}, ++{0x71C7, 0x02}, ++{0x71C8, 0x80}, ++{0x71C9, 0x0D}, ++{0x71CA, 0x10}, ++{0x71CB, 0x43}, ++{0x71CC, 0x19}, ++{0x71CD, 0x4A}, ++{0x71CE, 0x00}, ++{0x71CF, 0x23}, ++{0x71D0, 0x00}, ++{0x71D1, 0x92}, ++{0x71D2, 0x89}, ++{0x71D3, 0x0D}, ++{0x71D4, 0x01}, ++{0x71D5, 0x93}, ++{0x71D6, 0x40}, ++{0x71D7, 0x22}, ++{0x71D8, 0x8C}, ++{0x71D9, 0xF6}, ++{0x71DA, 0x98}, ++{0x71DB, 0xF9}, ++{0x71DC, 0xA1}, ++{0x71DD, 0x00}, ++{0x71DE, 0x64}, ++{0x71DF, 0x1C}, ++{0x71E0, 0x70}, ++{0x71E1, 0x50}, ++{0x71E2, 0x04}, ++{0x71E3, 0x2C}, ++{0x71E4, 0xDB}, ++{0x71E5, 0xD3}, ++{0x71E6, 0x14}, ++{0x71E7, 0x4D}, ++{0x71E8, 0x00}, ++{0x71E9, 0x24}, ++{0x71EA, 0x0B}, ++{0x71EB, 0x98}, ++{0x71EC, 0x67}, ++{0x71ED, 0x00}, ++{0x71EE, 0xC0}, ++{0x71EF, 0x5B}, ++{0x71F0, 0x2A}, ++{0x71F1, 0x46}, ++{0x71F2, 0x40}, ++{0x71F3, 0x21}, ++{0x71F4, 0x8C}, ++{0x71F5, 0xF6}, ++{0x71F6, 0x9A}, ++{0x71F7, 0xF9}, ++{0x71F8, 0x05}, ++{0x71F9, 0x99}, ++{0x71FA, 0x0E}, ++{0x71FB, 0x4A}, ++{0x71FC, 0xC8}, ++{0x71FD, 0x53}, ++{0x71FE, 0xA7}, ++{0x71FF, 0x00}, ++{0x7200, 0xF0}, ++{0x7201, 0x59}, ++{0x7202, 0x40}, ++{0x7203, 0x21}, ++{0x7204, 0x8C}, ++{0x7205, 0xF6}, ++{0x7206, 0x7B}, ++{0x7207, 0xF9}, ++{0x7208, 0x04}, ++{0x7209, 0x99}, ++{0x720A, 0x64}, ++{0x720B, 0x1C}, ++{0x720C, 0xC8}, ++{0x720D, 0x51}, ++{0x720E, 0x04}, ++{0x720F, 0x2C}, ++{0x7210, 0xEB}, ++{0x7211, 0xD3}, ++{0x7212, 0x0F}, ++{0x7213, 0xB0}, ++{0x7214, 0xF0}, ++{0x7215, 0xBD}, ++{0x7216, 0x00}, ++{0x7217, 0x00}, ++{0x7218, 0x76}, ++{0x7219, 0x69}, ++{0x721A, 0x18}, ++{0x721B, 0x00}, ++{0x721C, 0xEC}, ++{0x721D, 0x58}, ++{0x721E, 0x18}, ++{0x721F, 0x00}, ++{0x7220, 0x38}, ++{0x7221, 0x36}, ++{0x7222, 0x18}, ++{0x7223, 0x00}, ++{0x7224, 0x00}, ++{0x7225, 0x35}, ++{0x7226, 0x18}, ++{0x7227, 0x00}, ++{0x7228, 0x00}, ++{0x7229, 0x20}, ++{0x722A, 0x18}, ++{0x722B, 0x00}, ++{0x722C, 0xFF}, ++{0x722D, 0xFF}, ++{0x722E, 0xFF}, ++{0x722F, 0x3F}, ++{0x7230, 0xFF}, ++{0x7231, 0x07}, ++{0x7232, 0x00}, ++{0x7233, 0x00}, ++{0x7234, 0xFF}, ++{0x7235, 0xFF}, ++{0x7236, 0x07}, ++{0x7237, 0x00}, ++{0x7238, 0xFF}, ++{0x7239, 0x1F}, ++{0x723A, 0x00}, ++{0x723B, 0x00}, ++{0x723C, 0x01}, ++{0x723D, 0xF6}, ++{0x723E, 0x45}, ++{0x723F, 0x12}, ++{0x3450, 0x00}, /* use continuous clock */ ++//{0x3448, 0x2f}, // RAW20 DT ++//{0x3449, 0x2c}, // RAW12 DT ++{0x0000, 0x00}, ++}; ++ +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch new file mode 100644 index 00000000..84a7e44e --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch @@ -0,0 +1,620 @@ +From 0368ffc88e6aec7655d9b63c7ddc50c57714dd58 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Sat, 30 May 2020 00:48:18 +0300 +Subject: [PATCH] media: i2c: soc_camera: add dummy lvds sensor + +This adds sensor that is not detectable behind serializer + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/dummy.c | 539 +++++++++++++++++++++++++++++++++ + drivers/media/i2c/soc_camera/max9286.h | 3 + + drivers/media/i2c/soc_camera/ov106xx.c | 11 + + 3 files changed, 553 insertions(+) + create mode 100644 drivers/media/i2c/soc_camera/dummy.c + +diff --git a/drivers/media/i2c/soc_camera/dummy.c b/drivers/media/i2c/soc_camera/dummy.c +new file mode 100644 +index 0000000..346b5dd +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/dummy.c +@@ -0,0 +1,539 @@ ++/* ++ * Dummy sensor camera driver ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++struct dummy_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ u8 id[6]; ++ int max_width; ++ int max_height; ++ const char * media_bus_format; ++ int mbus_format; ++ int dummy; ++ /* serializers */ ++ int ti9x4_addr; ++ int ti9x3_addr; ++ int port; ++}; ++ ++static int width = 1920; ++module_param(width, int, 0644); ++MODULE_PARM_DESC(width, " width (default: 1920)"); ++ ++static int height = 1080; ++module_param(height, int, 0644); ++MODULE_PARM_DESC(height, " height (default: 1080)"); ++ ++static char *fmt = "yuyv"; ++module_param(fmt, charp, 0644); ++MODULE_PARM_DESC(fmt, " MEDIA_BUS_FORMAT (default: YUYV)"); ++ ++static int dummy = 0; ++module_param(dummy, int, 0644); ++MODULE_PARM_DESC(dummy, " dummy force (0 - dummy imager disabled)"); ++ ++static inline struct dummy_priv *to_dummy(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct dummy_priv, sd); ++} ++ ++static inline struct v4l2_subdev *dummy_to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct dummy_priv, hdl)->sd; ++} ++ ++static int dummy_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int dummy_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = priv->mbus_format; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int dummy_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ mf->code = priv->mbus_format; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int dummy_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = priv->mbus_format; ++ ++ return 0; ++} ++ ++static int dummy_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = 'D' >> 8; ++ edid->edid[9] = 'Y' & 0xff; ++ ++ return 0; ++} ++ ++static int dummy_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > priv->max_width) || ++ (rect->top + rect->height > priv->max_height)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ return 0; ++} ++ ++static int dummy_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int dummy_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int dummy_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ reg->val = 0; ++ reg->size = sizeof(u16); ++ ++ return 0; ++} ++ ++static int dummy_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ return 0; ++} ++#endif ++ ++static struct v4l2_subdev_core_ops dummy_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = dummy_g_register, ++ .s_register = dummy_s_register, ++#endif ++}; ++ ++static int dummy_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ case V4L2_CID_SHARPNESS: ++ case V4L2_CID_AUTOGAIN: ++ case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: ++ case V4L2_CID_EXPOSURE: ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ break; ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops dummy_ctrl_ops = { ++ .s_ctrl = dummy_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops dummy_video_ops = { ++ .s_stream = dummy_s_stream, ++ .g_mbus_config = dummy_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops dummy_subdev_pad_ops = { ++ .get_edid = dummy_get_edid, ++ .enum_mbus_code = dummy_enum_mbus_code, ++ .get_selection = dummy_get_selection, ++ .set_selection = dummy_set_selection, ++ .get_fmt = dummy_get_fmt, ++ .set_fmt = dummy_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops dummy_subdev_ops = { ++ .core = &dummy_core_ops, ++ .video = &dummy_video_ops, ++ .pad = &dummy_subdev_pad_ops, ++}; ++ ++static void dummy_otp_id_read(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = to_dummy(client); ++ ++ /* dummy camera id */ ++ priv->id[0] = 'd'; ++ priv->id[1] = 'u'; ++ priv->id[2] = 'm'; ++ priv->id[3] = 'm'; ++ priv->id[4] = 'y'; ++ priv->id[5] = '.'; ++} ++ ++static ssize_t dummy_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ dummy_otp_id_read(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_dummy, S_IRUGO, dummy_otp_id_show, NULL); ++ ++static int dummy_initialize(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = to_dummy(client); ++ u8 pid = 0xff; ++ int tmp_addr; ++ ++ tmp_addr = client->addr; ++ do { ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x3_addr; ++ /* check if UB953 ID */ ++ reg8_read(client, 0xf1, &pid); ++ if (pid == 'U') ++ break; ++ /* check if UB913 ID */ ++ reg8_read(client, 0x00, &pid); ++ if (pid == (TI913_ID << 1)) ++ break; ++ ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ client->addr = tmp_addr; ++ return -ENODEV; ++ } ++ } while(0); ++ client->addr = tmp_addr; ++ ++ if (strcmp(priv->media_bus_format, "yuyv") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_YUYV8_2X8; ++ else if (strcmp(priv->media_bus_format, "uyvy") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_UYVY8_2X8; ++ else if (strcmp(priv->media_bus_format, "grey") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_Y8_1X8; ++ else if (strcmp(priv->media_bus_format, "rggb8") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB8_1X8; ++ else if (strcmp(priv->media_bus_format, "bggr8") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR8_1X8; ++ else if (strcmp(priv->media_bus_format, "grbg8") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG8_1X8; ++ else if (strcmp(priv->media_bus_format, "rggb12") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB12_1X12; ++ else if (strcmp(priv->media_bus_format, "bggr12") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR12_1X12; ++ else if (strcmp(priv->media_bus_format, "grbg12") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG12_1X12; ++ else if (strcmp(priv->media_bus_format, "rggb14") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB14_1X14; ++ else if (strcmp(priv->media_bus_format, "bggr14") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR14_1X14; ++ else if (strcmp(priv->media_bus_format, "grbg14") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG14_1X14; ++ else if (strcmp(priv->media_bus_format, "rggb16") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB16_1X16; ++ else if (strcmp(priv->media_bus_format, "bggr16") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR16_1X16; ++ else if (strcmp(priv->media_bus_format, "grbg16") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG16_1X16; ++ else { ++ v4l_err(client, "failed to parse mbus format (%s)\n", priv->media_bus_format); ++ return -EINVAL; ++ } ++ ++ /* Read OTP IDs */ ++ dummy_otp_id_read(client); ++ ++ dev_info(&client->dev, "Dummy camera PID %x, res %dx%d, fmt %s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, priv->max_width, priv->max_height, priv->media_bus_format, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ ++ return 0; ++} ++ ++static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ int i; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ int tmp_addr = 0; ++ ++ for (i = 0; ; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; ++ ++ of_property_read_u32(endpoint, "dummy", &priv->dummy); ++ ++ if (of_property_read_u32(np, "dummy,width", &priv->max_width)) ++ priv->max_width = width; ++ if (of_property_read_u32(np, "dummy,height", &priv->max_height)) ++ priv->max_height = height; ++ if (of_property_read_string(np, "dummy,fmt", &priv->media_bus_format)) ++ priv->media_bus_format = fmt; ++ ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; ++ ++ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && ++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") && ++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) && ++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) ++ break; ++ } ++ ++ of_node_put(endpoint); ++ ++ if (!priv->ti9x4_addr) { ++ dev_dbg(&client->dev, "deserializer does not present\n"); ++ return -EINVAL; ++ } ++ ++ /* setup I2C translator address */ ++ tmp_addr = client->addr; ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ ++ ++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ ++ } ++ client->addr = tmp_addr; ++ ++ /* module params override dts */ ++ if (strcmp(fmt, "yuyv")) ++ priv->media_bus_format = fmt; ++ if (width != 1920) ++ priv->max_width = width; ++ if (height != 1080) ++ priv->max_height = height; ++ if (dummy) ++ priv->dummy = dummy; ++ ++ if (!priv->dummy) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++static int dummy_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct dummy_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &dummy_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_GAIN, 1, 0x7ff, 1, 0x200); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = dummy_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = dummy_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = priv->max_width; ++ priv->rect.height = priv->max_height; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_dummy) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", ++ client->addr, client->adapter->name); ++ return ret; ++} ++ ++static int dummy_remove(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_dummy); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} +diff --git a/drivers/media/i2c/soc_camera/max9286.h b/drivers/media/i2c/soc_camera/max9286.h +index 3fe713f..48233e2 100644 +--- a/drivers/media/i2c/soc_camera/max9286.h ++++ b/drivers/media/i2c/soc_camera/max9286.h +@@ -30,6 +30,9 @@ + #define MAX9290_ID 0x2C + #define BROADCAST 0x6f + ++#define TI913_ID 0x58 ++#define TI953_ID 0x30 ++ + static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val) + { + int ret, retries; +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c +index cf97f28..b3d84a6 100644 +--- a/drivers/media/i2c/soc_camera/ov106xx.c ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -32,6 +32,7 @@ static enum { + ID_ISX016, + ID_ISX019, + ID_OV2311, ++ ID_DUMMY, + } chip_id; + + #include "ov10635.c" +@@ -55,6 +56,7 @@ static enum { + #include "isx019.c" + #include "ov2311.c" + #include "ar0147.c" ++#include "dummy.c" + + static int ov106xx_probe(struct i2c_client *client, + const struct i2c_device_id *did) +@@ -62,6 +64,12 @@ static int ov106xx_probe(struct i2c_client *client, + int ret = -1; + chip_id = -EINVAL; + ++ ret = dummy_probe(client, did); ++ if (!ret) { ++ chip_id = ID_DUMMY; ++ goto out; ++ } ++ + ret = gw5200_probe(client, did); + if (!ret) { + chip_id = ID_GW5200_IMX390; +@@ -258,6 +266,9 @@ static int ov106xx_remove(struct i2c_client *client) + case ID_OV2311: + ov2311_remove(client); + break; ++ case ID_DUMMY: ++ dummy_remove(client); ++ break; + default: + break; + }; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0521-arm64-dts-renesas-add-V3H-GMSL2-8ch-Videobox.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0521-arm64-dts-renesas-add-V3H-GMSL2-8ch-Videobox.patch new file mode 100644 index 00000000..b3aef256 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0521-arm64-dts-renesas-add-V3H-GMSL2-8ch-Videobox.patch @@ -0,0 +1,1014 @@ +From ed70167620fa94494ade3a3192a8517d8a47c55d Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 3 Jun 2020 18:42:39 +0300 +Subject: [PATCH] arm64: dts: renesas: add V3H GMSL2 8ch Videobox + +This adds V3H GMSL2 8ch Videobox + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/Makefile | 1 + + .../boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts | 979 +++++++++++++++++++++ + 2 files changed, 980 insertions(+) + create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts + +diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile +index da23cbb..558ea98 100644 +--- a/arch/arm64/boot/dts/renesas/Makefile ++++ b/arch/arm64/boot/dts/renesas/Makefile +@@ -49,6 +49,7 @@ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-8ch.dtb r8a77980-v3hsk-vb-4ch.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-2x2.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-4.dtb ++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-8.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl-8ch.dtb + dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-4ch-hdmi.dtb r8a77980-v3hsk-vb-8ch-hdmi.dtb + +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts +new file mode 100644 +index 0000000..9bf6cd3 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts +@@ -0,0 +1,979 @@ ++/* ++ * Device Tree Source for the V3HSK GMSL2 Quad Videobox Mini board on r8a7798 ++ * ++ * Copyright (C) 2020 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include "r8a77980-v3hsk.dts" ++#include <dt-bindings/gpio/gpio.h> ++/* FDPLink output */ ++//#include "vb-fdplink-output.dtsi" ++#include "camera.dtsi" ++ ++/ { ++ model = "Renesas V3HSK 8ch GMSL2 Videobox board based on r8a77980"; ++ ++ aliases { ++ serial1 = &scif3; ++ ethernet1 = &avb; ++ }; ++ ++ cs2300_ref_clk: cs2300_ref_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <25000000>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led0 { ++ label = "board:status"; ++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "none"; ++ }; ++ }; ++ ++ mpcie_1v8: regulator2 { ++ compatible = "regulator-fixed"; ++ regulator-name = "mPCIe 1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ mpcie_3v3: regulator3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "mPCIe 3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ common_3v3: regulator4 { ++ compatible = "regulator-fixed"; ++ regulator-name = "main 3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ iio_hwmon: hwmon@1 { ++ compatible = "iio-hwmon"; ++ io-channels = ++ /* current */ ++ <&max2008x 0>, ++ <&max2008x 2>, ++ /* voltage */ ++ <&max2008x 4>, ++ <&max2008x 6>, ++ /* misc voltages */ ++ <&max2008x 8>, ++ <&max2008x 9>; ++ io-channel-names = ++ "camera-0-Iout", ++ "camera-1-Iout", ++ "camera-0-Vout", ++ "camera-1-Vout", ++ "cameras-Vregulator", ++ "cameras-3v3"; ++ }; ++ ++ iio_hwmon2: hwmon@2 { ++ compatible = "iio-hwmon"; ++ io-channels = ++ /* current */ ++ <&max2008x_2 0>, ++ <&max2008x_2 2>, ++ /* voltage */ ++ <&max2008x_2 4>, ++ <&max2008x_2 6>, ++ /* misc voltages */ ++ <&max2008x_2 8>, ++ <&max2008x_2 9>; ++ io-channel-names = ++ "camera-0-Iout", ++ "camera-1-Iout", ++ "camera-0-Vout", ++ "camera-1-Vout", ++ "cameras-Vregulator", ++ "cameras-3v3"; ++ }; ++}; ++ ++&canfd { ++ pinctrl-0 = <&canfd0_pins &canfd1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ channel0 { ++ status = "okay"; ++ }; ++ ++ channel1 { ++ status = "okay"; ++ }; ++}; ++ ++&avb { ++ pinctrl-0 = <&avb_pins>; ++ pinctrl-names = "default"; ++ renesas,no-ether-link; ++ phy-handle = <&avb_phy0>; ++ status = "okay"; ++ phy-int-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>; ++ ++ avb_phy0: eavb-phy@0 { ++ rxc-skew-ps = <1500>; ++ rxdv-skew-ps = <420>; /* default */ ++ rxd0-skew-ps = <420>; /* default */ ++ rxd1-skew-ps = <420>; /* default */ ++ rxd2-skew-ps = <420>; /* default */ ++ rxd3-skew-ps = <420>; /* default */ ++ txc-skew-ps = <900>; /* default */ ++ txen-skew-ps = <420>; /* default */ ++ txd0-skew-ps = <420>; /* default */ ++ txd1-skew-ps = <420>; /* default */ ++ txd2-skew-ps = <420>; /* default */ ++ txd3-skew-ps = <420>; /* default */ ++ reg = <3>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>; ++ max-speed = <1000>; ++ }; ++}; ++ ++&csi40 { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi40_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <1200>; ++ }; ++ }; ++}; ++ ++&csi41 { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi41_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <1200>; ++ }; ++ }; ++}; ++ ++&i2c1 { ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ clock-frequency = <400000>; ++ ++ i2cswitch1: i2c-switch@74 { ++ compatible = "nxp,pca9548"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x74>; ++ reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; ++ ++ /* CCTRL_SDA and CCTRL_SCL */ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ gpio_exp_ch0: gpio_ch0@76 { ++ compatible = "nxp,pca9539"; ++ reg = <0x76>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ cmr_pwr_en { ++ gpio-hog; ++ gpios = <3 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CmrPEn"; ++ }; ++ }; ++ ++ /* CS2300 node @0x4e */ ++ cs2300: clk_multiplier@4e { ++ #clock-cells = <0>; ++ compatible = "cirrus,cs2300-cp"; ++ reg = <0x4e>; ++ clocks = <&cs2300_ref_clk>; ++ clock-names = "clk_in"; ++ ++ assigned-clocks = <&cs2300>; ++ assigned-clock-rates = <25000000>; ++ }; ++ ++ dac_vcam: dac_vcam@60 { ++ compatible = "microchip,mcp4725"; ++ reg = <0x60>; ++ vdd-supply = <&common_3v3>; ++ }; ++ ++ max2008x: vcam_switch@28 { ++ compatible = "maxim,max2008x"; ++ reg = <0x28>; ++ #io-channel-cells = <1>; ++ enable-gpios = <&gpio_exp_ch0 5 GPIO_ACTIVE_HIGH>; ++ ++ regulators { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ vdd_cam0: SW0 { ++ reg = <0>; ++ regulator-name = "Camera-0"; ++ }; ++ vdd_cam1: SW1 { ++ reg = <1>; ++ regulator-name = "Camera-1"; ++ }; ++ vdd_cam2: SW2 { ++ reg = <2>; ++ regulator-name = "Camera-2"; ++ }; ++ vdd_cam3: SW3 { ++ reg = <3>; ++ regulator-name = "Camera-3"; ++ }; ++ }; ++ }; ++ ++ max2008x_2: vcam_switch@29 { ++ compatible = "maxim,max2008x"; ++ reg = <0x29>; ++ #io-channel-cells = <1>; ++ /* enable-gpios = <&gpio_exp_ch0 5 GPIO_ACTIVE_HIGH>; */ ++ ++ regulators { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ vdd_cam4: SW0 { ++ reg = <0>; ++ regulator-name = "Camera-4"; ++ }; ++ vdd_cam5: SW1 { ++ reg = <1>; ++ regulator-name = "Camera-5"; ++ }; ++ vdd_cam6: SW2 { ++ reg = <2>; ++ regulator-name = "Camera-6"; ++ }; ++ vdd_cam7: SW3 { ++ reg = <3>; ++ regulator-name = "Camera-7"; ++ }; ++ }; ++ }; ++ }; ++ ++ /* DS0_SDA and DS0_SCL */ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ max96712@29 { ++ compatible = "maxim,max96712"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x29>; ++ clocks = <&cs2300>; ++ clock-names = "ref_clk"; ++ shutdown-gpios = <&gpio_exp_ch0 1 GPIO_ACTIVE_LOW>; ++ ++ maxim,links-mipi-map = <2 2 2 2>; ++ ++ poc0-supply = <&vdd_cam1>; ++ poc1-supply = <&vdd_cam4>; ++ poc2-supply = <&vdd_cam6>; ++ poc3-supply = <&vdd_cam3>; ++ ++ port@0 { ++ max96712_des0ep0: endpoint@0 { ++ ser-addr = <0x0c>; ++ remote-endpoint = <&camera_in0>; ++ }; ++ max96712_des0ep1: endpoint@1 { ++ ser-addr = <0x0d>; ++ remote-endpoint = <&camera_in1>; ++ }; ++ max96712_des0ep2: endpoint@2 { ++ ser-addr = <0x0e>; ++ remote-endpoint = <&camera_in2>; ++ }; ++ max96712_des0ep3: endpoint@3 { ++ ser-addr = <0x0f>; ++ remote-endpoint = <&camera_in3>; ++ }; ++ }; ++ ++ port@1 { ++ max96712_des0mipi2: endpoint { ++ csi-rate = <1200>; ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ camera@60 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x60 0x0c>; ++ ++ port@0 { ++ camera_in0: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin0ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep0: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep0>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ camera@61 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x61 0x0d>; ++ ++ port@0 { ++ camera_in1: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin1ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep1: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep1>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ camera@62 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x62 0x0e>; ++ ++ port@0 { ++ camera_in2: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin2ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep2: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep2>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ camera@63 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x63 0x0f>; ++ ++ port@0 { ++ camera_in3: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin3ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des0ep3: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep3>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ max96712@29 { ++ compatible = "maxim,max96712"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x29>; ++ clocks = <&cs2300>; ++ clock-names = "ref_clk"; ++ shutdown-gpios = <&gpio_exp_ch0 2 GPIO_ACTIVE_LOW>; ++ ++ maxim,links-mipi-map = <1 1 1 1>; ++ ++ poc0-supply = <&vdd_cam0>; ++ poc1-supply = <&vdd_cam7>; ++ poc2-supply = <&vdd_cam5>; ++ poc3-supply = <&vdd_cam2>; ++ ++ port@0 { ++ max96712_des1ep0: endpoint@0 { ++ ser-addr = <0x0c>; ++ remote-endpoint = <&camera_in4>; ++ }; ++ max96712_des1ep1: endpoint@1 { ++ ser-addr = <0x0d>; ++ remote-endpoint = <&camera_in5>; ++ }; ++ max96712_des1ep2: endpoint@2 { ++ ser-addr = <0x0e>; ++ remote-endpoint = <&camera_in6>; ++ }; ++ max96712_des1ep3: endpoint@3 { ++ ser-addr = <0x0f>; ++ remote-endpoint = <&camera_in7>; ++ }; ++ }; ++ ++ port@1 { ++ max96712_des1mipi2: endpoint { ++ csi-rate = <1200>; ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ camera@60 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x60 0x0c>; ++ ++ port@0 { ++ camera_in4: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin4ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des1ep0: endpoint@1 { ++ remote-endpoint = <&max96712_des1ep0>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ camera@61 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x61 0x0d>; ++ ++ port@0 { ++ camera_in5: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin5ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des1ep1: endpoint@1 { ++ remote-endpoint = <&max96712_des1ep1>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ ++ camera@62 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x62 0x0e>; ++ ++ port@0 { ++ camera_in6: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin6ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des1ep2: endpoint@1 { ++ remote-endpoint = <&max96712_des1ep2>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ camera@63 { ++ compatible = COMPATIBLE_CAMERAS; ++ reg = <0x63 0x0f>; ++ ++ port@0 { ++ camera_in7: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin7ep0>; ++ }; ++ }; ++ port@1 { ++ camera_max96712_des1ep3: endpoint@1 { ++ remote-endpoint = <&max96712_des1ep3>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ /* Disp_SDA and Disp_SCL */ ++ i2c@5 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <5>; ++ ++ /* fan node - lm96063 */ ++ fan_ctrl: lm96063@4c { ++ compatible = "lm96163"; ++ reg = <0x4c>; ++ }; ++ }; ++ ++ /* ESDA and ESCL */ ++ i2c@7 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <7>; ++ ++ rtc: mcp79411@6f { ++ compatible = "microchip,mcp7941x"; ++ reg = <0x6f>; ++ }; ++ }; ++ }; ++}; ++ ++&gpio0 { ++ fpdl_shdn { ++ gpio-hog; ++ gpios = <1 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "FPDL_SHDN"; ++ }; ++ ++ cam_pwr_en { ++ gpio-hog; ++ gpios = <11 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "VIPWR_En"; ++ }; ++ ++ wake_pin_8 { ++ gpio-hog; ++ gpios = <0 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "WAKE INPUT PIN 8"; ++ }; ++}; ++ ++&gpio1 { ++ md_buf_en { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CPLD_If_En"; ++ }; ++}; ++ ++&gpio2 { ++ m2_rst { ++ gpio-hog; ++ gpios = <11 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "M.2 RST#"; ++ }; ++ ++ cctrl_rstn { ++ gpio-hog; ++ gpios = <16 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CCTRL_RSTn"; ++ }; ++ ++ can0_stby { ++ gpio-hog; ++ gpios = <27 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN0STBY"; ++ }; ++ ++ can1_load { ++ gpio-hog; ++ gpios = <29 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN1Loff"; ++ }; ++ ++ can1_stby { ++ gpio-hog; ++ gpios = <22 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "CAN1STBY"; ++ }; ++ ++ wake_pin_7 { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ input; ++ line-name = "WAKE INPUT PIN 7"; ++ }; ++ ++ vi1_gpioext_rst { ++ gpio-hog; ++ gpios = <13 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "VIP1_RST"; ++ }; ++}; ++ ++&gpio3 { ++ vi0_gpioext_rst { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "VIP0_RST"; ++ }; ++}; ++ ++&pcie_bus_clk { ++ clock-frequency = <100000000>; ++ status = "okay"; ++}; ++ ++&pciec { ++ pcie3v3-supply = <&mpcie_3v3>; ++ pcie1v8-supply = <&mpcie_1v8>; ++ status = "okay"; ++}; ++ ++&pcie_phy { ++ status = "okay"; ++}; ++ ++&pfc { ++ canfd0_pins: canfd0 { ++ groups = "canfd0_data_a"; ++ function = "canfd0"; ++ }; ++ ++ canfd1_pins: canfd1 { ++ groups = "canfd1_data"; ++ function = "canfd1"; ++ }; ++ ++ avb_pins: avb { ++ groups = "avb_mdio", "avb_rgmii"; ++ function = "avb"; ++ }; ++ ++ i2c1_pins: i2c1 { ++ groups = "i2c1"; ++ function = "i2c1"; ++ }; ++ ++ scif3_pins: scif3 { ++ groups = "scif3_data"; ++ function = "scif3"; ++ }; ++}; ++ ++&scif3 { ++ pinctrl-0 = <&scif3_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&tpu { ++ status = "disabled"; ++}; ++ ++&vin0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin0ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in0>; ++ }; ++ }; ++ port@1 { ++ csi0ep0: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin0_max96712_des0ep0: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin1 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin1ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <1>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in1>; ++ }; ++ }; ++ port@1 { ++ csi0ep1: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin1_max96712_des0ep1: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep1>; ++ }; ++ }; ++ }; ++}; ++ ++&vin2 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin2ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <2>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in2>; ++ }; ++ }; ++ port@1 { ++ csi0ep2: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin2_max96712_des0ep2: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep2>; ++ }; ++ }; ++ }; ++}; ++ ++&vin3 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin3ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <3>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in3>; ++ }; ++ }; ++ port@1 { ++ csi0ep3: endpoint { ++ remote-endpoint = <&csi40_ep>; ++ }; ++ }; ++ port@2 { ++ vin3_max96712_des0ep3: endpoint@1 { ++ remote-endpoint = <&max96712_des0ep3>; ++ }; ++ }; ++ }; ++}; ++ ++&vin4 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin4ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in4>; ++ }; ++ }; ++ port@1 { ++ csi1ep0: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin4_max96712_des1ep0: endpoint@1 { ++ remote-endpoint = <&max96712_des1ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&vin5 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin5ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <1>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in5>; ++ }; ++ }; ++ port@1 { ++ csi1ep1: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin5_max96712_des1ep1: endpoint@1 { ++ remote-endpoint = <&max96712_des1ep1>; ++ }; ++ }; ++ }; ++}; ++ ++&vin6 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin6ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <2>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in6>; ++ }; ++ }; ++ port@1 { ++ csi1ep2: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin6_max96712_des1ep2: endpoint@1 { ++ remote-endpoint = <&max96712_des1ep2>; ++ }; ++ }; ++ }; ++}; ++ ++&vin7 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin7ep0: endpoint { ++ csi,select = "csi41"; ++ virtual,channel = <3>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&camera_in7>; ++ }; ++ }; ++ port@1 { ++ csi1ep3: endpoint { ++ remote-endpoint = <&csi41_ep>; ++ }; ++ }; ++ port@2 { ++ vin7_max96712_des1ep3: endpoint@1 { ++ remote-endpoint = <&max96712_des1ep3>; ++ }; ++ }; ++ }; ++}; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0522-arm64-dts-renesas-vb-gmsl2-fix-typos.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0522-arm64-dts-renesas-vb-gmsl2-fix-typos.patch new file mode 100644 index 00000000..2272f48f --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0522-arm64-dts-renesas-vb-gmsl2-fix-typos.patch @@ -0,0 +1,106 @@ +From b025c0676549f2a075269e09ca9fc88b62a1c5af Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 3 Jun 2020 18:44:06 +0300 +Subject: [PATCH] arm64: dts: renesas: vb-gmsl2: fix typos + +This fixes varius typos on GMSL2 Videobox ECUs + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts | 12 ++++++------ + arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts | 8 ++++---- + 2 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts +index 4d284b1..c56adc0 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts +@@ -1,7 +1,7 @@ + /* +- * Device Tree Source for the V3HSK Videobox Mini board on r8a7798 ++ * Device Tree Source for the V3HSK GMSL2 Dual Videobox Mini board on r8a7798 + * +- * Copyright (C) 2018 Cogent Embedded, Inc. ++ * Copyright (C) 2020 Cogent Embedded, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any +@@ -254,7 +254,7 @@ + clock-names = "ref_clk"; + shutdown-gpios = <&gpio_exp_ch0 1 GPIO_ACTIVE_LOW>; + +- maxim,link-mipi-map = <1 1>; ++ maxim,links-mipi-map = <1 1>; + + poc0-supply = <®ulator_poc_0>; + poc1-supply = <®ulator_poc_1>; +@@ -342,7 +342,7 @@ + clock-names = "ref_clk"; + shutdown-gpios = <&gpio_exp_ch0 0 GPIO_ACTIVE_LOW>; + +- maxim,link-mipi-map = <1 1>; ++ maxim,links-mipi-map = <1 1>; + + poc0-supply = <®ulator_poc_2>; + poc1-supply = <®ulator_poc_3>; +@@ -353,7 +353,7 @@ + remote-endpoint = <&camera_in2>; + }; + max9296_des1ep1: endpoint@1 { +- ser-addr = <0x51>; ++ ser-addr = <0x0d>; + remote-endpoint = <&camera_in3>; + }; + }; +@@ -396,7 +396,7 @@ + + camera@61 { + compatible = COMPATIBLE_CAMERAS; +- reg = <0x61 0x0c>; ++ reg = <0x61 0x0d>; + + port@0 { + camera_in3: endpoint { +diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts +index ac2d825..919e775 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts +@@ -566,7 +566,7 @@ + }; + }; + port@1 { +- csi1ep0: endpoint { ++ csi0ep0: endpoint { + remote-endpoint = <&csi40_ep>; + }; + }; +@@ -594,7 +594,7 @@ + }; + }; + port@1 { +- csi1ep1: endpoint { ++ csi0ep1: endpoint { + remote-endpoint = <&csi40_ep>; + }; + }; +@@ -622,7 +622,7 @@ + }; + }; + port@1 { +- csi1ep2: endpoint { ++ csi0ep2: endpoint { + remote-endpoint = <&csi40_ep>; + }; + }; +@@ -650,7 +650,7 @@ + }; + }; + port@1 { +- csi1ep3: endpoint { ++ csi0ep3: endpoint { + remote-endpoint = <&csi40_ep>; + }; + }; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0523-media-i2c-isx019-do-not-disable-embedded-line.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0523-media-i2c-isx019-do-not-disable-embedded-line.patch new file mode 100644 index 00000000..a2c8870e --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0523-media-i2c-isx019-do-not-disable-embedded-line.patch @@ -0,0 +1,32 @@ +From 4c72275148ef3cc02ca8c6dc8a22cb8e67724322 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 17 Jun 2020 23:13:26 +0300 +Subject: [PATCH] media: i2c: isx019: do not disable embedded line + +Skip disale the embedded line by default. +Disableing of embedded line reduces the frame size by one line, +that is truncated in the end of frame, hence this is useless to disable +emb line + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/isx019.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/soc_camera/isx019.h b/drivers/media/i2c/soc_camera/isx019.h +index c7072a3..c3c36ba 100644 +--- a/drivers/media/i2c/soc_camera/isx019.h ++++ b/drivers/media/i2c/soc_camera/isx019.h +@@ -23,8 +23,8 @@ static const struct isx019_reg isx019_regs_wizard[] = { + #if 0 + /* enable FSIN */ + {ISX019_DELAY, 100}, +-#endif + /* disable embedded data */ + {0x504c, 0x0}, + {0x504e, 0x0}, ++#endif + }; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0524-media-i2c-dummy-fix-DT-parse.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0524-media-i2c-dummy-fix-DT-parse.patch new file mode 100644 index 00000000..f567d5df --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0524-media-i2c-dummy-fix-DT-parse.patch @@ -0,0 +1,28 @@ +From 8e338812615c72dad0fe17ea5a135ffdcc7b25a7 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Tue, 28 Jul 2020 21:12:51 +0300 +Subject: [PATCH] media: i2c: dummy: fix DT parse + +This fixes the parse of dummy field + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/dummy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/soc_camera/dummy.c b/drivers/media/i2c/soc_camera/dummy.c +index 346b5dd..3be2728 100644 +--- a/drivers/media/i2c/soc_camera/dummy.c ++++ b/drivers/media/i2c/soc_camera/dummy.c +@@ -386,7 +386,7 @@ static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv) + if (!endpoint) + break; + +- of_property_read_u32(endpoint, "dummy", &priv->dummy); ++ of_property_read_u32(np, "dummy", &priv->dummy); + + if (of_property_read_u32(np, "dummy,width", &priv->max_width)) + priv->max_width = width; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0525-arm64-dts-renesas-Add-r8a7796-m3ulcb-2x4g-kf.dts.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0525-arm64-dts-renesas-Add-r8a7796-m3ulcb-2x4g-kf.dts.patch new file mode 100644 index 00000000..1a727e37 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0525-arm64-dts-renesas-Add-r8a7796-m3ulcb-2x4g-kf.dts.patch @@ -0,0 +1,74 @@ +From 20b0cce7e2407ab766e849851d832006cabf9f2d Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Wed, 8 Jul 2020 19:21:13 +0300 +Subject: [PATCH] arm64: dts: renesas: Add r8a7796-m3ulcb-2x4g-kf.dts + +This adds Kingfisher board support for M3 v3.0 8GiB (2x4GiB) SK. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm64/boot/dts/renesas/Makefile | 2 +- + .../boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts | 38 ++++++++++++++++++++++ + 2 files changed, 39 insertions(+), 1 deletion(-) + create mode 100644 arch/arm64/boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts + +diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile +index 5680cde..45c555e 100644 +--- a/arch/arm64/boot/dts/renesas/Makefile ++++ b/arch/arm64/boot/dts/renesas/Makefile +@@ -24,7 +24,7 @@ dtb-$(CONFIG_ARCH_R8A77995) += r8a77995-draak.dtb + # ADAS boards + dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-salvator-x-view.dtb + dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-m3ulcb-view.dtb +-dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-m3ulcb-kf.dtb ++dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-m3ulcb-kf.dtb r8a7796-m3ulcb-2x4g.dtb + dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-salvator-x-view.dtb r8a7795-es1-salvator-x-view.dtb + dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-view.dtb r8a7795-es1-h3ulcb-view.dtb + dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-had-alfa.dtb r8a7795-h3ulcb-had-beta.dtb r8a7795-es1-h3ulcb-had-alfa.dtb r8a7795-es1-h3ulcb-had-beta.dtb +diff --git a/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts b/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts +new file mode 100644 +index 0000000..76e0e57 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Device Tree Source for the M3ULCB Kingfisher board ++ * ++ * Copyright (C) 2020 Renesas Electronics Corp. ++ * Copyright (C) 2020 Cogent Embedded, Inc. ++ */ ++ ++#include "r8a7796-m3ulcb-2x4g.dts" ++#include "ulcb-kf.dtsi" ++ ++/ { ++ model = "Renesas M3ULCB Kingfisher board based on r8a7796 ES3.0+"; ++ compatible = "shimafuji,kingfisher", "renesas,m3ulcb", ++ "renesas,r8a7796"; ++}; ++ ++&du { ++ ports { ++ port@0 { ++ endpoint { ++ remote-endpoint = <&adv7513_in>; ++ }; ++ }; ++ }; ++}; ++ ++&lvds0 { ++ status = "okay"; ++ ++ ports { ++ port@1 { ++ lvds0_out: endpoint { ++ remote-endpoint = <&lvds_in>; ++ }; ++ }; ++ }; ++}; +-- +2.7.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/enable.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/enable.cfg new file mode 100644 index 00000000..abd0bd76 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/enable.cfg @@ -0,0 +1,2 @@ +CONFIG_TMPFS=y +CONFIG_REGULATOR=y diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/hyperflash.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/hyperflash.cfg index df45d5e9..b078e242 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/hyperflash.cfg +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/hyperflash.cfg @@ -1,2 +1 @@ -CONFIG_MTD=y -CONFIG_MTD_RPC_HYPERFLASH=y +CONFIG_MTD_RENESAS_RPC_HYPERFLASH=y diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg index 9a1c695e..a88472a8 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg @@ -1,3 +1,3 @@ -CONFIG_SPI_RENESAS_RPC=y +CONFIG_MTD_RENESAS_RPC_QSPI=y CONFIG_MTD_BLOCK=y CONFIG_JFFS2_FS=y diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/renesas.scc b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/renesas.scc index 31146743..34855009 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/renesas.scc +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/renesas.scc @@ -291,7 +291,6 @@ patch 0351-arm64-dts-renesas-r8a77980-VB-4ch-and-8ch-Add-PCIE-p.patch patch 0352-gpu-drm-rcar_du-Fix-physical-address-of-the-CMA-back.patch patch 0353-media-soc_camera-rcar_csi2-add-dump-module-param.patch patch 0354-media-rcar_csi2-Disable-data-type-matching.patch -patch 0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch patch 0356-media-platform-vsp1-Extend-DRM-VSP1-interface.patch patch 0357-gpu-drm-rcar-du-rcar_du_vsp-Check-if-gem-buffer-has-.patch patch 0358-media-platform-vsp1-Add-cropping-handling-to-VSP-alp.patch @@ -355,3 +354,105 @@ patch 0416-arm64-dtb-renesas-vb2.1-enable-usb2-channel-3.patch patch 0417-USB-tusb8041-add-simple-driver-to-start-device-over-.patch patch 0418-arm64-dts-renesas-ulcb-vb2-fix-USB30-and-HUB.patch patch 0419-phy-rcar-gen3-usb2-power-on-port-in-host-mode-to.patch +patch 0420-media-i2c-ov2311-fix-otp-id-read.patch +patch 0421-media-i2c-imx390-add-user-defined-size-for-register-.patch +patch 0422-mmc-core-mmc-Try-other-timings-if-the-higher-one-fai.patch +patch 0423-media-i2c-ap0101_ar014x-add-AP0102-chip.patch +patch 0424-arm64-dts-renesas-ulcb-vb-Fix-lvds0-port-routing.patch +patch 0425-arm64-dts-r8a7798-v3hsk-vb-4-8ch-change-i2c-rate-to-.patch +patch 0426-media-i2c-ov106xx-change-order.patch +patch 0427-media-i2c-gw5200-fix-imager-hang.patch +patch 0428-arch64-dts-renesas-r8a77970-Fix-IPMMU-probe-order.patch +patch 0429-arch64-dts-renesas-r8a77980-Fix-IPMMU-probe-order.patch +patch 0430-media-i2c-ar0140-update-driver-to-use-rGPIO-and-dyna.patch +patch 0431-media-i2c-ti9x4-update-remote-gpio-function.patch +patch 0432-media-i2c-soc_camera-add-AR0220.patch +patch 0433-media-i2c-ar0220-add-rev2-rev3.patch +patch 0434-media-i2c-max9286-parse-crossbard-from-cmdline.patch +patch 0435-clk-renesas-r8a7795-cpg-mssr-Add-RPC-clocks.patch +patch 0436-clk-renesas-r8a7796-cpg-mssr-Add-RPC-clocks.patch +patch 0437-clk-renesas-r8a77965-cpg-mssr-Add-RPC-clocks.patch +patch 0438-clk-renesas-rcar-gen3-cpg-Allow-to-set-RPCD2-clock-p.patch +patch 0439-mtd-Consolidate-Renesas-RPC-drivers.patch +patch 0440-arm64-dts-renesas-r8a77970-Update-RPC-device-nodes.patch +patch 0441-arm64-dts-renesas-r8a77980-Update-RPC-device-nodes.patch +patch 0442-arm64-dts-renesas-r8a7795-Add-RPC-device-node.patch +patch 0443-arm64-dts-renesas-r8a7796-Add-RPC-device-node.patch +patch 0444-arm64-dts-renesas-r8a77965-Add-RPC-device-node.patch +patch 0445-arm64-dts-renesas-ulcb-Add-RPC-HyperFlash-device-nod.patch +patch 0446-arm64-dts-renesas-salvator-common-Add-RPC-HyperFlash.patch +patch 0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch +patch 0448-media-i2c-ar0xxx-append-embedded-data-stats-into-frame.patch +patch 0449-media-i2c-soc_camera-ov495_ov2775-Remove-early_param.patch +patch 0450-arm64-dts-renesas-ulcb-Add-tee-MTD-RPC-HyperFlash-pa.patch +patch 0451-arm64-dts-renesas-salvator-common-Add-tee-MTD-RPC-Hy.patch +patch 0452-arm64-dts-renesas-ulcb-Increase-U-Boot-partition-siz.patch +patch 0453-arm64-dts-renesas-salvator-common-Increase-U-Boot-pa.patch +patch 0454-media-i2c-imx390-fix-refclk.patch +patch 0455-media-i2c-ox01d10-add-imager-support.patch +patch 0456-media-i2c-max9286-fix-resetb-handling.patch +patch 0457-media-i2c-ov10640-fix-dvp-order-and-soft-reset.patch +patch 0458-arm64-dts-renesas-Add-V3x-VideoBox-GMSL-8ch-support.patch +patch 0459-media-i2c-ov10640-support-different-revisions.patch +patch 0460-media-ar0xxx-add-embedded-line-into-frame.patch +patch 0461-v3hsk-Add-separate-dts-for-dummy-camera-1920x1080.patch +patch 0462-media-i2c-ov10640-add-embedded-data-fix-crop.patch +patch 0463-net-can-rcar_can-fix-possible-IRQ-storm-on-high-load.patch +patch 0464-arm64-dts-renesas-ulcb-v2-use-CANFD-instead-CAN.patch +patch 0465-arm64-dts-renesas-add-cn12-support-on-VB2-1.patch +patch 0466-media-i2c-max9286-parse-crossbar-from-dt.patch +patch 0467-media-i2c-isx016-add-fixed-sensor.patch +patch 0468-imx390-Read-1-byte-registers-by-default.patch +patch 0469-rcar_canfd-fix-one-more-interrupt-storm-window.patch +patch 0470-media-i2c-add-fps-setup.patch +patch 0471-media-i2c-ov10640-add-fps-setup.patch +patch 0472-media-i2c-soc_camera-fix-compilation-warnings.patch +patch 0473-media-i2c-ov10640-add-different-imager-addresses.patch +patch 0474-media-i2c-soc_camera-add-V4L2_CID_MIN_BUFFERS_FOR_CA.patch +patch 0475-media-i2c-ar0233-add-fps-setup.patch +patch 0476-media-i2c-imx390-add-fps-setup.patch +patch 0477-media-i2c-ar0231-fix-FSIN-pin-input.patch +patch 0478-media-i2c-ti9x4-fix-framesync.patch +patch 0479-media-soc_camera-rcar_csi2-add-interrupts.patch +patch 0480-media-i2c-soc_camera-ov10640-fix-emb-lines-number.patch +patch 0481-r8a779-78-sysc-don-t-poweroff-Cortex-R7-core.patch +patch 0482-media-i2c-max9286-ti9x4-power-down-POCs-on-reboot.patch +patch 0484-media-platform-soc_camera-disable-mutex-locking-for-.patch +patch 0485-media-i2c-ov10640-compensate-disabled-mutex.patch +patch 0487-i2c-busses-i2c-rcar-block-pm_runtime.patch +patch 0488-arm64-dts-renesas-block-i2c-pm-runtime.patch +patch 0490-media-i2c-ti9x4-increase-i2c-freq-on-master-bus.patch +patch 0491-media-i2c-soc_camera-switch-to-u64-adv_debug-access.patch +patch 0492-media-i2c-move-gmsl-fpdlink-drivers-to-separate-fold.patch +patch 0493-media-i2c-add-max96712-and-max9296.patch +patch 0494-media-i2c-max9286-max9288-use-common.h-file.patch +patch 0495-media-i2c-ti9x4-fix-rebot_notify-and-gpiod_request.patch +patch 0496-media-i2c-add-interim-LVDS-imager-drivers.patch +patch 0497-media-i2c-soc_camera-rcar_csi2-adjust-debugging.patch +patch 0498-media-platform-soc_camera-rcar_vin-add-max96712-max9.patch +patch 0499-regulator-add-MAX2008X-camera-protector.patch +patch 0500-arm64-dts-renesas-add-V3H-GMSL2-Videoboxes.patch +patch 0501-media-i2c-ap0101-fix-fsin-on-AP0102.patch +patch 0502-media-i2c-max96712-add-MIPI-GMSL2-support.patch +patch 0503-media-i2c-ov2311-add-GMSL2-support.patch +patch 0504-media-i2c-max9296-add-MIPI-GMSL2-support.patch +patch 0505-media-i2c-gmsl-parse-gmsl_mode-from-deserializer.patch +patch 0506-media-i2c-imagers-add-AR0231-for-new-LVDS-support.patch +patch 0507-media-i2c-ap0101-ap0201-fix-vendor-name-fsin-fix-on-.patch +patch 0508-media-i2c-fix-indentation.patch +patch 0509-media-i2c-fix-broken-old-LVDS-imagers.patch +patch 0510-arm64-dts-renesas-add-camera-dtsi-file.patch +patch 0511-media-i2c-ap0201-detect-AP0200-AP0202.patch +patch 0512-arm64-dts-renesas-add-H3-GMSL2-Videobox.patch +patch 0513-MTD-renesas-rpc-fix-dummy-cycles.patch +patch 0514-media-i2c-gmsl2-add-fsync-support.patch +patch 0515-media-i2c-ap020x-add-fsync-support.patch +patch 0516-media-i2c-ar0231-fix-translator.patch +patch 0517-media-i2c-gmsl2-fix-fsync-in-manual-mode.patch +patch 0518-media-i2c-imagers-ar0231-fix-GMSL2.patch +patch 0519-media-i2c-imagers-add-IMX390-for-new-LVDS-support.patch +patch 0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch +patch 0521-arm64-dts-renesas-add-V3H-GMSL2-8ch-Videobox.patch +patch 0522-arm64-dts-renesas-vb-gmsl2-fix-typos.patch +patch 0523-media-i2c-isx019-do-not-disable-embedded-line.patch +patch 0524-media-i2c-dummy-fix-DT-parse.patch diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg index e053969e..4cce75a8 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg @@ -27,6 +27,8 @@ CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_SCALE_CROP=y CONFIG_SOC_CAMERA_PLATFORM=y CONFIG_SOC_CAMERA_MAX9286=y +CONFIG_SOC_CAMERA_MAX9296=y +CONFIG_SOC_CAMERA_MAX96712=y CONFIG_SOC_CAMERA_TI9X4=y CONFIG_SOC_CAMERA_OV106XX=y CONFIG_SOC_CAMERA_OV5647=y @@ -85,3 +87,5 @@ CONFIG_MD=y CONFIG_BLK_DEV_MD=y CONFIG_MD_RAID0=y CONFIG_GPIO_SYSFS=y +CONFIG_USB_TUSB8041=y +CONFIG_REGULATOR_MAX2008X=y diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg index c633e9ed..9baa6f0f 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg @@ -22,6 +22,8 @@ CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_SCALE_CROP=y CONFIG_SOC_CAMERA_PLATFORM=y CONFIG_SOC_CAMERA_MAX9286=y +CONFIG_SOC_CAMERA_MAX9296=y +CONFIG_SOC_CAMERA_MAX96712=y CONFIG_SOC_CAMERA_TI9X4=y CONFIG_SOC_CAMERA_OV106XX=y CONFIG_INPUT_TOUCHSCREEN=y @@ -41,3 +43,4 @@ CONFIG_GPIO_SYSFS=y CONFIG_DRM_THINE_THC63LVD1024=y CONFIG_MCP4725=y CONFIG_PHY_RCAR_GEN3_PCIE=y +CONFIG_REGULATOR_MAX2008X=y diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.14.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.14.bbappend index 5473336d..f066ca28 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.14.bbappend +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.14.bbappend @@ -6,13 +6,17 @@ COMPATIBLE_MACHINE_condor = "condor" COMPATIBLE_MACHINE_v3mzf = "v3mzf" COMPATIBLE_MACHINE_v3hsk = "v3hsk" +KF_ENABLE_M3V3SK8GB := "${@bb.utils.contains("KERNEL_DEVICETREE", "renesas/r8a7796-m3ulcb-2x4g.dtb", "1", "", d)}" + SRC_URI_append = " \ - ${@bb.utils.contains('MACHINE_FEATURES', 'h3ulcb-had', ' file://hyperflash.cfg', '', d)} \ + ${@oe.utils.conditional("DISABLE_RPC_ACCESS", "1", "", " file://hyperflash.cfg", d)} \ ${@oe.utils.conditional("SDHI_SEQ", "1", " file://sdhi_seq.cfg", "", d)} \ file://nvme.cfg \ file://imr.cfg \ file://disable-unused.cfg \ + file://enable.cfg \ file://renesas.scc \ + file://0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch \ ${@oe.utils.conditional("KF_ENABLE_SD3", "1", " file://0047-arm64-dts-renesas-ulcb-kf-enable-sd3.patch", "", d)} \ ${@oe.utils.conditional("KF_ENABLE_MOST", "1", " file://0048-arm64-dts-renesas-ulcb-kf-enable-most.patch", "", d)} \ ${@oe.utils.conditional("KF_ENABLE_IMX219", "1", " file://0115-arm64-dts-renesas-ulcb-kf-enable-enable-IMX219.patch", "", d)} \ @@ -20,6 +24,7 @@ SRC_URI_append = " \ ${@oe.utils.conditional("KF_PANEL_MODEL", "AA104XD12", " file://0121-arm64-dts-renesas-ulcb-kf-Set-Mitsubishi-AA104XD12-1.patch", "", d)} \ ${@oe.utils.conditional("KF_PANEL_MODEL", "AA121TD01", " file://0121-arm64-dts-renesas-ulcb-kf-Set-Mitsubishi-AA121TD01-1.patch", "", d)} \ ${@oe.utils.conditional("VB_ENABLE_FDPLINK", "1", " file://0391-arm64-dts-renesas-Enable-FDPLink-output-on-V3x-Video.patch", "", d)} \ + ${@oe.utils.conditional("KF_ENABLE_M3V3SK8GB", "1", " file://0525-arm64-dts-renesas-Add-r8a7796-m3ulcb-2x4g-kf.dts.patch", "", d)} \ " SRC_URI_append_h3ulcb = " file://ulcb.cfg" @@ -34,7 +39,7 @@ SRC_URI_append_v3hsk = " file://v3hsk.cfg" SRC_URI_append_rcar-gen3-v3x = " \ file://cma.cfg \ - file://qspi.cfg \ + ${@oe.utils.conditional("DISABLE_RPC_ACCESS", "1", "", " file://qspi.cfg", d)} \ " KERNEL_DEVICETREE_append_h3ulcb = " \ @@ -58,11 +63,14 @@ KERNEL_DEVICETREE_append_h3ulcb = " \ renesas/r8a7795-h3ulcb-4x2g-vb2.dtb \ renesas/r8a7795-h3ulcb-4x2g-vb2.1.dtb \ renesas/r8a7795-h3ulcb-4x2g-vbm.dtb \ + renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dtb \ + renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dtb \ " KERNEL_DEVICETREE_append_m3ulcb = " \ renesas/r8a7796-m3ulcb-view.dtb \ renesas/r8a7796-m3ulcb-kf.dtb \ + ${@oe.utils.conditional("KF_ENABLE_M3V3SK8GB", "1", " renesas/r8a7796-m3ulcb-2x4g-kf.dtb", "", d)} \ " KERNEL_DEVICETREE_append_m3nulcb = " \ @@ -112,6 +120,10 @@ KERNEL_DEVICETREE_append_v3hsk = " \ renesas/r8a77980-v3hsk-vbm-v3.dtb \ renesas/r8a77980-v3hsk-vb-4ch.dtb \ renesas/r8a77980-v3hsk-vb-8ch.dtb \ + renesas/r8a77980-v3hsk-vb-gmsl-8ch.dtb \ + renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dtb \ + renesas/r8a77980-v3hsk-vb-gmsl2-4.dtb \ + renesas/r8a77980-v3hsk-vb-gmsl2-8.dtb \ " # Prefer V4L2 rcar_imr driver over UIO uio_imr KERNEL_MODULE_AUTOLOAD_append = " rcar_imr" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/alsa/alsa-utils/0001-aplay-Fix-invalid-file-size-check-for-non-regular-fi.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/alsa/alsa-utils/0001-aplay-Fix-invalid-file-size-check-for-non-regular-fi.patch deleted file mode 100644 index 586f9731..00000000 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/alsa/alsa-utils/0001-aplay-Fix-invalid-file-size-check-for-non-regular-fi.patch +++ /dev/null @@ -1,36 +0,0 @@ -From da4d5bd53a1a57d1b39318b83d3280fbcd78e9f6 Mon Sep 17 00:00:00 2001 -From: Takashi Iwai <tiwai@suse.de> -Date: Tue, 15 May 2018 22:17:01 +0200 -Subject: [PATCH] aplay: Fix invalid file size check for non-regular files - -aplay tries to check the file size via fstat() at parsing the format -headers and avoids parsing when the size is shorter than the given -size. This works fine for regular files, but when a special file like -pipe is passed, it fails, eventually leading to the fallback mode -wrongly. - -A proper fix is to do this sanity check only for a regular file. - -Reported-by: Jay Foster <jay@systech.com> -Signed-off-by: Takashi Iwai <tiwai@suse.de> ---- - aplay/aplay.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/aplay/aplay.c b/aplay/aplay.c -index bbd7fff..63ec9ef 100644 ---- a/aplay/aplay.c -+++ b/aplay/aplay.c -@@ -2821,7 +2821,8 @@ static int read_header(int *loaded, int header_size) - - /* don't be adventurous, get out if file size is smaller than - * requested header size */ -- if (buf.st_size < header_size) -+ if ((buf.st_mode & S_IFMT) == S_IFREG && -+ buf.st_size < header_size) - return -1; - - if (*loaded < header_size) { --- -2.7.4 - diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/alsa/alsa-utils_1.1.6.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/alsa/alsa-utils_1.1.6.bbappend deleted file mode 100644 index a8c60aec..00000000 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/alsa/alsa-utils_1.1.6.bbappend +++ /dev/null @@ -1,5 +0,0 @@ -FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" - -SRC_URI_append = " \ - file://0001-aplay-Fix-invalid-file-size-check-for-non-regular-fi.patch \ -" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-omx_%.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-omx_%.bbappend new file mode 100644 index 00000000..0b6b1a5a --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-omx_%.bbappend @@ -0,0 +1,10 @@ +OMX_LIBS = "mp3dec_lib" + +do_configure_append() { + for lib in ${OMX_LIBS}; do + if ${@bb.utils.contains('DISTRO_FEATURES', '$lib', 'false', 'true', d)}; then + lib="omx${lib%%_lib}" + sed -i "/^\[$lib\]/,/^$/d" ${S}/config/rcar/gstomx.conf + fi + done +} diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugin-vspfilter/gstvspfilter-m3nulcb_r8a77965.conf b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugin-vspfilter/gstvspfilter-m3nulcb_r8a77965.conf deleted file mode 100644 index 890c5ad9..00000000 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugin-vspfilter/gstvspfilter-m3nulcb_r8a77965.conf +++ /dev/null @@ -1,2 +0,0 @@ -input-device-name=/dev/video6 -output-device-name=/dev/video7 diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugin-vspfilter_1.0.1.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugin-vspfilter_1.0.1.bbappend deleted file mode 100644 index 6d4804d1..00000000 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugin-vspfilter_1.0.1.bbappend +++ /dev/null @@ -1,2 +0,0 @@ -FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" - diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.14.%/0001-install-wayland.h-header.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.16.2/0001-install-wayland.h-header.patch index 0d9ed62e..d98ca26d 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.14.%/0001-install-wayland.h-header.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.16.2/0001-install-wayland.h-header.patch @@ -8,7 +8,7 @@ Subject: [PATCH] install wayland.h header 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gst-libs/gst/wayland/Makefile.am b/gst-libs/gst/wayland/Makefile.am -index 743a489..c59b06d 100644 +index a9f3f7b..7281a6e 100644 --- a/gst-libs/gst/wayland/Makefile.am +++ b/gst-libs/gst/wayland/Makefile.am @@ -5,6 +5,8 @@ libgstwayland_@GST_API_VERSION@_la_SOURCES = wayland.c @@ -20,7 +20,7 @@ index 743a489..c59b06d 100644 libgstwayland_@GST_API_VERSION@_la_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ -@@ -21,7 +23,3 @@ libgstwayland_@GST_API_VERSION@_la_LDFLAGS = \ +@@ -22,7 +24,3 @@ libgstwayland_@GST_API_VERSION@_la_LDFLAGS = \ $(GST_LIB_LDFLAGS) \ $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) @@ -29,5 +29,5 @@ index 743a489..c59b06d 100644 - wayland.h - -- -2.7.4 +2.5.0 diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.14.%/0002-pkgconfig-libgstwayland.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.16.2/0002-pkgconfig-libgstwayland.patch index 5f5e9948..f677b432 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.14.%/0002-pkgconfig-libgstwayland.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.16.2/0002-pkgconfig-libgstwayland.patch @@ -8,7 +8,7 @@ Subject: [PATCH] fix 1 file changed, 2 insertions(+) diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am -index 0e69cd1..b76f7b5 100644 +index 8e74a8e..f641285 100644 --- a/pkgconfig/Makefile.am +++ b/pkgconfig/Makefile.am @@ -1,6 +1,7 @@ @@ -20,7 +20,7 @@ index 0e69cd1..b76f7b5 100644 gstreamer-codecparsers-@GST_API_VERSION@.pc \ gstreamer-insertbin-@GST_API_VERSION@.pc \ @@ -11,6 +12,7 @@ pcverfiles = \ - gstreamer-bad-video-@GST_API_VERSION@.pc + gstreamer-bad-audio-@GST_API_VERSION@.pc pcverfiles_uninstalled = \ + gstreamer-wayland-@GST_API_VERSION@-uninstalled.pc \ @@ -28,5 +28,5 @@ index 0e69cd1..b76f7b5 100644 gstreamer-codecparsers-@GST_API_VERSION@-uninstalled.pc \ gstreamer-insertbin-@GST_API_VERSION@-uninstalled.pc \ -- -2.7.4 +2.5.0 diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.14.%/0003-gstkmssink-add-rcar-du-to-driver-list.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.16.2/0003-gstkmssink-add-rcar-du-to-driver-list.patch index 6a8050ef..6b421ac6 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.14.%/0003-gstkmssink-add-rcar-du-to-driver-list.patch +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.16.2/0003-gstkmssink-add-rcar-du-to-driver-list.patch @@ -8,10 +8,10 @@ Subject: [PATCH] gstkmssink: add rcar-du to driver list 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/kms/gstkmssink.c b/sys/kms/gstkmssink.c -index 1331883..5e45796 100644 +index cdecbf6..0b11233 100644 --- a/sys/kms/gstkmssink.c +++ b/sys/kms/gstkmssink.c -@@ -168,7 +168,7 @@ kms_open (gchar ** driver) +@@ -177,7 +177,7 @@ kms_open (gchar ** driver) { static const char *drivers[] = { "i915", "radeon", "nouveau", "vmwgfx", "exynos", "amdgpu", "imx-drm", "rockchip", "atmel-hlcdc", "msm", diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.14.%.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.16.2.bbappend index 1e630f9e..1e630f9e 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.14.%.bbappend +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.16.2.bbappend diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/pulseaudio/pulseaudio_12.2.bbappend b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/pulseaudio/pulseaudio_13.0.bbappend index 7d28801e..7d28801e 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/pulseaudio/pulseaudio_12.2.bbappend +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-multimedia/pulseaudio/pulseaudio_13.0.bbappend diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/glm/glm_0.9.7.6.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/glm/glm_0.9.7.6.bb index 7c013937..49e5b04d 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/glm/glm_0.9.7.6.bb +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/glm/glm_0.9.7.6.bb @@ -1,10 +1,11 @@ require glm.inc -SRC_URI = "\ - https://github.com/g-truc/${BPN}/archive/${PV}.tar.gz \ - file://0001-Fix-cmake-pathes.patch \ -" +S = "${WORKDIR}/git" -SRC_URI[md5sum] = "5b75955d21ce2c2d515919d30c69a3eb" -SRC_URI[sha256sum] = "872fdea580b69b752562adc60734d7472fd97d5724c4ead585564083deac3953" +SRC_URI = " \ + git://github.com/g-truc/${BPN}.git \ + file://0001-Fix-cmake-pathes.patch \ +" +# tag: 0.9.7.6 +SRCREV = "dff3af56a884e31d21eae7ab3eb72a8d192adc54" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libiio/libiio.inc b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libiio/libiio.inc deleted file mode 100644 index 81662a50..00000000 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libiio/libiio.inc +++ /dev/null @@ -1,11 +0,0 @@ -DESCRIPTION = "Library for interfacing with IIO devices" -HOMEPAGE = "http://wiki.analog.com/resources/tools-software/linux-software/libiio" -SECTION = "System/Libraries" -LICENSE = "LGPL-2.1" - -LIC_FILES_CHKSUM ??= "file://COPYING.txt;md5=7c13b3376cea0ce68d2d2da0a1b3a72c" - -inherit cmake pkgconfig - -DEPENDS = "libxml2 bison-native flex-native systemd" - diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libiio/libiio_0.5.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libiio/libiio_0.5.bb deleted file mode 100644 index 664dc963..00000000 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libiio/libiio_0.5.bb +++ /dev/null @@ -1,9 +0,0 @@ -require ${BPN}.inc - -SRC_URI = "https://github.com/analogdevicesinc/${BPN}/archive/v${PV}.tar.gz" -SRC_URI[md5sum] = "4496c24dabdce60bdcf231ebe19bb501" -SRC_URI[sha256sum] = "c41cdcfeae8717e72f1100b4dac9d7cc9d86f4e0731da3354149cb7e051666f3" - -LIC_FILES_CHKSUM ??= "file://COPYING;md5=7c13b3376cea0ce68d2d2da0a1b3a72c" - -S = "${WORKDIR}/${BPN}-${PV}" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libiio/libiio_git.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libiio/libiio_git.bb deleted file mode 100644 index 0c02133a..00000000 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libiio/libiio_git.bb +++ /dev/null @@ -1,8 +0,0 @@ -require ${BPN}.inc - -SRC_URI = "git://github.com/analogdevicesinc/${BPN}.git" -S = "${WORKDIR}/git" -SRCREV = "7ce5cd5b508389077aedaaa4d5f1c0b08b78ded5" - -DEFAULT_PREFERENCE = "1" - diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libusbg/libusbg_0.1.0.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libusbg/libusbg_0.1.0.bb index b63bcd48..6c594977 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libusbg/libusbg_0.1.0.bb +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/libusbg/libusbg_0.1.0.bb @@ -1,9 +1,8 @@ require libusbg.inc -SRC_URI = "https://github.com/libusbg/libusbg/archive/v${PV}.tar.gz" +S = "${WORKDIR}/git" -SRC_URI[md5sum] = "2d3af961f7007a35ed3816de6b712ac1" -SRC_URI[sha256sum] = "82fa5c71741a70477148ed455c307611075a4f9af6886ab3e7a4471377dfd2c7" - -S = "${WORKDIR}/libusbg-${PV}" +SRC_URI = "https://github.com/${BPN}/${BPN}.git" +# tag: v0.1.0 +SRCREV = "7e2b04363f319e8936a606bdb122dbde249a2f58" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/nlopt/nlopt_2.4.2.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/nlopt/nlopt_2.4.2.bb index 5c72a311..d331430d 100644 --- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/nlopt/nlopt_2.4.2.bb +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/nlopt/nlopt_2.4.2.bb @@ -1,7 +1,8 @@ require ${PN}.inc -SRC_URI = "https://github.com/stevengj/${BPN}/archive/${BPN}-${PV}.tar.gz" -SRC_URI[md5sum] = "5f60160dd0cb0f7c4fed983940bd5224" -SRC_URI[sha256sum] = "d838b5b4b1c6b6493666ff61a8817a4ebcee924f54fb95f6f64e5f727ddbf2a6" +S = "${WORKDIR}/git" -S = "${WORKDIR}/${BPN}-${BPN}-${PV}" +SRC_URI = "git://github.com/stevengj/${BPN}.git" + +# tag: nlopt-2.4.2 +SRCREV = "355a597b43c80f616252cb370fa9f7e5c997418e" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-3rdparty-ippicv-Use-pre-downloaded-ipp.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-3rdparty-ippicv-Use-pre-downloaded-ipp.patch new file mode 100644 index 00000000..4d76ad40 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-3rdparty-ippicv-Use-pre-downloaded-ipp.patch @@ -0,0 +1,38 @@ +From 4801a057730632225337d7f6d26b9335e6b9b078 Mon Sep 17 00:00:00 2001 +From: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> +Date: Thu, 31 Mar 2016 00:20:15 +0200 +Subject: [PATCH] 3rdparty/ippicv: Use pre-downloaded ipp + +Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> +Signed-off-by: Ismo Puustinen <ismo.puustinen@intel.com> +--- + 3rdparty/ippicv/ippicv.cmake | 15 +-------------- + 1 file changed, 1 insertion(+), 14 deletions(-) + +diff --git a/3rdparty/ippicv/ippicv.cmake b/3rdparty/ippicv/ippicv.cmake +index d601da4bb..f6fc1098c 100644 +--- a/3rdparty/ippicv/ippicv.cmake ++++ b/3rdparty/ippicv/ippicv.cmake +@@ -39,18 +39,5 @@ function(download_ippicv root_var) + endif() + + set(THE_ROOT "${OpenCV_BINARY_DIR}/3rdparty/ippicv") +- ocv_download(FILENAME ${OPENCV_ICV_NAME} +- HASH ${OPENCV_ICV_HASH} +- URL +- "${OPENCV_IPPICV_URL}" +- "$ENV{OPENCV_IPPICV_URL}" +- "https://raw.githubusercontent.com/opencv/opencv_3rdparty/${IPPICV_COMMIT}/ippicv/" +- DESTINATION_DIR "${THE_ROOT}" +- ID IPPICV +- STATUS res +- UNPACK RELATIVE_URL) +- +- if(res) +- set(${root_var} "${THE_ROOT}/${OPENCV_ICV_PACKAGE_SUBDIR}" PARENT_SCOPE) +- endif() ++ set(${root_var} "${THE_ROOT}/${OPENCV_ICV_PACKAGE_SUBDIR}" PARENT_SCOPE) + endfunction() +-- +2.13.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Add-missing-multi-line-separator.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Add-missing-multi-line-separator.patch new file mode 100644 index 00000000..513597b8 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Add-missing-multi-line-separator.patch @@ -0,0 +1,36 @@ +From 60857229aab13ccc426572a43ab891409bb76ea4 Mon Sep 17 00:00:00 2001 +From: Khem Raj <raj.khem@gmail.com> +Date: Sun, 9 Sep 2018 22:52:55 -0700 +Subject: [PATCH] Add missing multi-line separator + +Otherwise this fails to build ( found on mips ) + +Fixes +contrib/modules/surface_matching/src/hash_murmur86.hpp:97:15: error: +expected constructor, destructor, or type conversion before '(' token + && defined(__GNUC__) && (__GNUC__>4 || (__GNUC__==4 && +__GNUC_MINOR__>=3)) + ^ + +Upstream-Status: Submitted [https://github.com/opencv/opencv_contrib/pull/1764] +Signed-off-by: Khem Raj <raj.khem@gmail.com> +--- + modules/surface_matching/src/hash_murmur86.hpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/modules/surface_matching/src/hash_murmur86.hpp b/modules/surface_matching/src/hash_murmur86.hpp +index 1edf6bf4..0477d37e 100644 +--- a/modules/surface_matching/src/hash_murmur86.hpp ++++ b/modules/surface_matching/src/hash_murmur86.hpp +@@ -93,7 +93,7 @@ void hashMurmurx86 ( const void * key, const int len, const uint seed, void * ou + /* Now find best way we can to READ_UINT32 */ + #ifndef WORDS_BIGENDIAN + # define READ_UINT32(ptr) (*((uint32_t*)(ptr))) +-#elif defined(WORDS_BIGENDIAN) ++#elif defined(WORDS_BIGENDIAN) \ + && defined(__GNUC__) && (__GNUC__>4 || (__GNUC__==4 && __GNUC_MINOR__>=3)) + # define READ_UINT32(ptr) (__builtin_bswap32(*((uint32_t*)(ptr)))) + #endif +-- +2.18.0 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Check-for-clang-before-using-isystem.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Check-for-clang-before-using-isystem.patch new file mode 100644 index 00000000..319071a3 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Check-for-clang-before-using-isystem.patch @@ -0,0 +1,32 @@ +From fa76d8646bb2b9b514728eeef41afed7c43a36f2 Mon Sep 17 00:00:00 2001 +From: Khem Raj <raj.khem@gmail.com> +Date: Tue, 11 Sep 2018 18:18:33 -0700 +Subject: [PATCH] Check for clang before using -isystem + +When cross compiling with clang, the internal C++ headers are not found +when adding sysroot to -isystem, that is redundant anyway because it +will look for headers insider --sysroot path with same quality as it +would do with -isystem otherwise + +Upstream-Status: Submitted [https://github.com/opencv/opencv/pull/12504] +Signed-off-by: Khem Raj <raj.khem@gmail.com> +--- + cmake/OpenCVUtils.cmake | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake +index fae91c165f..60c20192dc 100644 +--- a/cmake/OpenCVUtils.cmake ++++ b/cmake/OpenCVUtils.cmake +@@ -259,7 +259,7 @@ function(ocv_include_directories) + ocv_is_opencv_directory(__is_opencv_dir "${dir}") + if(__is_opencv_dir) + list(APPEND __add_before "${dir}") +- elseif(CV_GCC AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0" AND ++ elseif(((CV_GCC AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0") OR CV_CLANG) AND + dir MATCHES "/usr/include$") + # workaround for GCC 6.x bug + else() +-- +2.18.0 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Dont-use-isystem.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Dont-use-isystem.patch new file mode 100644 index 00000000..bf0b80a3 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Dont-use-isystem.patch @@ -0,0 +1,30 @@ +From 7144c44ec70dee73a628463b99ffeed74b1a8ef6 Mon Sep 17 00:00:00 2001 +From: Khem Raj <raj.khem@gmail.com> +Date: Tue, 11 Sep 2018 00:21:18 -0700 +Subject: [PATCH] Dont use isystem + +clang really does not like it + +Upstream-Status: Pending + +Signed-off-by: Khem Raj <raj.khem@gmail.com> +--- + cmake/OpenCVPCHSupport.cmake | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/cmake/OpenCVPCHSupport.cmake b/cmake/OpenCVPCHSupport.cmake +index f9b1b48b65..fe27a136f5 100644 +--- a/cmake/OpenCVPCHSupport.cmake ++++ b/cmake/OpenCVPCHSupport.cmake +@@ -18,6 +18,8 @@ IF(CV_GCC) + SET(PCHSupport_FOUND TRUE) + ENDIF() + ++ SET(CMAKE_INCLUDE_SYSTEM_FLAG_C "-I") ++ SET(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-I") + SET(_PCH_include_prefix "-I") + SET(_PCH_isystem_prefix "-isystem") + SET(_PCH_define_prefix "-D") +-- +2.18.0 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Temporarliy-work-around-deprecated-ffmpeg-RAW-functi.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Temporarliy-work-around-deprecated-ffmpeg-RAW-functi.patch new file mode 100644 index 00000000..63cb7f94 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0001-Temporarliy-work-around-deprecated-ffmpeg-RAW-functi.patch @@ -0,0 +1,33 @@ +From 7d31f41d2a6759e244983504ce855fc32916b97a Mon Sep 17 00:00:00 2001 +From: Jason Wessel <jason.wessel@windriver.com> +Date: Wed, 9 May 2018 13:33:59 -0700 +Subject: [PATCH] Temporarliy work around deprecated ffmpeg RAW function + compile failure until next uprev + +Signed-off-by: Jason Wessel <jason.wessel@windriver.com> +--- + modules/videoio/src/cap_ffmpeg_impl.hpp | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp +index 5a9b10f075..97c6b74b07 100644 +--- a/modules/videoio/src/cap_ffmpeg_impl.hpp ++++ b/modules/videoio/src/cap_ffmpeg_impl.hpp +@@ -667,6 +667,14 @@ struct ImplMutex::Impl + + #endif + ++/* NOTE This is deprecated in ffmpeg and the code should be removed */ ++#ifndef AVFMT_RAWPICTURE ++#define AVFMT_RAWPICTURE 0x0020 ++#endif /* AVFMT_RAWPICTURE */ ++#ifndef CODEC_FLAG_GLOBAL_HEADER ++#define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER ++#endif ++ + void ImplMutex::init() + { + impl = new Impl(); +-- +2.11.0 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0002-Make-opencv-ts-create-share-library-intead-of-static.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0002-Make-opencv-ts-create-share-library-intead-of-static.patch new file mode 100644 index 00000000..a845505a --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0002-Make-opencv-ts-create-share-library-intead-of-static.patch @@ -0,0 +1,26 @@ +From 350525293aef65490e80104ddd99e1b21c5d54b0 Mon Sep 17 00:00:00 2001 +From: Bian Naimeng <biannm@cn.fujitsu.com> +Date: Wed, 19 Apr 2017 03:11:37 +0900 +Subject: [PATCH 2/3] Make opencv-ts create share library intead of static. + +Signed-off-by: Lei Maohui <leimaohui@cn.fujitsu.com> +--- + modules/ts/CMakeLists.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/modules/ts/CMakeLists.txt b/modules/ts/CMakeLists.txt +index f95bed079..ee67858df 100644 +--- a/modules/ts/CMakeLists.txt ++++ b/modules/ts/CMakeLists.txt +@@ -4,7 +4,7 @@ if(NOT BUILD_opencv_ts AND NOT BUILD_TESTS AND NOT BUILD_PERF_TESTS) + ocv_module_disable(ts) + endif() + +-set(OPENCV_MODULE_TYPE STATIC) ++#set(OPENCV_MODULE_TYPE STATIC) + set(OPENCV_MODULE_IS_PART_OF_WORLD FALSE) + + if(WINRT) +-- +2.13.4 + diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0003-To-fix-errors-as-following.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0003-To-fix-errors-as-following.patch new file mode 100644 index 00000000..5270b8c9 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/0003-To-fix-errors-as-following.patch @@ -0,0 +1,69 @@ +From ace48a628dca34d742615598afeef42ed323a029 Mon Sep 17 00:00:00 2001 +From: Huang Qiyu <huangqy.fnst@cn.fujitsu.com> +Date: Fri, 19 May 2017 04:27:50 +0900 +Subject: [PATCH 3/3] To fix errors as following: + +"test_main.cpp:45: undefined reference to `parseCustomOptions(int, char**)'" +"perf_abs.cpp:13: undefined reference to `cvtest::param_seed'" +"test_superres.cpp:270: undefined reference to `checkIppStatus()'" + +Signed-off-by: Huang Qiyu <huangqy.fnst@cn.fujitsu.com> + +Also add the visibility changes for certain OpenCL-related functions in +ts module. + +Signed-off-by: Ismo Puustinen <ismo.puustinen@intel.com> +--- + modules/ts/include/opencv2/ts.hpp | 6 +++--- + modules/ts/include/opencv2/ts/ocl_test.hpp | 2 +- + modules/ts/include/opencv2/ts/ts_ext.hpp | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +Index: git/modules/ts/include/opencv2/ts.hpp +=================================================================== +--- git.orig/modules/ts/include/opencv2/ts.hpp ++++ git/modules/ts/include/opencv2/ts.hpp +@@ -608,7 +608,7 @@ protected: + } + }; + +-extern uint64 param_seed; ++CV_EXPORTS extern uint64 param_seed; + + struct DefaultRngAuto + { +@@ -671,7 +671,7 @@ private: + #endif + #endif + +-void parseCustomOptions(int argc, char **argv); ++CV_EXPORTS void parseCustomOptions(int argc, char **argv); + + #define CV_TEST_INIT0_NOOP (void)0 + +Index: git/modules/ts/include/opencv2/ts/ocl_test.hpp +=================================================================== +--- git.orig/modules/ts/include/opencv2/ts/ocl_test.hpp ++++ git/modules/ts/include/opencv2/ts/ocl_test.hpp +@@ -82,7 +82,7 @@ inline UMat ToUMat(InputArray src) + return dst; + } + +-extern int test_loop_times; ++CV_EXPORTS extern int test_loop_times; + + #define MAX_VALUE 357 + +Index: git/modules/ts/include/opencv2/ts/ts_ext.hpp +=================================================================== +--- git.orig/modules/ts/include/opencv2/ts/ts_ext.hpp ++++ git/modules/ts/include/opencv2/ts/ts_ext.hpp +@@ -9,7 +9,7 @@ + #define OPENCV_TS_EXT_HPP + + namespace cvtest { +-void checkIppStatus(); ++CV_EXPORTS void checkIppStatus(); + extern bool skipUnstableTests; + extern bool runBigDataTests; + extern int testThreads; diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/fixpkgconfig.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/fixpkgconfig.patch new file mode 100644 index 00000000..3ed3468d --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/fixpkgconfig.patch @@ -0,0 +1,30 @@ +Index: git/cmake/OpenCVGenPkgconfig.cmake +=================================================================== +--- git.orig/cmake/OpenCVGenPkgconfig.cmake ++++ git/cmake/OpenCVGenPkgconfig.cmake +@@ -31,7 +31,7 @@ macro(fix_prefix lst isown) + get_filename_component(libdir "${item}" PATH) + get_filename_component(_libname "${item}" NAME) + ocv_get_libname(libname "${_libname}") +- list(APPEND _lst "-L${libdir}" "-l${libname}") ++ list(APPEND _lst "-l${libname}") + else() + list(APPEND _lst "-l${item}") + endif() +@@ -124,11 +124,14 @@ ocv_list_unique(_extra) + ocv_list_unique(_3rdparty) + + set(OPENCV_PC_LIBS +- "-L\${exec_prefix}/${OPENCV_LIB_INSTALL_PATH}" ++ "-L\${exec_prefix}/${OPENCV_3P_LIB_INSTALL_PATH}" + "${_modules}" + ) + if(BUILD_SHARED_LIBS) +- set(OPENCV_PC_LIBS_PRIVATE "${_extra}") ++ set(OPENCV_PC_LIBS_PRIVATE ++ "-L\${exec_prefix}/${OPENCV_LIB_INSTALL_PATH}" ++ "${_extra}" ++ ) + else() + set(OPENCV_PC_LIBS_PRIVATE + "-L\${exec_prefix}/${OPENCV_3P_LIB_INSTALL_PATH}" diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/uselocalxfeatures.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/uselocalxfeatures.patch new file mode 100644 index 00000000..fc273a89 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv/uselocalxfeatures.patch @@ -0,0 +1,20 @@ +diff --git a/modules/xfeatures2d/CMakeLists.txt b/modules/xfeatures2d/CMakeLists.txt +index e1755595..c7009c47 100644 +--- a/modules/xfeatures2d/CMakeLists.txt ++++ b/modules/xfeatures2d/CMakeLists.txt +@@ -5,10 +5,10 @@ ocv_define_module(xfeatures2d opencv_core opencv_imgproc opencv_features2d openc + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/download_vgg.cmake) + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/download_boostdesc.cmake) + set(DOWNLOAD_DIR "${OpenCV_BINARY_DIR}/downloads/xfeatures2d") +-download_boost_descriptors("${DOWNLOAD_DIR}" boost_status) +-download_vgg_descriptors("${DOWNLOAD_DIR}" vgg_status) +-if(NOT boost_status OR NOT vgg_status) +- ocv_module_disable(xfeatures2d) +-endif() ++#download_boost_descriptors("${DOWNLOAD_DIR}" boost_status) ++#download_vgg_descriptors("${DOWNLOAD_DIR}" vgg_status) ++#if(NOT boost_status OR NOT vgg_status) ++# ocv_module_disable(xfeatures2d) ++#endif() + + ocv_module_include_directories("${DOWNLOAD_DIR}") diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv_3.4.3.bb b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv_3.4.3.bb new file mode 100644 index 00000000..a96def9c --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-support/opencv/opencv_3.4.3.bb @@ -0,0 +1,194 @@ +SUMMARY = "Opencv : The Open Computer Vision Library" +HOMEPAGE = "http://opencv.org/" +SECTION = "libs" + +LICENSE = "BSD-3-Clause" +LIC_FILES_CHKSUM = "file://LICENSE;md5=62d89c5dcb0583609ea919c56be0ee76" + +ARM_INSTRUCTION_SET_armv4 = "arm" +ARM_INSTRUCTION_SET_armv5 = "arm" + +DEPENDS = "libtool swig-native bzip2 zlib glib-2.0 libwebp" + +SRCREV_opencv = "b38c50b3d0c31e82294315ec44b54b7ef559ef12" +SRCREV_contrib = "1f6d6f06266e1ef336437ae5404bee1c65d42cda" +SRCREV_ipp = "bdb7bb85f34a8cb0d35e40a81f58da431aa1557a" +SRCREV_boostdesc = "34e4206aef44d50e6bbcd0ab06354b52e7466d26" +SRCREV_vgg = "fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d" + +def ipp_filename(d): + import re + arch = d.getVar('TARGET_ARCH') + if re.match("i.86$", arch): + return "ippicv_2017u3_lnx_ia32_general_20180518.tgz" + else: + return "ippicv_2017u3_lnx_intel64_general_20180518.tgz" + +def ipp_md5sum(d): + import re + arch = d.getVar('TARGET_ARCH') + if re.match("i.86$", arch): + return "ea72de74dae3c604eb6348395366e78e" + else: + return "b7cc351267db2d34b9efa1cd22ff0572" + +IPP_FILENAME = "${@ipp_filename(d)}" +IPP_MD5 = "${@ipp_md5sum(d)}" + +SRCREV_FORMAT = "opencv_contrib_ipp_boostdesc_vgg" +SRC_URI = "git://github.com/opencv/opencv.git;name=opencv \ + git://github.com/opencv/opencv_contrib.git;destsuffix=contrib;name=contrib \ + git://github.com/opencv/opencv_3rdparty.git;branch=ippicv/master_20180518;destsuffix=ipp;name=ipp \ + git://github.com/opencv/opencv_3rdparty.git;branch=contrib_xfeatures2d_boostdesc_20161012;destsuffix=boostdesc;name=boostdesc \ + git://github.com/opencv/opencv_3rdparty.git;branch=contrib_xfeatures2d_vgg_20160317;destsuffix=vgg;name=vgg \ + file://0001-3rdparty-ippicv-Use-pre-downloaded-ipp.patch \ + file://uselocalxfeatures.patch;patchdir=../contrib/ \ + file://0001-Add-missing-multi-line-separator.patch;patchdir=../contrib/ \ + file://0002-Make-opencv-ts-create-share-library-intead-of-static.patch \ + file://0003-To-fix-errors-as-following.patch \ + file://fixpkgconfig.patch \ + file://0001-Temporarliy-work-around-deprecated-ffmpeg-RAW-functi.patch \ + file://0001-Dont-use-isystem.patch \ + file://0001-Check-for-clang-before-using-isystem.patch \ +" +PV = "3.4.3+git${SRCPV}" + +S = "${WORKDIR}/git" + +do_unpack_extra() { + tar xzf ${WORKDIR}/ipp/ippicv/${IPP_FILENAME} -C ${WORKDIR} + cp ${WORKDIR}/vgg/*.i ${WORKDIR}/contrib/modules/xfeatures2d/src + cp ${WORKDIR}/boostdesc/*.i ${WORKDIR}/contrib/modules/xfeatures2d/src +} +addtask unpack_extra after do_unpack before do_patch + +EXTRA_OECMAKE = "-DOPENCV_EXTRA_MODULES_PATH=${WORKDIR}/contrib/modules \ + -DWITH_1394=OFF \ + -DENABLE_PRECOMPILED_HEADERS=OFF \ + -DCMAKE_SKIP_RPATH=ON \ + -DOPENCV_ICV_HASH=${IPP_MD5} \ + -DIPPROOT=${WORKDIR}/ippicv_lnx \ + -DENABLE_NEON=1 \ + -DWITH_NEON=1 \ + ${@bb.utils.contains("TARGET_CC_ARCH", "-msse3", "-DENABLE_SSE=1 -DENABLE_SSE2=1 -DENABLE_SSE3=1 -DENABLE_SSSE3=1", "", d)} \ + ${@bb.utils.contains("TARGET_CC_ARCH", "-msse4.1", "-DENABLE_SSE=1 -DENABLE_SSE2=1 -DENABLE_SSE3=1 -DENABLE_SSSE3=1 -DENABLE_SSE41=1", "", d)} \ + ${@bb.utils.contains("TARGET_CC_ARCH", "-msse4.2", "-DENABLE_SSE=1 -DENABLE_SSE2=1 -DENABLE_SSE3=1 -DENABLE_SSSE3=1 -DENABLE_SSE41=1 -DENABLE_SSE42=1", "", d)} \ + ${@oe.utils.conditional("libdir", "/usr/lib64", "-DLIB_SUFFIX=64", "", d)} \ + ${@oe.utils.conditional("libdir", "/usr/lib32", "-DLIB_SUFFIX=32", "", d)} \ +" +EXTRA_OECMAKE_append_x86 = " -DX86=ON" + +PACKAGECONFIG ??= "python3 eigen jpeg png tiff v4l libv4l gstreamer samples tbb gphoto2 \ + ${@bb.utils.contains("DISTRO_FEATURES", "x11", "gtk", "", d)} \ + ${@bb.utils.contains("LICENSE_FLAGS_WHITELIST", "commercial", "libav", "", d)}" + +PACKAGECONFIG[amdblas] = "-DWITH_OPENCLAMDBLAS=ON,-DWITH_OPENCLAMDBLAS=OFF,libclamdblas," +PACKAGECONFIG[amdfft] = "-DWITH_OPENCLAMDFFT=ON,-DWITH_OPENCLAMDFFT=OFF,libclamdfft," +PACKAGECONFIG[dnn] = "-DBUILD_opencv_dnn=ON -DPROTOBUF_UPDATE_FILES=ON -DBUILD_PROTOBUF=OFF,-DBUILD_opencv_dnn=OFF,protobuf protobuf-native," +PACKAGECONFIG[eigen] = "-DWITH_EIGEN=ON,-DWITH_EIGEN=OFF,libeigen gflags glog," +PACKAGECONFIG[freetype] = "-DBUILD_opencv_freetype=ON,-DBUILD_opencv_freetype=OFF,freetype," +PACKAGECONFIG[gphoto2] = "-DWITH_GPHOTO2=ON,-DWITH_GPHOTO2=OFF,libgphoto2," +PACKAGECONFIG[gstreamer] = "-DWITH_GSTREAMER=ON,-DWITH_GSTREAMER=OFF,gstreamer1.0 gstreamer1.0-plugins-base," +PACKAGECONFIG[gtk] = "-DWITH_GTK=ON,-DWITH_GTK=OFF,gtk+3," +PACKAGECONFIG[jasper] = "-DWITH_JASPER=ON,-DWITH_JASPER=OFF,jasper," +PACKAGECONFIG[java] = "-DJAVA_INCLUDE_PATH=${JAVA_HOME}/include -DJAVA_INCLUDE_PATH2=${JAVA_HOME}/include/linux -DJAVA_AWT_INCLUDE_PATH=${JAVA_HOME}/include -DJAVA_AWT_LIBRARY=${JAVA_HOME}/lib/amd64/libjawt.so -DJAVA_JVM_LIBRARY=${JAVA_HOME}/lib/amd64/server/libjvm.so,,ant-native fastjar-native openjdk-8-native," +PACKAGECONFIG[jpeg] = "-DWITH_JPEG=ON,-DWITH_JPEG=OFF,jpeg," +PACKAGECONFIG[libav] = "-DWITH_FFMPEG=ON,-DWITH_FFMPEG=OFF,libav," +PACKAGECONFIG[libv4l] = "-DWITH_LIBV4L=ON,-DWITH_LIBV4L=OFF,v4l-utils," +PACKAGECONFIG[opencl] = "-DWITH_OPENCL=ON,-DWITH_OPENCL=OFF,opencl-headers virtual/opencl-icd," +PACKAGECONFIG[oracle-java] = "-DJAVA_INCLUDE_PATH=${ORACLE_JAVA_HOME}/include -DJAVA_INCLUDE_PATH2=${ORACLE_JAVA_HOME}/include/linux -DJAVA_AWT_INCLUDE_PATH=${ORACLE_JAVA_HOME}/include -DJAVA_AWT_LIBRARY=${ORACLE_JAVA_HOME}/lib/amd64/libjawt.so -DJAVA_JVM_LIBRARY=${ORACLE_JAVA_HOME}/lib/amd64/server/libjvm.so,,ant-native oracle-jse-jdk oracle-jse-jdk-native," +PACKAGECONFIG[png] = "-DWITH_PNG=ON,-DWITH_PNG=OFF,libpng," +PACKAGECONFIG[python2] = "-DPYTHON2_NUMPY_INCLUDE_DIRS:PATH=${STAGING_LIBDIR}/${PYTHON_DIR}/site-packages/numpy/core/include,,python-numpy," +PACKAGECONFIG[python3] = "-DPYTHON3_NUMPY_INCLUDE_DIRS:PATH=${STAGING_LIBDIR}/${PYTHON_DIR}/site-packages/numpy/core/include,,python3-numpy," +PACKAGECONFIG[samples] = "-DBUILD_EXAMPLES=ON -DINSTALL_PYTHON_EXAMPLES=ON,-DBUILD_EXAMPLES=OFF,," +PACKAGECONFIG[tbb] = "-DWITH_TBB=ON,-DWITH_TBB=OFF,tbb," +PACKAGECONFIG[text] = "-DBUILD_opencv_text=ON,-DBUILD_opencv_text=OFF,tesseract," +PACKAGECONFIG[tiff] = "-DWITH_TIFF=ON,-DWITH_TIFF=OFF,tiff," +PACKAGECONFIG[v4l] = "-DWITH_V4L=ON,-DWITH_V4L=OFF,v4l-utils," + +inherit pkgconfig cmake + +inherit ${@bb.utils.contains('PACKAGECONFIG', 'python3', 'distutils3-base', '', d)} +inherit ${@bb.utils.contains('PACKAGECONFIG', 'python2', 'distutils-base', '', d)} + +export PYTHON_CSPEC="-I${STAGING_INCDIR}/${PYTHON_DIR}" +export PYTHON="${STAGING_BINDIR_NATIVE}/${@bb.utils.contains('PACKAGECONFIG', 'python3', 'python3', 'python', d)}" +export ORACLE_JAVA_HOME="${STAGING_DIR_NATIVE}/usr/bin/java" +export JAVA_HOME="${STAGING_DIR_NATIVE}/usr/lib/jvm/openjdk-8-native" +export ANT_DIR="${STAGING_DIR_NATIVE}/usr/share/ant/" + +TARGET_CC_ARCH += "-I${S}/include " + +PACKAGES += "${@bb.utils.contains('PACKAGECONFIG', 'samples', '${PN}-samples', '', d)} \ + ${@bb.utils.contains('PACKAGECONFIG', 'oracle-java', '${PN}-java', '', d)} \ + ${@bb.utils.contains('PACKAGECONFIG', 'java', '${PN}-java', '', d)} \ + ${@bb.utils.contains('PACKAGECONFIG', 'python2', 'python-${BPN}', '', d)} \ + ${@bb.utils.contains('PACKAGECONFIG', 'python3', 'python3-${BPN}', '', d)} \ + ${PN}-apps" + +python populate_packages_prepend () { + cv_libdir = d.expand('${libdir}') + do_split_packages(d, cv_libdir, '^lib(.*)\.so$', 'lib%s-dev', 'OpenCV %s development package', extra_depends='${PN}-dev', allow_links=True) + do_split_packages(d, cv_libdir, '^lib(.*)\.la$', 'lib%s-dev', 'OpenCV %s development package', extra_depends='${PN}-dev') + do_split_packages(d, cv_libdir, '^lib(.*)\.a$', 'lib%s-dev', 'OpenCV %s development package', extra_depends='${PN}-dev') + do_split_packages(d, cv_libdir, '^lib(.*)\.so\.*', 'lib%s', 'OpenCV %s library', extra_depends='', allow_links=True) + + pn = d.getVar('PN') + metapkg = pn + '-dev' + d.setVar('ALLOW_EMPTY_' + metapkg, "1") + blacklist = [ metapkg ] + metapkg_rdepends = [ ] + packages = d.getVar('PACKAGES').split() + for pkg in packages[1:]: + if not pkg in blacklist and not pkg in metapkg_rdepends and pkg.endswith('-dev'): + metapkg_rdepends.append(pkg) + d.setVar('RRECOMMENDS_' + metapkg, ' '.join(metapkg_rdepends)) + + metapkg = pn + d.setVar('ALLOW_EMPTY_' + metapkg, "1") + blacklist = [ metapkg, "libopencv-ts" ] + metapkg_rdepends = [ ] + for pkg in packages[1:]: + if not pkg in blacklist and not pkg in metapkg_rdepends and not pkg.endswith('-dev') and not pkg.endswith('-dbg') and not pkg.endswith('-doc') and not pkg.endswith('-locale') and not pkg.endswith('-staticdev'): + metapkg_rdepends.append(pkg) + d.setVar('RDEPENDS_' + metapkg, ' '.join(metapkg_rdepends)) +} + +PACKAGES_DYNAMIC += "^libopencv-.*" + +FILES_${PN} = "" +FILES_${PN}-dbg += "${datadir}/OpenCV/java/.debug/* ${datadir}/OpenCV/samples/bin/.debug/*" +FILES_${PN}-dev = "${includedir} ${libdir}/pkgconfig ${datadir}/OpenCV/*.cmake" +FILES_${PN}-staticdev += "${datadir}/OpenCV/3rdparty/lib/*.a" +FILES_${PN}-apps = "${bindir}/* ${datadir}/OpenCV" +FILES_${PN}-java = "${datadir}/OpenCV/java" +FILES_${PN}-samples = "${datadir}/OpenCV/samples/" + +INSANE_SKIP_${PN}-java = "libdir" +INSANE_SKIP_${PN}-dbg = "libdir" + +ALLOW_EMPTY_${PN} = "1" + +SUMMARY_python-opencv = "Python bindings to opencv" +FILES_python-opencv = "${PYTHON_SITEPACKAGES_DIR}/*" +RDEPENDS_python-opencv = "python-core python-numpy" + +SUMMARY_python3-opencv = "Python bindings to opencv" +FILES_python3-opencv = "${PYTHON_SITEPACKAGES_DIR}/*" +RDEPENDS_python3-opencv = "python3-core python3-numpy" + +do_install_append() { + cp ${S}/include/opencv/*.h ${D}${includedir}/opencv/ + sed -i '/blobtrack/d' ${D}${includedir}/opencv/cvaux.h + + # Move Python files into correct library folder (for multilib build) + if [ "$libdir" != "/usr/lib" -a -d ${D}/usr/lib ]; then + mv ${D}/usr/lib/* ${D}/${libdir}/ + rm -rf ${D}/usr/lib + fi + + # Remove references to yocto directories + sed -i "s,${STAGING_DIR_TARGET},,g" ${D}${datadir}/OpenCV/*.cmake + sed -i "/INTERFACE_LINK_LIBRARIES/ s,${libdir}/lib,,g" ${D}${datadir}/OpenCV/*.cmake + sed -i "/INTERFACE_LINK_LIBRARIES/ s,[.]so,,g" ${D}${datadir}/OpenCV/*.cmake +} |