From 3cf1fe5508ee8a2a2c6e33a829bfb6c81381ccd0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 24 Jan 2024 09:23:12 +0100 Subject: [PATCH 01/19] bmips: bcm6368-enetsw: Bump max MTU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The safe max frame size for this ethernet switch is 1532 bytes, excluding the DSA TAG and extra VLAN header, so the maximum outgoing frame is 1542 bytes. The available overhead is needed when using the DSA switch with a cascaded Marvell DSA switch, which is something that exist in real products, in this case the Inteno XG6846. Use defines at the top of the size for max MTU so it is clear how we think about this, add comments. We need to adjust the RX buffer size to fit the new max frame size, which is 1542 when the DSA tag (6 bytes) and VLAN header (4 extra bytes) is added. We also drop this default MTU: #define ENETSW_TAG_SIZE (6 + VLAN_HLEN) ndev->mtu = ETH_DATA_LEN + ENETSW_TAG_SIZE; in favor of just: ndev->mtu = ETH_DATA_LEN; I don't know why the default MTU is trying to second guess the overhead required by DSA and VLAN but the framework will also try to bump the MTU for e.g. DSA tags, and the VLAN overhead is not supposed to be included in the MTU, so this is clearly not right. Before this patch (on the lan1 DSA port in this case): dsa_slave_change_mtu: master->max_mtu = 9724, dev->max_mtu = 10218, DSA overhead = 8 dsa_slave_change_mtu: master = extsw, dev = lan1 dsa_slave_change_mtu: master->max_mtu = 1510, dev->max_mtu = 9724, DSA overhead = 6 dsa_slave_change_mtu: master = eth0, dev = extsw dsa_slave_change_mtu new_master_mtu 1514 > mtu_limit 1510 mdio_mux-0.1:00: nonfatal error -34 setting MTU to 1500 on port 0 My added debug prints before the nonfatal error: the first switch from the top is the Marvell switch, the second in the bcm6368-enetsw with its 1510 limit. After this patch the error is gone. OpenWrt adds a VLAN to each port so we get VLAN tags on all frames. On this setup we even have 4 more bytes left after the two DSA tags and VLAN so we can go all the way up to 1532 as MTU. Testing the new 1532 MTU: eth0 ext1 enp7s0 .--------. .-----------. cable .------. | enetsw | <-> | mv88e6152 | <-----> | host | `--------´ `-----------´ `------´ On the router we set the max MTU for test: ifconfig eth0 mtu 1520 ifconfig br-wan mtu 1520 ifconfig ext1 mtu 1506 An MTU of 1506 on ext1 is a logic consequence of the above setup: this is the max bytes actually transferred. The framing added will be: - 18 bytes standard ethernet header - 4 bytes VLAN header - 6 bytes DSA tag for enetsw - 8 bytes DSA tag for mv88e6152 Sum: 1506 + 18 + 4 + 6 + 8 = 1542 which is out max frame size. Test pinging from host: ping -s 1478 -M do 192.168.1.220 PING 192.168.1.220 (192.168.1.220) 1478(1506) bytes of data. 1486 bytes from 192.168.1.220: icmp_seq=1 ttl=64 time=0.696 ms 1486 bytes from 192.168.1.220: icmp_seq=2 ttl=64 time=0.615 ms Test pinging from router: PING 192.168.1.2 (192.168.1.2): 1478 data bytes 1486 bytes from 192.168.1.2: seq=0 ttl=64 time=0.931 ms 1486 bytes from 192.168.1.2: seq=1 ttl=64 time=0.810 ms The max IP packet without headers is 1478, the outgoing ICMP packet is 1506 bytes. Then the DSA, VLAN and ethernet overhead is added. Let us verify the contents of the resulting ethernet frame of 1542 bytes. Ping packet on router side as viewed with tcpdump: 00:54:51.900869 AF Unknown (1429722180), length 1538: 0x0000: 3d93 bcae c56b a83d 8874 0300 0004 8100 =....k.=.t...... 0x0010: 0000 dada 0000 c020 0fff 0800 4500 05e2 ............E... 0x0020: 0000 4000 4001 b0ec c0a8 0102 c0a8 01dc ..@.@........... 0x0030: 0800 7628 00c3 0001 f5da 1d65 0000 0000 ..v(.......e.... 0x0040: ce65 0a00 0000 0000 1011 1213 1415 1617 .e.............. 0x0050: 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 .........!"#$%&' 0x0060: 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637 ()*+,-./0123456 (...) - 3d93 = First four bytes are the last two bytes of the destination ethernet address I don't know why the first four are missing, but it sure explains why the paket is 1538 bytes and not 1542 which is the actual max frame size. - bcae c56b a83b = source ethernet address - 8874 0300 0004 = Broadcom enetsw DSA tag - 8100 0000 = VLAN 802.1Q header - dada 0000 c020 0fff = EDSA tag for the Marvell (outer) switch, - 0800 is the ethertype (part of the EDSA tag technically) - Next follows the contents of the ping packet as it appears if we dump it on the DSA interface such as tcpdump -i lan1 etc, there we get the stripped out packet, 1506 bytes. - At the end 4 bytes of FCS. This clearly illustrates that the DSA tag is included in the MTU which we set up in Linux, but the VLAN tag and ethernet headers and checksum is not. Tested-by: Paul Donald Signed-off-by: Linus Walleij Signed-off-by: Álvaro Fernández Rojas --- .../net/ethernet/broadcom/bcm6368-enetsw.c | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c index 321e95dbbb..b72a788378 100644 --- a/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c +++ b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c @@ -22,10 +22,19 @@ #include #include -/* MTU */ -#define ENETSW_TAG_SIZE (6 + VLAN_HLEN) -#define ENETSW_MTU_OVERHEAD (VLAN_ETH_HLEN + VLAN_HLEN + \ - ENETSW_TAG_SIZE) +/* TODO: Bigger frames may work but we do not trust that they are safe on all + * platforms so more research is needed, a max frame size of 2048 has been + * tested. We use the safe frame size 1542 which is 1532 plus DSA and VLAN + * overhead. + */ +#define ENETSW_MAX_FRAME 1542 +#define ENETSW_DSA_TAG_SIZE 6 +/* The MTU in Linux does not include ethernet or VLAN headers, but it DOES + * include the DSA overhead (the framework will increase the MTU to fit + * any DSA header). + */ +#define ENETSW_MAX_MTU (ENETSW_MAX_FRAME - VLAN_ETH_HLEN - \ + VLAN_HLEN) #define ENETSW_FRAG_SIZE(x) (SKB_DATA_ALIGN(NET_SKB_PAD + x + \ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))) @@ -1006,7 +1015,7 @@ static int bcm6368_enetsw_probe(struct platform_device *pdev) dev_info(dev, "random mac\n"); } - priv->rx_buf_size = ALIGN(ndev->mtu + ENETSW_MTU_OVERHEAD, + priv->rx_buf_size = ALIGN(ENETSW_MAX_FRAME, ENETSW_DMA_MAXBURST * 4); priv->rx_frag_size = ENETSW_FRAG_SIZE(priv->rx_buf_size); @@ -1066,8 +1075,8 @@ static int bcm6368_enetsw_probe(struct platform_device *pdev) /* register netdevice */ ndev->netdev_ops = &bcm6368_enetsw_ops; ndev->min_mtu = ETH_ZLEN; - ndev->mtu = ETH_DATA_LEN + ENETSW_TAG_SIZE; - ndev->max_mtu = ETH_DATA_LEN + ENETSW_TAG_SIZE; + ndev->mtu = ETH_DATA_LEN; + ndev->max_mtu = ENETSW_MAX_MTU; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) netif_napi_add(ndev, &priv->napi, bcm6368_enetsw_poll); #else From 6fbe36a618566fae2d12486c0aac2a81dc6c8c48 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Wed, 24 Jan 2024 13:18:53 +0100 Subject: [PATCH 02/19] tools/cpio: update to 2.15 Release Notes: https://lists.gnu.org/archive/html/info-gnu/2024-01/msg00006.html Signed-off-by: Nick Hainke --- tools/cpio/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cpio/Makefile b/tools/cpio/Makefile index 1550785ddc..bd6e258980 100644 --- a/tools/cpio/Makefile +++ b/tools/cpio/Makefile @@ -3,11 +3,11 @@ include $(TOPDIR)/rules.mk PKG_NAME:=cpio PKG_CPE_ID:=cpe:/a:gnu:cpio -PKG_VERSION:=2.14 +PKG_VERSION:=2.15 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:=@GNU/cpio -PKG_HASH:=fcdc15d60f7267a6fc7efcd6b9db7b6c8966c4f2fbbb964c24d41336fd3f2c12 +PKG_HASH:=937610b97c329a1ec9268553fb780037bcfff0dcffe9725ebc4fd9c1aa9075db include $(INCLUDE_DIR)/host-build.mk From ae7a7ef5da250d59953f4365ce0ccf014dd89d14 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Wed, 24 Jan 2024 13:26:31 +0100 Subject: [PATCH 03/19] tools/mkimage: update to 2024.01 Update to latest version. Refresh patch: - 030-allow-to-use-different-magic.patch Signed-off-by: Nick Hainke --- tools/mkimage/Makefile | 4 ++-- tools/mkimage/patches/030-allow-to-use-different-magic.patch | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/mkimage/Makefile b/tools/mkimage/Makefile index 5dceb9a471..ae744f9bf3 100644 --- a/tools/mkimage/Makefile +++ b/tools/mkimage/Makefile @@ -7,14 +7,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mkimage -PKG_VERSION:=2023.10 +PKG_VERSION:=2024.01 PKG_SOURCE:=u-boot-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:= \ https://mirror.cyberbits.eu/u-boot \ https://ftp.denx.de/pub/u-boot \ ftp://ftp.denx.de/pub/u-boot -PKG_HASH:=e00e6c6f014e046101739d08d06f328811cebcf5ae101348f409cbbd55ce6900 +PKG_HASH:=b99611f1ed237bf3541bdc8434b68c96a6e05967061f992443cb30aabebef5b3 HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/u-boot-$(PKG_VERSION) diff --git a/tools/mkimage/patches/030-allow-to-use-different-magic.patch b/tools/mkimage/patches/030-allow-to-use-different-magic.patch index 3689fcb531..f2f57965f6 100644 --- a/tools/mkimage/patches/030-allow-to-use-different-magic.patch +++ b/tools/mkimage/patches/030-allow-to-use-different-magic.patch @@ -50,7 +50,7 @@ This patch makes it possible to set a custom image magic. break; --- a/tools/default_image.c +++ b/tools/default_image.c -@@ -68,7 +68,7 @@ static int image_verify_header(unsigned +@@ -67,7 +67,7 @@ static int image_verify_header(unsigned */ memcpy(hdr, ptr, sizeof(struct legacy_img_hdr)); @@ -59,7 +59,7 @@ This patch makes it possible to set a custom image magic. debug("%s: Bad Magic Number: \"%s\" is no valid image\n", params->cmdname, params->imagefile); return -FDT_ERR_BADMAGIC; -@@ -147,7 +147,7 @@ static void image_set_header(void *ptr, +@@ -146,7 +146,7 @@ static void image_set_header(void *ptr, } /* Build new header */ From 6f90118533cf25d816653cffda8a66976995d71d Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Wed, 24 Jan 2024 13:45:27 +0100 Subject: [PATCH 04/19] iproute2: update to 6.7.0 Release Notes: https://lwn.net/Articles/957171/ Remove patch "100-configure.patch" because support for ATM was dropped [0]. Manually refresh: - 200-drop_libbsd_dependency.patch Automatic refresh: - 130-no_netem_tipc_dcb_man_vdpa.patch - 140-keep_libmnl_optional.patch - 145-keep_libelf_optional.patch - 150-keep_libcap_optional.patch - 155-keep_tirpc_optional.patch - 190-fix-nls-rpath-link.patch - 300-selinux-configurable.patch [0] - https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=a66a73af6db74fdb64439316c69aa0e35dd02c47 Signed-off-by: Nick Hainke --- package/network/utils/iproute2/Makefile | 4 ++-- .../utils/iproute2/patches/100-configure.patch | 12 ------------ .../patches/130-no_netem_tipc_dcb_man_vdpa.patch | 2 +- .../iproute2/patches/140-keep_libmnl_optional.patch | 2 +- .../iproute2/patches/145-keep_libelf_optional.patch | 2 +- .../iproute2/patches/150-keep_libcap_optional.patch | 2 +- .../iproute2/patches/155-keep_tirpc_optional.patch | 2 +- .../iproute2/patches/190-fix-nls-rpath-link.patch | 4 ++-- .../patches/200-drop_libbsd_dependency.patch | 6 +++--- .../iproute2/patches/300-selinux-configurable.patch | 2 +- 10 files changed, 13 insertions(+), 25 deletions(-) delete mode 100644 package/network/utils/iproute2/patches/100-configure.patch diff --git a/package/network/utils/iproute2/Makefile b/package/network/utils/iproute2/Makefile index c21b78916b..2f9d2f2bc9 100644 --- a/package/network/utils/iproute2/Makefile +++ b/package/network/utils/iproute2/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=iproute2 -PKG_VERSION:=6.6.0 +PKG_VERSION:=6.7.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/utils/net/iproute2 -PKG_HASH:=8738c804afd09f0bf756937f0c3de23117832a98d8cbbf50386cf5005cd613ce +PKG_HASH:=ff942dd9828d7d1f867f61fe72ce433078c31e5d8e4a78e20f02cb5892e8841d PKG_BUILD_PARALLEL:=1 PKG_BUILD_DEPENDS:=iptables PKG_LICENSE:=GPL-2.0 diff --git a/package/network/utils/iproute2/patches/100-configure.patch b/package/network/utils/iproute2/patches/100-configure.patch deleted file mode 100644 index 2d4fb7b9b3..0000000000 --- a/package/network/utils/iproute2/patches/100-configure.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/configure -+++ b/configure -@@ -36,7 +36,8 @@ int main(int argc, char **argv) { - } - EOF - -- if $CC -I$INCLUDE -o $TMPDIR/atmtest $TMPDIR/atmtest.c -latm >/dev/null 2>&1; then -+# OpenWrt: disable ATM support even if present on host system -+ if [ 1 -eq 0 ]; then - echo "TC_CONFIG_ATM:=y" >>$CONFIG - echo yes - else diff --git a/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch b/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch index ba6ca4c9b2..8c70c14489 100644 --- a/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch +++ b/package/network/utils/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch @@ -1,6 +1,6 @@ --- a/Makefile +++ b/Makefile -@@ -67,9 +67,9 @@ WFLAGS += -Wmissing-declarations -Wold-s +@@ -68,9 +68,9 @@ WFLAGS += -Wmissing-declarations -Wold-s CFLAGS := $(WFLAGS) $(CCOPTS) -I../include -I../include/uapi $(DEFINES) $(CFLAGS) YACCFLAGS = -d -t -v diff --git a/package/network/utils/iproute2/patches/140-keep_libmnl_optional.patch b/package/network/utils/iproute2/patches/140-keep_libmnl_optional.patch index a8cdd103ba..0d22875751 100644 --- a/package/network/utils/iproute2/patches/140-keep_libmnl_optional.patch +++ b/package/network/utils/iproute2/patches/140-keep_libmnl_optional.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -411,7 +411,7 @@ check_tirpc() +@@ -391,7 +391,7 @@ check_tirpc() check_mnl() { diff --git a/package/network/utils/iproute2/patches/145-keep_libelf_optional.patch b/package/network/utils/iproute2/patches/145-keep_libelf_optional.patch index 0c5c3f59ed..bffacddb21 100644 --- a/package/network/utils/iproute2/patches/145-keep_libelf_optional.patch +++ b/package/network/utils/iproute2/patches/145-keep_libelf_optional.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -266,7 +266,7 @@ EOF +@@ -246,7 +246,7 @@ EOF check_elf() { diff --git a/package/network/utils/iproute2/patches/150-keep_libcap_optional.patch b/package/network/utils/iproute2/patches/150-keep_libcap_optional.patch index 4cce2c3ca6..570e9c7038 100644 --- a/package/network/utils/iproute2/patches/150-keep_libcap_optional.patch +++ b/package/network/utils/iproute2/patches/150-keep_libcap_optional.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -469,7 +469,7 @@ EOF +@@ -449,7 +449,7 @@ EOF check_cap() { diff --git a/package/network/utils/iproute2/patches/155-keep_tirpc_optional.patch b/package/network/utils/iproute2/patches/155-keep_tirpc_optional.patch index 28ba7e5217..4d7fb76308 100644 --- a/package/network/utils/iproute2/patches/155-keep_tirpc_optional.patch +++ b/package/network/utils/iproute2/patches/155-keep_tirpc_optional.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -398,7 +398,7 @@ check_selinux() +@@ -378,7 +378,7 @@ check_selinux() check_tirpc() { diff --git a/package/network/utils/iproute2/patches/190-fix-nls-rpath-link.patch b/package/network/utils/iproute2/patches/190-fix-nls-rpath-link.patch index c7fceb2e22..765e4ad2e8 100644 --- a/package/network/utils/iproute2/patches/190-fix-nls-rpath-link.patch +++ b/package/network/utils/iproute2/patches/190-fix-nls-rpath-link.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -290,7 +290,7 @@ int main(int argc, char **argv) { +@@ -270,7 +270,7 @@ int main(int argc, char **argv) { } EOF @@ -9,7 +9,7 @@ local ret=$? rm -f $TMPDIR/libbpf_test.c $TMPDIR/libbpf_test -@@ -308,7 +308,7 @@ int main(int argc, char **argv) { +@@ -288,7 +288,7 @@ int main(int argc, char **argv) { } EOF diff --git a/package/network/utils/iproute2/patches/200-drop_libbsd_dependency.patch b/package/network/utils/iproute2/patches/200-drop_libbsd_dependency.patch index d1948860e8..92bf5cb66d 100644 --- a/package/network/utils/iproute2/patches/200-drop_libbsd_dependency.patch +++ b/package/network/utils/iproute2/patches/200-drop_libbsd_dependency.patch @@ -1,12 +1,12 @@ --- a/configure +++ b/configure -@@ -455,14 +455,8 @@ EOF +@@ -435,14 +435,8 @@ EOF if $CC -I$INCLUDE -o $TMPDIR/strtest $TMPDIR/strtest.c >/dev/null 2>&1; then echo "no" else - if ${PKG_CONFIG} libbsd --exists; then -- echo 'CFLAGS += -DHAVE_LIBBSD' `${PKG_CONFIG} libbsd --cflags` >>$CONFIG -- echo 'LDLIBS +=' `${PKG_CONFIG} libbsd --libs` >> $CONFIG +- echo 'CFLAGS += -DHAVE_LIBBSD' "$(${PKG_CONFIG} libbsd --cflags)" >>$CONFIG +- echo 'LDLIBS +=' "$(${PKG_CONFIG} libbsd --libs)" >> $CONFIG - echo "no" - else - echo 'CFLAGS += -DNEED_STRLCPY' >>$CONFIG diff --git a/package/network/utils/iproute2/patches/300-selinux-configurable.patch b/package/network/utils/iproute2/patches/300-selinux-configurable.patch index 817abf7d17..a611ba75f0 100644 --- a/package/network/utils/iproute2/patches/300-selinux-configurable.patch +++ b/package/network/utils/iproute2/patches/300-selinux-configurable.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -385,7 +385,7 @@ check_libbpf() +@@ -365,7 +365,7 @@ check_libbpf() check_selinux() # SELinux is a compile time option in the ss utility { From 409052eadefaad018944819d67f343b5e1c259bf Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Thu, 25 Jan 2024 16:17:27 +0100 Subject: [PATCH 05/19] libtraceevent: update to 1.8.2 Changelog: 6f6d580 libtraceevent: 1.8.2 b29b192 kbuffer: Update kbuf->next in kbuffer_refresh 4b2286c kbuffer: Always walk the events to calculate timestamp in kbuffer_read_buffer() ce0acec libtraceevent meson: Add libdl dependency to meson 15a0121 libtraceevent Documentation: Fix tep_kbuffer() prototype 85a2078 libtraceevent: 1.8.1 6b21b4c libtraceevent: Add tep_get_sub_buffer_data_size() 8cf5315 libtraceevent: 1.8 7a4d5b2 kbuffer: Add kbuffer_refresh() API 33bad32 kbuffer: Add kbuffer_subbuffer() API f6bdff7 kbuffer: Add kbuffer_dup() 0582118 kbuffer: Add kbuffer_read_buffer() 014ca24 libtraceevent: Fix tep_kbuffer() to have kbuf assign long_size afead9a libtraceevent: Add tep_get_sub_buffer_commit_offset() 3152506 libtraceevent plugins: Parse sched_switch "prev_state" field for state info 4be92aa libtraceevent: Bump meson version to >=0.58.0 9b2e543 libtraceevent: sync state char array with the kernel 5b89385 libtraceevent: Add option to disable documentation a496a39 libtraceevent: Add tep_record_is_event() API Signed-off-by: Nick Hainke --- package/libs/libtraceevent/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/libs/libtraceevent/Makefile b/package/libs/libtraceevent/Makefile index bcba7eaf43..54e8652192 100644 --- a/package/libs/libtraceevent/Makefile +++ b/package/libs/libtraceevent/Makefile @@ -1,12 +1,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=libtraceevent -PKG_VERSION:=1.7.3 +PKG_VERSION:=1.8.2 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/snapshot/ -PKG_HASH:=097b72e0d907f3107825fb2edf0188324bf70dc9da360f6efa68dc484ffde541 +PKG_HASH:=919f0c024c7b5059eace52d854d4df00ae7e361a4033e1b4d6fe01d97064a1b9 PKG_MAINTAINER:=Nick Hainke From aa06f68c5202f6a4c55197fb78ed9cd24fc78bed Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Thu, 25 Jan 2024 16:23:07 +0100 Subject: [PATCH 06/19] libtracefs: update to 1.8 Changes: 67f3b2a libtracefs: version 1.8 8a1322f libtracefs utest: Add tests to use mapping if supported 0a65b79 libtracefs: Add tracefs_mapped_is_supported() API 805f650 libtracefs: Call mmap ioctl if a refresh happens cf7e2a5 libtracefs: Fix tracefs_mmap() kbuf usage 3a26b26 libtracefs: Have nonblock tracefs_cpu reads set errno EAGAIN 2b5bb09 libtracefs: Have tracefs_mmap_read() include subbuf meta data dee0448 libtracefs: Have mapping work with the other tracefs_cpu* functions 28eebc1 libtracefs: Have tracefs_cpu_flush(_buf)() use mapping 065d914 libtracefs: Use mmapping for iterating raw events 1124e0e libtracefs: Use tracefs_cpu_*_buf() calls for iterator f43b293 libtracefs: Unmap mmap mapping on tracefs_cpu close 0d24516 libtracefs Documentation: Fix tracefs_cpu_snapshot_open() man pages 5ff31c0 libtracefs Documentation: Add tracefs_follow_events_clear() to main man page 0c7d9f7 libtracefs: Add man pages for tracefs_snapshot_*() functions b2dc3e0 libtracefs sql: Rename TIMESTAMP_USECS_DELTA to TIMESTAMP_DELTA_USECS 585ec77 libtracefs: Force off trace mmapping 2ed14b5 libtracefs: Add ring buffer memory mapping APIs 173ffc0 libtracefs meson: Add option to disable samples a55e2e8 libtracefs meson: Add option to disable documentation 93e20af libtracefs: Fix tracefs_instance_reset to clear synthetic events a1ecbff libtracefs utest: Add more tests to test tracefs_sql() 975c37c libtracefs utest: Add matches to trace_sql() tests 0567e2d libtracefs synthetic: Handle hashed name variables fcb3a83 libtracefs synthetic: Remove multiple adding of action in tracefs_synth_save() a9dae65 libtracefs: Fix sqlhist used uninitialized error fe7a467 libtracefs: Add updating and reading snapshot buffers 1ad57ab libtracefs: Add PID filtering API d8726bf libtracefs: Also clear max_graph_depth on reset eb4dd60 libtracefs: Add TIMESTAMP_USECS_DELTA to simplify SQL timestamp compares 8c57eb4 libtracefs: Add tracefs_instance_set/get_subbuf_size() 9bafb21 libtracefs: Add API to extract ring buffer statistics 141d25e libtracefs: Add tracefs_load_headers() API ef3fae7 libtracefs: Add kerneldoc comments to tracefs_instance_set_buffer_size() 31acfe1 libtracefs utest: Add test to test tracefs_instance_set/get_buffer_percent() 3e6d975 libtracefs: Add tracefs_instance_clear() API c4efaaf libtracefs: Add tracefs_instance_get/set_buffer_percent() 1e1cc54 libtracefs: Add API to read tracefs_cpu and return a kbuffer 7d395b1 libtracefs: Add tracefs_instance_file_write_number() e34cbd8 libtracefs: Increase splice to use pipe max size 1f50965 libtracefs: Add API to remove followers from an instance or toplevel 576ee0b libtracefs: Reset tracing before and after unit tests 118b694 libtracefs: Free dynamic event list in utest 5159973 libtracefs: Free tracing_dir in case of remount df563eb libtracefs: Free buf in clear_func_filter() 3cbac37 libtracefs: Free "missed_followers" of instance 0cbe56e libtracefs testing: Use one tep handle for most tests adac30f libtracefs Documentation: Fix tracefs_event_file_exists() issues 07ab199 libtracefs: Pass enum value where expected instead of int bb299b4 libtracefs: fix cscope makefile rule 420d677 libtracefs: Free "followers" when freeing instance 3f436fc libtracefs: Fix documentation of tracefs_trace_pipe_stream() flags 1fde9df libtracefs: Add explicit pthread dependency to meson d1989ae tracefs-perf: Add missing headers for syscall() and SYS_* defines Signed-off-by: Nick Hainke --- package/libs/libtracefs/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/libs/libtracefs/Makefile b/package/libs/libtracefs/Makefile index eb879ee66d..0496f5983e 100644 --- a/package/libs/libtracefs/Makefile +++ b/package/libs/libtracefs/Makefile @@ -1,12 +1,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=libtracefs -PKG_VERSION:=1.7.0 +PKG_VERSION:=1.8.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/snapshot/ -PKG_HASH:=411fcbf3434ecbaefa6c2b1bf092266293a672e2d7ee46fdd6b402753cb8bd16 +PKG_HASH:=f92475d5c4cb509983697fb359ee615bef4f08ed8bdc9c690f6118ba68886de0 PKG_MAINTAINER:=Nick Hainke From 195cf4b58d2722a6cf3fd47538e51bd717db8dd7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 25 Jan 2024 15:04:31 +0100 Subject: [PATCH 07/19] hostapd: remove obsolete function Leftover from authsae, which was removed a long time ago Signed-off-by: Felix Fietkau --- package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh | 2 +- package/network/services/hostapd/files/hostapd.sh | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh index 6572999fbc..ed52822568 100644 --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh @@ -1038,7 +1038,7 @@ mac80211_set_noscan() { } drv_mac80211_cleanup() { - hostapd_common_cleanup + : } mac80211_reset_config() { diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index 271c1f7bec..c3fbf1e0b2 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -1592,7 +1592,3 @@ EOF fi return 0 } - -hostapd_common_cleanup() { - killall meshd-nl80211 -} From cdc4c551755115e0e1047a0c90a658e6238e96ee Mon Sep 17 00:00:00 2001 From: Jesus Fernandez Manzano Date: Mon, 22 Jan 2024 13:46:14 +0100 Subject: [PATCH 08/19] hostapd: fix 11r defaults when using WPA 802.11r can not be used when selecting WPA. It needs at least WPA2. This is because 802.11r advertises FT support in-part through the Authentication and Key Management (AKM) suites in the Robust Security Network (RSN) Information Element, which was included in the 802.11i amendment and WPA2 certification program. Pre-standard WPA did not include the RSN IE, but the WPA IE. This IE can not advertise the AKM suite for FT. Signed-off-by: Jesus Fernandez Manzano --- .../network/services/hostapd/files/hostapd.sh | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index c3fbf1e0b2..058d0f404b 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -43,7 +43,7 @@ hostapd_append_wpa_key_mgmt() { case "$auth_type" in psk|eap) append wpa_key_mgmt "WPA-$auth_type_l" - [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-${auth_type_l}" + [ "${wpa:-2}" -ge 2 ] && [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-${auth_type_l}" [ "${ieee80211w:-0}" -gt 0 ] && append wpa_key_mgmt "WPA-${auth_type_l}-SHA256" ;; eap192) @@ -897,10 +897,21 @@ hostapd_set_bss_options() { } fi + json_get_vars ieee80211r + set_default ieee80211r 0 if [ "$wpa" -ge "1" ]; then - json_get_vars ieee80211r - set_default ieee80211r 0 + if [ "$fils" -gt 0 ]; then + json_get_vars fils_realm + set_default fils_realm "$(echo "$ssid" | md5sum | head -c 8)" + fi + append bss_conf "wpa_disable_eapol_key_retries=$wpa_disable_eapol_key_retries" "$N" + + hostapd_append_wpa_key_mgmt + [ -n "$wpa_key_mgmt" ] && append bss_conf "wpa_key_mgmt=$wpa_key_mgmt" "$N" + fi + + if [ "$wpa" -ge "2" ]; then if [ "$ieee80211r" -gt "0" ]; then json_get_vars mobility_domain ft_psk_generate_local ft_over_ds reassociation_deadline @@ -950,18 +961,7 @@ hostapd_set_bss_options() { done fi fi - if [ "$fils" -gt 0 ]; then - json_get_vars fils_realm - set_default fils_realm "$(echo "$ssid" | md5sum | head -c 8)" - fi - append bss_conf "wpa_disable_eapol_key_retries=$wpa_disable_eapol_key_retries" "$N" - - hostapd_append_wpa_key_mgmt - [ -n "$wpa_key_mgmt" ] && append bss_conf "wpa_key_mgmt=$wpa_key_mgmt" "$N" - fi - - if [ "$wpa" -ge "2" ]; then if [ -n "$network_bridge" -a "$rsn_preauth" = 1 ]; then set_default auth_cache 1 append bss_conf "rsn_preauth=1" "$N" From e2f6bfb833a1ba099e1dcf0e569e4ef11c31c391 Mon Sep 17 00:00:00 2001 From: Jesus Fernandez Manzano Date: Mon, 22 Jan 2024 13:52:18 +0100 Subject: [PATCH 09/19] hostapd: fix 11r defaults when using SAE When using WPA3-SAE or WPA2/WPA3 Personal Mixed, we can not use ft_psk_generate_local because it will break FT for SAE. Instead use the r0kh and r1kh configuration approach. Signed-off-by: Jesus Fernandez Manzano --- package/network/services/hostapd/files/hostapd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index 058d0f404b..ca95fcf70f 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -920,7 +920,7 @@ hostapd_set_bss_options() { set_default reassociation_deadline 1000 case "$auth_type" in - psk|sae|psk-sae) + psk) set_default ft_psk_generate_local 1 ;; *) From 59f67b2010d30049c71e578b93043fb457eecee5 Mon Sep 17 00:00:00 2001 From: Rany Hany Date: Fri, 5 Jan 2024 19:01:40 +0200 Subject: [PATCH 10/19] hostapd: fail R0KH and R1KH derivation when wpa_psk_file is used When wpa_psk_file is used, there is a chance that no PSK is set. This means that the FT key will be generated using only the mobility domain which could be considered a security vulnerability but only for a very specific and niche config. Signed-off-by: Rany Hany --- package/network/services/hostapd/files/hostapd.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index ca95fcf70f..1a664abbf2 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -943,6 +943,10 @@ hostapd_set_bss_options() { set_default pmk_r1_push 0 [ -n "$r0kh" -a -n "$r1kh" ] || { + if [ -z "$auth_secret" -a -z "$key" ]; then + wireless_setup_vif_failed FT_KEY_CANT_BE_DERIVED + return 1 + fi ft_key=`echo -n "$mobility_domain/${auth_secret:-${key}}" | md5sum | awk '{print $1}'` set_default r0kh "ff:ff:ff:ff:ff:ff,*,$ft_key" From 53f338be43e050a49087ae87a8c410bcb4b34782 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 25 Jan 2024 21:42:49 +0100 Subject: [PATCH 11/19] generic: 6.1: add pending patch for ipq4019 MDIO MDC rate fix Add pending patch for ipq4019 MDIO MDC rate fix. The divisor was never actually set resulting in the MDC rate running at a very low speed. The same MDIO is used on ipq807x where Aquantia PHY are commonly used where MDIO is used to load the PHY firmware. Running at higher speed is required to make the firmware load faster as it does reduce load time from 60+ second to 5-6 seconds. Add as pending as upstream there seems to be some conflicts with quic and me and it might take lots of time before this is effectively merged upstream. Signed-off-by: Christian Marangi --- ...ipq4019-mdio-document-now-supported-.patch | 42 ++++ ...-add-support-for-clock-frequency-pro.patch | 204 ++++++++++++++++++ ...pq8074-add-clock-frequency-to-MDIO-n.patch | 25 +++ 3 files changed, 271 insertions(+) create mode 100644 target/linux/generic/pending-6.1/713-01-dt-bindings-net-ipq4019-mdio-document-now-supported-.patch create mode 100644 target/linux/generic/pending-6.1/713-02-net-mdio-ipq4019-add-support-for-clock-frequency-pro.patch create mode 100644 target/linux/generic/pending-6.1/713-03-arm64-dts-qcom-ipq8074-add-clock-frequency-to-MDIO-n.patch diff --git a/target/linux/generic/pending-6.1/713-01-dt-bindings-net-ipq4019-mdio-document-now-supported-.patch b/target/linux/generic/pending-6.1/713-01-dt-bindings-net-ipq4019-mdio-document-now-supported-.patch new file mode 100644 index 0000000000..35258d8541 --- /dev/null +++ b/target/linux/generic/pending-6.1/713-01-dt-bindings-net-ipq4019-mdio-document-now-supported-.patch @@ -0,0 +1,42 @@ +From 85e2038891989e41bc62f6a4625fd5865da8a1a2 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 24 Jan 2024 19:17:02 +0100 +Subject: [PATCH 1/3] dt-bindings: net: ipq4019-mdio: document now supported + clock-frequency + +Document support for clock-frequency and add details on why this +property is needed and what values are supported. + +From internal documentation, while other values are supported, the +correct function of the MDIO bus is not assured hence add only the +suggested supported values to the property enum. + +Signed-off-by: Christian Marangi +--- + .../bindings/net/qcom,ipq4019-mdio.yaml | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/Documentation/devicetree/bindings/net/qcom,ipq4019-mdio.yaml ++++ b/Documentation/devicetree/bindings/net/qcom,ipq4019-mdio.yaml +@@ -38,6 +38,21 @@ properties: + MDIO clock source frequency fixed to 100MHZ, this clock should be specified + by the platform IPQ807x, IPQ60xx and IPQ50xx. + ++ clock-frequency: ++ description: ++ The MDIO bus clock that must be output by the MDIO bus hardware, if ++ absent, the default hardware values are used. ++ ++ MDC rate is feed by an external clock (fixed 100MHz) and is divider ++ internally. The default divider is /256 resulting in the default rate ++ applied of 390KHz. ++ ++ To follow 802.3 standard that instruct up to 2.5MHz by default, if ++ this property is not declared and the divider is set to /256, by ++ default 1.5625Mhz is select. ++ enum: [ 390625, 781250, 1562500, 3125000, 6250000, 12500000 ] ++ default: 1562500 ++ + required: + - compatible + - reg diff --git a/target/linux/generic/pending-6.1/713-02-net-mdio-ipq4019-add-support-for-clock-frequency-pro.patch b/target/linux/generic/pending-6.1/713-02-net-mdio-ipq4019-add-support-for-clock-frequency-pro.patch new file mode 100644 index 0000000000..809d7a0441 --- /dev/null +++ b/target/linux/generic/pending-6.1/713-02-net-mdio-ipq4019-add-support-for-clock-frequency-pro.patch @@ -0,0 +1,204 @@ +From eacf1d2505dfecd3599d558cdade1a2da47fe06d Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 24 Jan 2024 18:52:33 +0100 +Subject: [PATCH 2/3] net: mdio: ipq4019: add support for clock-frequency + property + +The IPQ4019 MDIO internally divide the clock feed by AHB based on the +MDIO_MODE reg. On reset or power up, the default value for the +divider is 0xff that reflect the divider set to /256. + +This makes the MDC run at a very low rate, that is, considering AHB is +always fixed to 100Mhz, a value of 390KHz. + +This hasn't have been a problem as MDIO wasn't used for time sensitive +operation, it is now that on IPQ807x is usually mounted with PHY that +requires MDIO to load their firmware (example Aquantia PHY). + +To handle this problem and permit to set the correct designed MDC +frequency for the SoC add support for the standard "clock-frequency" +property for the MDIO node. + +The divider supports value from /1 to /256 and the common value are to +set it to /16 to reflect 6.25Mhz or to /8 on newer platform to reflect +12.5Mhz. + +To scan if the requested rate is supported by the divider, loop with +each supported divider and stop when the requested rate match the final +rate with the current divider. An error is returned if the rate doesn't +match any value. + +On MDIO reset, the divider is restored to the requested value to prevent +any kind of downclocking caused by the divider reverting to a default +value. + +To follow 802.3 spec of 2.5MHz of default value, if divider is set at +/256 and "clock-frequency" is not set in DT, assume nobody set the +divider and try to find the closest MDC rate to 2.5MHz. (in the case of +AHB set to 100MHz, it's 1.5625MHz) + +While at is also document other bits of the MDIO_MODE reg to have a +clear idea of what is actually applied there. + +Documentation of some BITs is skipped as they are marked as reserved and +their usage is not clear (RES 11:9 GENPHY 16:13 RES1 19:17) + +Signed-off-by: Christian Marangi +--- + drivers/net/mdio/mdio-ipq4019.c | 109 ++++++++++++++++++++++++++++++-- + 1 file changed, 103 insertions(+), 6 deletions(-) + +--- a/drivers/net/mdio/mdio-ipq4019.c ++++ b/drivers/net/mdio/mdio-ipq4019.c +@@ -14,6 +14,20 @@ + #include + + #define MDIO_MODE_REG 0x40 ++#define MDIO_MODE_MDC_MODE BIT(12) ++/* 0 = Clause 22, 1 = Clause 45 */ ++#define MDIO_MODE_C45 BIT(8) ++#define MDIO_MODE_DIV_MASK GENMASK(7, 0) ++#define MDIO_MODE_DIV(x) FIELD_PREP(MDIO_MODE_DIV_MASK, (x) - 1) ++#define MDIO_MODE_DIV_1 0x0 ++#define MDIO_MODE_DIV_2 0x1 ++#define MDIO_MODE_DIV_4 0x3 ++#define MDIO_MODE_DIV_8 0x7 ++#define MDIO_MODE_DIV_16 0xf ++#define MDIO_MODE_DIV_32 0x1f ++#define MDIO_MODE_DIV_64 0x3f ++#define MDIO_MODE_DIV_128 0x7f ++#define MDIO_MODE_DIV_256 0xff + #define MDIO_ADDR_REG 0x44 + #define MDIO_DATA_WRITE_REG 0x48 + #define MDIO_DATA_READ_REG 0x4c +@@ -26,9 +40,6 @@ + #define MDIO_CMD_ACCESS_CODE_C45_WRITE 1 + #define MDIO_CMD_ACCESS_CODE_C45_READ 2 + +-/* 0 = Clause 22, 1 = Clause 45 */ +-#define MDIO_MODE_C45 BIT(8) +- + #define IPQ4019_MDIO_TIMEOUT 10000 + #define IPQ4019_MDIO_SLEEP 10 + +@@ -41,6 +52,7 @@ struct ipq4019_mdio_data { + void __iomem *membase; + void __iomem *eth_ldo_rdy; + struct clk *mdio_clk; ++ unsigned int mdc_rate; + }; + + static int ipq4019_mdio_wait_busy(struct mii_bus *bus) +@@ -179,6 +191,38 @@ static int ipq4019_mdio_write(struct mii + return 0; + } + ++static int ipq4019_mdio_set_div(struct ipq4019_mdio_data *priv) ++{ ++ unsigned long ahb_rate; ++ int div; ++ u32 val; ++ ++ /* If we don't have a clock for AHB use the fixed value */ ++ ahb_rate = IPQ_MDIO_CLK_RATE; ++ if (priv->mdio_clk) ++ ahb_rate = clk_get_rate(priv->mdio_clk); ++ ++ /* MDC rate is ahb_rate/(MDIO_MODE_DIV + 1) ++ * While supported, internal documentation doesn't ++ * assure correct functionality of the MDIO bus ++ * with divider of 1, 2 or 4. ++ */ ++ for (div = 8; div <= 256; div *= 2) { ++ /* The requested rate is supported by the div */ ++ if (priv->mdc_rate == DIV_ROUND_UP(ahb_rate, div)) { ++ val = readl(priv->membase + MDIO_MODE_REG); ++ val &= ~MDIO_MODE_DIV_MASK; ++ val |= MDIO_MODE_DIV(div); ++ writel(val, priv->membase + MDIO_MODE_REG); ++ ++ return 0; ++ } ++ } ++ ++ /* The requested rate is not supported */ ++ return -EINVAL; ++} ++ + static int ipq_mdio_reset(struct mii_bus *bus) + { + struct ipq4019_mdio_data *priv = bus->priv; +@@ -201,10 +245,58 @@ static int ipq_mdio_reset(struct mii_bus + return ret; + + ret = clk_prepare_enable(priv->mdio_clk); +- if (ret == 0) +- mdelay(10); ++ if (ret) ++ return ret; ++ ++ mdelay(10); + +- return ret; ++ /* Restore MDC rate */ ++ return ipq4019_mdio_set_div(priv); ++} ++ ++static void ipq4019_mdio_select_mdc_rate(struct platform_device *pdev, ++ struct ipq4019_mdio_data *priv) ++{ ++ unsigned long ahb_rate; ++ int div; ++ u32 val; ++ ++ /* MDC rate defined in DT, we don't have to decide a default value */ ++ if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", ++ &priv->mdc_rate)) ++ return; ++ ++ /* If we don't have a clock for AHB use the fixed value */ ++ ahb_rate = IPQ_MDIO_CLK_RATE; ++ if (priv->mdio_clk) ++ ahb_rate = clk_get_rate(priv->mdio_clk); ++ ++ /* Check what is the current div set */ ++ val = readl(priv->membase + MDIO_MODE_REG); ++ div = FIELD_GET(MDIO_MODE_DIV_MASK, val); ++ ++ /* div is not set to the default value of /256 ++ * Probably someone changed that (bootloader, other drivers) ++ * Keep this and doesn't overwrite it. ++ */ ++ if (div != MDIO_MODE_DIV_256) { ++ priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div + 1); ++ return; ++ } ++ ++ /* If div is /256 assume nobody have set this value and ++ * try to find one MDC rate that is close the 802.3 spec of ++ * 2.5MHz ++ */ ++ for (div = 256; div >= 8; div /= 2) { ++ /* Stop as soon as we found a divider that ++ * reached the closest value to 2.5MHz ++ */ ++ if (DIV_ROUND_UP(ahb_rate, div) > 2500000) ++ break; ++ ++ priv->mdc_rate = DIV_ROUND_UP(ahb_rate, div); ++ } + } + + static int ipq4019_mdio_probe(struct platform_device *pdev) +@@ -228,6 +320,11 @@ static int ipq4019_mdio_probe(struct pla + if (IS_ERR(priv->mdio_clk)) + return PTR_ERR(priv->mdio_clk); + ++ ipq4019_mdio_select_mdc_rate(pdev, priv); ++ ret = ipq4019_mdio_set_div(priv); ++ if (ret) ++ return ret; ++ + /* The platform resource is provided on the chipset IPQ5018 */ + /* This resource is optional */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); diff --git a/target/linux/generic/pending-6.1/713-03-arm64-dts-qcom-ipq8074-add-clock-frequency-to-MDIO-n.patch b/target/linux/generic/pending-6.1/713-03-arm64-dts-qcom-ipq8074-add-clock-frequency-to-MDIO-n.patch new file mode 100644 index 0000000000..55f116ec5f --- /dev/null +++ b/target/linux/generic/pending-6.1/713-03-arm64-dts-qcom-ipq8074-add-clock-frequency-to-MDIO-n.patch @@ -0,0 +1,25 @@ +From 3b5a603bf66236b956287909556fd7ad4904450c Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 24 Jan 2024 19:38:01 +0100 +Subject: [PATCH 3/3] arm64: dts: qcom: ipq8074: add clock-frequency to MDIO + node + +Add clock-frequency to MDIO node to set the MDC rate to 6.25Mhz instead +of using the default value of 390KHz from MDIO default divider. + +Signed-off-by: Christian Marangi +--- + arch/arm64/boot/dts/qcom/ipq8074.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi +@@ -263,6 +263,8 @@ + clocks = <&gcc GCC_MDIO_AHB_CLK>; + clock-names = "gcc_mdio_ahb_clk"; + ++ clock-frequency = <6250000>; ++ + status = "disabled"; + }; + From 7ed1cca8d6ddc4c74694ca6323ee340895becba0 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 25 Jan 2024 22:20:27 +0100 Subject: [PATCH 12/19] ipq807x: add support for loading Aquantia FW from NVMEM for NBG7815 Add support for loading Aquantia FW from NVMEM for Zyxel NBG7815 restoring correct functionality of the 10g port. Signed-off-by: Christian Marangi --- .../arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts index 5fb8f3b4de..1e8e50875f 100644 --- a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts +++ b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq8074-nbg7815.dts @@ -234,6 +234,15 @@ label = "0:ethphyfw"; reg = <0x650000 0x80000>; read-only; + + nvmem-layout { + compatible = "fixed-layout"; + + aqr_fw: aqr-fw@0 { + /* Skip the QCOM MBN Header of 40 bytes */ + reg = <0x28 0x5f402>; + }; + }; }; partition@6d0000 { @@ -292,6 +301,9 @@ compatible = "ethernet-phy-ieee802.3-c45"; reg = <8>; reset-gpios = <&tlmm 63 GPIO_ACTIVE_LOW>; + + nvmem-cells = <&aqr_fw>; + nvmem-cell-names = "firmware"; }; }; From 9f4708f76cb0d1392323d6a700b786f73f765fa2 Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Thu, 4 Jan 2024 01:22:26 +0100 Subject: [PATCH 13/19] ath79: ubnt-bullet-m-xw: set PHY max-speed to 100Mbps Onboard AR8035 PHY supports 1000Base-T operation, but onboard Ethernet magnetics do not. Reduce advertised link speeds to 100Mbps and lower. Signed-off-by: Lech Perczak --- target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts b/target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts index 8c7d1dc918..16d27dc016 100644 --- a/target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts +++ b/target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts @@ -13,6 +13,7 @@ phy4: ethernet-phy@4 { phy-mode = "rgmii"; reg = <4>; + max-speed = <100>; }; }; From e405b96fe774fbad9c4c465f41ad853a970439bf Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Mon, 22 Jan 2024 00:14:16 +0100 Subject: [PATCH 14/19] ath79: ubnt-bullet-m-xw: fix Ethernet PHY traffic Since commit 6f2e1b7485f0 ("ath79: disable delays on AT803X config init") Ubiquiti XW boards equipped with AR8035 PHY suffered from lack of outbound traffic on the Ethernet port. This was caused by the fact, the U-boot has set this during boot and it wasn't reset by the PHY driver, and the corresponding setting in device tree was wrong. Set the 'phy-mode = "rgmii-txid"' at the ð0, and drop this property from PHY node, as it is not parsed there. This causes the device to connect using Ethernet once again. Fixes: db4b6535f837 ("ath79: Add support for Ubiquity Bullet M (XW)") Fixes: 6f2e1b7485f0 ("ath79: disable delays on AT803X config init") Signed-off-by: Lech Perczak --- target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts b/target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts index 16d27dc016..ee73428625 100644 --- a/target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts +++ b/target/linux/ath79/dts/ar9342_ubnt_bullet-m-xw.dts @@ -11,7 +11,6 @@ status = "okay"; phy4: ethernet-phy@4 { - phy-mode = "rgmii"; reg = <4>; max-speed = <100>; }; @@ -20,7 +19,7 @@ ð0 { status = "okay"; - phy-mode = "rgmii"; + phy-mode = "rgmii-txid"; phy-handle = <&phy4>; gmac-config { From 65f599223d6d24fa68059066c6fa85b862841632 Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Mon, 22 Jan 2024 00:34:34 +0100 Subject: [PATCH 15/19] ath79: add Ubiquiti Rocket M XW as alternate name to Bullet M XW Ubiquiti Rocket M XW is a single-band, 2x2:2 external Wi-Fi AP, with optional GPS receiver, with two external RP-SMA antenna connections, based on AR9342 SoC. Two band variants exists, for 2.4GHz and 5GHz band, usable with the same image. Specs: - CPU: Atheros AR9342 MIPS SoC at 535MHz - RAM: 64MB DDR400 - ROM: 8MB SPI-NOR in SO16W package, MX25L6408E - Wi-Fi Atheros AR9342 built-in 2x2:2 radio - Ethernet: Atheros AR8035 PHY, limited to 100Mbps speeds due to magnetics - Power: 24V passive PoE input. Installation: please refer to Ubiquiti Bullet M2HP for documentation. The device runs with exactly same image as the Bullet, and after fixes in preceding commit, is fully functional again. Add the alternative name to the build system. Signed-off-by: Lech Perczak --- target/linux/ath79/image/generic-ubnt.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/linux/ath79/image/generic-ubnt.mk b/target/linux/ath79/image/generic-ubnt.mk index 179de961be..a4d118456f 100644 --- a/target/linux/ath79/image/generic-ubnt.mk +++ b/target/linux/ath79/image/generic-ubnt.mk @@ -28,6 +28,9 @@ TARGET_DEVICES += ubnt_bullet-ac define Device/ubnt_bullet-m-xw $(Device/ubnt-xw) DEVICE_MODEL := Bullet M + DEVICE_ALT0_VENDOR := Ubiquiti + DEVICE_ALT0_MODEL := Rocket M + DEVICE_ALT0_VARIANT := XW DEVICE_PACKAGES += rssileds SUPPORTED_DEVICES += bullet-m-xw endef From 2e715fb4fc8014eefddf5d9232105740f10e06ba Mon Sep 17 00:00:00 2001 From: Marty Jones Date: Thu, 18 Jan 2024 16:23:52 -0500 Subject: [PATCH 16/19] bcm27xx: update 6.1 patches to latest version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for BCM2712 (Raspberry Pi 5). https://github.com/raspberrypi/linux/commit/3bb5880ab3dd31f75c07c3c33bf29c5d469b28f3 Patches were generated from the diff between linux kernel branch linux-6.1.y and rpi-6.1.y from raspberry pi kernel source: - git format-patch linux-6.1.y...rpi-6.1.y Build system: x86_64 Build-tested: bcm2708, bcm2709, bcm2710, bcm2711 Run-tested: bcm2710/RPi3B, bcm2711/RPi4B Signed-off-by: Marty Jones [Remove applied and reverted patches, squash patches and config commits] Signed-off-by: Álvaro Fernández Rojas --- target/linux/bcm27xx/bcm2708/config-6.1 | 7 +- target/linux/bcm27xx/bcm2709/config-6.1 | 7 +- target/linux/bcm27xx/bcm2710/config-6.1 | 10 +- target/linux/bcm27xx/bcm2711/config-6.1 | 10 +- ...ci_sync-Add-fallback-bd-address-prop.patch | 41 - ...-fix-binning-and-rate_factor-for-480.patch | 306 + ...7xx-Read-modem-line-state-at-startup.patch | 28 + ...m2835_unicam-Improve-frame-sequence-.patch | 79 + ...itft-28-35-overlays-for-6.1-driver-c.patch | 41 + ...-imx477-Re-enable-temperature-sensor.patch | 23 + ...lo-katana-dac-audio-Reduce-I2C-clock.patch | 25 + ...ys-jedec-spi-nor-Add-speed-parameter.patch | 308 + ...-constraints-for-E-AC3-DTS-HD-and-ML.patch | 137 + ...fix-channel-info-for-compressed-form.patch | 86 + ...m_64mp-Modify-the-line-length-of-128.patch | 44 + ...rducam_64mp-Add-8000x6000-resolution.patch | 105 + ...ia-i2c-arducam_64mp-Add-PDAF-support.patch | 163 + ...remap-Document-CM4-40-41-restriction.patch | 24 + ...ow-mac-address-to-be-set-in-smsc95xx.patch | 120 + ...hip-debian-certificates-as-hex-files.patch | 1455 ++++ ...t-for-all-the-downstream-rpi-sound-c.patch | 329 + ...62-Set-the-pre_enable_upstream_first.patch | 21 + ...-cards-Fix-Codec-Zero-rate-switching.patch | 48 + ...trickle-voltage-mv-parameter-to-RTCs.patch | 68 + ...mx296-Add-standby-delay-during-probe.patch | 25 + ...ays-Add-bmp380-to-i2c-sensor-overlay.patch | 78 + ...odule-parameter-for-maximum-pdu-size.patch | 162 + ...x296-Updated-imx296-driver-for-exter.patch | 40 + ...s-imx258-Fix-alternate-compatible-st.patch | 26 + ...-vc_mem-Fix-preprocessor-conditional.patch | 21 + ...ers-dwc_otg-Fix-fallthrough-warnings.patch | 32 + ...-sm-cma-Switch-one-bit-bitfields-to-.patch | 61 + ...311-Fix-uninitialized-variable-usage.patch | 21 + ...fault-values-for-Waveshare-7.9-inch-.patch | 29 + ...2c-bus-overrides-to-edt-ft5406-overl.patch | 102 + ...overlays-Fix-README-text-for-i2c-fan.patch | 25 + ...-irqchip-irq-bcm2835-Concurrency-fix.patch | 50 + ...s-Add-drm-option-to-piscreen-overlay.patch | 58 + ...Resolve-clash-in-spi_device_id-names.patch | 36 + ...46-Add-missing-spi_device_id-strings.patch | 50 + ...codec-Downgrade-the-level-for-a-debu.patch | 27 + ...-functions-into-a-more-logical-order.patch | 286 + ...ework-the-atomic-vs-non-atomic-split.patch | 192 + ...d-NULL-pointer-dereference-in-f2fs_i.patch | 63 + ...ng-iproc-rng200-Add-BCM2838-support.patch} | 22 +- ...t-for-100ms-following-PERST-deassert.patch | 39 + ...0-0850-overlays-Add-a-sample-hat_map.patch | 47 + ...-usb-phy-generic-Get-the-vbus-supply.patch | 26 + ...0853-dts-2712-Update-for-device-tree.patch | 7672 +++++++++++++++++ ...mstb-Allow-to-build-for-ARCH_BCM2835.patch | 282 + ...-Allow-RESET_BRCMSTB-on-ARCH_BCM2835.patch | 20 + ...nctrl-bcm2712-pinctrl-pinconf-driver.patch | 1324 +++ ...-mmc-brcmstb-add-support-for-BCM2712.patch | 498 ++ .../950-0860-sdhci-Add-SD-Express-hook.patch | 90 + ...river-though-not-yet-the-Makesfiles-.patch | 3788 ++++++++ ...q-bcm2712-mip-Support-for-2712-s-MIP.patch | 386 + ...et-brcmstb-rescal-Support-shared-use.patch | 47 + ...-net-macb-Also-set-DMA-coherent-mask.patch | 418 + ...wc3-Set-DMA-and-coherent-masks-early.patch | 384 + ...rrypi-touchscreen-Insert-more-delays.patch | 37 + ...0867-PCI-brcmstb-Add-BCM2712-support.patch | 1108 +++ ...V4L2-Add-PiSP-opaque-formats-to-V4L2.patch | 42 + ...-Add-PiSP-compressed-formats-to-V4L2.patch | 39 + ...mfd-Add-binding-for-Raspberry-Pi-RP1.patch | 249 + .../950-0872-mfd-Add-rp1-driver.patch | 442 + ...ck-Add-bindings-for-Raspberry-Pi-RP1.patch | 65 + .../950-0874-clk-Add-rp1-clock-driver.patch | 2208 +++++ ...trl-Add-bindings-for-Raspberry-Pi-RP.patch | 60 + .../950-0876-pinctrl-Add-rp1-driver.patch | 1666 ++++ ...0-0877-serial-pl011-rp1-uart-support.patch | 129 + ...f-dwcmshc-define-sdio-timeout-clocks.patch | 83 + ...mc-sdhci-of-dwcmshc-rp1-sdio-changes.patch | 83 + ...950-0880-clk-rp1-Add-sdio-clk-driver.patch | 641 ++ ...ware-Add-SMBUS-quick-command-support.patch | 76 + ...-dmaengine-dw-axi-dmac-Fixes-for-RP1.patch | 355 + ...w-Handle-combined-tx-and-rx-messages.patch | 64 + ...950-0884-pwm-Add-support-for-RP1-PWM.patch | 292 + .../950-0885-drm-Add-RP1-DSI-driver.patch | 2678 ++++++ .../950-0886-drm-Add-RP1-DPI-driver.patch | 1552 ++++ .../950-0887-drm-Add-RP1-VEC-driver.patch | 3078 +++++++ ...p-compression-format-support-to-v4l2.patch | 75 + ...rp1-Add-CFE-Camera-Front-End-support.patch | 4527 ++++++++++ ...-net-cdns-macb-AXI-tuning-properties.patch | 38 + ...-dwc-list-all-supported-sample-sizes.patch | 29 + ...0892-ASoC-dwc-Support-set_bclk_ratio.patch | 59 + ...950-0893-ASoC-dwc-Add-DMACR-handling.patch | 81 + ...0-0894-ASOC-dwc-Improve-DMA-shutdown.patch | 128 + ...5-ASOC-dwc-Fix-16-bit-audio-handling.patch | 88 + ...bcm-Remove-dependency-on-BCM2835-I2S.patch | 304 + ...n-Add-RP1-ADC-and-temperature-driver.patch | 343 + ...d-bcm2835-pm-Add-support-for-BCM2712.patch | 69 + ...cm2835-power-Add-support-for-BCM2712.patch | 76 + ...spi-gpio-to-correctly-implement-sck-.patch | 150 + ...lement-spidelay-when-requested-bit-r.patch | 55 + ...ix-up-register-addresses-for-V3D-7.x.patch | 672 ++ ...UAPI-to-match-user-space-for-V3D-7.x.patch | 24 + ...-2712-v3d-as-a-compatible-V3D-device.patch | 19 + ...Improve-MMU-support-for-larger-pages.patch | 64 + ...v3d-Add-BCM2712-to-compatibility-lis.patch | 19 + ...vers-char-add-generic-gpiomem-driver.patch | 328 + ...-drivers-char-delete-bcm2835-gpiomem.patch | 301 + ...1-adc-check-conversion-validity-befo.patch | 34 + ...maengine-bcm2835-Add-BCM2712-support.patch | 36 + ...m2835-HACK-Support-DMA-Lite-channels.patch | 57 + .../950-0913-clk-bcm-rpi-Add-disp-clock.patch | 46 + ...-optionally-enable-link-down-powersa.patch | 26 + ...5-Rename-to_bcm2711_cbaddr-to-to_40b.patch | 75 + ...cm2835-Fix-dma-driver-for-BCM2835-38.patch | 77 + ...0917-drivers-iommu-Add-BCM2712-IOMMU.patch | 855 ++ ...stb-l2-Add-config-for-2711-controlle.patch | 73 + ...d-simple-RTC-driver-for-Raspberry-Pi.patch | 237 + ...new-binding-for-Raspberry-Pi-RTC-dri.patch | 35 + ...m-fan-Add-fan-speed-register-support.patch | 164 + ...t-Add-bindings-for-raspberrypi-butto.patch | 63 + ...t-Add-bindings-for-raspberrypi-butto.patch | 27 + ...d-raspberrypi-button-firmware-driver.patch | 197 + ...6-dt-bindings-update-rpi-rtc-binding.patch | 29 + ...add-battery-charge-circuit-control-a.patch | 153 + ...-Avoid-panic-when-booted-with-no-kms.patch | 29 + ...ero-sized-destination-as-full-screen.patch | 28 + ...-for-when-the-YUV-chroma-planes-are-.patch | 50 + ...-drm-vc4-hdmi-Enable-the-audio-clock.patch | 39 + ...n-if-writing-to-an-unknown-HDMI-regi.patch | 31 + ...vs-More-logging-for-dlist-generation.patch | 41 + ...Print-error-if-we-fail-an-allocation.patch | 66 + ...dd-more-debugging-for-LBM-allocation.patch | 36 + ...-Use-return-variable-in-atomic_check.patch | 31 + ...-Move-assigned_channel-to-a-variable.patch | 47 + ...vc4-Introduce-generation-number-enum.patch | 1029 +++ ...-paths-unavailable-on-any-generation.patch | 577 ++ ...switch-statement-to-simplify-vc4_hvs.patch | 125 + ...switch-statement-to-simplify-enablin.patch | 74 + ...st-if-the-EOF-interrupts-are-enabled.patch | 100 + ...-drm-vc4-hvs-Create-hw_init-function.patch | 188 + ...drm-vc4-hvs-Create-cob_init-function.patch | 167 + ...945-drm-vc4-hvs-Rename-hvs_regs-list.patch | 38 + ...plane-Change-ptr0_offset-to-an-array.patch | 103 + ...947-drm-vc4-hvs-Rework-LBM-alignment.patch | 45 + ...ge-prototype-of-__vc4_hvs_alloc-to-p.patch | 93 + ...s-vertical-scaling-must-always-be-en.patch | 30 + ...id-hang-with-debug-registers-when-su.patch | 39 + ...-buffer-offset-out-of-the-vc4_plane_.patch | 154 + ...t-debug-not-resetting-the-next-entry.patch | 33 + ...ncorrect-limit-from-hvs_dlist-debugf.patch | 57 + ...m-vc4-hvs-Remove-ABORT_ON_EMPTY-flag.patch | 50 + ...ble-SCALER_CONTROL-early-in-HVS-init.patch | 59 + ...gs-display-Add-BCM2712-HDMI-bindings.patch | 26 + ...ngs-display-Add-BCM2712-HVS-bindings.patch | 34 + ...play-Add-BCM2712-PixelValve-bindings.patch | 28 + ...ngs-display-Add-BCM2712-MOP-bindings.patch | 28 + ...-display-Add-BCM2712-MOPLET-bindings.patch | 25 + ...play-Add-BCM2712-KMS-driver-bindings.patch | 23 + ...950-0962-drm-vc4-drv-Support-BCM2712.patch | 47 + ...0963-drm-vc4-hvs-Support-BCM2712-HVS.patch | 2139 +++++ ...-Add-support-for-BCM2712-PixelValves.patch | 144 + ...-support-for-BCM2712-HDMI-controller.patch | 1057 +++ ...oduce-structure-to-deal-with-revisio.patch | 117 + ...rm-vc4-txp-Rename-TXP-data-structure.patch | 66 + ...m-vc4-txp-Add-byte-enable-toggle-bit.patch | 56 + ...horizontal-and-vertical-size-offset-.patch | 59 + ...vc4-txp-Handle-40-bits-DMA-Addresses.patch | 59 + ...-the-encoder-type-in-the-variant-str.patch | 44 + ...m-vc4-txp-Add-a-new-TXP-encoder-type.patch | 475 + ...-vc4-txp-Add-support-for-BCM2712-MOP.patch | 64 + ...m-vc4-txp-Add-BCM2712-MOPLET-support.patch | 42 + ...-0975-drm-vc4-Add-additional-warn_on.patch | 240 + ...Switch-generation-mockup-to-a-switch.patch | 47 + ...op-drm-parameter-for-vc4_find_crtc_f.patch | 63 + ...c4-tests-Return-the-allocated-output.patch | 174 + ...rm-vc4-tests-Add-BCM2712-mock-driver.patch | 87 + ...d-tests-for-BCM2712-PixelValve-Muxin.patch | 138 + ...-fkms-Rename-plane-related-functions.patch | 64 + ...ests-Use-custom-plane-state-for-mock.patch | 95 + ...d-function-to-lookup-a-plane-for-a-C.patch | 36 + ...d-helper-to-add-a-new-plane-to-a-sta.patch | 62 + ...sts-Support-a-few-more-plane-formats.patch | 26 + ...Introduce-a-test-for-LBM-buffer-size.patch | 358 + ...d-setting-core-and-disp-clocks-for-h.patch | 40 + ...ssign-LBM-memory-during-atomic_flush.patch | 240 + ...-Alter-the-timing-for-the-Pi-7-DSI-d.patch | 33 + ...eshare-Fix-up-timings-for-10.1-panel.patch | 33 + ...-Fix-locking-in-imx477_init_controls.patch | 34 + ...-0994-overlays-Fix-vc4-kms-dsi-7inch.patch | 57 + ...dec-Fix-broken-channel-map-reporting.patch | 56 + ...fe-Fix-use-of-freed-memory-on-errors.patch | 48 + ...ix-width-height-in-cfe_start_channel.patch | 88 + ...edia-rp1-csi2-Fix-missing-reg-writes.patch | 36 + ...-0-not-1-when-working-with-unsigned-.patch | 33 + ...edia-rp1-cfe-Fix-verbose-debug-print.patch | 26 + ...ename-xxx_dbg_irq-to-xxx_dbg_verbose.patch | 227 + ...-rp1-Add-back-reg-write-debug-prints.patch | 41 + ...e-Add-verbose-debug-module-parameter.patch | 23 + ...05-media-rp1-csi2-Track-CSI-2-errors.patch | 245 + ...1006-media-rp1-cfe-Drop-unused-field.patch | 31 + ...1-csi2-Set-values-for-enum-csi2_mode.patch | 30 + ...8-media-rp1-fe-Fix-default-mbus-code.patch | 27 + ...-cfe-Fix-default-meta-format-s-field.patch | 25 + ...il-streaming-if-FE_CONFIG-node-is-no.patch | 31 + ...config-entry-for-IMX477-to-the-camer.patch | 51 + ...alias-for-the-displays-to-use-as-the.patch | 109 + ...dt-Add-DSI1-and-DSI2-aliases-to-2712.patch | 24 + ...e-the-clear-of-SCALER_DISPBKGND_FILL.patch | 64 + ...rcmstb-Use-dynamic-GPIO-base-numbers.patch | 117 + ...-rpivid-Allow-use-of-iommu-in-rpivid.patch | 57 + ...1019-dts-bcm2712-Add-iommu-to-rpivid.patch | 22 + ...1_cfe-Remove-PISP-specific-MBUS-form.patch | 117 + ...m2835-codec-Correct-alignment-requir.patch | 53 + ...n-edt-ft5x06-Suppress-bogus-data-on-.patch | 96 + ...7-allow-specification-of-the-i2c-bus.patch | 97 + ...-Set-default-I2C-baudrates-to-100kHz.patch | 46 + ...e-DMA-memcpy-support-from-bcm2708_fb.patch | 345 + ...address-offset-for-planes-with-src_-.patch | 48 + ...1_cfe-Fix-link-validate-test-for-pix.patch | 69 + ...4-dts-bcm2712-Use-the-new-model-name.patch | 23 + ...nt-to-request-a-particular-dev-fbN-n.patch | 93 + ...ok-up-preferred-fbdev-node-number-fr.patch | 41 + ...-for-drm-framebuffer-allocations-on-.patch | 72 + ...ange-DRM-card-alias-from-underscore-.patch | 26 + ...r-alias-names-from-_-to-for-drm_dsiN.patch | 24 + ...ange-query-for-FB-designation-from-d.patch | 28 + ...ames-from-_-to-for-drm_fbN_-override.patch | 43 + .../950-1044-Typo-in-overlays-README.patch | 21 + ...-dts-bcm2712-Add-the-krnbt-parameter.patch | 23 + ...-up-interrupt-handler-for-both-2835-.patch | 109 + ...2-firmware-kms-node-to-using-the-271.patch | 25 + ...vers-media-imx477-Disable-the-scaler.patch | 35 + ...-Add-drm_fbN_vc4-overrides-for-Pi0-4.patch | 37 + ...cp23017-allow-specification-of-the-i.patch | 95 + ...sp_be-Add-back-V4L2_PIX_FMT_RPI_BE-f.patch | 54 + ...brcmstb-add-optional-property-brcm-t.patch | 32 + ...stb-optionally-extend-Tperst_clk-tim.patch | 71 + ...arams-for-PCIe-reset-timing-override.patch | 59 + ...on-t-unconditionally-enable-MPS-read.patch | 35 + ...x477-Set-horizontal-binning-when-dis.patch | 39 + ...-Add-Revision-Serial-Model-to-cpuinf.patch | 25 + ...0-rpi-zero-2-w-Remove-WLAN-firmwares.patch | 35 + ...e-Set-the-CSI-2-link-frequency-corre.patch | 111 + ...2712-rpi-5-b-Create-some-dummy-nodes.patch | 42 + ...-rp1-Add-spi6-fix-spi1-address-cells.patch | 49 + ...art-n-pi5-Add-the-pinctrl-0-property.patch | 67 + ...mx477-Add-V4L2_CID_LINK_FREQ-control.patch | 51 + ...x477-Correctly-set-IMX477_PIXEL_RATE.patch | 24 + ...ect-logic-on-stopping-an-HVS-channel.patch | 52 + ...p-WARN-for-HVS-FIFOs-not-being-empty.patch | 30 + ...-stale-dlists-if-channel-is-disabled.patch | 85 + ...dd-hvs_dlist_allocs-debugfs-function.patch | 64 + ...size-of-the-dlist-allocation-that-wa.patch | 23 + ...port-odd-horizontal-timings-on-BCM27.patch | 104 + ...t-the-last-DMA-scoop-out-of-the-FIFO.patch | 41 + ...mc-sdhci-add-SPURIOUS_INT_RESP-quirk.patch | 62 + ...sdhci-of-dwcmhsc-Add-Raspberry-Pi-RP.patch | 42 + ...i-of-dwcmshc-add-RP1-dt-ID-and-quirk.patch | 41 + ...P1-SDHCI-controller-compatible-strin.patch | 104 + ...dioinjector_octo-Add-soundcard-owner.patch | 22 + ...x708-Adjust-broken-line-correction-p.patch | 139 + ...media-cfe-Don-t-confuse-MHz-and-Mbps.patch | 96 + ...Fix-cam-port-override-for-regulators.patch | 25 + ...v5647-Regularise-vcm-node-label-name.patch | 32 + ...ov5647-cam0-mode-should-use-cam0_reg.patch | 27 + .../950-1150-w1-Disable-kernel-log-spam.patch | 25 + ...s-Add-a-media-bus-format-enum-for-16.patch | 21 + ...2-Add-additional-pixel-formats-for-u.patch | 73 + ...e-Add-16-bit-and-compressed-mono-for.patch | 52 + ...sp_be-Add-mono-and-48-bit-RGB-pixel-.patch | 72 + ...ove-check-in-set_bclk_ratio-handling.patch | 32 + ...lays-README-Fix-cut-and-paste-errors.patch | 39 + ...-Switch-from-V4L2_CID_GAIN-to-V4L2_C.patch | 38 + ...lanes-that-are-completely-off-screen.patch | 63 + ...play-connector-Select-DRM_KMS_HELPER.patch | 29 + ...-dlist-alloc-immediately-if-it-never.patch | 56 + ...-Include-I2C-details-in-names-for-th.patch | 48 + ...lude-I2C-details-in-names-for-the-de.patch | 52 + ...iotlb-bounce-buffers-being-imported-.patch | 84 + ...rlays-i2c-sensor-Add-adt7410-support.patch | 75 + ...overlays-hat_map-Add-pisound-mapping.patch | 26 + ...argins-on-the-composite-connector-st.patch | 47 + ...070me05000-Add-prepare_upstream_firs.patch | 26 + ...e-Find-the-source-pads-on-the-sensor.patch | 55 + ...ption-for-cam0-to-camera-mux-Nport-o.patch | 101 + ...dwc-Permit-sample-rates-up-to-384kHz.patch | 26 + ...0-1176-ASoC-dwc-Fix-full-duplex-mode.patch | 63 + ...2x-Adds-bindings-for-TAS575x-devices.patch | 45 + ...rt-for-TAS575x-to-the-pcm512x-driver.patch | 102 + .../950-1182-drm-panel-add-panel-dsi.patch | 176 + ...-bindings-display-panel-dsi-bindings.patch | 136 + ...e-overlay-for-using-panel-dsi-on-RPi.patch | 176 + ...5-allow-specification-of-the-i2c-bus.patch | 159 + ...ts-bcm2712-put-usb-under-axi-not-soc.patch | 59 + ...rect-HVS-muxing-setup-for-the-moplet.patch | 26 + ...moplet-have-different-register-offse.patch | 68 + ...orrect-the-size-of-the-register-rang.patch | 25 + ...CCI-register-access-helper-functions.patch | 388 + ...a-dt-bindings-Add-OmniVision-OV64A40.patch | 114 + ...ndings-i2c-Add-Rohm-BU64754-bindings.patch | 83 + ...2c-Add-driver-for-OmniVision-OV64A40.patch | 3763 ++++++++ ...HM-BU64754-Camera-Autofocus-Actuator.patch | 368 + ...rlay-for-the-OV64A40-Arducam-Camera-.patch | 426 + ...edia-rp1-cfe-Fix-verbose-debug-print.patch | 26 + ...ia-rp1-cfe-Expose-find_format_by_pix.patch | 33 + ...201-media-rp1-cfe-Add-missing-remaps.patch | 43 + ...p1-cfe-Add-missing-compressed-remaps.patch | 43 + ...d-cfe_find_16bit_code-and-cfe_find_c.patch | 74 + ...-media-rp1-csi2-Fix-csi2_pad_set_fmt.patch | 95 + ...media-rp1-fe-Fix-pisp_fe_pad_set_fmt.patch | 104 + ...se-get_frame_desc-to-get-CSI-2-VC-an.patch | 146 + ...1207-media-rp1-cfe-Add-is_image_node.patch | 91 + ...dia-rp1-cfe-Dual-purpose-video-nodes.patch | 621 ++ .../950-1209-media-rp1-Drop-LE-handling.patch | 127 + ...-rp1-csi2-Use-standard-link_validate.patch | 75 + ...ia-rp1-fe-Use-standard-link_validate.patch | 70 + ...Improve-link-validation-for-metadata.patch | 61 + ...pinctrl-bcm-Kconfig-Fix-BCM2712-help.patch | 24 + ...panel-fix-waveshare-panel-software-r.patch | 41 + ...-Pass-given-partition-number-through.patch | 33 + ...2712-rpi-5-b-Enable-warm-reboot-mode.patch | 23 + ...c-imx296-imx477-Configure-tigger_mod.patch | 85 + ...ays-on-parameter-to-imx477-and-imx29.patch | 99 + ...06-Correct-prefix-length-in-snprintf.patch | 29 + ...712-rpi-5-b-Allow-RTC-to-be-disabled.patch | 38 + ...designware-Look-for-CNT-values-in-DT.patch | 57 + .../950-1227-dts-rp1-Add-I2C-timings.patch | 103 + ...sp_be-pisp_fe-Update-UAPI-header-lic.patch | 58 + ...dia-cfe-Add-more-robust-ISR-handlers.patch | 207 + ...fer-bclk_ratio-handling-to-hw_params.patch | 89 + ...x-reading-of-frame-count-on-GEN5-Pi4.patch | 79 + ...2712-rpi-5-b-Add-eth_ledx-parameters.patch | 56 + ...m2712-rpi-5-b-Add-fan-speed-dtparams.patch | 71 + ...n-t-check-if-plane-state-fb-state-fb.patch | 93 + ...-Support-spi0-0cs-and-SPI_NO_CS-mode.patch | 42 + ...mx519-Add-V4L2_CID_LINK_FREQ-control.patch | 51 + ...ducam_64mp-Add-V4L2_CID_LINK_FREQ-co.patch | 56 + ...panel-Modify-the-DSI-mode-to-fix-the.patch | 25 + ...panel-Modified-the-timing-of-11.9inc.patch | 22 + ...12-support-to-vc4_plane_async_set_fb.patch | 88 + ...ic_async_check-to-call-the-right-mod.patch | 38 + ...Allow-non-standard-modes-with-variou.patch | 343 + ...M-pl011-Add-rs485-to-the-RP1-support.patch | 24 + ...q-bcm2712-mip-Support-for-2712-s-MIP.patch | 38 + .../960-hwrng-iproc-set-quality-to-1000.patch | 2 +- target/linux/generic/config-6.1 | 22 + 340 files changed, 69558 insertions(+), 75 deletions(-) delete mode 100644 target/linux/bcm27xx/patches-6.1/950-0699-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0790-media-i2c-imx219-fix-binning-and-rate_factor-for-480.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0791-serial-sc16is7xx-Read-modem-line-state-at-startup.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0792-drivers-media-bcm2835_unicam-Improve-frame-sequence-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0793-dtoverlays-Fix-pitft-28-35-overlays-for-6.1-driver-c.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0795-driver-media-i2c-imx477-Re-enable-temperature-sensor.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0796-overlays-allo-katana-dac-audio-Reduce-I2C-clock.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0797-overlays-jedec-spi-nor-Add-speed-parameter.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0798-ALSA-pcm-fix-ELD-constraints-for-E-AC3-DTS-HD-and-ML.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0799-ASoC-hdmi-codec-fix-channel-info-for-compressed-form.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0800-media-i2c-arducam_64mp-Modify-the-line-length-of-128.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0801-media-i2c-arducam_64mp-Add-8000x6000-resolution.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0802-media-i2c-arducam_64mp-Add-PDAF-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0803-overlays-audremap-Document-CM4-40-41-restriction.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0804-fixup-Allow-mac-address-to-be-set-in-smsc95xx.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0809-cfg80211-ship-debian-certificates-as-hex-files.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0810-fixup-Add-support-for-all-the-downstream-rpi-sound-c.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0815-fixup-drm-tc358762-Set-the-pre_enable_upstream_first.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0816-rpi-sound-cards-Fix-Codec-Zero-rate-switching.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0818-overlays-Add-trickle-voltage-mv-parameter-to-RTCs.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0819-drivers-media-imx296-Add-standby-delay-during-probe.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0820-overlays-Add-bmp380-to-i2c-sensor-overlay.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0821-can-isotp-add-module-parameter-for-maximum-pdu-size.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0822-drivers-media-imx296-Updated-imx296-driver-for-exter.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0823-media-dt-bindings-imx258-Fix-alternate-compatible-st.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0825-char-broadcom-vc_mem-Fix-preprocessor-conditional.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0826-drivers-dwc_otg-Fix-fallthrough-warnings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0827-vc04_services-vc-sm-cma-Switch-one-bit-bitfields-to-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0828-media-i2c-ov2311-Fix-uninitialized-variable-usage.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0830-drm-panel-Fix-default-values-for-Waveshare-7.9-inch-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0831-dtoverlays-Add-i2c-bus-overrides-to-edt-ft5406-overl.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0832-dtoverlays-Fix-README-text-for-i2c-fan.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0833-drivers-irqchip-irq-bcm2835-Concurrency-fix.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0835-dtoverlays-Add-drm-option-to-piscreen-overlay.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0836-drm-ili9486-Resolve-clash-in-spi_device_id-names.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0837-input-ads7846-Add-missing-spi_device_id-strings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0838-staging-bcm2835-codec-Downgrade-the-level-for-a-debu.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0840-gpio-fsm-Sort-functions-into-a-more-logical-order.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0841-gpio_fsm-Rework-the-atomic-vs-non-atomic-split.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0842-f2fs-fix-to-avoid-NULL-pointer-dereference-in-f2fs_i.patch rename target/linux/bcm27xx/patches-6.1/{950-0177-hwrng-iproc-rng200-Add-BCM2838-support.patch => 950-0846-hwrng-iproc-rng200-Add-BCM2838-support.patch} (88%) create mode 100644 target/linux/bcm27xx/patches-6.1/950-0847-PCI-brcmstb-Wait-for-100ms-following-PERST-deassert.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0850-overlays-Add-a-sample-hat_map.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0851-Revert-usb-phy-generic-Get-the-vbus-supply.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0853-dts-2712-Update-for-device-tree.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0855-gpio_brcmstb-Allow-to-build-for-ARCH_BCM2835.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0856-Allow-RESET_BRCMSTB-on-ARCH_BCM2835.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0857-pinctrl-bcm2712-pinctrl-pinconf-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0859-mmc-brcmstb-add-support-for-BCM2712.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0860-sdhci-Add-SD-Express-hook.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0861-Add-new-pispbe-driver-though-not-yet-the-Makesfiles-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0862-irqchip-irq-bcm2712-mip-Support-for-2712-s-MIP.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0863-reset-reset-brcmstb-rescal-Support-shared-use.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0864-net-macb-Also-set-DMA-coherent-mask.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0865-usb-dwc3-Set-DMA-and-coherent-masks-early.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0866-drm-panel-raspberrypi-touchscreen-Insert-more-delays.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0867-PCI-brcmstb-Add-BCM2712-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0868-V4L2-Add-PiSP-opaque-formats-to-V4L2.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0869-V4L2-Add-PiSP-compressed-formats-to-V4L2.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0871-dt-binding-mfd-Add-binding-for-Raspberry-Pi-RP1.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0872-mfd-Add-rp1-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0873-dt-bindings-clock-Add-bindings-for-Raspberry-Pi-RP1.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0874-clk-Add-rp1-clock-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0875-dt-bindings-pinctrl-Add-bindings-for-Raspberry-Pi-RP.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0876-pinctrl-Add-rp1-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0877-serial-pl011-rp1-uart-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0878-mmc-sdhci-of-dwcmshc-define-sdio-timeout-clocks.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0879-mmc-sdhci-of-dwcmshc-rp1-sdio-changes.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0880-clk-rp1-Add-sdio-clk-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0881-i2c-designware-Add-SMBUS-quick-command-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0882-dmaengine-dw-axi-dmac-Fixes-for-RP1.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0883-spi-dw-Handle-combined-tx-and-rx-messages.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0884-pwm-Add-support-for-RP1-PWM.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0885-drm-Add-RP1-DSI-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0886-drm-Add-RP1-DPI-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0887-drm-Add-RP1-VEC-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0888-v4l2-Add-pisp-compression-format-support-to-v4l2.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0889-media-rp1-Add-CFE-Camera-Front-End-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0890-dt-bindings-net-cdns-macb-AXI-tuning-properties.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0891-ASoC-dwc-list-all-supported-sample-sizes.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0892-ASoC-dwc-Support-set_bclk_ratio.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0893-ASoC-dwc-Add-DMACR-handling.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0894-ASOC-dwc-Improve-DMA-shutdown.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0895-ASOC-dwc-Fix-16-bit-audio-handling.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0896-ASoC-bcm-Remove-dependency-on-BCM2835-I2S.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0897-hwmon-Add-RP1-ADC-and-temperature-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0898-mfd-bcm2835-pm-Add-support-for-BCM2712.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0899-soc-bcm-bcm2835-power-Add-support-for-BCM2712.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0900-drivers-spi-Fix-spi-gpio-to-correctly-implement-sck-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0901-spi-spi-gpio-Implement-spidelay-when-requested-bit-r.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0902-drm-v3d-fix-up-register-addresses-for-V3D-7.x.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0903-drm-v3d-update-UAPI-to-match-user-space-for-V3D-7.x.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0904-drm-v3d-add-brcm-2712-v3d-as-a-compatible-V3D-device.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0905-drm-v3d-Improve-MMU-support-for-larger-pages.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0906-dt-bindings-gpu-v3d-Add-BCM2712-to-compatibility-lis.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0907-drivers-char-add-generic-gpiomem-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0909-drivers-char-delete-bcm2835-gpiomem.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0910-drivers-hwmon-rp1-adc-check-conversion-validity-befo.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0911-dmaengine-bcm2835-Add-BCM2712-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0912-dmaengine-bcm2835-HACK-Support-DMA-Lite-channels.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0913-clk-bcm-rpi-Add-disp-clock.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0914-net-phy-broadcom-optionally-enable-link-down-powersa.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0915-dmaengine-bcm2835-Rename-to_bcm2711_cbaddr-to-to_40b.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0916-dmaengine-bcm2835-Fix-dma-driver-for-BCM2835-38.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0917-drivers-iommu-Add-BCM2712-IOMMU.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0918-irqchip-irq-brcmstb-l2-Add-config-for-2711-controlle.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0919-rtc-rtc-rpi-Add-simple-RTC-driver-for-Raspberry-Pi.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0920-dt-bindings-rtc-new-binding-for-Raspberry-Pi-RTC-dri.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0921-hwmon-pwm-fan-Add-fan-speed-register-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0923-dt-bindings-input-Add-bindings-for-raspberrypi-butto.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0924-dt-bindings-input-Add-bindings-for-raspberrypi-butto.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0925-Input-Add-raspberrypi-button-firmware-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0926-dt-bindings-update-rpi-rtc-binding.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0927-drivers-rtc-rpi-add-battery-charge-circuit-control-a.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0928-vc4_drv-Avoid-panic-when-booted-with-no-kms.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0929-drm-vc4-Treat-zero-sized-destination-as-full-screen.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0930-drm-vc4-Fix-FKMS-for-when-the-YUV-chroma-planes-are-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0931-drm-vc4-hdmi-Enable-the-audio-clock.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0932-drm-vc4-hdmi-Warn-if-writing-to-an-unknown-HDMI-regi.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0933-drm-vc4-hvs-More-logging-for-dlist-generation.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0934-drm-vc4-hvs-Print-error-if-we-fail-an-allocation.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0935-drm-vc4-plane-Add-more-debugging-for-LBM-allocation.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0936-drm-vc4-plane-Use-return-variable-in-atomic_check.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0937-drm-vc4-crtc-Move-assigned_channel-to-a-variable.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0938-drm-vc4-Introduce-generation-number-enum.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0939-drm-vc4-Make-v3d-paths-unavailable-on-any-generation.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0940-drm-vc4-hvs-Use-switch-statement-to-simplify-vc4_hvs.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0941-drm-vc4-hvs-Use-switch-statement-to-simplify-enablin.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0942-drm-vc4-hvs-Test-if-the-EOF-interrupts-are-enabled.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0943-drm-vc4-hvs-Create-hw_init-function.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0944-drm-vc4-hvs-Create-cob_init-function.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0945-drm-vc4-hvs-Rename-hvs_regs-list.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0946-drm-vc4-plane-Change-ptr0_offset-to-an-array.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0947-drm-vc4-hvs-Rework-LBM-alignment.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0948-drm-vc4-hvs-Change-prototype-of-__vc4_hvs_alloc-to-p.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0949-drm-vc4-UV-planes-vertical-scaling-must-always-be-en.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0950-drm-vc4-hdmi-Avoid-hang-with-debug-registers-when-su.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0951-drm-vc4-Move-the-buffer-offset-out-of-the-vc4_plane_.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0952-drm-vc4-Fix-dlist-debug-not-resetting-the-next-entry.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0953-drm-vc4-Remove-incorrect-limit-from-hvs_dlist-debugf.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0954-drm-vc4-hvs-Remove-ABORT_ON_EMPTY-flag.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0955-drm-vc4-Enable-SCALER_CONTROL-early-in-HVS-init.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0956-dt-bindings-display-Add-BCM2712-HDMI-bindings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0957-dt-bindings-display-Add-BCM2712-HVS-bindings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0958-dt-bindings-display-Add-BCM2712-PixelValve-bindings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0959-dt-bindings-display-Add-BCM2712-MOP-bindings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0960-dt-bindings-display-Add-BCM2712-MOPLET-bindings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0961-dt-bindings-display-Add-BCM2712-KMS-driver-bindings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0962-drm-vc4-drv-Support-BCM2712.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0963-drm-vc4-hvs-Support-BCM2712-HVS.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0964-drm-vc4-crtc-Add-support-for-BCM2712-PixelValves.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0965-drm-vc4-hdmi-Add-support-for-BCM2712-HDMI-controller.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0966-drm-vc4-txp-Introduce-structure-to-deal-with-revisio.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0967-drm-vc4-txp-Rename-TXP-data-structure.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0968-drm-vc4-txp-Add-byte-enable-toggle-bit.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0969-drm-vc4-txp-Add-horizontal-and-vertical-size-offset-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0970-drm-vc4-txp-Handle-40-bits-DMA-Addresses.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0971-drm-vc4-txp-Move-the-encoder-type-in-the-variant-str.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0972-drm-vc4-txp-Add-a-new-TXP-encoder-type.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0973-drm-vc4-txp-Add-support-for-BCM2712-MOP.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0974-drm-vc4-txp-Add-BCM2712-MOPLET-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0975-drm-vc4-Add-additional-warn_on.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0976-drm-vc4-tests-Switch-generation-mockup-to-a-switch.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0977-drm-vc4-tests-Drop-drm-parameter-for-vc4_find_crtc_f.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0978-drm-vc4-tests-Return-the-allocated-output.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0979-drm-vc4-tests-Add-BCM2712-mock-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0980-drm-vc4-tests-Add-tests-for-BCM2712-PixelValve-Muxin.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0981-drm-vc4-fkms-Rename-plane-related-functions.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0982-drm-vc4-tests-Use-custom-plane-state-for-mock.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0983-drm-vc4-tests-Add-function-to-lookup-a-plane-for-a-C.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0984-drm-vc4-tests-Add-helper-to-add-a-new-plane-to-a-sta.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0985-drm-vc4-tests-Support-a-few-more-plane-formats.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0986-drm-vc4-tests-Introduce-a-test-for-LBM-buffer-size.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0987-drm-vc4-kms-Avoid-setting-core-and-disp-clocks-for-h.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0988-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0989-drm-panel-simple-Alter-the-timing-for-the-Pi-7-DSI-d.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0990-drm-panel-waveshare-Fix-up-timings-for-10.1-panel.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0991-media-i2c-imx477-Fix-locking-in-imx477_init_controls.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0994-overlays-Fix-vc4-kms-dsi-7inch.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0996-ASoC-hdmi-codec-Fix-broken-channel-map-reporting.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0997-media-rp1-cfe-Fix-use-of-freed-memory-on-errors.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0998-media-rp1-cfe-Fix-width-height-in-cfe_start_channel.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-0999-media-rp1-csi2-Fix-missing-reg-writes.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1000-media-rp1-fe-Use-0-not-1-when-working-with-unsigned-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1001-media-rp1-cfe-Fix-verbose-debug-print.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1002-media-rp1-cfe-Rename-xxx_dbg_irq-to-xxx_dbg_verbose.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1003-media-rp1-Add-back-reg-write-debug-prints.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1004-media-rp1-cfe-Add-verbose-debug-module-parameter.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1005-media-rp1-csi2-Track-CSI-2-errors.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1006-media-rp1-cfe-Drop-unused-field.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1007-media-rp1-csi2-Set-values-for-enum-csi2_mode.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1008-media-rp1-fe-Fix-default-mbus-code.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1009-media-rp1-cfe-Fix-default-meta-format-s-field.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1010-media-rp1-cfe-Fail-streaming-if-FE_CONFIG-node-is-no.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1011-media-i2c-Move-Kconfig-entry-for-IMX477-to-the-camer.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1013-drm-Look-for-an-alias-for-the-displays-to-use-as-the.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1014-dt-Add-DSI1-and-DSI2-aliases-to-2712.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1015-vc4-drm-Remove-the-clear-of-SCALER_DISPBKGND_FILL.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1017-gpio-brcmstb-Use-dynamic-GPIO-base-numbers.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1018-media-rpivid-Allow-use-of-iommu-in-rpivid.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1019-dts-bcm2712-Add-iommu-to-rpivid.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1020-drivers-media-rp1_cfe-Remove-PISP-specific-MBUS-form.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1022-vc04_services-bcm2835-codec-Correct-alignment-requir.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1025-input-touchscreen-edt-ft5x06-Suppress-bogus-data-on-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1029-overlays-mcp23017-allow-specification-of-the-i2c-bus.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1030-dts-bcm2712-Set-default-I2C-baudrates-to-100kHz.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1031-vc_mem-Add-the-DMA-memcpy-support-from-bcm2708_fb.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1032-drm-vc4-Correct-address-offset-for-planes-with-src_-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1033-drivers-media-rp1_cfe-Fix-link-validate-test-for-pix.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1034-dts-bcm2712-Use-the-new-model-name.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1035-fbdev-Allow-client-to-request-a-particular-dev-fbN-n.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1036-drm-fb-helper-Look-up-preferred-fbdev-node-number-fr.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1037-dt-Add-overrides-for-drm-framebuffer-allocations-on-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1039-drm-connector-Change-DRM-card-alias-from-underscore-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1040-dt-Alter-alias-names-from-_-to-for-drm_dsiN.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1041-drm-fb_helper-Change-query-for-FB-designation-from-d.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1042-dt-Alter-alias-names-from-_-to-for-drm_fbN_-override.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1044-Typo-in-overlays-README.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1045-dts-bcm2712-Add-the-krnbt-parameter.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1047-drm-vc4_fkms-Fix-up-interrupt-handler-for-both-2835-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1048-dt-Switch-bcm2712-firmware-kms-node-to-using-the-271.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1049-drivers-media-imx477-Disable-the-scaler.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1050-dt-Add-drm_fbN_vc4-overrides-for-Pi0-4.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1051-fixup-overlays-mcp23017-allow-specification-of-the-i.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1052-drivers-media-pisp_be-Add-back-V4L2_PIX_FMT_RPI_BE-f.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1053-dt-bindings-PCI-brcmstb-add-optional-property-brcm-t.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1054-drivers-pci-brcmstb-optionally-extend-Tperst_clk-tim.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1055-arm-dt-add-dtparams-for-PCIe-reset-timing-override.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1056-arm-dt-bcm2712-don-t-unconditionally-enable-MPS-read.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1057-drivers-media-imx477-Set-horizontal-binning-when-dis.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1058-fixup-arch-arm64-Add-Revision-Serial-Model-to-cpuinf.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1060-dts-bcm2710-rpi-zero-2-w-Remove-WLAN-firmwares.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1061-drivers-media-cfe-Set-the-CSI-2-link-frequency-corre.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1062-dts-bcm2712-rpi-5-b-Create-some-dummy-nodes.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1063-dts-rp1-Add-spi6-fix-spi1-address-cells.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1064-overlays-uart-n-pi5-Add-the-pinctrl-0-property.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1065-drivers-media-imx477-Add-V4L2_CID_LINK_FREQ-control.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1066-drivers-media-imx477-Correctly-set-IMX477_PIXEL_RATE.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1067-drm-vc4-Correct-logic-on-stopping-an-HVS-channel.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1068-drm-vc4-Drop-WARN-for-HVS-FIFOs-not-being-empty.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1069-drm-vc4-Free-all-stale-dlists-if-channel-is-disabled.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1070-drm-vc4-Add-hvs_dlist_allocs-debugfs-function.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1071-drm-vc4-Log-the-size-of-the-dlist-allocation-that-wa.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1072-drm-vc4-crtc-Support-odd-horizontal-timings-on-BCM27.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1073-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1075-drivers-mmc-sdhci-add-SPURIOUS_INT_RESP-quirk.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1076-dt-bindings-mmc-sdhci-of-dwcmhsc-Add-Raspberry-Pi-RP.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1077-drivers-mmc-sdhci-of-dwcmshc-add-RP1-dt-ID-and-quirk.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1078-arm-dts-change-RP1-SDHCI-controller-compatible-strin.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1079-ASoC-bcm-audioinjector_octo-Add-soundcard-owner.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1080-drivers-media-imx708-Adjust-broken-line-correction-p.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1082-drivers-media-cfe-Don-t-confuse-MHz-and-Mbps.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1083-overlays-imx296-Fix-cam-port-override-for-regulators.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1148-overlays-ov5647-Regularise-vcm-node-label-name.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1149-overlays-ov5647-cam0-mode-should-use-cam0_reg.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1150-w1-Disable-kernel-log-spam.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1151-include-uapi-mbus-Add-a-media-bus-format-enum-for-16.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1152-include-uapi-v4l2-Add-additional-pixel-formats-for-u.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1153-drivers-media-cfe-Add-16-bit-and-compressed-mono-for.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1154-drivers-media-pisp_be-Add-mono-and-48-bit-RGB-pixel-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1155-ASoC-dwc-Remove-check-in-set_bclk_ratio-handling.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1159-overlays-README-Fix-cut-and-paste-errors.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1160-media-i2c-ov7251-Switch-from-V4L2_CID_GAIN-to-V4L2_C.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1161-drm-vc4-Drop-planes-that-are-completely-off-screen.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1162-drm-bridge-display-connector-Select-DRM_KMS_HELPER.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1163-drm-vc4-Free-the-dlist-alloc-immediately-if-it-never.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1164-input-edt-ft5x06-Include-I2C-details-in-names-for-th.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1165-input-goodix-Include-I2C-details-in-names-for-the-de.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1166-drm-vc4-Block-swiotlb-bounce-buffers-being-imported-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1167-overlays-i2c-sensor-Add-adt7410-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1168-overlays-hat_map-Add-pisound-mapping.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1169-drm-vc4-Set-TV-margins-on-the-composite-connector-st.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1170-drm-panel-jdi-lt070me05000-Add-prepare_upstream_firs.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1172-drivers-media-cfe-Find-the-source-pads-on-the-sensor.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1173-dtoverlays-Add-option-for-cam0-to-camera-mux-Nport-o.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1174-ASoC-dwc-Permit-sample-rates-up-to-384kHz.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1176-ASoC-dwc-Fix-full-duplex-mode.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1179-ASoC-pcm512x-Adds-bindings-for-TAS575x-devices.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1180-ASoC-Adds-support-for-TAS575x-to-the-pcm512x-driver.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1182-drm-panel-add-panel-dsi.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1183-dt-bindings-display-panel-dsi-bindings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1184-overlays-example-overlay-for-using-panel-dsi-on-RPi.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1185-overlays-ADS1115-allow-specification-of-the-i2c-bus.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1186-dts-bcm2712-put-usb-under-axi-not-soc.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1187-drm-vc4-Correct-HVS-muxing-setup-for-the-moplet.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1188-drm-vc4-Mop-and-moplet-have-different-register-offse.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1189-arm-dt-bcm2712-Correct-the-size-of-the-register-rang.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1192-media-Add-MIPI-CCI-register-access-helper-functions.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1193-media-dt-bindings-Add-OmniVision-OV64A40.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1194-media-dt-bindings-i2c-Add-Rohm-BU64754-bindings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1195-media-i2c-Add-driver-for-OmniVision-OV64A40.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1196-media-i2c-Add-ROHM-BU64754-Camera-Autofocus-Actuator.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1197-overlays-Add-overlay-for-the-OV64A40-Arducam-Camera-.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1199-media-rp1-cfe-Fix-verbose-debug-print.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1200-media-rp1-cfe-Expose-find_format_by_pix.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1201-media-rp1-cfe-Add-missing-remaps.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1202-media-rp1-cfe-Add-missing-compressed-remaps.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1203-media-rp1-cfe-Add-cfe_find_16bit_code-and-cfe_find_c.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1204-media-rp1-csi2-Fix-csi2_pad_set_fmt.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1205-media-rp1-fe-Fix-pisp_fe_pad_set_fmt.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1206-media-rp1-csi2-Use-get_frame_desc-to-get-CSI-2-VC-an.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1207-media-rp1-cfe-Add-is_image_node.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1208-media-rp1-cfe-Dual-purpose-video-nodes.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1209-media-rp1-Drop-LE-handling.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1210-media-rp1-csi2-Use-standard-link_validate.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1211-media-rp1-fe-Use-standard-link_validate.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1212-media-rp1-cfe-Improve-link-validation-for-metadata.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1214-drivers-pinctrl-bcm-Kconfig-Fix-BCM2712-help.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1216-drivers-gpu-drm-panel-fix-waveshare-panel-software-r.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1217-firmware-psci-Pass-given-partition-number-through.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1218-dts-bcm2712-rpi-5-b-Enable-warm-reboot-mode.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1222-drivers-media-i2c-imx296-imx477-Configure-tigger_mod.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1223-overlays-Add-always-on-parameter-to-imx477-and-imx29.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1224-input-edt-ft5x06-Correct-prefix-length-in-snprintf.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1225-ARM-dts-bcm2712-rpi-5-b-Allow-RTC-to-be-disabled.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1226-i2c-designware-Look-for-CNT-values-in-DT.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1227-dts-rp1-Add-I2C-timings.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1228-drivers-media-pisp_be-pisp_fe-Update-UAPI-header-lic.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1229-drivers-media-cfe-Add-more-robust-ISR-handlers.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1231-ASoC-dwc-Defer-bclk_ratio-handling-to-hw_params.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1232-drm-vc4-Fix-reading-of-frame-count-on-GEN5-Pi4.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1233-ARM-dts-bcm2712-rpi-5-b-Add-eth_ledx-parameters.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1234-ARM-dts-bcm2712-rpi-5-b-Add-fan-speed-dtparams.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1235-drm-vc4-don-t-check-if-plane-state-fb-state-fb.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1236-spi-bcm2835-Support-spi0-0cs-and-SPI_NO_CS-mode.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1237-drivers-media-imx519-Add-V4L2_CID_LINK_FREQ-control.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1238-drivers-media-arducam_64mp-Add-V4L2_CID_LINK_FREQ-co.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1239-drivers-gpu-drm-panel-Modify-the-DSI-mode-to-fix-the.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1240-drivers-gpu-drm-panel-Modified-the-timing-of-11.9inc.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1241-drm-vc4-Add-2712-support-to-vc4_plane_async_set_fb.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1242-drm-vc4-Fix-atomic_async_check-to-call-the-right-mod.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1244-drm-rp1-rp1-vec-Allow-non-standard-modes-with-variou.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1245-ARM-pl011-Add-rs485-to-the-RP1-support.patch create mode 100644 target/linux/bcm27xx/patches-6.1/950-1246-fixup-irqchip-irq-bcm2712-mip-Support-for-2712-s-MIP.patch diff --git a/target/linux/bcm27xx/bcm2708/config-6.1 b/target/linux/bcm27xx/bcm2708/config-6.1 index c5d604e6bc..cef17940a3 100644 --- a/target/linux/bcm27xx/bcm2708/config-6.1 +++ b/target/linux/bcm27xx/bcm2708/config-6.1 @@ -30,7 +30,6 @@ CONFIG_ARM_UNWIND=y CONFIG_AUTO_ZRELADDR=y CONFIG_BCM2708_VCMEM=y # CONFIG_BCM2711_THERMAL is not set -CONFIG_BCM2835_DEVGPIOMEM=y CONFIG_BCM2835_FAST_MEMCPY=y CONFIG_BCM2835_MBOX=y CONFIG_BCM2835_POWER=y @@ -151,7 +150,6 @@ CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_IMAGEBLIT=y CONFIG_FB_CMDLINE=y -# CONFIG_FB_RPISENSE is not set CONFIG_FB_SIMPLE=y CONFIG_FIQ=y CONFIG_FIXED_PHY=y @@ -239,8 +237,6 @@ CONFIG_MDIO_DEVRES=y CONFIG_MEMFD_CREATE=y CONFIG_MEMORY_ISOLATION=y CONFIG_MFD_CORE=y -# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set -# CONFIG_MFD_RPISENSE_CORE is not set CONFIG_MFD_SYSCON=y CONFIG_MIGHT_HAVE_CACHE_L2X0=y CONFIG_MIGRATION=y @@ -266,6 +262,7 @@ CONFIG_NO_HZ=y CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y CONFIG_NVMEM=y +CONFIG_NVMEM_LAYOUTS=y CONFIG_OF=y CONFIG_OF_ADDRESS=y CONFIG_OF_CONFIGFS=y @@ -296,7 +293,6 @@ CONFIG_PM_GENERIC_DOMAINS_OF=y CONFIG_PM_GENERIC_DOMAINS_SLEEP=y CONFIG_PM_OPP=y CONFIG_PM_SLEEP=y -# CONFIG_PM_USERSPACE_AUTOSLEEP is not set CONFIG_POWER_SUPPLY=y CONFIG_PREEMPT_NONE_BUILD=y CONFIG_PRINTK_TIME=y @@ -306,6 +302,7 @@ CONFIG_PWM_BCM2835=y CONFIG_PWM_SYSFS=y CONFIG_RANDSTRUCT_NONE=y CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_GPIOMEM=y CONFIG_RASPBERRYPI_POWER=y CONFIG_RATIONAL=y # CONFIG_RAVE_SP_CORE is not set diff --git a/target/linux/bcm27xx/bcm2709/config-6.1 b/target/linux/bcm27xx/bcm2709/config-6.1 index ec2e7f3fa6..15bbaabd74 100644 --- a/target/linux/bcm27xx/bcm2709/config-6.1 +++ b/target/linux/bcm27xx/bcm2709/config-6.1 @@ -39,7 +39,6 @@ CONFIG_ASSOCIATIVE_ARRAY=y CONFIG_AUTO_ZRELADDR=y CONFIG_BCM2708_VCMEM=y CONFIG_BCM2711_THERMAL=y -CONFIG_BCM2835_DEVGPIOMEM=y CONFIG_BCM2835_MBOX=y CONFIG_BCM2835_POWER=y # CONFIG_BCM2835_SMI is not set @@ -186,7 +185,6 @@ CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_IMAGEBLIT=y CONFIG_FB_CMDLINE=y -# CONFIG_FB_RPISENSE is not set CONFIG_FB_SIMPLE=y CONFIG_FIQ=y CONFIG_FIXED_PHY=y @@ -297,8 +295,6 @@ CONFIG_MDIO_DEVRES=y CONFIG_MEMFD_CREATE=y CONFIG_MEMORY_ISOLATION=y CONFIG_MFD_CORE=y -# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set -# CONFIG_MFD_RPISENSE_CORE is not set CONFIG_MFD_SYSCON=y CONFIG_MICROCHIP_PHY=y CONFIG_MIGHT_HAVE_CACHE_L2X0=y @@ -332,6 +328,7 @@ CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y CONFIG_NR_CPUS=4 CONFIG_NVMEM=y +CONFIG_NVMEM_LAYOUTS=y CONFIG_OF=y CONFIG_OF_ADDRESS=y CONFIG_OF_CONFIGFS=y @@ -374,7 +371,6 @@ CONFIG_PM_GENERIC_DOMAINS_SLEEP=y CONFIG_PM_OPP=y CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y -# CONFIG_PM_USERSPACE_AUTOSLEEP is not set CONFIG_POWER_SUPPLY=y CONFIG_PPS=y CONFIG_PREEMPT_NONE_BUILD=y @@ -387,6 +383,7 @@ CONFIG_PWM_SYSFS=y CONFIG_RANDSTRUCT_NONE=y CONFIG_RAS=y CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_GPIOMEM=y CONFIG_RASPBERRYPI_POWER=y CONFIG_RATIONAL=y # CONFIG_RAVE_SP_CORE is not set diff --git a/target/linux/bcm27xx/bcm2710/config-6.1 b/target/linux/bcm27xx/bcm2710/config-6.1 index b0abd49c7f..50b3f87d7d 100644 --- a/target/linux/bcm27xx/bcm2710/config-6.1 +++ b/target/linux/bcm27xx/bcm2710/config-6.1 @@ -60,7 +60,6 @@ CONFIG_ASSOCIATIVE_ARRAY=y CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y CONFIG_BCM2708_VCMEM=y # CONFIG_BCM2711_THERMAL is not set -CONFIG_BCM2835_DEVGPIOMEM=y CONFIG_BCM2835_MBOX=y CONFIG_BCM2835_POWER=y # CONFIG_BCM2835_SMI is not set @@ -152,7 +151,6 @@ CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y CONFIG_CRYPTO_LIB_SHA1=y CONFIG_CRYPTO_LIB_SHA256=y CONFIG_CRYPTO_LIB_UTILS=y -# CONFIG_CRYPTO_POLYVAL_ARM64_CE is not set CONFIG_CRYPTO_RNG=y CONFIG_CRYPTO_RNG2=y CONFIG_CRYPTO_RNG_DEFAULT=y @@ -161,8 +159,6 @@ CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA256_ARM64=y CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_SHA512_ARM64=y -# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set -# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set CONFIG_CRYPTO_XTS=y CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_BUGVERBOSE=y @@ -195,7 +191,6 @@ CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_IMAGEBLIT=y CONFIG_FB_CMDLINE=y -# CONFIG_FB_RPISENSE is not set CONFIG_FB_SIMPLE=y CONFIG_FIXED_PHY=y CONFIG_FIX_EARLYCON_MEM=y @@ -299,8 +294,6 @@ CONFIG_MDIO_DEVRES=y CONFIG_MEMFD_CREATE=y CONFIG_MEMORY_ISOLATION=y CONFIG_MFD_CORE=y -# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set -# CONFIG_MFD_RPISENSE_CORE is not set CONFIG_MFD_SYSCON=y CONFIG_MICROCHIP_PHY=y CONFIG_MIGRATION=y @@ -332,6 +325,7 @@ CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y CONFIG_NR_CPUS=4 CONFIG_NVMEM=y +CONFIG_NVMEM_LAYOUTS=y CONFIG_OF=y CONFIG_OF_ADDRESS=y CONFIG_OF_CONFIGFS=y @@ -368,7 +362,6 @@ CONFIG_PM_GENERIC_DOMAINS_SLEEP=y CONFIG_PM_OPP=y CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y -# CONFIG_PM_USERSPACE_AUTOSLEEP is not set CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y CONFIG_POWER_RESET=y CONFIG_POWER_SUPPLY=y @@ -382,6 +375,7 @@ CONFIG_QUEUED_RWLOCKS=y CONFIG_QUEUED_SPINLOCKS=y CONFIG_RANDSTRUCT_NONE=y CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_GPIOMEM=y CONFIG_RASPBERRYPI_POWER=y CONFIG_RATIONAL=y # CONFIG_RAVE_SP_CORE is not set diff --git a/target/linux/bcm27xx/bcm2711/config-6.1 b/target/linux/bcm27xx/bcm2711/config-6.1 index 1912b653e5..0441305067 100644 --- a/target/linux/bcm27xx/bcm2711/config-6.1 +++ b/target/linux/bcm27xx/bcm2711/config-6.1 @@ -54,7 +54,6 @@ CONFIG_ASSOCIATIVE_ARRAY=y CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y CONFIG_BCM2708_VCMEM=y CONFIG_BCM2711_THERMAL=y -CONFIG_BCM2835_DEVGPIOMEM=y CONFIG_BCM2835_MBOX=y CONFIG_BCM2835_POWER=y # CONFIG_BCM2835_SMI is not set @@ -150,7 +149,6 @@ CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y CONFIG_CRYPTO_LIB_SHA1=y CONFIG_CRYPTO_LIB_SHA256=y CONFIG_CRYPTO_LIB_UTILS=y -# CONFIG_CRYPTO_POLYVAL_ARM64_CE is not set CONFIG_CRYPTO_RNG=y CONFIG_CRYPTO_RNG2=y CONFIG_CRYPTO_RNG_DEFAULT=y @@ -159,8 +157,6 @@ CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA256_ARM64=y CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_SHA512_ARM64=y -# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set -# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set CONFIG_CRYPTO_XTS=y CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_BUGVERBOSE=y @@ -194,7 +190,6 @@ CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_IMAGEBLIT=y CONFIG_FB_CMDLINE=y -# CONFIG_FB_RPISENSE is not set CONFIG_FB_SIMPLE=y CONFIG_FIXED_PHY=y CONFIG_FIX_EARLYCON_MEM=y @@ -300,8 +295,6 @@ CONFIG_MDIO_DEVRES=y CONFIG_MEMFD_CREATE=y CONFIG_MEMORY_ISOLATION=y CONFIG_MFD_CORE=y -# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set -# CONFIG_MFD_RPISENSE_CORE is not set CONFIG_MFD_SYSCON=y CONFIG_MIGRATION=y CONFIG_MMC=y @@ -333,6 +326,7 @@ CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y CONFIG_NR_CPUS=4 CONFIG_NVMEM=y +CONFIG_NVMEM_LAYOUTS=y CONFIG_OF=y CONFIG_OF_ADDRESS=y CONFIG_OF_CONFIGFS=y @@ -372,7 +366,6 @@ CONFIG_PM_GENERIC_DOMAINS_SLEEP=y CONFIG_PM_OPP=y CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y -# CONFIG_PM_USERSPACE_AUTOSLEEP is not set CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y CONFIG_POWER_RESET=y CONFIG_POWER_SUPPLY=y @@ -389,6 +382,7 @@ CONFIG_QUEUED_SPINLOCKS=y CONFIG_RANDSTRUCT_NONE=y CONFIG_RAS=y CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_GPIOMEM=y CONFIG_RASPBERRYPI_POWER=y CONFIG_RATIONAL=y # CONFIG_RAVE_SP_CORE is not set diff --git a/target/linux/bcm27xx/patches-6.1/950-0699-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch b/target/linux/bcm27xx/patches-6.1/950-0699-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch deleted file mode 100644 index d4c5a0183e..0000000000 --- a/target/linux/bcm27xx/patches-6.1/950-0699-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch +++ /dev/null @@ -1,41 +0,0 @@ -From dffb648dffeab7246040a30b7d1669387d1e767e Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 25 Apr 2023 11:49:41 +0100 -Subject: [PATCH] Bluetooth: hci_sync: Add fallback-bd-address prop - -The kernel Bluetooth framework understands that devices may not -be programmed with valid Bluetooth addresses. It also has the ability -to override a Bluetooth address with the value of the local-bd-address -DT property, but it ignores the validity of the existing address when -doing so. - -Add a new boolean property, fallback-bd-address, which indicates that -the given local-bd-address property should only be used if the device -does not already have a valid BDADDR. - -Signed-off-by: Phil Elwell ---- - net/bluetooth/hci_sync.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - ---- a/net/bluetooth/hci_sync.c -+++ b/net/bluetooth/hci_sync.c -@@ -4630,6 +4630,7 @@ static const struct { - */ - static int hci_dev_setup_sync(struct hci_dev *hdev) - { -+ struct fwnode_handle *fwnode = dev_fwnode(hdev->dev.parent); - int ret = 0; - bool invalid_bdaddr; - size_t i; -@@ -4658,7 +4659,9 @@ static int hci_dev_setup_sync(struct hci - - if (!ret) { - if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks) && -- !bacmp(&hdev->public_addr, BDADDR_ANY)) -+ !bacmp(&hdev->public_addr, BDADDR_ANY) && -+ (invalid_bdaddr || -+ !fwnode_property_present(fwnode, "fallback-bd-address"))) - hci_dev_get_bd_addr_from_property(hdev); - - if ((invalid_bdaddr || diff --git a/target/linux/bcm27xx/patches-6.1/950-0790-media-i2c-imx219-fix-binning-and-rate_factor-for-480.patch b/target/linux/bcm27xx/patches-6.1/950-0790-media-i2c-imx219-fix-binning-and-rate_factor-for-480.patch new file mode 100644 index 0000000000..276e51d2d9 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0790-media-i2c-imx219-fix-binning-and-rate_factor-for-480.patch @@ -0,0 +1,306 @@ +From 3ad8e28669e0058e3cec482a47215e50e33f2574 Mon Sep 17 00:00:00 2001 +From: Vinay Varma +Date: Sun, 11 Jun 2023 23:45:03 +0800 +Subject: [PATCH] media: i2c: imx219: fix binning and rate_factor for 480p and + 1232p + +At a high FPS with RAW10, there is frame corruption for 480p because the +rate_factor of 2 is used with the normal 2x2 bining [1]. This commit +ties the rate_factor to the selected binning mode. For the 480p mode, +analog 2x2 binning mode with a rate_factor of 2 is always used. For the +1232p mode the normal 2x2 binning mode is used for RAW10 while analog +2x2 binning mode is used for RAW8. + +[1] https://github.com/raspberrypi/linux/issues/5493 + +Signed-off-by: Vinay Varma +--- + drivers/media/i2c/imx219.c | 143 ++++++++++++++++++++++++++----------- + 1 file changed, 100 insertions(+), 43 deletions(-) + +--- a/drivers/media/i2c/imx219.c ++++ b/drivers/media/i2c/imx219.c +@@ -136,6 +136,18 @@ enum pad_types { + NUM_PADS + }; + ++enum binning_mode { ++ BINNING_NONE, ++ BINNING_DIGITAL_2x2, ++ BINNING_ANALOG_2x2, ++}; ++ ++enum binning_bit_depths { ++ BINNING_IDX_8_BIT, ++ BINNING_IDX_10_BIT, ++ BINNING_IDX_MAX ++}; ++ + struct imx219_reg { + u16 address; + u8 val; +@@ -162,11 +174,8 @@ struct imx219_mode { + /* Default register values */ + struct imx219_reg_list reg_list; + +- /* 2x2 binning is used */ +- bool binning; +- +- /* Relative pixel clock rate factor for the mode. */ +- unsigned int rate_factor; ++ /* binning mode based on format code */ ++ enum binning_mode binning[BINNING_IDX_MAX]; + }; + + static const struct imx219_reg imx219_common_regs[] = { +@@ -404,8 +413,10 @@ static const struct imx219_mode supporte + .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), + .regs = mode_3280x2464_regs, + }, +- .binning = false, +- .rate_factor = 1, ++ .binning = { ++ [BINNING_IDX_8_BIT] = BINNING_NONE, ++ [BINNING_IDX_10_BIT] = BINNING_NONE, ++ }, + }, + { + /* 1080P 30fps cropped */ +@@ -422,8 +433,10 @@ static const struct imx219_mode supporte + .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs), + .regs = mode_1920_1080_regs, + }, +- .binning = false, +- .rate_factor = 1, ++ .binning = { ++ [BINNING_IDX_8_BIT] = BINNING_NONE, ++ [BINNING_IDX_10_BIT] = BINNING_NONE, ++ }, + }, + { + /* 2x2 binned 30fps mode */ +@@ -440,8 +453,10 @@ static const struct imx219_mode supporte + .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs), + .regs = mode_1640_1232_regs, + }, +- .binning = true, +- .rate_factor = 1, ++ .binning = { ++ [BINNING_IDX_8_BIT] = BINNING_ANALOG_2x2, ++ [BINNING_IDX_10_BIT] = BINNING_DIGITAL_2x2, ++ }, + }, + { + /* 640x480 30fps mode */ +@@ -458,12 +473,10 @@ static const struct imx219_mode supporte + .num_of_regs = ARRAY_SIZE(mode_640_480_regs), + .regs = mode_640_480_regs, + }, +- .binning = true, +- /* +- * This mode uses a special 2x2 binning that doubles the +- * internal pixel clock rate. +- */ +- .rate_factor = 2, ++ .binning = { ++ [BINNING_IDX_8_BIT] = BINNING_ANALOG_2x2, ++ [BINNING_IDX_10_BIT] = BINNING_ANALOG_2x2, ++ }, + }, + }; + +@@ -652,12 +665,51 @@ static int imx219_open(struct v4l2_subde + return 0; + } + ++static int imx219_resolve_binning(struct imx219 *imx219, ++ enum binning_mode *binning) ++{ ++ switch (imx219->fmt.code) { ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ *binning = imx219->mode->binning[BINNING_IDX_8_BIT]; ++ return 0; ++ ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ *binning = imx219->mode->binning[BINNING_IDX_10_BIT]; ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int imx219_get_rate_factor(struct imx219 *imx219) ++{ ++ enum binning_mode binning = BINNING_NONE; ++ int ret = imx219_resolve_binning(imx219, &binning); ++ ++ if (ret < 0) ++ return ret; ++ switch (binning) { ++ case BINNING_NONE: ++ case BINNING_DIGITAL_2x2: ++ return 1; ++ case BINNING_ANALOG_2x2: ++ return 2; ++ } ++ return -EINVAL; ++} ++ + static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) + { + struct imx219 *imx219 = + container_of(ctrl->handler, struct imx219, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + int ret; ++ int rate_factor; + + if (ctrl->id == V4L2_CID_VBLANK) { + int exposure_max, exposure_def; +@@ -679,6 +731,10 @@ static int imx219_set_ctrl(struct v4l2_c + if (pm_runtime_get_if_in_use(&client->dev) == 0) + return 0; + ++ rate_factor = imx219_get_rate_factor(imx219); ++ if (rate_factor < 0) ++ return rate_factor; ++ + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN, +@@ -687,7 +743,7 @@ static int imx219_set_ctrl(struct v4l2_c + case V4L2_CID_EXPOSURE: + ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE, + IMX219_REG_VALUE_16BIT, +- ctrl->val / imx219->mode->rate_factor); ++ ctrl->val / rate_factor); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN, +@@ -708,7 +764,7 @@ static int imx219_set_ctrl(struct v4l2_c + ret = imx219_write_reg(imx219, IMX219_REG_VTS, + IMX219_REG_VALUE_16BIT, + (imx219->mode->height + ctrl->val) / +- imx219->mode->rate_factor); ++ rate_factor); + break; + case V4L2_CID_HBLANK: + ret = imx219_write_reg(imx219, IMX219_REG_HTS, +@@ -890,7 +946,7 @@ static int imx219_set_pad_format(struct + struct imx219 *imx219 = to_imx219(sd); + const struct imx219_mode *mode; + struct v4l2_mbus_framefmt *framefmt; +- int exposure_max, exposure_def, hblank, pixel_rate; ++ int exposure_max, exposure_def, hblank, pixel_rate, rate_factor; + unsigned int i; + + if (fmt->pad >= NUM_PADS) +@@ -924,6 +980,9 @@ static int imx219_set_pad_format(struct + + imx219->fmt = fmt->format; + imx219->mode = mode; ++ rate_factor = imx219_get_rate_factor(imx219); ++ if (rate_factor < 0) ++ return rate_factor; + /* Update limits and set FPS to default */ + __v4l2_ctrl_modify_range(imx219->vblank, + IMX219_VBLANK_MIN, +@@ -957,8 +1016,7 @@ static int imx219_set_pad_format(struct + __v4l2_ctrl_s_ctrl(imx219->hblank, hblank); + + /* Scale the pixel rate based on the mode specific factor */ +- pixel_rate = +- IMX219_PIXEL_RATE * imx219->mode->rate_factor; ++ pixel_rate = IMX219_PIXEL_RATE * rate_factor; + __v4l2_ctrl_modify_range(imx219->pixel_rate, pixel_rate, + pixel_rate, 1, pixel_rate); + } +@@ -1001,30 +1059,25 @@ static int imx219_set_framefmt(struct im + + static int imx219_set_binning(struct imx219 *imx219) + { +- if (!imx219->mode->binning) { ++ enum binning_mode binning = BINNING_NONE; ++ int ret = imx219_resolve_binning(imx219, &binning); ++ ++ if (ret < 0) ++ return ret; ++ switch (binning) { ++ case BINNING_NONE: + return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, + IMX219_REG_VALUE_16BIT, + IMX219_BINNING_NONE); +- } +- +- switch (imx219->fmt.code) { +- case MEDIA_BUS_FMT_SRGGB8_1X8: +- case MEDIA_BUS_FMT_SGRBG8_1X8: +- case MEDIA_BUS_FMT_SGBRG8_1X8: +- case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case BINNING_DIGITAL_2x2: + return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, + IMX219_REG_VALUE_16BIT, +- IMX219_BINNING_2X2_ANALOG); +- +- case MEDIA_BUS_FMT_SRGGB10_1X10: +- case MEDIA_BUS_FMT_SGRBG10_1X10: +- case MEDIA_BUS_FMT_SGBRG10_1X10: +- case MEDIA_BUS_FMT_SBGGR10_1X10: ++ IMX219_BINNING_2X2); ++ case BINNING_ANALOG_2x2: + return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, + IMX219_REG_VALUE_16BIT, +- IMX219_BINNING_2X2); ++ IMX219_BINNING_2X2_ANALOG); + } +- + return -EINVAL; + } + +@@ -1342,7 +1395,7 @@ static int imx219_init_controls(struct i + struct v4l2_ctrl_handler *ctrl_hdlr; + unsigned int height = imx219->mode->height; + struct v4l2_fwnode_device_properties props; +- int exposure_max, exposure_def, hblank, pixel_rate; ++ int exposure_max, exposure_def, hblank, pixel_rate, rate_factor; + int i, ret; + + ctrl_hdlr = &imx219->ctrl_handler; +@@ -1353,8 +1406,12 @@ static int imx219_init_controls(struct i + mutex_init(&imx219->mutex); + ctrl_hdlr->lock = &imx219->mutex; + ++ rate_factor = imx219_get_rate_factor(imx219); ++ if (rate_factor < 0) ++ return rate_factor; ++ + /* By default, PIXEL_RATE is read only */ +- pixel_rate = IMX219_PIXEL_RATE * imx219->mode->rate_factor; ++ pixel_rate = IMX219_PIXEL_RATE * rate_factor; + imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_PIXEL_RATE, + pixel_rate, pixel_rate, +@@ -1576,6 +1633,9 @@ static int imx219_probe(struct i2c_clien + goto error_power_off; + usleep_range(100, 110); + ++ /* Initialize default format */ ++ imx219_set_default_format(imx219); ++ + ret = imx219_init_controls(imx219); + if (ret) + goto error_power_off; +@@ -1590,9 +1650,6 @@ static int imx219_probe(struct i2c_clien + imx219->pad[IMAGE_PAD].flags = MEDIA_PAD_FL_SOURCE; + imx219->pad[METADATA_PAD].flags = MEDIA_PAD_FL_SOURCE; + +- /* Initialize default format */ +- imx219_set_default_format(imx219); +- + ret = media_entity_pads_init(&imx219->sd.entity, NUM_PADS, imx219->pad); + if (ret) { + dev_err(dev, "failed to init entity pads: %d\n", ret); diff --git a/target/linux/bcm27xx/patches-6.1/950-0791-serial-sc16is7xx-Read-modem-line-state-at-startup.patch b/target/linux/bcm27xx/patches-6.1/950-0791-serial-sc16is7xx-Read-modem-line-state-at-startup.patch new file mode 100644 index 0000000000..c93ebf3e7e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0791-serial-sc16is7xx-Read-modem-line-state-at-startup.patch @@ -0,0 +1,28 @@ +From 52039b6ffb6e78c2f77319b167dceab9aa51d13f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 13 Jun 2023 16:12:54 +0100 +Subject: [PATCH] serial: sc16is7xx: Read modem line state at startup + +This patch sets the driver modem line state to the actual line state +at driver startup. + +See: https://github.com/raspberrypi/linux/issues/5501 + +Signed-off-by: Earl Schmidt +Signed-off-by: Phil Elwell +--- + drivers/tty/serial/sc16is7xx.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -1221,6 +1221,9 @@ static int sc16is7xx_startup(struct uart + SC16IS7XX_IER_MSI_BIT; + sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); + ++ /* Initialize the Modem Control signals to current status */ ++ one->old_mctrl = sc16is7xx_get_hwmctrl(port); ++ + /* Enable modem status polling */ + spin_lock_irqsave(&port->lock, flags); + sc16is7xx_enable_ms(port); diff --git a/target/linux/bcm27xx/patches-6.1/950-0792-drivers-media-bcm2835_unicam-Improve-frame-sequence-.patch b/target/linux/bcm27xx/patches-6.1/950-0792-drivers-media-bcm2835_unicam-Improve-frame-sequence-.patch new file mode 100644 index 0000000000..6de340c2a9 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0792-drivers-media-bcm2835_unicam-Improve-frame-sequence-.patch @@ -0,0 +1,79 @@ +From 6ef818eed60db70e9caf6bdf74cc1f9943994226 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Fri, 16 Jun 2023 16:24:19 +0100 +Subject: [PATCH] drivers: media: bcm2835_unicam: Improve frame sequence count + handling + +Ensure that the frame sequence counter is incremented only if a previous +frame start interrupt has occurred, or a frame start + frame end has +occurred simultaneously. + +This corresponds the sequence number with the actual number of frames +produced by the sensor, not the number of frame buffers dequeued back +to userland. + +Signed-off-by: Naushir Patuck +--- + .../media/platform/bcm2835/bcm2835-unicam.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c ++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c +@@ -522,6 +522,7 @@ struct unicam_device { + /* subdevice async Notifier */ + struct v4l2_async_notifier notifier; + unsigned int sequence; ++ bool frame_started; + + /* ptr to sub device */ + struct v4l2_subdev *sensor; +@@ -914,6 +915,8 @@ static irqreturn_t unicam_isr(int irq, v + * buffer forever. + */ + if (fe) { ++ bool inc_seq = unicam->frame_started; ++ + /* + * Ensure we have swapped buffers already as we can't + * stop the peripheral. If no buffer is available, use a +@@ -949,11 +952,23 @@ static irqreturn_t unicam_isr(int irq, v + unicam_process_buffer_complete(node, sequence); + node->cur_frm = node->next_frm; + node->next_frm = NULL; ++ inc_seq = true; + } else { + node->cur_frm = node->next_frm; + } + } +- unicam->sequence++; ++ ++ /* ++ * Increment the sequence number conditionally on either a FS ++ * having already occurred, or in the FE + FS condition as ++ * caught in the FE handler above. This ensures the sequence ++ * number corresponds to the frames generated by the sensor, not ++ * the frames dequeued to userland. ++ */ ++ if (inc_seq) { ++ unicam->sequence++; ++ unicam->frame_started = false; ++ } + } + + if (ista & UNICAM_FSI) { +@@ -996,6 +1011,7 @@ static irqreturn_t unicam_isr(int irq, v + } + + unicam_queue_event_sof(unicam); ++ unicam->frame_started = true; + } + + /* +@@ -2600,6 +2616,7 @@ static int unicam_start_streaming(struct + vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + } + ++ dev->frame_started = false; + unicam_start_rx(dev, buffer_addr); + + ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1); diff --git a/target/linux/bcm27xx/patches-6.1/950-0793-dtoverlays-Fix-pitft-28-35-overlays-for-6.1-driver-c.patch b/target/linux/bcm27xx/patches-6.1/950-0793-dtoverlays-Fix-pitft-28-35-overlays-for-6.1-driver-c.patch new file mode 100644 index 0000000000..d8307f9009 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0793-dtoverlays-Fix-pitft-28-35-overlays-for-6.1-driver-c.patch @@ -0,0 +1,41 @@ +From bd8e59b0456870997fb917bcd3b3b696e78d4ac2 Mon Sep 17 00:00:00 2001 +From: 6by9 <6by9@users.noreply.github.com> +Date: Mon, 19 Jun 2023 16:02:36 +0100 +Subject: [PATCH] dtoverlays: Fix pitft[28|35] overlays for 6.1 driver change. + (#5508) + +The overlays configured both irq-gpio and an interrupts/ +interrupt-parent configuration for the stmpe MFD device. + +irq-gpio was reworked in 6.1 and has issues with the configuration +as provided. Removing it and using the interrupts/interrupt-parent +configuration works fine, so do that. + +See: https://forums.raspberrypi.com/viewtopic.php?t=351394 + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts | 1 - + arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 1 - + 2 files changed, 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts +@@ -68,7 +68,6 @@ + reg = <1>; + + spi-max-frequency = <500000>; +- irq-gpio = <&gpio 24 0x2>; /* IRQF_TRIGGER_FALLING */ + interrupts = <24 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; + interrupt-controller; +--- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts +@@ -68,7 +68,6 @@ + reg = <1>; + + spi-max-frequency = <500000>; +- irq-gpio = <&gpio 24 0x2>; /* IRQF_TRIGGER_FALLING */ + interrupts = <24 2>; /* high-to-low edge triggered */ + interrupt-parent = <&gpio>; + interrupt-controller; diff --git a/target/linux/bcm27xx/patches-6.1/950-0795-driver-media-i2c-imx477-Re-enable-temperature-sensor.patch b/target/linux/bcm27xx/patches-6.1/950-0795-driver-media-i2c-imx477-Re-enable-temperature-sensor.patch new file mode 100644 index 0000000000..2255efd988 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0795-driver-media-i2c-imx477-Re-enable-temperature-sensor.patch @@ -0,0 +1,23 @@ +From 713a7ef9d73fca0f7fed122cb854d930b7a6ba5a Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 21 Jun 2023 08:45:02 +0100 +Subject: [PATCH] driver: media: i2c: imx477: Re-enable temperature sensor + +The temperature sensor enable register write got lost at some point. +Re-enable it. + +Signed-off-by: Naushir Patuck +--- + drivers/media/i2c/imx477.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/media/i2c/imx477.c ++++ b/drivers/media/i2c/imx477.c +@@ -167,6 +167,7 @@ struct imx477_mode { + static const struct imx477_reg mode_common_regs[] = { + {0x0136, 0x18}, + {0x0137, 0x00}, ++ {0x0138, 0x01}, + {0xe000, 0x00}, + {0xe07a, 0x01}, + {0x0808, 0x02}, diff --git a/target/linux/bcm27xx/patches-6.1/950-0796-overlays-allo-katana-dac-audio-Reduce-I2C-clock.patch b/target/linux/bcm27xx/patches-6.1/950-0796-overlays-allo-katana-dac-audio-Reduce-I2C-clock.patch new file mode 100644 index 0000000000..43f63a1c63 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0796-overlays-allo-katana-dac-audio-Reduce-I2C-clock.patch @@ -0,0 +1,25 @@ +From d4c3133378b377ee519ea50247339cd61221fc47 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 21 Jun 2023 09:20:36 +0100 +Subject: [PATCH] overlays: allo-katana-dac-audio: Reduce I2C clock + +Higher speeds have been shown to cause data corruption on a Pi 4, +possibly due to clock-stretching. + +See: https://github.com/raspberrypi/linux/issues/5511 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts +@@ -30,6 +30,7 @@ + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; ++ clock-frequency = <50000>; + + allo-katana-codec@30 { + #sound-dai-cells = <0>; diff --git a/target/linux/bcm27xx/patches-6.1/950-0797-overlays-jedec-spi-nor-Add-speed-parameter.patch b/target/linux/bcm27xx/patches-6.1/950-0797-overlays-jedec-spi-nor-Add-speed-parameter.patch new file mode 100644 index 0000000000..66c147837d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0797-overlays-jedec-spi-nor-Add-speed-parameter.patch @@ -0,0 +1,308 @@ +From 76c457e7e2920342637b1955fbaadf2aae282f05 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 23 Jun 2023 09:48:59 +0100 +Subject: [PATCH] overlays: jedec-spi-nor: Add speed parameter + +Add a speed parameter to the jedec-spi-nor overlay to allow much +faster accesses, taking the opportunity to simplify the internals. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 8 +- + .../dts/overlays/jedec-spi-nor-overlay.dts | 245 +++--------------- + 2 files changed, 41 insertions(+), 212 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2557,9 +2557,11 @@ Name: jedec-spi-nor + Info: Adds support for JEDEC-compliant SPI NOR flash devices. (Note: The + "jedec,spi-nor" kernel driver was formerly known as "m25p80".) + Load: dtoverlay=jedec-spi-nor,= +-Params: flash-spi- Enables flash device on SPI, CS#. +- flash-fastr-spi- Enables flash device with fast read capability +- on SPI, CS#. ++Params: spi- Enable flash device on SPI, CS# ++ fastr Add fast read capability to the flash device ++ speed Maximum SPI frequency (Hz) ++ flash-spi- Same as spi- (deprecated) ++ flash-fastr-spi- Same as spi->m>,fastr (deprecated) + + + Name: justboom-both +--- a/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts ++++ b/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts +@@ -3,6 +3,7 @@ + // dtparams: + // flash-spi- - Enables flash device on SPI, CS#. + // flash-fastr-spi- - Enables flash device with fast read capability on SPI, CS#. ++// speed - Set the SPI clock speed in Hz + // + // If devices are present on SPI1 or SPI2, those interfaces must be enabled with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays. + // +@@ -79,50 +80,23 @@ + }; + }; + +- // enable flash on spi0.0 ++ // Enable fast read for device ++ // Use default active low interrupt signalling. + fragment@8 { +- target = <&spi0>; ++ target = <&spi_nor>; + __dormant__ { +- status = "okay"; +- #address-cells = <1>; +- #size-cells = <0>; +- spi_nor_00: spi_nor@0 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "jedec,spi-nor"; +- reg = <0>; +- spi-max-frequency = <500000>; +- }; ++ m25p,fast-read; + }; + }; + +- // enable flash on spi0.1 +- fragment@9 { ++ payload: fragment@100 { + target = <&spi0>; +- __dormant__ { ++ __overlay__ { + status = "okay"; +- #address-cells = <1>; +- #size-cells = <0>; +- spi_nor_01: spi_nor@1 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "jedec,spi-nor"; +- reg = <1>; +- spi-max-frequency = <500000>; +- }; +- }; +- }; ++ #address-cells = <1>; ++ #size-cells = <0>; + +- // enable flash on spi1.0 +- fragment@10 { +- target = <&spi1>; +- __dormant__ { +- status = "okay"; +- #address-cells = <1>; +- #size-cells = <0>; +- spi_nor_10: spi_nor@0 { +- #address-cells = <1>; +- #size-cells = <1>; ++ spi_nor: spi_nor@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <500000>; +@@ -130,180 +104,33 @@ + }; + }; + +- // enable flash on spi1.1 +- fragment@11 { +- target = <&spi1>; +- __dormant__ { +- status = "okay"; +- #address-cells = <1>; +- #size-cells = <0>; +- spi_nor_11: spi_nor@1 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "jedec,spi-nor"; +- reg = <1>; +- spi-max-frequency = <500000>; +- }; +- }; +- }; +- +- // enable flash on spi1.2 +- fragment@12 { +- target = <&spi1>; +- __dormant__ { +- status = "okay"; +- #address-cells = <1>; +- #size-cells = <0>; +- spi_nor_12: spi_nor@2 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "jedec,spi-nor"; +- reg = <2>; +- spi-max-frequency = <500000>; +- }; +- }; +- }; +- +- // enable flash on spi2.0 +- fragment@13 { +- target = <&spi2>; +- __dormant__ { +- status = "okay"; +- #address-cells = <1>; +- #size-cells = <0>; +- spi_nor_20: spi_nor@0 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "jedec,spi-nor"; +- reg = <0>; +- spi-max-frequency = <500000>; +- }; +- }; +- }; +- +- // enable flash on spi2.1 +- fragment@14 { +- target = <&spi2>; +- __dormant__ { +- status = "okay"; +- #address-cells = <1>; +- #size-cells = <0>; +- spi_nor_21: spi_nor@1 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "jedec,spi-nor"; +- reg = <1>; +- spi-max-frequency = <500000>; +- }; +- }; +- }; +- +- // enable flash on spi2.2 +- fragment@15 { +- target = <&spi2>; +- __dormant__ { +- status = "okay"; +- #address-cells = <1>; +- #size-cells = <0>; +- spi_nor_22: spi_nor@2 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "jedec,spi-nor"; +- reg = <2>; +- spi-max-frequency = <500000>; +- }; +- }; +- }; +- +- // Enable fast read for device on spi0.0. +- // Use default active low interrupt signalling. +- fragment@16 { +- target = <&spi_nor_00>; +- __dormant__ { +- m25p,fast-read; +- }; +- }; +- +- // Enable fast read for device on spi0.1. +- // Use default active low interrupt signalling. +- fragment@17 { +- target = <&spi_nor_01>; +- __dormant__ { +- m25p,fast-read; +- }; +- }; +- +- // Enable fast read for device on spi1.0. +- // Use default active low interrupt signalling. +- fragment@18 { +- target = <&spi_nor_10>; +- __dormant__ { +- m25p,fast-read; +- }; +- }; +- +- // Enable fast read for device on spi1.1. +- // Use default active low interrupt signalling. +- fragment@19 { +- target = <&spi_nor_11>; +- __dormant__ { +- m25p,fast-read; +- }; +- }; +- +- // Enable fast read for device on spi1.2. +- // Use default active low interrupt signalling. +- fragment@20 { +- target = <&spi_nor_12>; +- __dormant__ { +- m25p,fast-read; +- }; +- }; +- +- // Enable fast read for device on spi2.0. +- // Use default active low interrupt signalling. +- fragment@21 { +- target = <&spi_nor_20>; +- __dormant__ { +- m25p,fast-read; +- }; +- }; +- +- // Enable fast read for device on spi2.1. +- // Use default active low interrupt signalling. +- fragment@22 { +- target = <&spi_nor_21>; +- __dormant__ { +- m25p,fast-read; +- }; +- }; +- +- // Enable fast read for device on spi2.2. +- // Use default active low interrupt signalling. +- fragment@23 { +- target = <&spi_nor_22>; +- __dormant__ { +- m25p,fast-read; +- }; +- }; +- + __overrides__ { +- flash-spi0-0 = <0>,"+0+8"; +- flash-spi0-1 = <0>,"+1+9"; +- flash-spi1-0 = <0>,"+2+10"; +- flash-spi1-1 = <0>,"+3+11"; +- flash-spi1-2 = <0>,"+4+12"; +- flash-spi2-0 = <0>,"+5+13"; +- flash-spi2-1 = <0>,"+6+14"; +- flash-spi2-2 = <0>,"+7+15"; +- flash-fastr-spi0-0 = <0>,"+0+8+16"; +- flash-fastr-spi0-1 = <0>,"+1+9+17"; +- flash-fastr-spi1-0 = <0>,"+2+10+18"; +- flash-fastr-spi1-1 = <0>,"+3+11+19"; +- flash-fastr-spi1-2 = <0>,"+4+12+20"; +- flash-fastr-spi2-0 = <0>,"+5+13+21"; +- flash-fastr-spi2-1 = <0>,"+6+14+22"; +- flash-fastr-spi2-2 = <0>,"+7+15+23"; ++ spi0-0 = <0>,"+0", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=0"; ++ spi0-1 = <0>,"+1", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=1"; ++ spi1-0 = <0>,"+2", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=0"; ++ spi1-1 = <0>,"+3", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=1"; ++ spi1-2 = <0>,"+4", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=2"; ++ spi2-0 = <0>,"+5", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=0"; ++ spi2-1 = <0>,"+6", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=1"; ++ spi2-2 = <0>,"+7", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=2"; ++ flash-spi0-0 = <0>,"+0", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=0"; ++ flash-spi0-1 = <0>,"+1", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=1"; ++ flash-spi1-0 = <0>,"+2", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=0"; ++ flash-spi1-1 = <0>,"+3", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=1"; ++ flash-spi1-2 = <0>,"+4", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=2"; ++ flash-spi2-0 = <0>,"+5", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=0"; ++ flash-spi2-1 = <0>,"+6", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=1"; ++ flash-spi2-2 = <0>,"+7", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=2"; ++ flash-fastr-spi0-0 = <0>,"+0+8", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=0"; ++ flash-fastr-spi0-1 = <0>,"+1+8", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=1"; ++ flash-fastr-spi1-0 = <0>,"+2+8", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=0"; ++ flash-fastr-spi1-1 = <0>,"+3+8", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=1"; ++ flash-fastr-spi1-2 = <0>,"+4+8", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=2"; ++ flash-fastr-spi2-0 = <0>,"+5+8", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=0"; ++ flash-fastr-spi2-1 = <0>,"+6+8", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=1"; ++ flash-fastr-spi2-2 = <0>,"+7+8", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=2"; ++ fastr = <0>,"+8"; ++ speed = <&spi_nor>, "spi-max-frequency:0"; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-0798-ALSA-pcm-fix-ELD-constraints-for-E-AC3-DTS-HD-and-ML.patch b/target/linux/bcm27xx/patches-6.1/950-0798-ALSA-pcm-fix-ELD-constraints-for-E-AC3-DTS-HD-and-ML.patch new file mode 100644 index 0000000000..a35e7f4d1b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0798-ALSA-pcm-fix-ELD-constraints-for-E-AC3-DTS-HD-and-ML.patch @@ -0,0 +1,137 @@ +From e866f9fc7c6dd6af1e74ce6fa50db9ba21acae5e Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sat, 24 Jun 2023 18:52:16 +0200 +Subject: [PATCH] ALSA: pcm: fix ELD constraints for (E)AC3, DTS(-HD) and MLP + formats + +commit 04b49b90caeed0b5544ff616d654900d27d403b6 upstream. + +The SADs of compressed formats contain the channel and sample rate +info of the audio data inside the compressed stream, but when +building constraints we must use the rates and channels used to +transport the compressed streams. + +eg 48kHz 6ch EAC3 needs to be transmitted as a 2ch 192kHz stream. + +This patch fixes the constraints for the common AC3 and DTS formats, +the constraints for the less common MPEG, DSD etc formats are copied +directly from the info in the SADs as before as I don't have the specs +and equipment to test those. + +Signed-off-by: Matthias Reichl +Link: https://lore.kernel.org/r/20230624165216.5719-1-hias@horus.com +Signed-off-by: Takashi Iwai +--- + sound/core/pcm_drm_eld.c | 73 ++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 70 insertions(+), 3 deletions(-) + +--- a/sound/core/pcm_drm_eld.c ++++ b/sound/core/pcm_drm_eld.c +@@ -2,11 +2,25 @@ + /* + * PCM DRM helpers + */ ++#include + #include ++#include + #include + #include + #include + ++#define SAD0_CHANNELS_MASK GENMASK(2, 0) /* max number of channels - 1 */ ++#define SAD0_FORMAT_MASK GENMASK(6, 3) /* audio format */ ++ ++#define SAD1_RATE_MASK GENMASK(6, 0) /* bitfield of supported rates */ ++#define SAD1_RATE_32000_MASK BIT(0) ++#define SAD1_RATE_44100_MASK BIT(1) ++#define SAD1_RATE_48000_MASK BIT(2) ++#define SAD1_RATE_88200_MASK BIT(3) ++#define SAD1_RATE_96000_MASK BIT(4) ++#define SAD1_RATE_176400_MASK BIT(5) ++#define SAD1_RATE_192000_MASK BIT(6) ++ + static const unsigned int eld_rates[] = { + 32000, + 44100, +@@ -17,9 +31,62 @@ static const unsigned int eld_rates[] = + 192000, + }; + ++static unsigned int map_rate_families(const u8 *sad, ++ unsigned int mask_32000, ++ unsigned int mask_44100, ++ unsigned int mask_48000) ++{ ++ unsigned int rate_mask = 0; ++ ++ if (sad[1] & SAD1_RATE_32000_MASK) ++ rate_mask |= mask_32000; ++ if (sad[1] & (SAD1_RATE_44100_MASK | SAD1_RATE_88200_MASK | SAD1_RATE_176400_MASK)) ++ rate_mask |= mask_44100; ++ if (sad[1] & (SAD1_RATE_48000_MASK | SAD1_RATE_96000_MASK | SAD1_RATE_192000_MASK)) ++ rate_mask |= mask_48000; ++ return rate_mask; ++} ++ ++static unsigned int sad_rate_mask(const u8 *sad) ++{ ++ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) { ++ case HDMI_AUDIO_CODING_TYPE_PCM: ++ return sad[1] & SAD1_RATE_MASK; ++ case HDMI_AUDIO_CODING_TYPE_AC3: ++ case HDMI_AUDIO_CODING_TYPE_DTS: ++ return map_rate_families(sad, ++ SAD1_RATE_32000_MASK, ++ SAD1_RATE_44100_MASK, ++ SAD1_RATE_48000_MASK); ++ case HDMI_AUDIO_CODING_TYPE_EAC3: ++ case HDMI_AUDIO_CODING_TYPE_DTS_HD: ++ case HDMI_AUDIO_CODING_TYPE_MLP: ++ return map_rate_families(sad, ++ 0, ++ SAD1_RATE_176400_MASK, ++ SAD1_RATE_192000_MASK); ++ default: ++ /* TODO adjust for other compressed formats as well */ ++ return sad[1] & SAD1_RATE_MASK; ++ } ++} ++ + static unsigned int sad_max_channels(const u8 *sad) + { +- return 1 + (sad[0] & 7); ++ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) { ++ case HDMI_AUDIO_CODING_TYPE_PCM: ++ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]); ++ case HDMI_AUDIO_CODING_TYPE_AC3: ++ case HDMI_AUDIO_CODING_TYPE_DTS: ++ case HDMI_AUDIO_CODING_TYPE_EAC3: ++ return 2; ++ case HDMI_AUDIO_CODING_TYPE_DTS_HD: ++ case HDMI_AUDIO_CODING_TYPE_MLP: ++ return 8; ++ default: ++ /* TODO adjust for other compressed formats as well */ ++ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]); ++ } + } + + static int eld_limit_rates(struct snd_pcm_hw_params *params, +@@ -42,7 +109,7 @@ static int eld_limit_rates(struct snd_pc + * requested number of channels. + */ + if (c->min <= max_channels) +- rate_mask |= sad[1]; ++ rate_mask |= sad_rate_mask(sad); + } + } + +@@ -70,7 +137,7 @@ static int eld_limit_channels(struct snd + rate_mask |= BIT(i); + + for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) +- if (rate_mask & sad[1]) ++ if (rate_mask & sad_rate_mask(sad)) + t.max = max(t.max, sad_max_channels(sad)); + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-0799-ASoC-hdmi-codec-fix-channel-info-for-compressed-form.patch b/target/linux/bcm27xx/patches-6.1/950-0799-ASoC-hdmi-codec-fix-channel-info-for-compressed-form.patch new file mode 100644 index 0000000000..31a351a4e8 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0799-ASoC-hdmi-codec-fix-channel-info-for-compressed-form.patch @@ -0,0 +1,86 @@ +From 3f388718331b5ce2acd34730448db001759868aa Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sat, 24 Jun 2023 18:52:32 +0200 +Subject: [PATCH] ASoC: hdmi-codec: fix channel info for compressed formats + +commit 4e0871333661d2ec0ed3dc00a945c2160eccae77 upstream. + +According to CTA 861 the channel/speaker allocation info in the +audio infoframe only applies to uncompressed (PCM) audio streams. + +The channel count info should indicate the number of channels +in the transmitted audio, which usually won't match the number of +channels used to transmit the compressed bitstream. + +Some devices (eg some Sony TVs) will refuse to decode compressed +audio if these values are not set correctly. + +To fix this we can simply set the channel count to 0 (which means +"refer to stream header") and set the channel/speaker allocation to 0 +as well (which would mean stereo FL/FR for PCM, a safe value all sinks +will support) when transmitting compressed audio. + +Signed-off-by: Matthias Reichl +Link: https://lore.kernel.org/r/20230624165232.5751-1-hias@horus.com +Signed-off-by: Takashi Iwai +--- + sound/soc/codecs/hdmi-codec.c | 36 +++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -484,31 +484,43 @@ static int hdmi_codec_fill_codec_params( + struct hdmi_codec_params *hp) + { + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); +- int idx; ++ int idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; ++ u8 ca_id = 0; ++ bool pcm_audio = !(hcp->iec_status[0] & IEC958_AES0_NONAUDIO); ++ ++ if (pcm_audio) { ++ /* Select a channel allocation that matches with ELD and pcm channels */ ++ idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels); ++ ++ if (idx < 0) { ++ dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", ++ idx); ++ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; ++ return idx; ++ } + +- /* Select a channel allocation that matches with ELD and pcm channels */ +- idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels); +- if (idx < 0) { +- dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", +- idx); +- hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; +- return idx; ++ ca_id = hdmi_codec_channel_alloc[idx].ca_id; + } + + memset(hp, 0, sizeof(*hp)); + + hdmi_audio_infoframe_init(&hp->cea); +- hp->cea.channels = channels; ++ ++ if (pcm_audio) ++ hp->cea.channels = channels; ++ else ++ hp->cea.channels = 0; ++ + hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; + hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; + hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; +- hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; ++ hp->cea.channel_allocation = ca_id; + + hp->sample_width = sample_width; + hp->sample_rate = sample_rate; + hp->channels = channels; + +- hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; ++ hcp->chmap_idx = idx; + + return 0; + } diff --git a/target/linux/bcm27xx/patches-6.1/950-0800-media-i2c-arducam_64mp-Modify-the-line-length-of-128.patch b/target/linux/bcm27xx/patches-6.1/950-0800-media-i2c-arducam_64mp-Modify-the-line-length-of-128.patch new file mode 100644 index 0000000000..a423b8061b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0800-media-i2c-arducam_64mp-Modify-the-line-length-of-128.patch @@ -0,0 +1,44 @@ +From 9c5a7f04cab6b020389d7c5af155b1ee7f46537d Mon Sep 17 00:00:00 2001 +From: Lee Jackson +Date: Thu, 4 May 2023 11:14:04 +0800 +Subject: [PATCH] media: i2c: arducam_64mp: Modify the line length of 1280x720 + resolution + +Arducam 64MP has specific requirements for the line length, and if these +conditions are not met, the camera will not function properly. Under the +previous configuration, once a stream off operation is performed, the +camera will not output any data, even if a stream on operation is +performed. This prevents us from switching from 1280x720 to another +resolution. + +Signed-off-by: Lee Jackson +--- + drivers/media/i2c/arducam_64mp.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/media/i2c/arducam_64mp.c ++++ b/drivers/media/i2c/arducam_64mp.c +@@ -1063,10 +1063,10 @@ static const struct arducam_64mp_reg mod + + /* 720p 120fps mode */ + static const struct arducam_64mp_reg mode_1280x720_regs[] = { +- {0x0342, 0x1d}, +- {0x0343, 0xc4}, +- {0x0340, 0x03}, +- {0x0341, 0xd8}, ++ {0x0342, 0x1b}, ++ {0x0343, 0x08}, ++ {0x0340, 0x04}, ++ {0x0341, 0x3b}, + {0x0344, 0x08}, + {0x0345, 0x10}, + {0x0346, 0x07}, +@@ -1209,7 +1209,7 @@ static const struct arducam_64mp_mode su + }, { + .width = 1280, + .height = 720, +- .line_length_pix = 0x1dc4, ++ .line_length_pix = 0x1b08, + .crop = { + .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 2064, + .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 2032, diff --git a/target/linux/bcm27xx/patches-6.1/950-0801-media-i2c-arducam_64mp-Add-8000x6000-resolution.patch b/target/linux/bcm27xx/patches-6.1/950-0801-media-i2c-arducam_64mp-Add-8000x6000-resolution.patch new file mode 100644 index 0000000000..475ae634ad --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0801-media-i2c-arducam_64mp-Add-8000x6000-resolution.patch @@ -0,0 +1,105 @@ +From 7b3d0124c5cf462d5be0b0d4e558002b74750911 Mon Sep 17 00:00:00 2001 +From: Lee Jackson +Date: Fri, 5 May 2023 14:36:15 +0800 +Subject: [PATCH] media: i2c: arducam_64mp: Add 8000x6000 resolution + +Added 8000x6000 10-bit (cropped) @ 3fps mode for Arducam 64MP + +Signed-off-by: Lee Jackson +--- + drivers/media/i2c/arducam_64mp.c | 77 ++++++++++++++++++++++++++++++++ + 1 file changed, 77 insertions(+) + +--- a/drivers/media/i2c/arducam_64mp.c ++++ b/drivers/media/i2c/arducam_64mp.c +@@ -849,6 +849,65 @@ static const struct arducam_64mp_reg mod + {0x020f, 0x00}, + }; + ++/* 48 mpix 3.0fps */ ++static const struct arducam_64mp_reg mode_8000x6000_regs[] = { ++ {0x0342, 0xb6}, ++ {0x0343, 0xb2}, ++ {0x0340, 0x19}, ++ {0x0341, 0x0e}, ++ {0x0344, 0x02}, ++ {0x0345, 0x70}, ++ {0x0346, 0x01}, ++ {0x0347, 0xd8}, ++ {0x0348, 0x21}, ++ {0x0349, 0xaf}, ++ {0x034a, 0x19}, ++ {0x034b, 0x47}, ++ {0x0900, 0x00}, ++ {0x0901, 0x11}, ++ {0x0902, 0x0a}, ++ {0x30d8, 0x00}, ++ {0x3200, 0x01}, ++ {0x3201, 0x01}, ++ {0x0408, 0x00}, ++ {0x0409, 0x00}, ++ {0x040a, 0x00}, ++ {0x040b, 0x00}, ++ {0x040c, 0x1f}, ++ {0x040d, 0x40}, ++ {0x040e, 0x17}, ++ {0x040f, 0x70}, ++ {0x034c, 0x1f}, ++ {0x034d, 0x40}, ++ {0x034e, 0x17}, ++ {0x034f, 0x70}, ++ {0x30d9, 0x01}, ++ {0x32d5, 0x01}, ++ {0x32d6, 0x00}, ++ {0x401e, 0x00}, ++ {0x40b8, 0x04}, ++ {0x40b9, 0x20}, ++ {0x40bc, 0x02}, ++ {0x40bd, 0x58}, ++ {0x40be, 0x02}, ++ {0x40bf, 0x58}, ++ {0x41a4, 0x00}, ++ {0x5a09, 0x01}, ++ {0x5a17, 0x01}, ++ {0x5a25, 0x01}, ++ {0x5a33, 0x01}, ++ {0x98d7, 0x14}, ++ {0x98d8, 0x14}, ++ {0x98d9, 0x00}, ++ {0x99c4, 0x00}, ++ {0x0202, 0x03}, ++ {0x0203, 0xe8}, ++ {0x0204, 0x00}, ++ {0x0205, 0x00}, ++ {0x020e, 0x01}, ++ {0x020f, 0x00}, ++}; ++ + /* 16 mpix 10fps */ + static const struct arducam_64mp_reg mode_4624x3472_regs[] = { + {0x0342, 0x63}, +@@ -1135,6 +1194,24 @@ static const struct arducam_64mp_mode su + .regs = mode_9152x6944_regs, + } + }, { ++ .width = 8000, ++ .height = 6000, ++ .line_length_pix = 0xb6b2, ++ .crop = { ++ .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 624, ++ .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 472, ++ .width = 9248, ++ .height = 6944, ++ }, ++ .timeperframe_default = { ++ .numerator = 100, ++ .denominator = 300 ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_8000x6000_regs), ++ .regs = mode_8000x6000_regs, ++ } ++ }, { + .width = 4624, + .height = 3472, + .line_length_pix = 0x6397, diff --git a/target/linux/bcm27xx/patches-6.1/950-0802-media-i2c-arducam_64mp-Add-PDAF-support.patch b/target/linux/bcm27xx/patches-6.1/950-0802-media-i2c-arducam_64mp-Add-PDAF-support.patch new file mode 100644 index 0000000000..8f96b33baa --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0802-media-i2c-arducam_64mp-Add-PDAF-support.patch @@ -0,0 +1,163 @@ +From b9d2d1862aa5b798cecb87a95d970ad34a4aebc0 Mon Sep 17 00:00:00 2001 +From: Lee Jackson +Date: Tue, 30 May 2023 15:50:05 +0800 +Subject: [PATCH] media: i2c: arducam_64mp: Add PDAF support + +Enable PDAF output for all modes, and also need to modify Embedded Line +Width to 11560 * 3 (two lines of Embedded Data + one line of PDAF). + +Signed-off-by: Lee Jackson +--- + drivers/media/i2c/arducam_64mp.c | 64 ++++++++++++++++++++++++++++++-- + 1 file changed, 61 insertions(+), 3 deletions(-) + +--- a/drivers/media/i2c/arducam_64mp.c ++++ b/drivers/media/i2c/arducam_64mp.c +@@ -95,7 +95,7 @@ + #define ARDUCAM_64MP_TEST_PATTERN_GB_DEFAULT 0 + + /* Embedded metadata stream structure */ +-#define ARDUCAM_64MP_EMBEDDED_LINE_WIDTH 16384 ++#define ARDUCAM_64MP_EMBEDDED_LINE_WIDTH (11560 * 3) + #define ARDUCAM_64MP_NUM_EMBEDDED_LINES 1 + + enum pad_types { +@@ -144,6 +144,7 @@ struct arducam_64mp_mode { + }; + + static const struct arducam_64mp_reg mode_common_regs[] = { ++ {0x0100, 0x00}, + {0x0136, 0x18}, + {0x0137, 0x00}, + {0x33F0, 0x01}, +@@ -788,6 +789,7 @@ static const struct arducam_64mp_reg mod + {0x3092, 0x01}, + {0x3093, 0x00}, + {0x0350, 0x00}, ++ {0x3419, 0x00}, + }; + + /* 64 mpix 2.7fps */ +@@ -847,6 +849,14 @@ static const struct arducam_64mp_reg mod + {0x0205, 0x00}, + {0x020e, 0x01}, + {0x020f, 0x00}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x02}, ++ {0x341f, 0x3c}, ++ {0x3420, 0x02}, ++ {0x3421, 0x42}, + }; + + /* 48 mpix 3.0fps */ +@@ -906,6 +916,14 @@ static const struct arducam_64mp_reg mod + {0x0205, 0x00}, + {0x020e, 0x01}, + {0x020f, 0x00}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x01}, ++ {0x341f, 0xf4}, ++ {0x3420, 0x01}, ++ {0x3421, 0xf4}, + }; + + /* 16 mpix 10fps */ +@@ -959,6 +977,14 @@ static const struct arducam_64mp_reg mod + {0x98d8, 0x8c}, + {0x98d9, 0x0a}, + {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x01}, ++ {0x341f, 0x21}, ++ {0x3420, 0x01}, ++ {0x3421, 0x21}, + }; + + /* 4k 20fps mode */ +@@ -1012,6 +1038,14 @@ static const struct arducam_64mp_reg mod + {0x98d8, 0x8c}, + {0x98d9, 0x0a}, + {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0xf0}, ++ {0x3420, 0x00}, ++ {0x3421, 0xb4}, + }; + + /* 4x4 binned 30fps mode */ +@@ -1031,7 +1065,7 @@ static const struct arducam_64mp_reg mod + {0x0900, 0x01}, + {0x0901, 0x44}, + {0x0902, 0x08}, +- {0x30d8, 0x00}, ++ {0x30d8, 0x04}, + {0x3200, 0x43}, + {0x3201, 0x43}, + {0x0408, 0x00}, +@@ -1046,7 +1080,7 @@ static const struct arducam_64mp_reg mod + {0x034d, 0x08}, + {0x034e, 0x06}, + {0x034f, 0xc8}, +- {0x30d9, 0x01}, ++ {0x30d9, 0x00}, + {0x32d5, 0x00}, + {0x32d6, 0x00}, + {0x401e, 0x00}, +@@ -1065,6 +1099,14 @@ static const struct arducam_64mp_reg mod + {0x98d8, 0x8c}, + {0x98d9, 0x0a}, + {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0x90}, ++ {0x3420, 0x00}, ++ {0x3421, 0x90}, + }; + + /* 1080p 60fps mode */ +@@ -1118,6 +1160,14 @@ static const struct arducam_64mp_reg mod + {0x98d8, 0x8c}, + {0x98d9, 0x0a}, + {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0x78}, ++ {0x3420, 0x00}, ++ {0x3421, 0x5a}, + }; + + /* 720p 120fps mode */ +@@ -1171,6 +1221,14 @@ static const struct arducam_64mp_reg mod + {0x98d8, 0x8c}, + {0x98d9, 0x0a}, + {0x99c4, 0x16}, ++ {0x341a, 0x00}, ++ {0x341b, 0x00}, ++ {0x341c, 0x00}, ++ {0x341d, 0x00}, ++ {0x341e, 0x00}, ++ {0x341f, 0x50}, ++ {0x3420, 0x00}, ++ {0x3421, 0x3c}, + }; + + /* Mode configs */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0803-overlays-audremap-Document-CM4-40-41-restriction.patch b/target/linux/bcm27xx/patches-6.1/950-0803-overlays-audremap-Document-CM4-40-41-restriction.patch new file mode 100644 index 0000000000..bf1646322b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0803-overlays-audremap-Document-CM4-40-41-restriction.patch @@ -0,0 +1,24 @@ +From 6f4106f7a7fdcbc03290008713915b4122988c90 Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Wed, 5 Jul 2023 15:43:30 +0100 +Subject: [PATCH] overlays: audremap: Document CM4 40&41 restriction + +Update audremap information to state pins 40,41 are not available on the CM4. + +Signed-off-by: James Hughes (james.hughes@raspberrypi.com) +--- + arch/arm/boot/dts/overlays/README | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -703,7 +703,8 @@ Params: swap_lr Reverse + nothing on BCM2711 (default off) + pins_12_13 Select GPIOs 12 & 13 (default) + pins_18_19 Select GPIOs 18 & 19 +- pins_40_41 Select GPIOs 40 & 41 ++ pins_40_41 Select GPIOs 40 & 41 (not available on CM4, used ++ for other purposes) + pins_40_45 Select GPIOs 40 & 45 (don't use on BCM2711 - the + pins are on different controllers) + diff --git a/target/linux/bcm27xx/patches-6.1/950-0804-fixup-Allow-mac-address-to-be-set-in-smsc95xx.patch b/target/linux/bcm27xx/patches-6.1/950-0804-fixup-Allow-mac-address-to-be-set-in-smsc95xx.patch new file mode 100644 index 0000000000..9265e931fa --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0804-fixup-Allow-mac-address-to-be-set-in-smsc95xx.patch @@ -0,0 +1,120 @@ +From 1d15e6a34222cc8d8eb1050e7a3e276b0348be41 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 3 Jul 2023 11:04:56 +0100 +Subject: [PATCH] fixup! Allow mac address to be set in smsc95xx + +usbnet: smsc95xx: Fix indentation of smsc95xx_is_macaddr_param() + +smsc95xx_is_macaddr_param() is incorrectly indented, it uses 7 spaces +instead of tabs. Fix it. + +Fixes: aac7b105788e ("Allow mac address to be set in smsc95xx") +Signed-off-by: Philipp Rosenberger +[lukas: fix netif_dbg() indentation as well, wordsmith commit message] +Signed-off-by: Lukas Wunner + +usbnet: smsc95xx: Simplify MAC address parsing + +Parsing the MAC address provided on the kernel command line can be +simplified quite a bit by taking advantage of the kernel's built-in +mac_pton() helper. + +Likewise emitting the MAC address can be simplified with the %pM +format string conversion. + +Signed-off-by: Lukas Wunner + +usbnet: smsc95xx: Fix style issues in smsc95xx_is_macaddr_param() + +It is bad practice to have a function named ..._is_...() which has side +effects. So drop the 'is' from the name. + +Per kernel convention return 0 on success and a negative errno on +failure. + +Validate the MAC address retrieved from the command line. + +Signed-off-by: Philipp Rosenberger +[lukas: leave 2nd function parameter unchanged, wordsmith commit message] +Signed-off-by: Lukas Wunner +--- + drivers/net/usb/smsc95xx.c | 61 +++++++++++--------------------------- + 1 file changed, 17 insertions(+), 44 deletions(-) + +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -814,49 +814,18 @@ static int smsc95xx_ioctl(struct net_dev + } + + /* Check the macaddr module parameter for a MAC address */ +-static int smsc95xx_is_macaddr_param(struct usbnet *dev, struct net_device *nd) ++static int smsc95xx_macaddr_param(struct usbnet *dev, struct net_device *nd) + { +- int i, j, got_num, num; +- u8 mtbl[ETH_ALEN]; ++ u8 mtbl[ETH_ALEN]; + +- if (macaddr[0] == ':') +- return 0; +- +- i = 0; +- j = 0; +- num = 0; +- got_num = 0; +- while (j < ETH_ALEN) { +- if (macaddr[i] && macaddr[i] != ':') { +- got_num++; +- if ('0' <= macaddr[i] && macaddr[i] <= '9') +- num = num * 16 + macaddr[i] - '0'; +- else if ('A' <= macaddr[i] && macaddr[i] <= 'F') +- num = num * 16 + 10 + macaddr[i] - 'A'; +- else if ('a' <= macaddr[i] && macaddr[i] <= 'f') +- num = num * 16 + 10 + macaddr[i] - 'a'; +- else +- break; +- i++; +- } else if (got_num == 2) { +- mtbl[j++] = (u8) num; +- num = 0; +- got_num = 0; +- i++; +- } else { +- break; +- } +- } +- +- if (j == ETH_ALEN) { +- netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: " +- "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2], +- mtbl[3], mtbl[4], mtbl[5]); +- dev_addr_mod(nd, 0, mtbl, ETH_ALEN); +- return 1; +- } else { +- return 0; +- } ++ if (mac_pton(macaddr, mtbl)) { ++ netif_dbg(dev, ifup, dev->net, ++ "Overriding MAC address with: %pM\n", mtbl); ++ dev_addr_mod(nd, 0, mtbl, ETH_ALEN); ++ return 0; ++ } else { ++ return -EINVAL; ++ } + } + + static void smsc95xx_init_mac_address(struct usbnet *dev) +@@ -883,8 +852,12 @@ static void smsc95xx_init_mac_address(st + } + + /* Check module parameters */ +- if (smsc95xx_is_macaddr_param(dev, dev->net)) +- return; ++ if (smsc95xx_macaddr_param(dev, dev->net) == 0) { ++ if (is_valid_ether_addr(dev->net->dev_addr)) { ++ netif_dbg(dev, ifup, dev->net, "MAC address read from module parameter\n"); ++ return; ++ } ++ } + + /* no useful static MAC address found. generate a random one */ + eth_hw_addr_random(dev->net); diff --git a/target/linux/bcm27xx/patches-6.1/950-0809-cfg80211-ship-debian-certificates-as-hex-files.patch b/target/linux/bcm27xx/patches-6.1/950-0809-cfg80211-ship-debian-certificates-as-hex-files.patch new file mode 100644 index 0000000000..593c95e2a2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0809-cfg80211-ship-debian-certificates-as-hex-files.patch @@ -0,0 +1,1455 @@ +From a2d2745c311baa588fb0fffbe38076294f06b7c0 Mon Sep 17 00:00:00 2001 +From: Nicolai Buchwitz +Date: Wed, 12 Jul 2023 11:30:42 +0200 +Subject: [PATCH] cfg80211: ship debian certificates as hex files + +Loading the regulatory database from the debian files fails with + +"loaded regulatory.db is malformed or signature is missing/invalid" + +due to missing certificates. Add these debian-specific certificates +from upstream to fix this error. See #5536 for details. + +The certificates have been imported as following: + +patch -p1 <<<$( +curl https://salsa.debian.org/kernel-team/linux/-/raw/\ +master/debian/patches/debian/\ +wireless-add-debian-wireless-regdb-certificates.patch +) + +Signed-off-by: Nicolai Buchwitz +--- + net/wireless/certs/debian.hex | 1426 +++++++++++++++++++++++++++++++++ + 1 file changed, 1426 insertions(+) + create mode 100644 net/wireless/certs/debian.hex + +--- /dev/null ++++ b/net/wireless/certs/debian.hex +@@ -0,0 +1,1426 @@ ++0x30, ++0x82, ++0x02, ++0xbd, ++0x30, ++0x82, ++0x01, ++0xa5, ++0x02, ++0x14, ++0x57, ++0x7e, ++0x02, ++0x1c, ++0xb9, ++0x80, ++0xe0, ++0xe8, ++0x20, ++0x82, ++0x1b, ++0xa7, ++0xb5, ++0x4b, ++0x49, ++0x61, ++0xb8, ++0xb4, ++0xfa, ++0xdf, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x0b, ++0x05, ++0x00, ++0x30, ++0x1a, ++0x31, ++0x18, ++0x30, ++0x16, ++0x06, ++0x03, ++0x55, ++0x04, ++0x03, ++0x0c, ++0x0f, ++0x62, ++0x65, ++0x6e, ++0x68, ++0x40, ++0x64, ++0x65, ++0x62, ++0x69, ++0x61, ++0x6e, ++0x2e, ++0x6f, ++0x72, ++0x67, ++0x30, ++0x20, ++0x17, ++0x0d, ++0x32, ++0x30, ++0x30, ++0x31, ++0x33, ++0x30, ++0x31, ++0x33, ++0x32, ++0x36, ++0x31, ++0x33, ++0x5a, ++0x18, ++0x0f, ++0x32, ++0x31, ++0x32, ++0x30, ++0x30, ++0x31, ++0x30, ++0x36, ++0x31, ++0x33, ++0x32, ++0x36, ++0x31, ++0x33, ++0x5a, ++0x30, ++0x1a, ++0x31, ++0x18, ++0x30, ++0x16, ++0x06, ++0x03, ++0x55, ++0x04, ++0x03, ++0x0c, ++0x0f, ++0x62, ++0x65, ++0x6e, ++0x68, ++0x40, ++0x64, ++0x65, ++0x62, ++0x69, ++0x61, ++0x6e, ++0x2e, ++0x6f, ++0x72, ++0x67, ++0x30, ++0x82, ++0x01, ++0x22, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x01, ++0x05, ++0x00, ++0x03, ++0x82, ++0x01, ++0x0f, ++0x00, ++0x30, ++0x82, ++0x01, ++0x0a, ++0x02, ++0x82, ++0x01, ++0x01, ++0x00, ++0x9d, ++0xe1, ++0x77, ++0xa0, ++0x24, ++0xa0, ++0xd5, ++0x79, ++0x65, ++0x3a, ++0x07, ++0x90, ++0xc9, ++0xf6, ++0xa5, ++0xa6, ++0x1f, ++0x84, ++0x1c, ++0x23, ++0x07, ++0x4b, ++0x4f, ++0xa5, ++0x03, ++0xc6, ++0x0f, ++0xf7, ++0x54, ++0xd5, ++0x8b, ++0x7e, ++0x79, ++0x81, ++0x00, ++0xd2, ++0xe9, ++0x3d, ++0xf4, ++0x97, ++0xfe, ++0x84, ++0xcd, ++0x55, ++0xbd, ++0xc9, ++0x8f, ++0x21, ++0x57, ++0x88, ++0x06, ++0x39, ++0x90, ++0x66, ++0x41, ++0x26, ++0x79, ++0x2c, ++0xca, ++0x3f, ++0x95, ++0x87, ++0x01, ++0x11, ++0x2f, ++0x2f, ++0xb0, ++0xe1, ++0x0b, ++0x43, ++0xfc, ++0x5f, ++0x2f, ++0x4f, ++0x67, ++0x04, ++0xdb, ++0x4d, ++0xb7, ++0x72, ++0x4d, ++0xd1, ++0xc5, ++0x76, ++0x73, ++0x4d, ++0x91, ++0x69, ++0xb0, ++0x71, ++0x17, ++0x36, ++0xea, ++0xab, ++0x0a, ++0x3a, ++0xcd, ++0x95, ++0x9b, ++0x76, ++0x1b, ++0x8e, ++0x21, ++0x17, ++0x8f, ++0xc5, ++0x02, ++0xbf, ++0x24, ++0xc7, ++0xc0, ++0x40, ++0xb1, ++0x3b, ++0xc4, ++0x80, ++0x7c, ++0x71, ++0xa5, ++0x51, ++0xdc, ++0xf7, ++0x3a, ++0x58, ++0x7f, ++0xb1, ++0x07, ++0x81, ++0x8a, ++0x10, ++0xd1, ++0xf6, ++0x93, ++0x17, ++0x71, ++0xe0, ++0xfa, ++0x51, ++0x79, ++0x15, ++0xd4, ++0xd7, ++0x8f, ++0xad, ++0xbd, ++0x6f, ++0x38, ++0xe1, ++0x26, ++0x7d, ++0xbc, ++0xf0, ++0x3e, ++0x80, ++0x89, ++0xb4, ++0xec, ++0x8e, ++0x69, ++0x90, ++0xdb, ++0x97, ++0x8a, ++0xf0, ++0x23, ++0x23, ++0x83, ++0x82, ++0x3b, ++0x6a, ++0xb1, ++0xac, ++0xeb, ++0xe7, ++0x99, ++0x74, ++0x2a, ++0x35, ++0x8e, ++0xa9, ++0x64, ++0xfd, ++0x46, ++0x9e, ++0xe8, ++0xe5, ++0x48, ++0x61, ++0x31, ++0x6e, ++0xe6, ++0xfc, ++0x19, ++0x18, ++0x54, ++0xc3, ++0x1b, ++0x4f, ++0xd6, ++0x00, ++0x44, ++0x87, ++0x1c, ++0x37, ++0x45, ++0xea, ++0xf5, ++0xc9, ++0xcb, ++0x0f, ++0x0c, ++0x55, ++0xec, ++0xcf, ++0x6a, ++0xc2, ++0x45, ++0x26, ++0x23, ++0xa2, ++0x31, ++0x52, ++0x4d, ++0xee, ++0x21, ++0x7d, ++0xfd, ++0x58, ++0x72, ++0xc2, ++0x28, ++0xc5, ++0x8e, ++0xa9, ++0xd0, ++0xee, ++0x01, ++0x77, ++0x08, ++0xa5, ++0xf0, ++0x22, ++0x2b, ++0x47, ++0x79, ++0x2b, ++0xcf, ++0x9a, ++0x46, ++0xb5, ++0x8f, ++0xfd, ++0x64, ++0xa2, ++0xb5, ++0xed, ++0x02, ++0x03, ++0x01, ++0x00, ++0x01, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x0b, ++0x05, ++0x00, ++0x03, ++0x82, ++0x01, ++0x01, ++0x00, ++0x20, ++0x44, ++0xfe, ++0xa9, ++0x9e, ++0xdd, ++0x9b, ++0xea, ++0xce, ++0x25, ++0x75, ++0x08, ++0xf0, ++0x2b, ++0x53, ++0xf7, ++0x5a, ++0x36, ++0x1c, ++0x4a, ++0x23, ++0x7f, ++0xd0, ++0x41, ++0x3c, ++0x12, ++0x2b, ++0xb9, ++0x80, ++0x4e, ++0x8a, ++0x15, ++0x5d, ++0x1f, ++0x40, ++0xa7, ++0x26, ++0x28, ++0x32, ++0xc3, ++0x5b, ++0x06, ++0x28, ++0x2d, ++0x3d, ++0x08, ++0x09, ++0x1e, ++0x01, ++0xe9, ++0x67, ++0xe3, ++0x33, ++0xe6, ++0x15, ++0x45, ++0x39, ++0xee, ++0x17, ++0x83, ++0xdb, ++0x42, ++0xff, ++0x7f, ++0x35, ++0xf4, ++0xac, ++0x16, ++0xdb, ++0xba, ++0xb8, ++0x1a, ++0x20, ++0x21, ++0x41, ++0xff, ++0xf3, ++0x92, ++0xff, ++0x65, ++0x6e, ++0x29, ++0x16, ++0xd0, ++0xbf, ++0x8d, ++0xdf, ++0x48, ++0x2c, ++0x73, ++0x36, ++0x7f, ++0x22, ++0xe6, ++0xee, ++0x78, ++0xb4, ++0x63, ++0x83, ++0x0e, ++0x39, ++0xeb, ++0xaf, ++0x10, ++0x2a, ++0x90, ++0xd3, ++0xfc, ++0xe6, ++0xc3, ++0x8f, ++0x97, ++0x5b, ++0x76, ++0xbf, ++0x9b, ++0xf5, ++0x98, ++0xd2, ++0x53, ++0x06, ++0x8b, ++0xf8, ++0xa4, ++0x04, ++0x9b, ++0x1b, ++0x62, ++0x6a, ++0x9d, ++0xac, ++0xe6, ++0x4b, ++0x0d, ++0xc9, ++0xd7, ++0x56, ++0x63, ++0x15, ++0x01, ++0x38, ++0x8c, ++0xbe, ++0xf1, ++0x44, ++0xc4, ++0x38, ++0x27, ++0xe0, ++0xcf, ++0x72, ++0xd6, ++0x3d, ++0xe4, ++0xf7, ++0x4b, ++0x3b, ++0xd2, ++0xb1, ++0x0c, ++0xd5, ++0x83, ++0x6d, ++0x1e, ++0x10, ++0x04, ++0x69, ++0x29, ++0x88, ++0x69, ++0xe0, ++0x7d, ++0xd7, ++0xdb, ++0xb4, ++0x59, ++0x72, ++0x8d, ++0x9d, ++0x3c, ++0x43, ++0xaf, ++0xc6, ++0x7d, ++0xb7, ++0x21, ++0x15, ++0x52, ++0x8a, ++0xe9, ++0x9b, ++0x6b, ++0x2e, ++0xe8, ++0x27, ++0x3c, ++0x3f, ++0x2d, ++0x84, ++0xfb, ++0x9a, ++0x22, ++0x0a, ++0x9f, ++0x6a, ++0x25, ++0xe6, ++0x39, ++0xe4, ++0x74, ++0x73, ++0xb6, ++0x2a, ++0x70, ++0xaa, ++0x1d, ++0xcb, ++0xcc, ++0xd4, ++0xa0, ++0x1b, ++0x26, ++0x71, ++0x63, ++0x04, ++0xc5, ++0x12, ++0x21, ++0x48, ++0xba, ++0x92, ++0x27, ++0x06, ++0xa8, ++0x3e, ++0x6d, ++0xa1, ++0x43, ++0xa5, ++0xd2, ++0x2a, ++0xf7, ++0xca, ++0xc4, ++0x26, ++0xe8, ++0x5b, ++0x1f, ++0xe4, ++0xdc, ++0x89, ++0xdc, ++0x1f, ++0x04, ++0x79, ++0x3f, ++0x30, ++0x82, ++0x02, ++0xcd, ++0x30, ++0x82, ++0x01, ++0xb5, ++0x02, ++0x14, ++0x3a, ++0xbb, ++0xc6, ++0xec, ++0x14, ++0x6e, ++0x09, ++0xd1, ++0xb6, ++0x01, ++0x6a, ++0xb9, ++0xd6, ++0xcf, ++0x71, ++0xdd, ++0x23, ++0x3f, ++0x03, ++0x28, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x0b, ++0x05, ++0x00, ++0x30, ++0x22, ++0x31, ++0x20, ++0x30, ++0x1e, ++0x06, ++0x03, ++0x55, ++0x04, ++0x03, ++0x0c, ++0x17, ++0x72, ++0x6f, ++0x6d, ++0x61, ++0x69, ++0x6e, ++0x2e, ++0x70, ++0x65, ++0x72, ++0x69, ++0x65, ++0x72, ++0x40, ++0x67, ++0x6d, ++0x61, ++0x69, ++0x6c, ++0x2e, ++0x63, ++0x6f, ++0x6d, ++0x30, ++0x20, ++0x17, ++0x0d, ++0x32, ++0x30, ++0x30, ++0x32, ++0x32, ++0x34, ++0x31, ++0x39, ++0x30, ++0x31, ++0x34, ++0x34, ++0x5a, ++0x18, ++0x0f, ++0x32, ++0x31, ++0x32, ++0x30, ++0x30, ++0x31, ++0x33, ++0x31, ++0x31, ++0x39, ++0x30, ++0x31, ++0x34, ++0x34, ++0x5a, ++0x30, ++0x22, ++0x31, ++0x20, ++0x30, ++0x1e, ++0x06, ++0x03, ++0x55, ++0x04, ++0x03, ++0x0c, ++0x17, ++0x72, ++0x6f, ++0x6d, ++0x61, ++0x69, ++0x6e, ++0x2e, ++0x70, ++0x65, ++0x72, ++0x69, ++0x65, ++0x72, ++0x40, ++0x67, ++0x6d, ++0x61, ++0x69, ++0x6c, ++0x2e, ++0x63, ++0x6f, ++0x6d, ++0x30, ++0x82, ++0x01, ++0x22, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x01, ++0x05, ++0x00, ++0x03, ++0x82, ++0x01, ++0x0f, ++0x00, ++0x30, ++0x82, ++0x01, ++0x0a, ++0x02, ++0x82, ++0x01, ++0x01, ++0x00, ++0xf0, ++0xb8, ++0x4f, ++0x3f, ++0x70, ++0x78, ++0xf8, ++0x74, ++0x45, ++0xa2, ++0x28, ++0xaf, ++0x04, ++0x75, ++0x04, ++0xa3, ++0xf3, ++0xa7, ++0xc7, ++0x04, ++0xac, ++0xb6, ++0xe1, ++0xfc, ++0xe1, ++0xc0, ++0x3d, ++0xe0, ++0x26, ++0x90, ++0x8a, ++0x45, ++0x60, ++0xc4, ++0x75, ++0xf3, ++0x1a, ++0x33, ++0x37, ++0x56, ++0x7d, ++0x30, ++0x07, ++0x75, ++0x0e, ++0xa6, ++0x79, ++0x06, ++0x95, ++0x9d, ++0x17, ++0x3c, ++0x09, ++0xa9, ++0x7f, ++0xab, ++0x95, ++0x5d, ++0xed, ++0xe0, ++0x75, ++0x26, ++0x2f, ++0x65, ++0x65, ++0xcd, ++0x61, ++0xb1, ++0x33, ++0x27, ++0x67, ++0x41, ++0xa1, ++0x01, ++0x13, ++0xe9, ++0x13, ++0x6a, ++0x6d, ++0x4e, ++0x98, ++0xe1, ++0x9e, ++0x7b, ++0x0b, ++0x5b, ++0x44, ++0xef, ++0x68, ++0x5a, ++0x6f, ++0x7d, ++0x97, ++0xa1, ++0x33, ++0x22, ++0x97, ++0x12, ++0x21, ++0x09, ++0x8f, ++0x90, ++0xe0, ++0x25, ++0x94, ++0xdd, ++0x8a, ++0x3a, ++0xf7, ++0x4a, ++0x60, ++0x04, ++0x26, ++0x6d, ++0x00, ++0x82, ++0xe4, ++0xcf, ++0x64, ++0x1c, ++0x79, ++0x15, ++0x24, ++0xf2, ++0x42, ++0x86, ++0xf5, ++0x10, ++0x86, ++0xac, ++0x20, ++0x88, ++0x90, ++0x87, ++0xdf, ++0x8c, ++0x37, ++0x7c, ++0xbf, ++0x35, ++0xd5, ++0x6f, ++0x9f, ++0x77, ++0xc3, ++0xcd, ++0x69, ++0x25, ++0x06, ++0xc2, ++0x65, ++0x51, ++0x71, ++0x89, ++0x7f, ++0x6e, ++0x4d, ++0xe5, ++0xd5, ++0x8a, ++0x36, ++0x1a, ++0xad, ++0xc1, ++0x18, ++0xd6, ++0x14, ++0x42, ++0x87, ++0xf0, ++0x93, ++0x83, ++0xf1, ++0x99, ++0x74, ++0xc4, ++0x13, ++0xaa, ++0x3b, ++0x66, ++0x85, ++0x6f, ++0xe0, ++0xbc, ++0x5f, ++0xb6, ++0x40, ++0xa6, ++0x41, ++0x06, ++0x0a, ++0xba, ++0x0e, ++0xe9, ++0x32, ++0x44, ++0x10, ++0x39, ++0x53, ++0xcd, ++0xbf, ++0xf3, ++0xd3, ++0x26, ++0xf6, ++0xb6, ++0x2b, ++0x40, ++0x2e, ++0xb9, ++0x88, ++0xc1, ++0xf4, ++0xe3, ++0xa0, ++0x28, ++0x77, ++0x4f, ++0xba, ++0xa8, ++0xca, ++0x9c, ++0x05, ++0xba, ++0x88, ++0x96, ++0x99, ++0x54, ++0x89, ++0xa2, ++0x8d, ++0xf3, ++0x73, ++0xa1, ++0x8c, ++0x4a, ++0xa8, ++0x71, ++0xee, ++0x2e, ++0xd2, ++0x83, ++0x14, ++0x48, ++0xbd, ++0x98, ++0xc6, ++0xce, ++0xdc, ++0xa8, ++0xa3, ++0x97, ++0x2e, ++0x40, ++0x16, ++0x2f, ++0x02, ++0x03, ++0x01, ++0x00, ++0x01, ++0x30, ++0x0d, ++0x06, ++0x09, ++0x2a, ++0x86, ++0x48, ++0x86, ++0xf7, ++0x0d, ++0x01, ++0x01, ++0x0b, ++0x05, ++0x00, ++0x03, ++0x82, ++0x01, ++0x01, ++0x00, ++0x76, ++0x5d, ++0x03, ++0x3d, ++0xb6, ++0x96, ++0x00, ++0x1b, ++0x6e, ++0x0c, ++0xdd, ++0xbb, ++0xc8, ++0xdf, ++0xbc, ++0xeb, ++0x6c, ++0x01, ++0x40, ++0x1a, ++0x2b, ++0x07, ++0x60, ++0xa1, ++0x1a, ++0xe1, ++0x43, ++0x57, ++0xfa, ++0xbe, ++0xde, ++0xbb, ++0x8f, ++0x73, ++0xf3, ++0x92, ++0xa2, ++0xaa, ++0x83, ++0x01, ++0xc1, ++0x17, ++0xe4, ++0x9d, ++0x09, ++0x41, ++0xe0, ++0x32, ++0x33, ++0x97, ++0x4b, ++0xf2, ++0xdc, ++0x0f, ++0x8b, ++0xa8, ++0xb8, ++0x5a, ++0x04, ++0x86, ++0xf6, ++0x71, ++0xa1, ++0x97, ++0xd0, ++0x54, ++0x56, ++0x10, ++0x8e, ++0x54, ++0x99, ++0x0d, ++0x2a, ++0xa9, ++0xaf, ++0x1b, ++0x55, ++0x59, ++0x06, ++0x2b, ++0xa4, ++0x5f, ++0xb1, ++0x54, ++0xa6, ++0xec, ++0xc7, ++0xd6, ++0x43, ++0xee, ++0x86, ++0x2c, ++0x9b, ++0x18, ++0x9d, ++0x8f, ++0x00, ++0x82, ++0xc1, ++0x88, ++0x61, ++0x16, ++0x85, ++0x3c, ++0x17, ++0x56, ++0xfe, ++0x6a, ++0xa0, ++0x7a, ++0x68, ++0xc5, ++0x7b, ++0x3d, ++0x3c, ++0xb6, ++0x13, ++0x18, ++0x99, ++0x6d, ++0x74, ++0x65, ++0x13, ++0x67, ++0xb7, ++0xfc, ++0x5a, ++0x44, ++0x48, ++0x72, ++0xa0, ++0x73, ++0xb8, ++0xff, ++0x02, ++0x9d, ++0x7c, ++0x5b, ++0xf9, ++0x7c, ++0x75, ++0x0a, ++0x3c, ++0x81, ++0x80, ++0x3c, ++0x41, ++0xf2, ++0xd5, ++0xfa, ++0x3d, ++0x1f, ++0xe3, ++0xda, ++0x8c, ++0xa5, ++0x17, ++0x1f, ++0x53, ++0x1a, ++0x75, ++0xad, ++0x4e, ++0x11, ++0x1c, ++0x07, ++0xec, ++0x0a, ++0x69, ++0xfd, ++0x33, ++0xfa, ++0x32, ++0x7e, ++0x66, ++0xf5, ++0x29, ++0xe8, ++0x4d, ++0x8a, ++0xfa, ++0x0d, ++0x4b, ++0x68, ++0xc3, ++0x95, ++0x11, ++0xba, ++0x6f, ++0x1e, ++0x07, ++0x8c, ++0x85, ++0xc7, ++0xc7, ++0xc9, ++0xc1, ++0x30, ++0xa3, ++0x70, ++0xb0, ++0xa1, ++0xe0, ++0xd5, ++0x85, ++0x15, ++0x94, ++0x77, ++0xc1, ++0x1c, ++0x91, ++0xf1, ++0x5f, ++0x50, ++0xcd, ++0x2c, ++0x57, ++0x4b, ++0x22, ++0x4f, ++0xee, ++0x95, ++0xd7, ++0xa7, ++0xa4, ++0x59, ++0x62, ++0xae, ++0xb9, ++0xbf, ++0xd7, ++0x63, ++0x5a, ++0x04, ++0xfc, ++0x24, ++0x11, ++0xae, ++0x34, ++0x4b, ++0xf4, ++0x0c, ++0x9f, ++0x0b, ++0x59, ++0x7d, ++0x27, ++0x39, ++0x54, ++0x69, ++0x4f, ++0xfd, ++0x6e, ++0x44, ++0x9f, ++0x21, diff --git a/target/linux/bcm27xx/patches-6.1/950-0810-fixup-Add-support-for-all-the-downstream-rpi-sound-c.patch b/target/linux/bcm27xx/patches-6.1/950-0810-fixup-Add-support-for-all-the-downstream-rpi-sound-c.patch new file mode 100644 index 0000000000..87097d2bbf --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0810-fixup-Add-support-for-all-the-downstream-rpi-sound-c.patch @@ -0,0 +1,329 @@ +From 3ece03b1575b0c3a0989e372aaaa4557ae74dc89 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 20 Jul 2023 11:28:20 +0100 +Subject: [PATCH] fixup! Add support for all the downstream rpi sound card + drivers + +Replace the Allo Dac clock driver with an extension of the +HiFiBerry clock driver that it cloned. + +Signed-off-by: Phil Elwell +--- + drivers/clk/Makefile | 1 - + drivers/clk/clk-allo-dac.c | 161 ----------------------------- + drivers/clk/clk-hifiberry-dacpro.c | 57 ++++++---- + sound/soc/bcm/Kconfig | 1 + + 4 files changed, 40 insertions(+), 180 deletions(-) + delete mode 100644 drivers/clk/clk-allo-dac.c + +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -19,7 +19,6 @@ endif + + # hardware specific clock types + # please keep this section sorted lexicographically by file path name +-obj-$(CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC) += clk-allo-dac.o + obj-$(CONFIG_COMMON_CLK_APPLE_NCO) += clk-apple-nco.o + obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o + obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o +--- a/drivers/clk/clk-allo-dac.c ++++ /dev/null +@@ -1,161 +0,0 @@ +-/* +- * Clock Driver for Allo DAC +- * +- * Author: Baswaraj K +- * Copyright 2016 +- * based on code by Stuart MacLean +- * +- * 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. +- * +- * 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 +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* Clock rate of CLK44EN attached to GPIO6 pin */ +-#define CLK_44EN_RATE 45158400UL +-/* Clock rate of CLK48EN attached to GPIO3 pin */ +-#define CLK_48EN_RATE 49152000UL +- +-/** +- * struct allo_dac_clk - Common struct to the Allo DAC +- * @hw: clk_hw for the common clk framework +- * @mode: 0 => CLK44EN, 1 => CLK48EN +- */ +-struct clk_allo_hw { +- struct clk_hw hw; +- uint8_t mode; +-}; +- +-#define to_allo_clk(_hw) container_of(_hw, struct clk_allo_hw, hw) +- +-static const struct of_device_id clk_allo_dac_dt_ids[] = { +- { .compatible = "allo,dac-clk",}, +- { } +-}; +-MODULE_DEVICE_TABLE(of, clk_allo_dac_dt_ids); +- +-static unsigned long clk_allo_dac_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) +-{ +- return (to_allo_clk(hw)->mode == 0) ? CLK_44EN_RATE : +- CLK_48EN_RATE; +-} +- +-static long clk_allo_dac_round_rate(struct clk_hw *hw, +- unsigned long rate, unsigned long *parent_rate) +-{ +- long actual_rate; +- +- if (rate <= CLK_44EN_RATE) { +- actual_rate = (long)CLK_44EN_RATE; +- } else if (rate >= CLK_48EN_RATE) { +- actual_rate = (long)CLK_48EN_RATE; +- } else { +- long diff44Rate = (long)(rate - CLK_44EN_RATE); +- long diff48Rate = (long)(CLK_48EN_RATE - rate); +- +- if (diff44Rate < diff48Rate) +- actual_rate = (long)CLK_44EN_RATE; +- else +- actual_rate = (long)CLK_48EN_RATE; +- } +- return actual_rate; +-} +- +- +-static int clk_allo_dac_set_rate(struct clk_hw *hw, +- unsigned long rate, unsigned long parent_rate) +-{ +- unsigned long actual_rate; +- struct clk_allo_hw *clk = to_allo_clk(hw); +- +- actual_rate = (unsigned long)clk_allo_dac_round_rate(hw, rate, +- &parent_rate); +- clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1; +- return 0; +-} +- +- +-const struct clk_ops clk_allo_dac_rate_ops = { +- .recalc_rate = clk_allo_dac_recalc_rate, +- .round_rate = clk_allo_dac_round_rate, +- .set_rate = clk_allo_dac_set_rate, +-}; +- +-static int clk_allo_dac_probe(struct platform_device *pdev) +-{ +- int ret; +- struct clk_allo_hw *proclk; +- struct clk *clk; +- struct device *dev; +- struct clk_init_data init; +- +- dev = &pdev->dev; +- +- proclk = kzalloc(sizeof(struct clk_allo_hw), GFP_KERNEL); +- if (!proclk) +- return -ENOMEM; +- +- init.name = "clk-allo-dac"; +- init.ops = &clk_allo_dac_rate_ops; +- init.flags = 0; +- init.parent_names = NULL; +- init.num_parents = 0; +- +- proclk->mode = 0; +- proclk->hw.init = &init; +- +- clk = devm_clk_register(dev, &proclk->hw); +- if (!IS_ERR(clk)) { +- ret = of_clk_add_provider(dev->of_node, of_clk_src_simple_get, +- clk); +- } else { +- dev_err(dev, "Fail to register clock driver\n"); +- kfree(proclk); +- ret = PTR_ERR(clk); +- } +- return ret; +-} +- +-static int clk_allo_dac_remove(struct platform_device *pdev) +-{ +- of_clk_del_provider(pdev->dev.of_node); +- return 0; +-} +- +-static struct platform_driver clk_allo_dac_driver = { +- .probe = clk_allo_dac_probe, +- .remove = clk_allo_dac_remove, +- .driver = { +- .name = "clk-allo-dac", +- .of_match_table = clk_allo_dac_dt_ids, +- }, +-}; +- +-static int __init clk_allo_dac_init(void) +-{ +- return platform_driver_register(&clk_allo_dac_driver); +-} +-core_initcall(clk_allo_dac_init); +- +-static void __exit clk_allo_dac_exit(void) +-{ +- platform_driver_unregister(&clk_allo_dac_driver); +-} +-module_exit(clk_allo_dac_exit); +- +-MODULE_DESCRIPTION("Allo DAC clock driver"); +-MODULE_LICENSE("GPL v2"); +-MODULE_ALIAS("platform:clk-allo-dac"); +--- a/drivers/clk/clk-hifiberry-dacpro.c ++++ b/drivers/clk/clk-hifiberry-dacpro.c +@@ -22,10 +22,12 @@ + #include + #include + +-/* Clock rate of CLK44EN attached to GPIO6 pin */ +-#define CLK_44EN_RATE 22579200UL +-/* Clock rate of CLK48EN attached to GPIO3 pin */ +-#define CLK_48EN_RATE 24576000UL ++struct ext_clk_rates { ++ /* Clock rate of CLK44EN attached to GPIO6 pin */ ++ unsigned long clk_44en; ++ /* Clock rate of CLK48EN attached to GPIO3 pin */ ++ unsigned long clk_48en; ++}; + + /** + * struct hifiberry_dacpro_clk - Common struct to the HiFiBerry DAC Pro +@@ -35,12 +37,24 @@ + struct clk_hifiberry_hw { + struct clk_hw hw; + uint8_t mode; ++ struct ext_clk_rates clk_rates; + }; + + #define to_hifiberry_clk(_hw) container_of(_hw, struct clk_hifiberry_hw, hw) + ++static const struct ext_clk_rates hifiberry_dacpro_clks = { ++ .clk_44en = 22579200UL, ++ .clk_48en = 24576000UL, ++}; ++ ++static const struct ext_clk_rates allo_dac_clks = { ++ .clk_44en = 45158400UL, ++ .clk_48en = 49152000UL, ++}; ++ + static const struct of_device_id clk_hifiberry_dacpro_dt_ids[] = { +- { .compatible = "hifiberry,dacpro-clk",}, ++ { .compatible = "hifiberry,dacpro-clk", &hifiberry_dacpro_clks }, ++ { .compatible = "allo,dac-clk", &allo_dac_clks }, + { } + }; + MODULE_DEVICE_TABLE(of, clk_hifiberry_dacpro_dt_ids); +@@ -48,27 +62,29 @@ MODULE_DEVICE_TABLE(of, clk_hifiberry_da + static unsigned long clk_hifiberry_dacpro_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +- return (to_hifiberry_clk(hw)->mode == 0) ? CLK_44EN_RATE : +- CLK_48EN_RATE; ++ struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw); ++ return (clk->mode == 0) ? clk->clk_rates.clk_44en : ++ clk->clk_rates.clk_48en; + } + + static long clk_hifiberry_dacpro_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate) + { ++ struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw); + long actual_rate; + +- if (rate <= CLK_44EN_RATE) { +- actual_rate = (long)CLK_44EN_RATE; +- } else if (rate >= CLK_48EN_RATE) { +- actual_rate = (long)CLK_48EN_RATE; ++ if (rate <= clk->clk_rates.clk_44en) { ++ actual_rate = (long)clk->clk_rates.clk_44en; ++ } else if (rate >= clk->clk_rates.clk_48en) { ++ actual_rate = (long)clk->clk_rates.clk_48en; + } else { +- long diff44Rate = (long)(rate - CLK_44EN_RATE); +- long diff48Rate = (long)(CLK_48EN_RATE - rate); ++ long diff44Rate = (long)(rate - clk->clk_rates.clk_44en); ++ long diff48Rate = (long)(clk->clk_rates.clk_48en - rate); + + if (diff44Rate < diff48Rate) +- actual_rate = (long)CLK_44EN_RATE; ++ actual_rate = (long)clk->clk_rates.clk_44en; + else +- actual_rate = (long)CLK_48EN_RATE; ++ actual_rate = (long)clk->clk_rates.clk_48en; + } + return actual_rate; + } +@@ -77,12 +93,12 @@ static long clk_hifiberry_dacpro_round_r + static int clk_hifiberry_dacpro_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) + { +- unsigned long actual_rate; + struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw); ++ unsigned long actual_rate; + + actual_rate = (unsigned long)clk_hifiberry_dacpro_round_rate(hw, rate, + &parent_rate); +- clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1; ++ clk->mode = (actual_rate == clk->clk_rates.clk_44en) ? 0 : 1; + return 0; + } + +@@ -95,13 +111,17 @@ const struct clk_ops clk_hifiberry_dacpr + + static int clk_hifiberry_dacpro_probe(struct platform_device *pdev) + { +- int ret; ++ const struct of_device_id *of_id; + struct clk_hifiberry_hw *proclk; + struct clk *clk; + struct device *dev; + struct clk_init_data init; ++ int ret; + + dev = &pdev->dev; ++ of_id = of_match_node(clk_hifiberry_dacpro_dt_ids, dev->of_node); ++ if (!of_id) ++ return -EINVAL; + + proclk = kzalloc(sizeof(struct clk_hifiberry_hw), GFP_KERNEL); + if (!proclk) +@@ -115,6 +135,7 @@ static int clk_hifiberry_dacpro_probe(st + + proclk->mode = 0; + proclk->hw.init = &init; ++ memcpy(&proclk->clk_rates, of_id->data, sizeof(proclk->clk_rates)); + + clk = devm_clk_register(dev, &proclk->hw); + if (!IS_ERR(clk)) { +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -271,6 +271,7 @@ config SND_BCM2708_SOC_ALLO_BOSS_DAC + tristate "Support for Allo Boss DAC" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C ++ select COMMON_CLK_HIFIBERRY_DACPRO + help + Say Y or M if you want to add support for Allo Boss DAC. + diff --git a/target/linux/bcm27xx/patches-6.1/950-0815-fixup-drm-tc358762-Set-the-pre_enable_upstream_first.patch b/target/linux/bcm27xx/patches-6.1/950-0815-fixup-drm-tc358762-Set-the-pre_enable_upstream_first.patch new file mode 100644 index 0000000000..22bca6c7f4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0815-fixup-drm-tc358762-Set-the-pre_enable_upstream_first.patch @@ -0,0 +1,21 @@ +From 2addf7045f2b4866ab819f48e4d32f5734a32134 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Thu, 20 Jul 2023 15:15:27 +0100 +Subject: [PATCH] fixup! drm/tc358762: Set the pre_enable_upstream_first flag + to configure DSI host + +--- + drivers/gpu/drm/bridge/tc358762.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/bridge/tc358762.c ++++ b/drivers/gpu/drm/bridge/tc358762.c +@@ -229,7 +229,7 @@ static int tc358762_probe(struct mipi_ds + ctx->bridge.funcs = &tc358762_bridge_funcs; + ctx->bridge.type = DRM_MODE_CONNECTOR_DPI; + ctx->bridge.of_node = dev->of_node; +- ctx->bridge.pre_enable_upstream_first = true; ++ ctx->bridge.pre_enable_prev_first = true; + + drm_bridge_add(&ctx->bridge); + diff --git a/target/linux/bcm27xx/patches-6.1/950-0816-rpi-sound-cards-Fix-Codec-Zero-rate-switching.patch b/target/linux/bcm27xx/patches-6.1/950-0816-rpi-sound-cards-Fix-Codec-Zero-rate-switching.patch new file mode 100644 index 0000000000..82a3c9ea5b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0816-rpi-sound-cards-Fix-Codec-Zero-rate-switching.patch @@ -0,0 +1,48 @@ +From b84b8a9ad2046a855a7044b6368def01ddd5de6e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 21 Jul 2023 16:50:56 +0100 +Subject: [PATCH] rpi sound cards: Fix Codec Zero rate switching + +The Raspberry Pi Codec Zero (and IQaudIO Codec) don't notify the DA7213 +codec when it needs to change PLL frequencies. As a result, audio can +be played at the wrong rate - play a 48kHz sound immediately after a +44.1kHz sound to see the effect, but in some configurations the codec +can lock into the wrong state and always get some rates wrong. + +Add the necessary notification to fix the issue. + +Signed-off-by: Phil Elwell +--- + sound/soc/bcm/iqaudio-codec.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/sound/soc/bcm/iqaudio-codec.c ++++ b/sound/soc/bcm/iqaudio-codec.c +@@ -143,6 +143,7 @@ static int snd_rpi_iqaudio_codec_hw_para + struct snd_pcm_hw_params *params) + { + struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + unsigned int samplerate = params_rate(params); + + switch (samplerate) { +@@ -152,15 +153,17 @@ static int snd_rpi_iqaudio_codec_hw_para + case 48000: + case 96000: + pll_out = DA7213_PLL_FREQ_OUT_98304000; +- return 0; ++ break; + case 44100: + case 88200: + pll_out = DA7213_PLL_FREQ_OUT_90316800; +- return 0; ++ break; + default: + dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate); + return -EINVAL; + } ++ ++ return snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0, pll_out); + } + + static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = { diff --git a/target/linux/bcm27xx/patches-6.1/950-0818-overlays-Add-trickle-voltage-mv-parameter-to-RTCs.patch b/target/linux/bcm27xx/patches-6.1/950-0818-overlays-Add-trickle-voltage-mv-parameter-to-RTCs.patch new file mode 100644 index 0000000000..0539b19cf5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0818-overlays-Add-trickle-voltage-mv-parameter-to-RTCs.patch @@ -0,0 +1,68 @@ +From 31822340129e3c4030500d7f30ce4d19bbf9dd40 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 24 Jul 2023 17:34:47 +0100 +Subject: [PATCH] overlays: Add trickle-voltage-mv parameter to RTCs + +The RV3032 RTC requires an additional DT property to enable trickle +charging. Add a parameter - trickle-voltage-mv - to the i2c-rtc +and i2c-rtc-gpio overlays to set it. + +See: https://github.com/raspberrypi/linux/issues/5547 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 12 ++++++++---- + arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi | 2 ++ + 2 files changed, 10 insertions(+), 4 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1957,13 +1957,15 @@ Params: abx80x Select o + "schottky" (ABx80x and RV1805 only) + + trickle-resistor-ohms Resistor value for trickle charge (DS1339, +- ABx80x, RV1805, RV3028) ++ ABx80x, BQ32000, RV1805, RV3028, RV3032) ++ ++ trickle-voltage-mv Charge pump voltage for trickle charge (RV3032) + + wakeup-source Specify that the RTC can be used as a wakeup + source + + backup-switchover-mode Backup power supply switch mode. Must be 0 for +- off or 1 for Vdd < VBackup (RV3028 only) ++ off or 1 for Vdd < VBackup (RV3028, RV3032) + + + Name: i2c-rtc-gpio +@@ -2027,13 +2029,15 @@ Params: abx80x Select o + "schottky" (ABx80x and RV1805 only) + + trickle-resistor-ohms Resistor value for trickle charge (DS1339, +- ABx80x, RV1805, RV3028) ++ ABx80x, BQ32000, RV1805, RV3028, RV3032) ++ ++ trickle-voltage-mv Charge pump voltage for trickle charge (RV3032) + + wakeup-source Specify that the RTC can be used as a wakeup + source + + backup-switchover-mode Backup power supply switch mode. Must be 0 for +- off or 1 for Vdd < VBackup (RV3028 only) ++ off or 1 for Vdd < VBackup (RV3028, RV3032) + + i2c_gpio_sda GPIO used for I2C data (default "23") + +--- a/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi ++++ b/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi +@@ -339,8 +339,10 @@ + <&ds1340>,"trickle-resistor-ohms:0", + <&abx80x>,"abracon,tc-resistor:0", + <&rv3028>,"trickle-resistor-ohms:0", ++ <&rv3032>,"trickle-resistor-ohms:0", + <&rv1805>,"abracon,tc-resistor:0", + <&bq32000>,"abracon,tc-resistor:0"; ++ trickle-voltage-mv = <&rv3032>,"trickle-voltage-millivolts:0"; + backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0"; + wakeup-source = <&ds1339>,"wakeup-source?", + <&ds3231>,"wakeup-source?", diff --git a/target/linux/bcm27xx/patches-6.1/950-0819-drivers-media-imx296-Add-standby-delay-during-probe.patch b/target/linux/bcm27xx/patches-6.1/950-0819-drivers-media-imx296-Add-standby-delay-during-probe.patch new file mode 100644 index 0000000000..f10c0f03b5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0819-drivers-media-imx296-Add-standby-delay-during-probe.patch @@ -0,0 +1,25 @@ +From 5fb3b300557d6a6902e7321f42fdabb8c09eef54 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Fri, 28 Jul 2023 12:00:40 +0100 +Subject: [PATCH] drivers: media: imx296: Add standby delay during probe + +Add a 2-5ms delay when coming out of standby and before reading the +sensor info register durning probe, as instructed by the datasheet. This +standby delay is already present when the sensor starts streaming. + +Signed-off-by: Naushir Patuck +--- + drivers/media/i2c/imx296.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/media/i2c/imx296.c ++++ b/drivers/media/i2c/imx296.c +@@ -1022,6 +1022,8 @@ static int imx296_identify_model(struct + return ret; + } + ++ usleep_range(2000, 5000); ++ + ret = imx296_read(sensor, IMX296_SENSOR_INFO); + if (ret < 0) { + dev_err(sensor->dev, "failed to read sensor information (%d)\n", diff --git a/target/linux/bcm27xx/patches-6.1/950-0820-overlays-Add-bmp380-to-i2c-sensor-overlay.patch b/target/linux/bcm27xx/patches-6.1/950-0820-overlays-Add-bmp380-to-i2c-sensor-overlay.patch new file mode 100644 index 0000000000..535511eb93 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0820-overlays-Add-bmp380-to-i2c-sensor-overlay.patch @@ -0,0 +1,78 @@ +From e1016d61e3dcb058932e8ec5072f2c4bbb05fcb7 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Sun, 30 Jul 2023 18:27:03 +0100 +Subject: [PATCH] overlays: Add bmp380 to i2c-sensor overlay + +Add support for the BMP380 pressor sensor to the i2c-sensor overlay. + +See: https://github.com/raspberrypi/linux/issues/5558 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 7 +++++-- + .../boot/dts/overlays/i2c-sensor-common.dtsi | 19 ++++++++++++++++++- + 2 files changed, 23 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2052,8 +2052,8 @@ Info: Adds support for a number of I2C + light level and chemical sensors on i2c_arm + Load: dtoverlay=i2c-sensor,= + Params: addr Set the address for the BH1750, BME280, BME680, +- BMP280, CCS811, DS1621, HDC100X, JC42, LM75, +- MCP980x, MPU6050, MPU9250, MS5637, MS5803, ++ BMP280, BMP380, CCS811, DS1621, HDC100X, JC42, ++ LM75, MCP980x, MPU6050, MPU9250, MS5637, MS5803, + MS5805, MS5837, MS8607, SHT3x or TMP102 + + aht10 Select the Aosong AHT10 temperature and humidity +@@ -2075,6 +2075,9 @@ Params: addr Set the + bmp280 Select the Bosch Sensortronic BMP280 + Valid addresses 0x76-0x77, default 0x76 + ++ bmp380 Select the Bosch Sensortronic BMP380 ++ Valid addresses 0x76-0x77, default 0x76 ++ + bno055 Select the Bosch Sensortronic BNO055 IMU + Valid address 0x28-0x29, default 0x29 + +--- a/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi ++++ b/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi +@@ -493,11 +493,27 @@ + }; + }; + ++ fragment@33 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ bmp380: bmp380@76 { ++ compatible = "bosch,bmp380"; ++ reg = <0x76>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ + __overrides__ { + bme280 = <0>,"+0"; + bmp085 = <0>,"+1"; + bmp180 = <0>,"+2"; + bmp280 = <0>,"+3"; ++ bmp380 = <0>,"+33"; + htu21 = <0>,"+4"; + lm75 = <0>,"+5"; + lm75addr = <&lm75>,"reg:0"; +@@ -535,7 +551,8 @@ + <&ms5637>,"reg:0", <&ms5803>,"reg:0", <&ms5805>,"reg:0", + <&ms5837>,"reg:0", <&ms8607>,"reg:0", + <&mpu6050>,"reg:0", <&mpu9250>,"reg:0", +- <&bno055>,"reg:0", <&sht4x>,"reg:0"; ++ <&bno055>,"reg:0", <&sht4x>,"reg:0", ++ <&bmp380>,"reg:0"; + int_pin = <&max30102>, "interrupts:0", + <&mpu6050>, "interrupts:0", + <&mpu9250>, "interrupts:0"; diff --git a/target/linux/bcm27xx/patches-6.1/950-0821-can-isotp-add-module-parameter-for-maximum-pdu-size.patch b/target/linux/bcm27xx/patches-6.1/950-0821-can-isotp-add-module-parameter-for-maximum-pdu-size.patch new file mode 100644 index 0000000000..d5cce9a433 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0821-can-isotp-add-module-parameter-for-maximum-pdu-size.patch @@ -0,0 +1,162 @@ +From 4b729a06b15fc5ee3694dcc62346dcb718ae4290 Mon Sep 17 00:00:00 2001 +From: Oliver Hartkopp +Date: Sun, 26 Mar 2023 13:59:11 +0200 +Subject: [PATCH] can: isotp: add module parameter for maximum pdu size + +commit 96d1c81e6a0478535342dff6c730adb076cd84e8 upstream. + +With ISO 15765-2:2016 the PDU size is not limited to 2^12 - 1 (4095) +bytes but can be represented as a 32 bit unsigned integer value which +allows 2^32 - 1 bytes (~4GB). The use-cases like automotive unified +diagnostic services (UDS) and flashing of ECUs still use the small +static buffers which are provided at socket creation time. + +When a use-case requires to transfer PDUs up to 1025 kByte the maximum +PDU size can now be extended by setting the module parameter +max_pdu_size. The extended size buffers are only allocated on a +per-socket/connection base when needed at run-time. + +changes since v2: https://lore.kernel.org/all/20230313172510.3851-1-socketcan@hartkopp.net +- use ARRAY_SIZE() to reference DEFAULT_MAX_PDU_SIZE only at one place + +changes since v1: https://lore.kernel.org/all/20230311143446.3183-1-socketcan@hartkopp.net +- limit the minimum 'max_pdu_size' to 4095 to maintain the classic + behavior before ISO 15765-2:2016 + +Link: https://github.com/raspberrypi/linux/issues/5371 +Signed-off-by: Oliver Hartkopp +Link: https://lore.kernel.org/all/20230326115911.15094-1-socketcan@hartkopp.net +Signed-off-by: Marc Kleine-Budde +--- + net/can/isotp.c | 65 ++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 56 insertions(+), 9 deletions(-) + +--- a/net/can/isotp.c ++++ b/net/can/isotp.c +@@ -85,10 +85,21 @@ MODULE_ALIAS("can-proto-6"); + + /* ISO 15765-2:2016 supports more than 4095 byte per ISO PDU as the FF_DL can + * take full 32 bit values (4 Gbyte). We would need some good concept to handle +- * this between user space and kernel space. For now increase the static buffer +- * to something about 64 kbyte to be able to test this new functionality. ++ * this between user space and kernel space. For now set the static buffer to ++ * something about 8 kbyte to be able to test this new functionality. + */ +-#define MAX_MSG_LENGTH 66000 ++#define DEFAULT_MAX_PDU_SIZE 8300 ++ ++/* maximum PDU size before ISO 15765-2:2016 extension was 4095 */ ++#define MAX_12BIT_PDU_SIZE 4095 ++ ++/* limit the isotp pdu size from the optional module parameter to 1MByte */ ++#define MAX_PDU_SIZE (1025 * 1024U) ++ ++static unsigned int max_pdu_size __read_mostly = DEFAULT_MAX_PDU_SIZE; ++module_param(max_pdu_size, uint, 0444); ++MODULE_PARM_DESC(max_pdu_size, "maximum isotp pdu size (default " ++ __stringify(DEFAULT_MAX_PDU_SIZE) ")"); + + /* N_PCI type values in bits 7-4 of N_PCI bytes */ + #define N_PCI_SF 0x00 /* single frame */ +@@ -124,13 +135,15 @@ enum { + }; + + struct tpcon { +- unsigned int idx; ++ u8 *buf; ++ unsigned int buflen; + unsigned int len; ++ unsigned int idx; + u32 state; + u8 bs; + u8 sn; + u8 ll_dl; +- u8 buf[MAX_MSG_LENGTH + 1]; ++ u8 sbuf[DEFAULT_MAX_PDU_SIZE]; + }; + + struct isotp_sock { +@@ -498,7 +511,17 @@ static int isotp_rcv_ff(struct sock *sk, + if (so->rx.len + ae + off + ff_pci_sz < so->rx.ll_dl) + return 1; + +- if (so->rx.len > MAX_MSG_LENGTH) { ++ /* PDU size > default => try max_pdu_size */ ++ if (so->rx.len > so->rx.buflen && so->rx.buflen < max_pdu_size) { ++ u8 *newbuf = kmalloc(max_pdu_size, GFP_ATOMIC); ++ ++ if (newbuf) { ++ so->rx.buf = newbuf; ++ so->rx.buflen = max_pdu_size; ++ } ++ } ++ ++ if (so->rx.len > so->rx.buflen) { + /* send FC frame with overflow status */ + isotp_send_fc(sk, ae, ISOTP_FC_OVFLW); + return 1; +@@ -802,7 +825,7 @@ static void isotp_create_fframe(struct c + cf->data[0] = so->opt.ext_address; + + /* create N_PCI bytes with 12/32 bit FF_DL data length */ +- if (so->tx.len > 4095) { ++ if (so->tx.len > MAX_12BIT_PDU_SIZE) { + /* use 32 bit FF_DL notation */ + cf->data[ae] = N_PCI_FF; + cf->data[ae + 1] = 0; +@@ -939,7 +962,17 @@ static int isotp_sendmsg(struct socket * + goto err_event_drop; + } + +- if (!size || size > MAX_MSG_LENGTH) { ++ /* PDU size > default => try max_pdu_size */ ++ if (size > so->tx.buflen && so->tx.buflen < max_pdu_size) { ++ u8 *newbuf = kmalloc(max_pdu_size, GFP_KERNEL); ++ ++ if (newbuf) { ++ so->tx.buf = newbuf; ++ so->tx.buflen = max_pdu_size; ++ } ++ } ++ ++ if (!size || size > so->tx.buflen) { + err = -EINVAL; + goto err_out_drop; + } +@@ -1194,6 +1227,12 @@ static int isotp_release(struct socket * + so->ifindex = 0; + so->bound = 0; + ++ if (so->rx.buf != so->rx.sbuf) ++ kfree(so->rx.buf); ++ ++ if (so->tx.buf != so->tx.sbuf) ++ kfree(so->tx.buf); ++ + sock_orphan(sk); + sock->sk = NULL; + +@@ -1588,6 +1627,11 @@ static int isotp_init(struct sock *sk) + so->rx.state = ISOTP_IDLE; + so->tx.state = ISOTP_IDLE; + ++ so->rx.buf = so->rx.sbuf; ++ so->tx.buf = so->tx.sbuf; ++ so->rx.buflen = ARRAY_SIZE(so->rx.sbuf); ++ so->tx.buflen = ARRAY_SIZE(so->tx.sbuf); ++ + hrtimer_init(&so->rxtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); + so->rxtimer.function = isotp_rx_timer_handler; + hrtimer_init(&so->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); +@@ -1670,7 +1714,10 @@ static __init int isotp_module_init(void + { + int err; + +- pr_info("can: isotp protocol\n"); ++ max_pdu_size = max_t(unsigned int, max_pdu_size, MAX_12BIT_PDU_SIZE); ++ max_pdu_size = min_t(unsigned int, max_pdu_size, MAX_PDU_SIZE); ++ ++ pr_info("can: isotp protocol (max_pdu_size %d)\n", max_pdu_size); + + err = can_proto_register(&isotp_can_proto); + if (err < 0) diff --git a/target/linux/bcm27xx/patches-6.1/950-0822-drivers-media-imx296-Updated-imx296-driver-for-exter.patch b/target/linux/bcm27xx/patches-6.1/950-0822-drivers-media-imx296-Updated-imx296-driver-for-exter.patch new file mode 100644 index 0000000000..ee4079cd64 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0822-drivers-media-imx296-Updated-imx296-driver-for-exter.patch @@ -0,0 +1,40 @@ +From e1b03ea9e84320e6bf36a1486abaebbceadd7fc7 Mon Sep 17 00:00:00 2001 +From: Ben Benson +Date: Fri, 21 Jul 2023 15:59:51 +0100 +Subject: [PATCH] drivers: media: imx296: Updated imx296 driver for external + trigger + +Updated imx296 driver to support external trigger mode via XTR pin. +Added module parameter to control this mode. + +Signed-off-by: Ben Benson +--- + drivers/media/i2c/imx296.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/media/i2c/imx296.c ++++ b/drivers/media/i2c/imx296.c +@@ -20,6 +20,10 @@ + #include + #include + ++static int trigger_mode; ++module_param(trigger_mode, int, 0644); ++MODULE_PARM_DESC(trigger_mode, "Set trigger mode: 0=default, 1=XTRIG"); ++ + #define IMX296_PIXEL_ARRAY_WIDTH 1456 + #define IMX296_PIXEL_ARRAY_HEIGHT 1088 + +@@ -645,6 +649,12 @@ static int imx296_stream_on(struct imx29 + + imx296_write(sensor, IMX296_CTRL00, 0, &ret); + usleep_range(2000, 5000); ++ ++ if (trigger_mode == 1) { ++ imx296_write(sensor, IMX296_CTRL0B, IMX296_CTRL0B_TRIGEN, &ret); ++ imx296_write(sensor, IMX296_LOWLAGTRG, IMX296_LOWLAGTRG_FAST, &ret); ++ } ++ + imx296_write(sensor, IMX296_CTRL0A, 0, &ret); + + /* vflip and hflip cannot change during streaming */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0823-media-dt-bindings-imx258-Fix-alternate-compatible-st.patch b/target/linux/bcm27xx/patches-6.1/950-0823-media-dt-bindings-imx258-Fix-alternate-compatible-st.patch new file mode 100644 index 0000000000..f45b68f154 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0823-media-dt-bindings-imx258-Fix-alternate-compatible-st.patch @@ -0,0 +1,26 @@ +From 74bc238e86e62109c74d8f229dc105bf3818b4a7 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 2 Aug 2023 14:35:32 +0100 +Subject: [PATCH] media: dt-bindings: imx258: Fix alternate compatible strings + +Multiple compatible strings must appear as an enum. + +Signed-off-by: Phil Elwell +--- + Documentation/devicetree/bindings/media/i2c/imx258.yaml | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/media/i2c/imx258.yaml ++++ b/Documentation/devicetree/bindings/media/i2c/imx258.yaml +@@ -19,8 +19,9 @@ description: |- + + properties: + compatible: +- const: sony,imx258 +- const: sony,imx258-pdaf ++ enum: ++ - sony,imx258 ++ - sony,imx258-pdaf + + assigned-clocks: true + assigned-clock-parents: true diff --git a/target/linux/bcm27xx/patches-6.1/950-0825-char-broadcom-vc_mem-Fix-preprocessor-conditional.patch b/target/linux/bcm27xx/patches-6.1/950-0825-char-broadcom-vc_mem-Fix-preprocessor-conditional.patch new file mode 100644 index 0000000000..43283784dd --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0825-char-broadcom-vc_mem-Fix-preprocessor-conditional.patch @@ -0,0 +1,21 @@ +From 282819aead0166af415b780241dc2def4caee7f4 Mon Sep 17 00:00:00 2001 +From: Alexander Winkowski +Date: Mon, 3 Jul 2023 18:12:01 +0000 +Subject: [PATCH] char: broadcom: vc_mem: Fix preprocessor conditional + +Signed-off-by: Alexander Winkowski +--- + drivers/char/broadcom/vc_mem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/char/broadcom/vc_mem.c ++++ b/drivers/char/broadcom/vc_mem.c +@@ -353,7 +353,7 @@ vc_mem_exit(void) + pr_debug("%s: called\n", __func__); + + if (vc_mem_inited) { +-#if CONFIG_DEBUG_FS ++#ifdef CONFIG_DEBUG_FS + vc_mem_debugfs_deinit(); + #endif + device_destroy(vc_mem_class, vc_mem_devnum); diff --git a/target/linux/bcm27xx/patches-6.1/950-0826-drivers-dwc_otg-Fix-fallthrough-warnings.patch b/target/linux/bcm27xx/patches-6.1/950-0826-drivers-dwc_otg-Fix-fallthrough-warnings.patch new file mode 100644 index 0000000000..fe74c75e07 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0826-drivers-dwc_otg-Fix-fallthrough-warnings.patch @@ -0,0 +1,32 @@ +From ec61075a786c455444a1d5df338a41bacfce0bb1 Mon Sep 17 00:00:00 2001 +From: Alexander Winkowski +Date: Mon, 3 Jul 2023 18:23:02 +0000 +Subject: [PATCH] drivers: dwc_otg: Fix fallthrough warnings + +Signed-off-by: Alexander Winkowski +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 1 + + drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +@@ -2049,6 +2049,7 @@ int fiq_fsm_queue_split_transaction(dwc_ + } else { + st->fsm = FIQ_PER_SSPLIT_QUEUED; + } ++ break; + default: + break; + } +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +@@ -402,7 +402,7 @@ int32_t dwc_otg_hcd_handle_rx_status_q_l + hc->xfer_count += grxsts.b.bcnt; + hc->xfer_buff += grxsts.b.bcnt; + } +- ++ break; + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: + case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR: + case DWC_GRXSTS_PKTSTS_CH_HALTED: diff --git a/target/linux/bcm27xx/patches-6.1/950-0827-vc04_services-vc-sm-cma-Switch-one-bit-bitfields-to-.patch b/target/linux/bcm27xx/patches-6.1/950-0827-vc04_services-vc-sm-cma-Switch-one-bit-bitfields-to-.patch new file mode 100644 index 0000000000..edd117c9b5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0827-vc04_services-vc-sm-cma-Switch-one-bit-bitfields-to-.patch @@ -0,0 +1,61 @@ +From 2dd2f36d10961e3819ff0525ae2567e601973826 Mon Sep 17 00:00:00 2001 +From: Alexander Winkowski +Date: Mon, 3 Jul 2023 18:29:37 +0000 +Subject: [PATCH] vc04_services/vc-sm-cma: Switch one-bit bitfields to bool + +Clang 16 warns: + +../drivers/staging/vc04_services/vc-sm-cma/vc_sm.c:816:19: warning: implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1 [-Wsingle-bit-bitfield-constant-conversion] + buffer->imported = 1; + ^ ~ +../drivers/staging/vc04_services/vc-sm-cma/vc_sm.c:822:17: warning: implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1 [-Wsingle-bit-bitfield-constant-conversion] + buffer->in_use = 1; + ^ ~ +2 warnings generated. + +Signed-off-by: Alexander Winkowski +--- + drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 6 +++--- + drivers/staging/vc04_services/vc-sm-cma/vc_sm.h | 4 ++-- + 2 files changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c +@@ -533,7 +533,7 @@ static void vc_sm_dma_buf_release(struct + + pr_debug("%s dmabuf %p, buffer %p\n", __func__, dmabuf, buffer); + +- buffer->in_use = 0; ++ buffer->in_use = false; + + /* Unmap on the VPU */ + vc_sm_vpu_free(buffer); +@@ -813,13 +813,13 @@ vc_sm_cma_import_dmabuf_internal(struct + buffer->size = import.size; + buffer->vpu_state = VPU_MAPPED; + +- buffer->imported = 1; ++ buffer->imported = true; + buffer->import.dma_buf = dma_buf; + + buffer->import.attach = attach; + buffer->import.sgt = sgt; + buffer->dma_addr = dma_addr; +- buffer->in_use = 1; ++ buffer->in_use = true; + buffer->kernel_id = import.kernel_id; + + /* +--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h +@@ -57,8 +57,8 @@ struct vc_sm_buffer { + + char name[VC_SM_MAX_NAME_LEN]; + +- int in_use:1; /* Kernel is still using this resource */ +- int imported:1; /* Imported dmabuf */ ++ bool in_use:1; /* Kernel is still using this resource */ ++ bool imported:1; /* Imported dmabuf */ + + enum vc_sm_vpu_mapping_state vpu_state; + u32 vc_handle; /* VideoCore handle for this buffer */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0828-media-i2c-ov2311-Fix-uninitialized-variable-usage.patch b/target/linux/bcm27xx/patches-6.1/950-0828-media-i2c-ov2311-Fix-uninitialized-variable-usage.patch new file mode 100644 index 0000000000..d6fd3a9f92 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0828-media-i2c-ov2311-Fix-uninitialized-variable-usage.patch @@ -0,0 +1,21 @@ +From 3333d45347d313ea589b8b8da1193d342060a946 Mon Sep 17 00:00:00 2001 +From: Alexander Winkowski +Date: Mon, 3 Jul 2023 18:36:45 +0000 +Subject: [PATCH] media: i2c: ov2311: Fix uninitialized variable usage + +Signed-off-by: Alexander Winkowski +--- + drivers/media/i2c/ov2311.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/media/i2c/ov2311.c ++++ b/drivers/media/i2c/ov2311.c +@@ -1018,7 +1018,7 @@ static int ov2311_check_sensor_id(struct + struct i2c_client *client) + { + struct device *dev = &ov2311->client->dev; +- u32 id = 0, id_msb; ++ u32 id = 0, id_msb = 0; + int ret; + + ret = ov2311_read_reg(client, OV2311_REG_CHIP_ID + 1, diff --git a/target/linux/bcm27xx/patches-6.1/950-0830-drm-panel-Fix-default-values-for-Waveshare-7.9-inch-.patch b/target/linux/bcm27xx/patches-6.1/950-0830-drm-panel-Fix-default-values-for-Waveshare-7.9-inch-.patch new file mode 100644 index 0000000000..035b5b0049 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0830-drm-panel-Fix-default-values-for-Waveshare-7.9-inch-.patch @@ -0,0 +1,29 @@ +From e89e7655a197d28df49da2be7e2003436cf52197 Mon Sep 17 00:00:00 2001 +From: Ignacio Larrain +Date: Tue, 22 Aug 2023 11:11:56 -0400 +Subject: [PATCH] drm/panel: Fix default values for Waveshare 7.9 inch DSI + touchscreen (#5565) + +This fixes touchscreen calibration, axis swapping and inversion. + +As referenced in https://github.com/raspberrypi/linux/issues/5550 +--- + .../dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts +@@ -93,10 +93,10 @@ + <&touch>, "touchscreen-size-x:0=800", + <&touch>, "touchscreen-size-y:0=480"; + 7_9_inch = <&panel>, "compatible=waveshare,7.9inch-panel", +- <&touch>, "touchscreen-size-x:0=400", +- <&touch>, "touchscreen-size-y:0=1280", ++ <&touch>, "touchscreen-size-x:0=4096", ++ <&touch>, "touchscreen-size-y:0=4096", + <&touch>, "touchscreen-inverted-x?", +- <&touch>, "touchscreen-inverted-y?"; ++ <&touch>, "touchscreen-swapped-x-y?"; + 8_0_inch = <&panel>, "compatible=waveshare,8.0inch-panel", + <&touch>, "touchscreen-size-x:0=800", + <&touch>, "touchscreen-size-y:0=1280", diff --git a/target/linux/bcm27xx/patches-6.1/950-0831-dtoverlays-Add-i2c-bus-overrides-to-edt-ft5406-overl.patch b/target/linux/bcm27xx/patches-6.1/950-0831-dtoverlays-Add-i2c-bus-overrides-to-edt-ft5406-overl.patch new file mode 100644 index 0000000000..cf703b0029 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0831-dtoverlays-Add-i2c-bus-overrides-to-edt-ft5406-overl.patch @@ -0,0 +1,102 @@ +From 3fa2fbb7f6e60b85086e454403c5eab1af63b1aa Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 14 Jun 2023 13:43:58 +0100 +Subject: [PATCH] dtoverlays: Add i2c bus overrides to edt-ft5406 overlay + +Adds the option for the touch controller to be connected to any +of the I2C ports. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/README | 17 +++++++++++++++- + .../boot/dts/overlays/edt-ft5406-overlay.dts | 20 +++++++++++++++++++ + arch/arm/boot/dts/overlays/edt-ft5406.dtsi | 9 ++++++++- + 3 files changed, 44 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1040,9 +1040,11 @@ Params: dr_mode Dual rol + + + Name: edt-ft5406 +-Info: Overlay for the EDT FT5406 touchscreen on the CSI/DSI I2C interface. ++Info: Overlay for the EDT FT5406 touchscreen. + This works with the Raspberry Pi 7" touchscreen when not being polled + by the firmware. ++ By default the overlay uses the i2c_csi_dsi I2C interface, but this ++ can be overridden + You MUST use either "disable_touchscreen=1" or "ignore_lcd=1" in + config.txt to stop the firmware polling the touchscreen. + Load: dtoverlay=edt-ft5406,= +@@ -1051,6 +1053,19 @@ Params: sizex Touchscr + invx Touchscreen inverted x axis + invy Touchscreen inverted y axis + swapxy Touchscreen swapped x y axis ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ i2c1 Choose the I2C1 bus on GPIOs 2&3 ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ i2c4 Choose the I2C4 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ i2c5 Choose the I2C5 bus (configure with the i2c5 ++ overlay - BCM2711 only) ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) ++ addr Sets the address for the touch controller. Note ++ that the device must be configured to use the ++ specified address. + + + Name: enc28j60 +--- a/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts ++++ b/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts +@@ -23,4 +23,24 @@ + status = "okay"; + }; + }; ++ ++ __overrides__ { ++ i2c0 = <&frag13>,"target:0=",<&i2c0>; ++ i2c1 = <&frag13>, "target?=0", ++ <&frag13>, "target-path=i2c1", ++ <0>,"-0-1"; ++ i2c3 = <&frag13>, "target?=0", ++ <&frag13>, "target-path=i2c3", ++ <0>,"-0-1"; ++ i2c4 = <&frag13>, "target?=0", ++ <&frag13>, "target-path=i2c4", ++ <0>,"-0-1"; ++ i2c5 = <&frag13>, "target?=0", ++ <&frag13>, "target-path=i2c5", ++ <0>,"-0-1"; ++ i2c6 = <&frag13>, "target?=0", ++ <&frag13>, "target-path=i2c6", ++ <0>,"-0-1"; ++ addr = <&ft5406>,"reg:0"; ++ }; + }; +--- a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi ++++ b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi +@@ -23,7 +23,7 @@ + }; + + fragment@12 { +- target = <&i2c_csi_dsi>; ++ target = <&i2cbus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; +@@ -37,6 +37,13 @@ + }; + }; + ++ frag13: fragment@13 { ++ target = <&i2c_csi_dsi>; ++ i2cbus: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { + sizex = <&ft5406>,"touchscreen-size-x:0"; + sizey = <&ft5406>,"touchscreen-size-y:0"; diff --git a/target/linux/bcm27xx/patches-6.1/950-0832-dtoverlays-Fix-README-text-for-i2c-fan.patch b/target/linux/bcm27xx/patches-6.1/950-0832-dtoverlays-Fix-README-text-for-i2c-fan.patch new file mode 100644 index 0000000000..23953c9636 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0832-dtoverlays-Fix-README-text-for-i2c-fan.patch @@ -0,0 +1,25 @@ +From 9d9586dc0c0deecb90675bd70862fe262f7376ab Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 14 Jun 2023 14:25:21 +0100 +Subject: [PATCH] dtoverlays: Fix README text for i2c-fan + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/README | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1800,10 +1800,10 @@ Params: addr Sets the + i2c3 Choose the I2C3 bus (configure with the i2c3 + overlay - BCM2711 only) + +- i2c4 Choose the I2C3 bus (configure with the i2c3 ++ i2c4 Choose the I2C4 bus (configure with the i2c4 + overlay - BCM2711 only) + +- i2c5 Choose the I2C5 bus (configure with the i2c4 ++ i2c5 Choose the I2C5 bus (configure with the i2c5 + overlay - BCM2711 only) + + i2c6 Choose the I2C6 bus (configure with the i2c6 diff --git a/target/linux/bcm27xx/patches-6.1/950-0833-drivers-irqchip-irq-bcm2835-Concurrency-fix.patch b/target/linux/bcm27xx/patches-6.1/950-0833-drivers-irqchip-irq-bcm2835-Concurrency-fix.patch new file mode 100644 index 0000000000..48e2fcdc74 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0833-drivers-irqchip-irq-bcm2835-Concurrency-fix.patch @@ -0,0 +1,50 @@ +From e804bd1843236a63815e9acfb1a38ebf9a28ef5b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 31 Aug 2023 16:45:44 +0100 +Subject: [PATCH] drivers: irqchip: irq-bcm2835: Concurrency fix + +The commit shown in Fixes: aims to improve interrupt throughput by +getting the handlers invoked on different CPU cores. It does so (*) by +using an irq_ack hook to change the interrupt routing. + +Unfortunately, the IRQ status bits must be cleared at source, which only +happens once the interrupt handler has run - there is no easy way for +one core to claim one of the IRQs before sending the remainder to the +next core on the list, so waking another core immediately results in a +race with a chance of both cores handling the same IRQ. It is probably +for this reason that the routing change is deferred to irq_ack, but that +doesn't guarantee no clashes - after irq_ack is called, control returns +to bcm2836_chained_handler_irq which proceeds to check for other pending +IRQs at a time when the next core is probably doing the same thing. + +Since the whole point of the original commit is to distribute the IRQ +handling, there is no reason to attempt to handle multiple IRQs in one +interrupt callback, so the problem can be solved (or at least made much +harder to reproduce) by changing a "while" into an "if", so that each +invocation only handles one IRQ. + +(*) I'm not convinced it's as effective as claimed since irq_ack is +called _after_ the interrupt handler, but the author thought it made a +difference. + +See: https://github.com/raspberrypi/linux/issues/5214 + https://github.com/raspberrypi/linux/pull/1794 + +Fixes: fd4c9785bde8 ("ARM64: Round-Robin dispatch IRQs between CPUs.") +Signed-off-by: Phil Elwell +--- + drivers/irqchip/irq-bcm2835.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/irqchip/irq-bcm2835.c ++++ b/drivers/irqchip/irq-bcm2835.c +@@ -343,7 +343,8 @@ static void bcm2836_chained_handle_irq(s + { + u32 hwirq; + +- while ((hwirq = get_next_armctrl_hwirq()) != ~0) ++ hwirq = get_next_armctrl_hwirq(); ++ if (hwirq != ~0) + generic_handle_domain_irq(intc.domain, hwirq); + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-0835-dtoverlays-Add-drm-option-to-piscreen-overlay.patch b/target/linux/bcm27xx/patches-6.1/950-0835-dtoverlays-Add-drm-option-to-piscreen-overlay.patch new file mode 100644 index 0000000000..10b1f15d2c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0835-dtoverlays-Add-drm-option-to-piscreen-overlay.patch @@ -0,0 +1,58 @@ +From 5e54398e1b61335883dff1be46a6c8b3ca973926 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 30 Aug 2023 18:03:37 +0100 +Subject: [PATCH] dtoverlays: Add drm option to piscreen overlay + +Adds the option of selecting the DRM/KMS TinyDRM driver for +this panel, rather than the deprecated FBTFT one. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/README | 3 +++ + arch/arm/boot/dts/overlays/piscreen-overlay.dts | 10 +++++++--- + 2 files changed, 10 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -3245,6 +3245,9 @@ Params: speed Display + + xohms Touchpanel sensitivity (X-plate resistance) + ++ drm Select the DRM/KMS driver instead of the FBTFT ++ one ++ + + Name: piscreen2r + Info: PiScreen 2 with resistive TP display by OzzMaker.com +--- a/arch/arm/boot/dts/overlays/piscreen-overlay.dts ++++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts +@@ -6,6 +6,8 @@ + /dts-v1/; + /plugin/; + ++#include ++ + / { + compatible = "brcm,bcm2835"; + +@@ -59,9 +61,9 @@ + fps = <30>; + buswidth = <8>; + regwidth = <16>; +- reset-gpios = <&gpio 25 1>; +- dc-gpios = <&gpio 24 0>; +- led-gpios = <&gpio 22 0>; ++ reset-gpios = <&gpio 25 GPIO_ACTIVE_LOW>; ++ dc-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; ++ led-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; + debug = <0>; + + init = <0x10000b0 0x00 +@@ -98,5 +100,7 @@ + fps = <&piscreen>,"fps:0"; + debug = <&piscreen>,"debug:0"; + xohms = <&piscreen_ts>,"ti,x-plate-ohms;0"; ++ drm = <&piscreen>,"compatible=waveshare,rpi-lcd-35", ++ <&piscreen>,"reset-gpios:8=",; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-0836-drm-ili9486-Resolve-clash-in-spi_device_id-names.patch b/target/linux/bcm27xx/patches-6.1/950-0836-drm-ili9486-Resolve-clash-in-spi_device_id-names.patch new file mode 100644 index 0000000000..0bce9f9e78 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0836-drm-ili9486-Resolve-clash-in-spi_device_id-names.patch @@ -0,0 +1,36 @@ +From f59fe2d1bd056af117eb512bb0e9210a943c6d47 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 1 Sep 2023 12:17:38 +0100 +Subject: [PATCH] drm/ili9486: Resolve clash in spi_device_id names + +For "Really Good Reasons" [1] the SPI core requires a match +between compatible device strings and the name in spi_device_id. + +The ili9486 driver uses compatible strings "waveshare,rpi-lcd-35" +and "ozzmaker,piscreen", but "rpi-lcd-35" and "piscreen" are missing, +so add them. + +Compatible string "ilitek,ili9486" is already used by +staging/fbtft/fb_ili9486, therefore leaving it present in ili9486 as an +spi_device_id causes the incorrect module to be loaded, therefore remove +this id. + +[1] https://elixir.bootlin.com/linux/latest/source/drivers/spi/spi.c#L487 + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/tiny/ili9486.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/tiny/ili9486.c ++++ b/drivers/gpu/drm/tiny/ili9486.c +@@ -187,7 +187,8 @@ static const struct of_device_id ili9486 + MODULE_DEVICE_TABLE(of, ili9486_of_match); + + static const struct spi_device_id ili9486_id[] = { +- { "ili9486", 0 }, ++ { "rpi-lcd-35", 0 }, ++ { "piscreen", 0 }, + { } + }; + MODULE_DEVICE_TABLE(spi, ili9486_id); diff --git a/target/linux/bcm27xx/patches-6.1/950-0837-input-ads7846-Add-missing-spi_device_id-strings.patch b/target/linux/bcm27xx/patches-6.1/950-0837-input-ads7846-Add-missing-spi_device_id-strings.patch new file mode 100644 index 0000000000..71f1063986 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0837-input-ads7846-Add-missing-spi_device_id-strings.patch @@ -0,0 +1,50 @@ +From 50c5a8558f4aaa54a3c4f5a8c2b6053f641d94eb Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 1 Sep 2023 12:23:30 +0100 +Subject: [PATCH] input: ads7846: Add missing spi_device_id strings + +The SPI core logs error messages if a compatible string device +name is not also present as an spi_device_id. + +No spi_device_id values are specified by the driver, therefore +we get 4 log lines every time it is loaded: +SPI driver ads7846 has no spi_device_id for ti,tsc2046 +SPI driver ads7846 has no spi_device_id for ti,ads7843 +SPI driver ads7846 has no spi_device_id for ti,ads7845 +SPI driver ads7846 has no spi_device_id for ti,ads7873 + +Add the spi_device_id values for these devices. + +Signed-off-by: Dave Stevenson +--- + drivers/input/touchscreen/ads7846.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/input/touchscreen/ads7846.c ++++ b/drivers/input/touchscreen/ads7846.c +@@ -1127,6 +1127,17 @@ static const struct of_device_id ads7846 + }; + MODULE_DEVICE_TABLE(of, ads7846_dt_ids); + ++static const struct spi_device_id ads7846_spi_ids[] = { ++ { "tsc2046", 0 }, ++ { "ads7843", 0 }, ++ { "ads7843", 0 }, ++ { "ads7845", 0 }, ++ { "ads7846", 0 }, ++ { "ads7873", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(spi, ads7846_spi_ids); ++ + static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) + { + struct ads7846_platform_data *pdata; +@@ -1424,6 +1435,7 @@ static struct spi_driver ads7846_driver + .pm = &ads7846_pm, + .of_match_table = of_match_ptr(ads7846_dt_ids), + }, ++ .id_table = ads7846_spi_ids, + .probe = ads7846_probe, + .remove = ads7846_remove, + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-0838-staging-bcm2835-codec-Downgrade-the-level-for-a-debu.patch b/target/linux/bcm27xx/patches-6.1/950-0838-staging-bcm2835-codec-Downgrade-the-level-for-a-debu.patch new file mode 100644 index 0000000000..5af23821a8 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0838-staging-bcm2835-codec-Downgrade-the-level-for-a-debu.patch @@ -0,0 +1,27 @@ +From 65742d7116e89b08858fcd7d67bd521ee19ee837 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 30 Aug 2023 18:05:43 +0100 +Subject: [PATCH] staging: bcm2835-codec: Downgrade the level for a debug + message + +The debug message from bcm2835_codec_buf_prepare when the buffer +size is incorrect can be a little spammy if the application isn't +careful on how it drives it, therefore drop the priority of the +message. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -2883,7 +2883,7 @@ static int bcm2835_codec_buf_prepare(str + } + + if (vb2_plane_size(vb, 0) < q_data->sizeimage) { +- v4l2_err(&ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n", ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->sizeimage); + return -EINVAL; diff --git a/target/linux/bcm27xx/patches-6.1/950-0840-gpio-fsm-Sort-functions-into-a-more-logical-order.patch b/target/linux/bcm27xx/patches-6.1/950-0840-gpio-fsm-Sort-functions-into-a-more-logical-order.patch new file mode 100644 index 0000000000..873077f51c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0840-gpio-fsm-Sort-functions-into-a-more-logical-order.patch @@ -0,0 +1,286 @@ +From cee471c3ada3215d6dfc53fb0f1b97548444dea7 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 5 Sep 2023 11:56:19 +0100 +Subject: [PATCH] gpio-fsm: Sort functions into a more logical order + +Move some functions into a more logical ordering. This change causes +no functional change and is essentially cosmetic. + +Signed-off-by: Phil Elwell +--- + drivers/gpio/gpio-fsm.c | 245 ++++++++++++++++++++-------------------- + 1 file changed, 125 insertions(+), 120 deletions(-) + +--- a/drivers/gpio/gpio-fsm.c ++++ b/drivers/gpio/gpio-fsm.c +@@ -193,131 +193,14 @@ static void free_symbols(struct symtab_e + } + } + +-static int gpio_fsm_get_direction(struct gpio_chip *gc, unsigned int off) +-{ +- struct gpio_fsm *gf = gpiochip_get_data(gc); +- struct soft_gpio *sg; +- +- if (off >= gf->num_soft_gpios) +- return -EINVAL; +- sg = &gf->soft_gpios[off]; +- +- return sg->dir; +-} +- +-static int gpio_fsm_get(struct gpio_chip *gc, unsigned int off) +-{ +- struct gpio_fsm *gf = gpiochip_get_data(gc); +- struct soft_gpio *sg; +- +- if (off >= gf->num_soft_gpios) +- return -EINVAL; +- sg = &gf->soft_gpios[off]; +- +- return sg->value; +-} +- + static void gpio_fsm_go_to_state(struct gpio_fsm *gf, +- struct fsm_state *new_state) +-{ +- struct input_gpio_state *inp_state; +- struct gpio_event *gp_ev; +- struct fsm_state *state; +- int i; +- +- dev_dbg(gf->dev, "go_to_state(%s)\n", +- new_state ? new_state->name : ""); +- +- spin_lock(&gf->spinlock); +- +- if (gf->next_state) { +- /* Something else has already requested a transition */ +- spin_unlock(&gf->spinlock); +- return; +- } +- +- gf->next_state = new_state; +- state = gf->current_state; +- gf->delay_target_state = NULL; +- +- if (state) { +- /* Disarm any GPIO IRQs */ +- for (i = 0; i < state->num_gpio_events; i++) { +- gp_ev = &state->gpio_events[i]; +- inp_state = &gf->input_gpio_states[gp_ev->index]; +- inp_state->target = NULL; +- } +- } +- +- spin_unlock(&gf->spinlock); +- +- if (new_state) +- schedule_work(&gf->work); +-} ++ struct fsm_state *new_state); + + static void gpio_fsm_set_soft(struct gpio_fsm *gf, +- unsigned int off, int val) +-{ +- struct soft_gpio *sg = &gf->soft_gpios[off]; +- struct gpio_event *gp_ev; +- struct fsm_state *state; +- int i; +- +- dev_dbg(gf->dev, "set(%d,%d)\n", off, val); +- state = gf->current_state; +- sg->value = val; +- for (i = 0; i < state->num_soft_events; i++) { +- gp_ev = &state->soft_events[i]; +- if (gp_ev->index == off && gp_ev->value == val) { +- if (gf->debug) +- dev_info(gf->dev, +- "GF_SOFT %d->%d -> %s\n", gp_ev->index, +- gp_ev->value, gp_ev->target->name); +- gpio_fsm_go_to_state(gf, gp_ev->target); +- break; +- } +- } +-} +- +-static int gpio_fsm_direction_input(struct gpio_chip *gc, unsigned int off) +-{ +- struct gpio_fsm *gf = gpiochip_get_data(gc); +- struct soft_gpio *sg; +- +- if (off >= gf->num_soft_gpios) +- return -EINVAL; +- sg = &gf->soft_gpios[off]; +- sg->dir = GPIOF_DIR_IN; +- +- return 0; +-} +- +-static int gpio_fsm_direction_output(struct gpio_chip *gc, unsigned int off, +- int value) +-{ +- struct gpio_fsm *gf = gpiochip_get_data(gc); +- struct soft_gpio *sg; +- +- if (off >= gf->num_soft_gpios) +- return -EINVAL; +- sg = &gf->soft_gpios[off]; +- sg->dir = GPIOF_DIR_OUT; +- gpio_fsm_set_soft(gf, off, value); +- +- return 0; +-} +- +-static void gpio_fsm_set(struct gpio_chip *gc, unsigned int off, int val) +-{ +- struct gpio_fsm *gf; +- +- gf = gpiochip_get_data(gc); +- if (off < gf->num_soft_gpios) +- gpio_fsm_set_soft(gf, off, val); +-} ++ unsigned int off, int val); + + static void gpio_fsm_enter_state(struct gpio_fsm *gf, +- struct fsm_state *state) ++ struct fsm_state *state) + { + struct input_gpio_state *inp_state; + struct output_signal *signal; +@@ -431,6 +314,44 @@ static void gpio_fsm_enter_state(struct + } + } + ++static void gpio_fsm_go_to_state(struct gpio_fsm *gf, ++ struct fsm_state *new_state) ++{ ++ struct input_gpio_state *inp_state; ++ struct gpio_event *gp_ev; ++ struct fsm_state *state; ++ int i; ++ ++ dev_dbg(gf->dev, "go_to_state(%s)\n", ++ new_state ? new_state->name : ""); ++ ++ spin_lock(&gf->spinlock); ++ ++ if (gf->next_state) { ++ /* Something else has already requested a transition */ ++ spin_unlock(&gf->spinlock); ++ return; ++ } ++ ++ gf->next_state = new_state; ++ state = gf->current_state; ++ gf->delay_target_state = NULL; ++ ++ if (state) { ++ /* Disarm any GPIO IRQs */ ++ for (i = 0; i < state->num_gpio_events; i++) { ++ gp_ev = &state->gpio_events[i]; ++ inp_state = &gf->input_gpio_states[gp_ev->index]; ++ inp_state->target = NULL; ++ } ++ } ++ ++ spin_unlock(&gf->spinlock); ++ ++ if (new_state) ++ schedule_work(&gf->work); ++} ++ + static void gpio_fsm_work(struct work_struct *work) + { + struct input_gpio_state *inp_state; +@@ -851,6 +772,90 @@ static int resolve_sym_to_state(struct g + return 0; + } + ++static void gpio_fsm_set_soft(struct gpio_fsm *gf, ++ unsigned int off, int val) ++{ ++ struct soft_gpio *sg = &gf->soft_gpios[off]; ++ struct gpio_event *gp_ev; ++ struct fsm_state *state; ++ int i; ++ ++ dev_dbg(gf->dev, "set(%d,%d)\n", off, val); ++ state = gf->current_state; ++ sg->value = val; ++ for (i = 0; i < state->num_soft_events; i++) { ++ gp_ev = &state->soft_events[i]; ++ if (gp_ev->index == off && gp_ev->value == val) { ++ if (gf->debug) ++ dev_info(gf->dev, ++ "GF_SOFT %d->%d -> %s\n", gp_ev->index, ++ gp_ev->value, gp_ev->target->name); ++ gpio_fsm_go_to_state(gf, gp_ev->target); ++ break; ++ } ++ } ++} ++ ++static int gpio_fsm_get(struct gpio_chip *gc, unsigned int off) ++{ ++ struct gpio_fsm *gf = gpiochip_get_data(gc); ++ struct soft_gpio *sg; ++ ++ if (off >= gf->num_soft_gpios) ++ return -EINVAL; ++ sg = &gf->soft_gpios[off]; ++ ++ return sg->value; ++} ++ ++static void gpio_fsm_set(struct gpio_chip *gc, unsigned int off, int val) ++{ ++ struct gpio_fsm *gf; ++ ++ gf = gpiochip_get_data(gc); ++ if (off < gf->num_soft_gpios) ++ gpio_fsm_set_soft(gf, off, val); ++} ++ ++static int gpio_fsm_get_direction(struct gpio_chip *gc, unsigned int off) ++{ ++ struct gpio_fsm *gf = gpiochip_get_data(gc); ++ struct soft_gpio *sg; ++ ++ if (off >= gf->num_soft_gpios) ++ return -EINVAL; ++ sg = &gf->soft_gpios[off]; ++ ++ return sg->dir; ++} ++ ++static int gpio_fsm_direction_input(struct gpio_chip *gc, unsigned int off) ++{ ++ struct gpio_fsm *gf = gpiochip_get_data(gc); ++ struct soft_gpio *sg; ++ ++ if (off >= gf->num_soft_gpios) ++ return -EINVAL; ++ sg = &gf->soft_gpios[off]; ++ sg->dir = GPIOF_DIR_IN; ++ ++ return 0; ++} ++ ++static int gpio_fsm_direction_output(struct gpio_chip *gc, unsigned int off, ++ int value) ++{ ++ struct gpio_fsm *gf = gpiochip_get_data(gc); ++ struct soft_gpio *sg; ++ ++ if (off >= gf->num_soft_gpios) ++ return -EINVAL; ++ sg = &gf->soft_gpios[off]; ++ sg->dir = GPIOF_DIR_OUT; ++ gpio_fsm_set_soft(gf, off, value); ++ ++ return 0; ++} + + /* + * /sys/class/gpio-fsm// diff --git a/target/linux/bcm27xx/patches-6.1/950-0841-gpio_fsm-Rework-the-atomic-vs-non-atomic-split.patch b/target/linux/bcm27xx/patches-6.1/950-0841-gpio_fsm-Rework-the-atomic-vs-non-atomic-split.patch new file mode 100644 index 0000000000..ae3c019e25 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0841-gpio_fsm-Rework-the-atomic-vs-non-atomic-split.patch @@ -0,0 +1,192 @@ +From f0061ffc98c6e027c5774e2a24ceadcfee4167ea Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 5 Sep 2023 12:01:13 +0100 +Subject: [PATCH] gpio_fsm: Rework the atomic-vs-non-atomic split + +Partition the code to separate atomic and non-atomic methods so that +none of them have to handle both cases. The result avoids using deferred +work unless necessary, and should be easier to understand. + +Signed-off-by: Phil Elwell +--- + drivers/gpio/gpio-fsm.c | 84 ++++++++++++++++++++--------------------- + 1 file changed, 41 insertions(+), 43 deletions(-) + +--- a/drivers/gpio/gpio-fsm.c ++++ b/drivers/gpio/gpio-fsm.c +@@ -193,9 +193,6 @@ static void free_symbols(struct symtab_e + } + } + +-static void gpio_fsm_go_to_state(struct gpio_fsm *gf, +- struct fsm_state *new_state); +- + static void gpio_fsm_set_soft(struct gpio_fsm *gf, + unsigned int off, int val); + +@@ -213,6 +210,7 @@ static void gpio_fsm_enter_state(struct + dev_dbg(gf->dev, "enter_state(%s)\n", state->name); + + gf->current_state = state; ++ gf->delay_target_state = NULL; + + // 1. Apply any listed signals + for (i = 0; i < state->num_signals; i++) { +@@ -271,7 +269,7 @@ static void gpio_fsm_enter_state(struct + dev_info(gf->dev, + "GF_SOFT %d=%d -> %s\n", event->index, + event->value, event->target->name); +- gpio_fsm_go_to_state(gf, event->target); ++ gpio_fsm_enter_state(gf, event->target); + return; + } + } +@@ -284,7 +282,7 @@ static void gpio_fsm_enter_state(struct + inp_state->value = event->value; + inp_state->enabled = true; + +- value = gpiod_get_value(gf->input_gpios->desc[event->index]); ++ value = gpiod_get_value_cansleep(gf->input_gpios->desc[event->index]); + + // Clear stale event state + disable_irq(inp_state->irq); +@@ -299,7 +297,7 @@ static void gpio_fsm_enter_state(struct + dev_info(gf->dev, + "GF_IN %d=%d -> %s\n", event->index, + event->value, event->target->name); +- gpio_fsm_go_to_state(gf, event->target); ++ gpio_fsm_enter_state(gf, event->target); + return; + } + } +@@ -325,6 +323,33 @@ static void gpio_fsm_go_to_state(struct + dev_dbg(gf->dev, "go_to_state(%s)\n", + new_state ? new_state->name : ""); + ++ state = gf->current_state; ++ ++ /* Disable any enabled GPIO IRQs */ ++ for (i = 0; i < state->num_gpio_events; i++) { ++ gp_ev = &state->gpio_events[i]; ++ inp_state = &gf->input_gpio_states[gp_ev->index]; ++ if (inp_state->enabled) { ++ inp_state->enabled = false; ++ irq_set_irq_type(inp_state->irq, ++ IRQF_TRIGGER_NONE); ++ } ++ } ++ ++ gpio_fsm_enter_state(gf, new_state); ++} ++ ++static void gpio_fsm_go_to_state_deferred(struct gpio_fsm *gf, ++ struct fsm_state *new_state) ++{ ++ struct input_gpio_state *inp_state; ++ struct gpio_event *gp_ev; ++ struct fsm_state *state; ++ int i; ++ ++ dev_dbg(gf->dev, "go_to_state_deferred(%s)\n", ++ new_state ? new_state->name : ""); ++ + spin_lock(&gf->spinlock); + + if (gf->next_state) { +@@ -335,57 +360,31 @@ static void gpio_fsm_go_to_state(struct + + gf->next_state = new_state; + state = gf->current_state; +- gf->delay_target_state = NULL; + +- if (state) { +- /* Disarm any GPIO IRQs */ +- for (i = 0; i < state->num_gpio_events; i++) { +- gp_ev = &state->gpio_events[i]; +- inp_state = &gf->input_gpio_states[gp_ev->index]; +- inp_state->target = NULL; +- } ++ /* Disarm any GPIO IRQs */ ++ for (i = 0; i < state->num_gpio_events; i++) { ++ gp_ev = &state->gpio_events[i]; ++ inp_state = &gf->input_gpio_states[gp_ev->index]; ++ inp_state->target = NULL; + } + + spin_unlock(&gf->spinlock); + +- if (new_state) +- schedule_work(&gf->work); ++ schedule_work(&gf->work); + } + + static void gpio_fsm_work(struct work_struct *work) + { +- struct input_gpio_state *inp_state; + struct fsm_state *new_state; +- struct fsm_state *state; +- struct gpio_event *gp_ev; + struct gpio_fsm *gf; +- int i; + + gf = container_of(work, struct gpio_fsm, work); + spin_lock(&gf->spinlock); +- state = gf->current_state; + new_state = gf->next_state; +- if (!new_state) +- new_state = gf->delay_target_state; + gf->next_state = NULL; +- gf->delay_target_state = NULL; + spin_unlock(&gf->spinlock); + +- if (state) { +- /* Disable any enabled GPIO IRQs */ +- for (i = 0; i < state->num_gpio_events; i++) { +- gp_ev = &state->gpio_events[i]; +- inp_state = &gf->input_gpio_states[gp_ev->index]; +- if (inp_state->enabled) { +- inp_state->enabled = false; +- irq_set_irq_type(inp_state->irq, +- IRQF_TRIGGER_NONE); +- } +- } +- } +- +- if (new_state) +- gpio_fsm_enter_state(gf, new_state); ++ gpio_fsm_go_to_state(gf, new_state); + } + + static irqreturn_t gpio_fsm_gpio_irq_handler(int irq, void *dev_id) +@@ -404,7 +403,7 @@ static irqreturn_t gpio_fsm_gpio_irq_han + if (gf->debug) + dev_info(gf->dev, "GF_IN %d->%d -> %s\n", + inp_state->index, inp_state->value, target->name); +- gpio_fsm_go_to_state(gf, target); ++ gpio_fsm_go_to_state_deferred(gf, target); + return IRQ_HANDLED; + } + +@@ -416,12 +415,11 @@ static void gpio_fsm_timer(struct timer_ + target = gf->delay_target_state; + if (!target) + return; +- + if (gf->debug) + dev_info(gf->dev, "GF_DELAY %d -> %s\n", gf->delay_ms, + target->name); + +- gpio_fsm_go_to_state(gf, target); ++ gpio_fsm_go_to_state_deferred(gf, target); + } + + int gpio_fsm_parse_signals(struct gpio_fsm *gf, struct fsm_state *state, +@@ -1119,7 +1117,7 @@ static int gpio_fsm_probe(struct platfor + if (gf->debug) + dev_info(gf->dev, "Start -> %s\n", gf->start_state->name); + +- gpio_fsm_go_to_state(gf, gf->start_state); ++ gpio_fsm_enter_state(gf, gf->start_state); + + return devm_gpiochip_add_data(dev, &gf->gc, gf); + } diff --git a/target/linux/bcm27xx/patches-6.1/950-0842-f2fs-fix-to-avoid-NULL-pointer-dereference-in-f2fs_i.patch b/target/linux/bcm27xx/patches-6.1/950-0842-f2fs-fix-to-avoid-NULL-pointer-dereference-in-f2fs_i.patch new file mode 100644 index 0000000000..33150551b3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0842-f2fs-fix-to-avoid-NULL-pointer-dereference-in-f2fs_i.patch @@ -0,0 +1,63 @@ +From bf9fb25f3265605572f04e5c7836bb83ee345236 Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Fri, 30 Dec 2022 23:43:32 +0800 +Subject: [PATCH] f2fs: fix to avoid NULL pointer dereference in + f2fs_issue_flush() + +commit b3d83066cbebc76dbac8a5fca931f64b4c6fff34 upstream. + +With below two cases, it will cause NULL pointer dereference when +accessing SM_I(sbi)->fcc_info in f2fs_issue_flush(). + +a) If kthread_run() fails in f2fs_create_flush_cmd_control(), it will +release SM_I(sbi)->fcc_info, + +- mount -o noflush_merge /dev/vda /mnt/f2fs +- mount -o remount,flush_merge /dev/vda /mnt/f2fs -- kthread_run() fails +- dd if=/dev/zero of=/mnt/f2fs/file bs=4k count=1 conv=fsync + +b) we will never allocate memory for SM_I(sbi)->fcc_info w/ below +testcase, + +- mount -o ro /dev/vda /mnt/f2fs +- mount -o rw,remount /dev/vda /mnt/f2fs +- dd if=/dev/zero of=/mnt/f2fs/file bs=4k count=1 conv=fsync + +In order to fix this issue, let change as below: +- fix error path handling in f2fs_create_flush_cmd_control(). +- allocate SM_I(sbi)->fcc_info even if readonly is on. + +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +--- + fs/f2fs/segment.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -663,9 +663,7 @@ init_thread: + "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev)); + if (IS_ERR(fcc->f2fs_issue_flush)) { + err = PTR_ERR(fcc->f2fs_issue_flush); +- kfree(fcc); +- SM_I(sbi)->fcc_info = NULL; +- return err; ++ fcc->f2fs_issue_flush = NULL; + } + + return err; +@@ -5062,11 +5060,9 @@ int f2fs_build_segment_manager(struct f2 + + init_f2fs_rwsem(&sm_info->curseg_lock); + +- if (!f2fs_readonly(sbi->sb)) { +- err = f2fs_create_flush_cmd_control(sbi); +- if (err) +- return err; +- } ++ err = f2fs_create_flush_cmd_control(sbi); ++ if (err) ++ return err; + + err = create_discard_cmd_control(sbi); + if (err) diff --git a/target/linux/bcm27xx/patches-6.1/950-0177-hwrng-iproc-rng200-Add-BCM2838-support.patch b/target/linux/bcm27xx/patches-6.1/950-0846-hwrng-iproc-rng200-Add-BCM2838-support.patch similarity index 88% rename from target/linux/bcm27xx/patches-6.1/950-0177-hwrng-iproc-rng200-Add-BCM2838-support.patch rename to target/linux/bcm27xx/patches-6.1/950-0846-hwrng-iproc-rng200-Add-BCM2838-support.patch index 9a36dd1bcd..a179d930df 100644 --- a/target/linux/bcm27xx/patches-6.1/950-0177-hwrng-iproc-rng200-Add-BCM2838-support.patch +++ b/target/linux/bcm27xx/patches-6.1/950-0846-hwrng-iproc-rng200-Add-BCM2838-support.patch @@ -1,4 +1,4 @@ -From b642f64d629df5515f3a01fc5b2e17c3fa7b404c Mon Sep 17 00:00:00 2001 +From e079555a4c68356e58249cfc041b28f6eb455bd5 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 4 May 2019 17:06:15 +0200 Subject: [PATCH] hwrng: iproc-rng200: Add BCM2838 support @@ -17,8 +17,8 @@ Fixes: "hwrng: iproc-rng200: Add BCM2838 support" Signed-off-by: Phil Elwell --- drivers/char/hw_random/Kconfig | 2 +- - drivers/char/hw_random/iproc-rng200.c | 78 +++++++++++++++++++++++++-- - 2 files changed, 76 insertions(+), 4 deletions(-) + drivers/char/hw_random/iproc-rng200.c | 79 ++++++++++++++++++++++++++- + 2 files changed, 77 insertions(+), 4 deletions(-) --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -33,7 +33,15 @@ Signed-off-by: Phil Elwell module will be called iproc-rng200 --- a/drivers/char/hw_random/iproc-rng200.c +++ b/drivers/char/hw_random/iproc-rng200.c -@@ -21,6 +21,7 @@ +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -21,6 +22,7 @@ #define RNG_CTRL_OFFSET 0x00 #define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF #define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001 @@ -41,7 +49,7 @@ Signed-off-by: Phil Elwell #define RNG_SOFT_RESET_OFFSET 0x04 #define RNG_SOFT_RESET 0x00000001 -@@ -28,16 +29,23 @@ +@@ -28,16 +30,23 @@ #define RBG_SOFT_RESET_OFFSET 0x08 #define RBG_SOFT_RESET 0x00000001 @@ -65,7 +73,7 @@ Signed-off-by: Phil Elwell struct iproc_rng200_dev { struct hwrng rng; -@@ -158,6 +166,64 @@ static int iproc_rng200_init(struct hwrn +@@ -158,6 +167,64 @@ static int iproc_rng200_init(struct hwrn return 0; } @@ -130,7 +138,7 @@ Signed-off-by: Phil Elwell static void iproc_rng200_cleanup(struct hwrng *rng) { struct iproc_rng200_dev *priv = to_rng_priv(rng); -@@ -184,11 +250,17 @@ static int iproc_rng200_probe(struct pla +@@ -184,11 +251,17 @@ static int iproc_rng200_probe(struct pla dev_set_drvdata(dev, priv); diff --git a/target/linux/bcm27xx/patches-6.1/950-0847-PCI-brcmstb-Wait-for-100ms-following-PERST-deassert.patch b/target/linux/bcm27xx/patches-6.1/950-0847-PCI-brcmstb-Wait-for-100ms-following-PERST-deassert.patch new file mode 100644 index 0000000000..b08676253e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0847-PCI-brcmstb-Wait-for-100ms-following-PERST-deassert.patch @@ -0,0 +1,39 @@ +From 6f634d7efb8876e5953c30c0a613aaa5f575fe05 Mon Sep 17 00:00:00 2001 +From: Jim Quinlan +Date: Tue, 11 Oct 2022 14:42:07 -0400 +Subject: [PATCH] PCI: brcmstb: Wait for 100ms following PERST# deassert + +commit 3ae140ad827b359bc4fa7c7985691c4c1e3ca8f4 upstream. + +Be prudent and give some time for power and clocks to become stable. As +described in the PCIe CEM specification sections 2.2 and 2.2.1; as well as +PCIe r5.0, 6.6.1. + +Link: https://lore.kernel.org/r/20221011184211.18128-3-jim2101024@gmail.com +Signed-off-by: Jim Quinlan +Signed-off-by: Lorenzo Pieralisi +Acked-by: Florian Fainelli +--- + drivers/pci/controller/pcie-brcmstb.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -1038,8 +1038,15 @@ static int brcm_pcie_start_link(struct b + pcie->perst_set(pcie, 0); + + /* +- * Give the RC/EP time to wake up, before trying to configure RC. +- * Intermittently check status for link-up, up to a total of 100ms. ++ * Wait for 100ms after PERST# deassertion; see PCIe CEM specification ++ * sections 2.2, PCIe r5.0, 6.6.1. ++ */ ++ msleep(100); ++ ++ /* ++ * Give the RC/EP even more time to wake up, before trying to ++ * configure RC. Intermittently check status for link-up, up to a ++ * total of 100ms. + */ + for (i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5) + msleep(5); diff --git a/target/linux/bcm27xx/patches-6.1/950-0850-overlays-Add-a-sample-hat_map.patch b/target/linux/bcm27xx/patches-6.1/950-0850-overlays-Add-a-sample-hat_map.patch new file mode 100644 index 0000000000..19550b6fd5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0850-overlays-Add-a-sample-hat_map.patch @@ -0,0 +1,47 @@ +From cc08810f89e52337a99cc6ae5f53f08588357c5f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 19 Sep 2023 20:31:34 +0100 +Subject: [PATCH] overlays: Add a sample hat_map + +The HAT map is way of associating named overlays with HATs whose +EEPROMs were programmed with the contents of the overlay. +Unfortunately, change in the DT and kernel drivers has meant that some +of these embedded overlays no longer function, or even don't apply. + +The HAT map is a mapping from HAT UUIDs to overlay names. If a HAT with +a listed UUID is detected, the embedded overlay is ignored and the +overlay named in the mapping is loaded in its place. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/Makefile | 2 +- + arch/arm/boot/dts/overlays/hat_map.dts | 13 +++++++++++++ + 2 files changed, 14 insertions(+), 1 deletion(-) + create mode 100644 arch/arm/boot/dts/overlays/hat_map.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -1,6 +1,6 @@ + # Overlays for the Raspberry Pi platform + +-dtb-$(CONFIG_ARCH_BCM2835) += overlay_map.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += overlay_map.dtb hat_map.dtb + + dtbo-$(CONFIG_ARCH_BCM2835) += \ + act-led.dtbo \ +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hat_map.dts +@@ -0,0 +1,13 @@ ++/dts-v1/; ++ ++/ { ++ iqaudio-pi-codecplus { ++ uuid = [ dc1c9594 c1ab 4c6c acda a88dc59a3c5b ]; ++ overlay = "iqaudio-codec"; ++ }; ++ ++ recalbox-rgbdual { ++ uuid = [ 1c955808 681f 4bbc a2ef b7ea47cd388e ]; ++ overlay = "recalboxrgbdual"; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-6.1/950-0851-Revert-usb-phy-generic-Get-the-vbus-supply.patch b/target/linux/bcm27xx/patches-6.1/950-0851-Revert-usb-phy-generic-Get-the-vbus-supply.patch new file mode 100644 index 0000000000..aaf49e6a7c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0851-Revert-usb-phy-generic-Get-the-vbus-supply.patch @@ -0,0 +1,26 @@ +From 406e7dc82be6ce1b81c88b418640daeef6c2be42 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Mon, 23 May 2022 16:56:44 +0100 +Subject: [PATCH] Revert "usb: phy: generic: Get the vbus supply" + +This reverts commit c0ea202fbc855d60bc4a0603ca52a9e80654b327. +--- + drivers/usb/phy/phy-generic.c | 7 ------- + 1 file changed, 7 deletions(-) + +--- a/drivers/usb/phy/phy-generic.c ++++ b/drivers/usb/phy/phy-generic.c +@@ -265,13 +265,6 @@ int usb_phy_gen_create_phy(struct device + return -EPROBE_DEFER; + } + +- nop->vbus_draw = devm_regulator_get_exclusive(dev, "vbus"); +- if (PTR_ERR(nop->vbus_draw) == -ENODEV) +- nop->vbus_draw = NULL; +- if (IS_ERR(nop->vbus_draw)) +- return dev_err_probe(dev, PTR_ERR(nop->vbus_draw), +- "could not get vbus regulator\n"); +- + nop->dev = dev; + nop->phy.dev = nop->dev; + nop->phy.label = "nop-xceiv"; diff --git a/target/linux/bcm27xx/patches-6.1/950-0853-dts-2712-Update-for-device-tree.patch b/target/linux/bcm27xx/patches-6.1/950-0853-dts-2712-Update-for-device-tree.patch new file mode 100644 index 0000000000..6a5c40ef4e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0853-dts-2712-Update-for-device-tree.patch @@ -0,0 +1,7672 @@ +From 1196bf1a7736ff0ab79f5012fa84082e298031a7 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Tue, 19 Sep 2023 15:55:00 +0100 +Subject: [PATCH] dts: 2712: Update for device tree + +dtoverlays: Fix up edt5406 entries to match with vc4-kms-dsi-7inch + +vc4-kms-dsi-7inch expects the touch fragment to be named ts_i2c_frag, +but edt5406 didn't do this. + +Fixes: 736d601fb38c ("dts: 2712: Update for device tree") + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/Makefile | 3 +- + arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 3 + + arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts | 3 + + arch/arm/boot/dts/bcm2708-rpi-b.dts | 3 + + arch/arm/boot/dts/bcm2708-rpi-cm.dts | 3 + + arch/arm/boot/dts/bcm2708-rpi-zero-w.dts | 1 + + arch/arm/boot/dts/bcm2708-rpi-zero.dts | 1 + + arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 3 + + arch/arm/boot/dts/bcm2709-rpi-cm2.dts | 3 + + arch/arm/boot/dts/bcm270x-rpi.dtsi | 3 + + arch/arm/boot/dts/bcm2710-rpi-2-b.dts | 3 + + arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 3 + + arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 3 + + arch/arm/boot/dts/bcm2710-rpi-cm3.dts | 3 + + arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts | 3 + + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 3 + + arch/arm/boot/dts/bcm2711-rpi-cm4.dts | 3 + + arch/arm/boot/dts/bcm2711-rpi-cm4s.dts | 3 + + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 824 +++++++++++ + arch/arm/boot/dts/bcm2712-rpi.dtsi | 281 ++++ + arch/arm/boot/dts/bcm2712.dtsi | 1287 +++++++++++++++++ + arch/arm/boot/dts/overlays/Makefile | 23 + + arch/arm/boot/dts/overlays/README | 360 ++++- + .../dts/overlays/adau1977-adc-overlay.dts | 4 +- + .../dts/overlays/adau7002-simple-overlay.dts | 4 +- + .../overlays/akkordion-iqdacplus-overlay.dts | 4 +- + .../allo-boss-dac-pcm512x-audio-overlay.dts | 10 +- + .../overlays/allo-boss2-dac-audio-overlay.dts | 2 +- + .../dts/overlays/allo-digione-overlay.dts | 4 +- + .../allo-katana-dac-audio-overlay.dts | 2 +- + .../allo-piano-dac-pcm512x-audio-overlay.dts | 4 +- + ...o-piano-dac-plus-pcm512x-audio-overlay.dts | 4 +- + .../boot/dts/overlays/applepi-dac-overlay.dts | 4 +- + .../dts/overlays/arducam-64mp-overlay.dts | 2 +- + .../overlays/arducam-pivariety-overlay.dts | 2 +- + .../overlays/audioinjector-addons-overlay.dts | 4 +- + .../audioinjector-bare-i2s-overlay.dts | 6 +- + ...dioinjector-isolated-soundcard-overlay.dts | 4 +- + .../overlays/audioinjector-ultra-overlay.dts | 6 +- + .../audioinjector-wm8731-audio-overlay.dts | 4 +- + .../dts/overlays/audiosense-pi-overlay.dts | 4 +- + .../boot/dts/overlays/chipdip-dac-overlay.dts | 4 +- + .../dts/overlays/cirrus-wm5102-overlay.dts | 4 +- + .../boot/dts/overlays/dacberry400-overlay.dts | 4 +- + .../dts/overlays/dionaudio-kiwi-overlay.dts | 4 +- + .../dts/overlays/dionaudio-loco-overlay.dts | 4 +- + .../overlays/dionaudio-loco-v2-overlay.dts | 4 +- + .../dts/overlays/disable-bt-pi5-overlay.dts | 17 + + .../dts/overlays/disable-wifi-pi5-overlay.dts | 13 + + arch/arm/boot/dts/overlays/draws-overlay.dts | 6 +- + .../boot/dts/overlays/edt-ft5406-overlay.dts | 22 +- + arch/arm/boot/dts/overlays/edt-ft5406.dtsi | 2 +- + .../boot/dts/overlays/fe-pi-audio-overlay.dts | 4 +- + .../boot/dts/overlays/ghost-amp-overlay.dts | 4 +- + .../googlevoicehat-soundcard-overlay.dts | 4 +- + .../dts/overlays/hifiberry-amp-overlay.dts | 4 +- + .../dts/overlays/hifiberry-amp100-overlay.dts | 11 +- + .../dts/overlays/hifiberry-amp3-overlay.dts | 4 +- + .../dts/overlays/hifiberry-dac-overlay.dts | 4 +- + .../overlays/hifiberry-dacplus-overlay.dts | 11 +- + .../overlays/hifiberry-dacplusadc-overlay.dts | 10 +- + .../hifiberry-dacplusadcpro-overlay.dts | 10 +- + .../overlays/hifiberry-dacplusdsp-overlay.dts | 4 +- + .../overlays/hifiberry-dacplushd-overlay.dts | 4 +- + .../dts/overlays/hifiberry-digi-overlay.dts | 4 +- + .../overlays/hifiberry-digi-pro-overlay.dts | 4 +- + .../boot/dts/overlays/i-sabre-q2m-overlay.dts | 4 +- + .../boot/dts/overlays/i2c0-pi5-overlay.dts | 34 + + .../boot/dts/overlays/i2c1-pi5-overlay.dts | 34 + + .../boot/dts/overlays/i2c2-pi5-overlay.dts | 21 + + .../boot/dts/overlays/i2c3-pi5-overlay.dts | 22 + + .../arm/boot/dts/overlays/i2s-dac-overlay.dts | 4 +- + arch/arm/boot/dts/overlays/imx219-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/imx258-overlay.dts | 2 +- + .../boot/dts/overlays/imx290_327-overlay.dtsi | 2 +- + arch/arm/boot/dts/overlays/imx296-overlay.dts | 2 +- + .../boot/dts/overlays/imx477_378-overlay.dtsi | 2 +- + arch/arm/boot/dts/overlays/imx519-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/imx708-overlay.dts | 4 +- + .../dts/overlays/iqaudio-codec-overlay.dts | 4 +- + .../boot/dts/overlays/iqaudio-dac-overlay.dts | 4 +- + .../dts/overlays/iqaudio-dacplus-overlay.dts | 4 +- + .../iqaudio-digi-wm8804-audio-overlay.dts | 4 +- + .../arm/boot/dts/overlays/irs1125-overlay.dts | 2 +- + .../dts/overlays/justboom-both-overlay.dts | 4 +- + .../dts/overlays/justboom-dac-overlay.dts | 4 +- + .../dts/overlays/justboom-digi-overlay.dts | 4 +- + .../boot/dts/overlays/max98357a-overlay.dts | 6 +- + .../boot/dts/overlays/mbed-dac-overlay.dts | 6 +- + .../boot/dts/overlays/merus-amp-overlay.dts | 4 +- + .../dts/overlays/midi-uart0-pi5-overlay.dts | 35 + + .../dts/overlays/midi-uart1-pi5-overlay.dts | 35 + + .../dts/overlays/midi-uart2-pi5-overlay.dts | 35 + + .../dts/overlays/midi-uart3-pi5-overlay.dts | 35 + + .../dts/overlays/midi-uart4-pi5-overlay.dts | 35 + + arch/arm/boot/dts/overlays/ov2311-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/ov5647-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/ov7251-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/ov9281-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/overlay_map.dts | 226 +++ + arch/arm/boot/dts/overlays/pibell-overlay.dts | 6 +- + .../arm/boot/dts/overlays/pifi-40-overlay.dts | 4 +- + .../boot/dts/overlays/pifi-dac-hd-overlay.dts | 4 +- + .../dts/overlays/pifi-dac-zero-overlay.dts | 4 +- + .../dts/overlays/pifi-mini-210-overlay.dts | 4 +- + .../arm/boot/dts/overlays/pisound-overlay.dts | 4 +- + .../boot/dts/overlays/proto-codec-overlay.dts | 4 +- + .../rra-digidac1-wm8741-audio-overlay.dts | 4 +- + .../dts/overlays/spi2-1cs-pi5-overlay.dts | 33 + + .../dts/overlays/spi2-2cs-pi5-overlay.dts | 44 + + .../dts/overlays/spi3-1cs-pi5-overlay.dts | 33 + + .../dts/overlays/spi3-2cs-pi5-overlay.dts | 44 + + .../dts/overlays/spi5-1cs-pi5-overlay.dts | 33 + + .../dts/overlays/spi5-2cs-pi5-overlay.dts | 44 + + .../dts/overlays/superaudioboard-overlay.dts | 6 +- + .../dts/overlays/tc358743-audio-overlay.dts | 10 +- + .../boot/dts/overlays/tc358743-overlay.dts | 2 +- + .../boot/dts/overlays/uart0-pi5-overlay.dts | 17 + + .../boot/dts/overlays/uart1-pi5-overlay.dts | 17 + + .../boot/dts/overlays/uart2-pi5-overlay.dts | 17 + + .../boot/dts/overlays/uart3-pi5-overlay.dts | 17 + + .../boot/dts/overlays/uart4-pi5-overlay.dts | 17 + + arch/arm/boot/dts/overlays/udrc-overlay.dts | 6 +- + .../dts/overlays/ugreen-dabboard-overlay.dts | 10 +- + .../dts/overlays/vc4-fkms-v3d-overlay.dts | 6 + + .../dts/overlays/vc4-fkms-v3d-pi4-overlay.dts | 6 + + .../overlays/vc4-kms-dsi-7inch-overlay.dts | 18 +- + .../vc4-kms-dsi-waveshare-panel-overlay.dts | 8 +- + .../dts/overlays/vc4-kms-v3d-pi5-overlay.dts | 147 ++ + .../dts/overlays/vc4-kms-vga666-overlay.dts | 9 +- + .../dts/overlays/wm8960-soundcard-overlay.dts | 4 +- + arch/arm/boot/dts/rp1.dtsi | 1168 +++++++++++++++ + arch/arm64/boot/dts/broadcom/Makefile | 1 + + .../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 1 + + 134 files changed, 5143 insertions(+), 264 deletions(-) + create mode 100644 arch/arm/boot/dts/bcm2712-rpi-5-b.dts + create mode 100644 arch/arm/boot/dts/bcm2712-rpi.dtsi + create mode 100644 arch/arm/boot/dts/bcm2712.dtsi + create mode 100644 arch/arm/boot/dts/overlays/disable-bt-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/disable-wifi-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2c0-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2c1-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2c2-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2c3-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart0-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart1-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart2-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart3-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/midi-uart4-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi2-1cs-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi2-2cs-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi3-1cs-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi3-2cs-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi5-1cs-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/spi5-2cs-pi5-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart0-pi5-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart1-pi5-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart2-pi5-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart3-pi5-overlay.dts + create mode 100755 arch/arm/boot/dts/overlays/uart4-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/rp1.dtsi + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -18,7 +18,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ + bcm2709-rpi-cm2.dtb \ + bcm2710-rpi-cm3.dtb \ + bcm2711-rpi-cm4.dtb \ +- bcm2711-rpi-cm4s.dtb ++ bcm2711-rpi-cm4s.dtb \ ++ bcm2712-rpi-5-b.dtb + + dtb-$(CONFIG_ARCH_ALPINE) += \ + alpine-db.dtb +--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +@@ -192,6 +192,9 @@ i2c_arm: &i2c1 { + i2c_vc: &i2c0 { + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts +@@ -203,6 +203,9 @@ i2c_arm: &i2c0 { + i2c_vc: &i2c1 { + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts +@@ -185,6 +185,9 @@ i2c_arm: &i2c1 { + i2c_vc: &i2c0 { + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts +@@ -19,6 +19,9 @@ cam0_reg: &cam0_regulator { + gpio = <&gpio 31 GPIO_ACTIVE_HIGH>; + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + &uart0 { + status = "okay"; + }; +--- a/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts +@@ -243,6 +243,7 @@ cam0_reg: &cam_dummy_reg { + + i2c_arm: &i2c1 {}; + i2c_vc: &i2c0 {}; ++i2c_csi_dsi0: &i2c0 {}; + + / { + __overrides__ { +--- a/arch/arm/boot/dts/bcm2708-rpi-zero.dts ++++ b/arch/arm/boot/dts/bcm2708-rpi-zero.dts +@@ -178,6 +178,7 @@ cam0_reg: &cam_dummy_reg { + + i2c_arm: &i2c1 {}; + i2c_vc: &i2c0 {}; ++i2c_csi_dsi0: &i2c0 {}; + + / { + __overrides__ { +--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +@@ -186,6 +186,9 @@ + cam0_reg: &cam_dummy_reg { + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2709-rpi-cm2.dts ++++ b/arch/arm/boot/dts/bcm2709-rpi-cm2.dts +@@ -20,6 +20,9 @@ cam0_reg: &cam0_regulator { + gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + &uart0 { + status = "okay"; + }; +--- a/arch/arm/boot/dts/bcm270x-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi +@@ -127,6 +127,9 @@ + status = "disabled"; + }; + ++i2s_clk_producer: &i2s {}; ++i2s_clk_consumer: &i2s {}; ++ + &clocks { + firmware = <&firmware>; + }; +--- a/arch/arm/boot/dts/bcm2710-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-2-b.dts +@@ -186,6 +186,9 @@ + cam0_reg: &cam_dummy_reg { + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts +@@ -274,6 +274,9 @@ + cam0_reg: &cam_dummy_reg { + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +@@ -283,6 +283,9 @@ + cam0_reg: &cam_dummy_reg { + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts +@@ -19,6 +19,9 @@ cam0_reg: &cam0_regulator { + gpio = <&gpio 31 GPIO_ACTIVE_HIGH>; + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + &uart0 { + status = "okay"; + }; +--- a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts +@@ -262,6 +262,9 @@ + cam0_reg: &cam_dummy_reg { + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -400,6 +400,9 @@ + cam0_reg: &cam_dummy_reg { + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_headphones=1 snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_headphones=0 snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts +@@ -409,6 +409,9 @@ cam0_reg: &cam1_reg { + gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>; + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; +--- a/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts +@@ -282,6 +282,9 @@ cam0_reg: &cam0_regulator { + status = "disabled"; + }; + ++i2c_csi_dsi0: &i2c0 { ++}; ++ + / { + __overrides__ { + audio = <&chosen>,"bootargs{on='snd_bcm2835.enable_hdmi=1',off='snd_bcm2835.enable_hdmi=0'}"; +--- /dev/null ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -0,0 +1,824 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define i2c0 _i2c0 ++#define i2c3 _i2c3 ++#define i2c4 _i2c4 ++#define i2c5 _i2c5 ++#define i2c6 _i2c6 ++#define i2c8 _i2c8 ++#define i2s _i2s ++#define pwm0 _pwm0 ++#define pwm1 _pwm1 ++#define spi0 _spi0 ++#define spi3 _spi3 ++#define spi4 _spi4 ++#define spi5 _spi5 ++#define spi6 _spi6 ++#define uart0 _uart0 ++#define uart2 _uart2 ++#define uart3 _uart3 ++#define uart4 _uart4 ++#define uart5 _uart5 ++ ++#include "bcm2712.dtsi" ++ ++#undef i2c0 ++#undef i2c3 ++#undef i2c4 ++#undef i2c5 ++#undef i2c6 ++#undef i2c8 ++#undef i2s ++#undef pwm0 ++#undef pwm1 ++#undef spi0 ++#undef spi3 ++#undef spi4 ++#undef spi5 ++#undef spi6 ++#undef uart0 ++#undef uart2 ++#undef uart3 ++#undef uart4 ++#undef uart5 ++ ++/ { ++ compatible = "raspberrypi,5-model-b", "brcm,bcm2712"; ++ model = "Raspberry Pi 5 Model B"; ++ ++ /* Will be filled by the bootloader */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0 0 0x28000000>; ++ }; ++ ++ leds: leds { ++ compatible = "gpio-leds"; ++ ++ pwr_led: led-pwr { ++ label = "PWR"; ++ gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "none"; ++ }; ++ ++ act_led: led-act { ++ label = "ACT"; ++ gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++ }; ++ }; ++ ++ sd_io_1v8_reg: sd_io_1v8_reg { ++ compatible = "regulator-gpio"; ++ regulator-name = "vdd-sd-io"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-settling-time-us = <5000>; ++ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>; ++ states = <1800000 0x1 ++ 3300000 0x0>; ++ status = "okay"; ++ }; ++ ++ sd_vcc_reg: sd_vcc_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc-sd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ enable-active-high; ++ gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++ }; ++ ++ wl_on_reg: wl_on_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "wl-on-regulator"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ pinctrl-0 = <&wl_on_pins>; ++ pinctrl-names = "default"; ++ ++ gpio = <&gio 28 GPIO_ACTIVE_HIGH>; ++ ++ startup-delay-us = <150000>; ++ enable-active-high; ++ }; ++ ++ clocks: clocks { ++ }; ++ ++ cam1_clk: cam1_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ cam0_clk: cam0_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ cam0_reg: cam0_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam0_reg"; ++ enable-active-high; ++ status = "okay"; ++ gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to MIPI 0 connector ++ }; ++ ++ cam1_reg: cam1_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam1_reg"; ++ enable-active-high; ++ status = "okay"; ++ gpio = <&rp1_gpio 46 0>; // CD1_IO0_MICCLK, to MIPI 1 connector ++ }; ++ ++ cam_dummy_reg: cam_dummy_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam-dummy-reg"; ++ status = "okay"; ++ }; ++ ++ dummy: dummy { ++ // A target for unwanted overlay fragments ++ }; ++}; ++ ++rp1_target: &pcie2 { ++ brcm,vdm-qos-map = <0xbbaa9888>; ++ aspm-no-l0s; ++ status = "okay"; ++}; ++ ++// Add some labels to 2712 device ++ ++// The system UART ++uart10: &_uart0 { status = "okay"; }; ++ ++// The system SPI for the bootloader EEPROM ++spi10: &_spi0 { status = "okay"; }; ++ ++i2c_rp1boot: &_i2c3 { }; ++ ++#include "rp1.dtsi" ++ ++&rp1 { ++ // PCIe address space layout: ++ // 00_00000000-00_00xxxxxx = RP1 peripherals ++ // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM ++ ++ // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx ++ // This is the RP1 peripheral space ++ ranges = <0xc0 0x40000000 ++ 0x02000000 0x00 0x00000000 ++ 0x00 0x00400000>; ++ ++ dma-ranges = ++ // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x10 0x00000000 ++ 0x43000000 0x10 0x00000000 ++ 0x10 0x00000000>, ++ ++ // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx ++ // This allows the RP1 DMA controller to address RP1 hardware ++ <0xc0 0x40000000 ++ 0x02000000 0x0 0x00000000 ++ 0x0 0x00400000>, ++ ++ // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x00 0x00000000 ++ 0x02000000 0x10 0x00000000 ++ 0x10 0x00000000>; ++}; ++ ++// Expose RP1 nodes as system nodes with labels ++ ++&rp1_dma { ++ status = "okay"; ++}; ++ ++&rp1_eth { ++ status = "okay"; ++ phy-handle = <&phy1>; ++ phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>; ++ phy-reset-duration = <5>; ++ ++ phy1: ethernet-phy@1 { ++ reg = <0x1>; ++ brcm,powerdown-enable; ++ }; ++}; ++ ++gpio: &rp1_gpio { ++ status = "okay"; ++}; ++ ++aux: &dummy {}; ++ ++&rp1_usb0 { ++ pinctrl-0 = <&usb_vbus_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&rp1_usb1 { ++ status = "okay"; ++}; ++ ++#include "bcm2712-rpi.dtsi" ++ ++// A few extra labels to keep overlays happy ++ ++i2c0if: &rp1_gpio {}; ++i2c0mux: &rp1_gpio {}; ++ ++i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only ++ pinctrl-0 = <&rp1_i2c6_38_39>; ++ pinctrl-names = "default"; ++}; ++ ++i2c_csi_dsi1: &i2c4 { // Note: This is for MIPI1 connector only ++ pinctrl-0 = <&rp1_i2c4_40_41>; ++ pinctrl-names = "default"; ++}; ++ ++i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility ++ ++csi0: &rp1_csi0 { }; ++csi1: &rp1_csi1 { }; ++dsi0: &rp1_dsi0 { }; ++dsi1: &rp1_dsi1 { }; ++dpi: &rp1_dpi { }; ++vec: &rp1_vec { }; ++dpi_gpio0: &rp1_dpi_24bit_gpio0 { }; ++dpi_gpio1: &rp1_dpi_24bit_gpio2 { }; ++dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { }; ++dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { }; ++dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { }; ++dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { }; ++dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { }; ++dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { }; ++dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { }; ++dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { }; ++ ++/* Add the IOMMUs for some RP1 bus masters */ ++ ++&csi0 { ++ iommus = <&iommu5>; ++}; ++ ++&csi1 { ++ iommus = <&iommu5>; ++}; ++ ++&dsi0 { ++ iommus = <&iommu5>; ++}; ++ ++&dsi1 { ++ iommus = <&iommu5>; ++}; ++ ++&dpi { ++ iommus = <&iommu5>; ++}; ++ ++&vec { ++ iommus = <&iommu5>; ++}; ++ ++&ddc0 { ++ status = "disabled"; ++}; ++ ++&ddc1 { ++ status = "disabled"; ++}; ++ ++&hdmi0 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; ++ status = "disabled"; ++}; ++ ++&hdmi1 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; ++ status = "disabled"; ++}; ++ ++&hvs { ++ clocks = <&firmware_clocks 4>, <&firmware_clocks 16>; ++ clock-names = "core", "disp"; ++}; ++ ++&mop { ++ status = "disabled"; ++}; ++ ++&moplet { ++ status = "disabled"; ++}; ++ ++&pixelvalve0 { ++ status = "disabled"; ++}; ++ ++&pixelvalve1 { ++ status = "disabled"; ++}; ++ ++&disp_intr { ++ status = "disabled"; ++}; ++ ++/* SDIO1 is used to drive the SD card */ ++&sdio1 { ++ pinctrl-0 = <&emmc_sd_pulls>, <&emmc_aon_cd_pins>; ++ pinctrl-names = "default"; ++ vqmmc-supply = <&sd_io_1v8_reg>; ++ vmmc-supply = <&sd_vcc_reg>; ++ bus-width = <4>; ++ sd-uhs-sdr50; ++ sd-uhs-ddr50; ++ sd-uhs-sdr104; ++ //broken-cd; ++ //no-1-8-v; ++ status = "okay"; ++}; ++ ++&pinctrl_aon { ++ emmc_aon_cd_pins: emmc_aon_cd_pins { ++ function = "sd_card_g"; ++ pins = "aon_gpio5"; ++ bias-pull-up; ++ }; ++ ++ /* Slight hack - only one PWM pin (status LED) is usable */ ++ aon_pwm_1pin: aon_pwm_1pin { ++ function = "aon_pwm"; ++ pins = "aon_gpio9"; ++ }; ++}; ++ ++&pinctrl { ++ pwr_button_pins: pwr_button_pins { ++ function = "gpio"; ++ pins = "gpio20"; ++ bias-pull-up; ++ }; ++ ++ wl_on_pins: wl_on_pins { ++ function = "gpio"; ++ pins = "gpio28"; ++ }; ++ ++ bt_shutdown_pins: bt_shutdown_pins { ++ function = "gpio"; ++ pins = "gpio29"; ++ }; ++ ++ emmc_sd_pulls: emmc_sd_pulls { ++ function = "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3"; ++ bias-pull-up; ++ }; ++}; ++ ++/* uarta communicates with the BT module */ ++&uarta { ++ uart-has-rtscts; ++ auto-flow-control; ++ status = "okay"; ++ clock-frequency = <96000000>; ++ pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>; ++ pinctrl-names = "default"; ++ ++ bluetooth: bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <3000000>; ++ shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>; ++ local-bd-address = [ 00 00 00 00 00 00 ]; ++ }; ++}; ++ ++&i2c_rp1boot { ++ clock-frequency = <400000>; ++ pinctrl-0 = <&i2c3_m4_agpio0_pins>; ++ pinctrl-names = "default"; ++}; ++ ++/ { ++ chosen: chosen { ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; ++ stdout-path = "serial10:115200n8"; ++ }; ++ ++ fan: cooling_fan { ++ status = "disabled"; ++ compatible = "pwm-fan"; ++ #cooling-cells = <2>; ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ cooling-levels = <0 75 125 175 250>; ++ pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>; ++ rpm-regmap = <&rp1_pwm1>; ++ rpm-offset = <0x3c>; ++ }; ++ ++ pwr_button { ++ compatible = "gpio-keys"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwr_button_pins>; ++ status = "okay"; ++ ++ pwr_key: pwr { ++ label = "pwr_button"; ++ // linux,code = <205>; // KEY_SUSPEND ++ linux,code = <116>; // KEY_POWER ++ gpios = <&gio 20 GPIO_ACTIVE_LOW>; ++ debounce-interval = <50>; // ms ++ }; ++ }; ++}; ++ ++&usb { ++ power-domains = <&power RPI_POWER_DOMAIN_USB>; ++}; ++ ++/* SDIO2 drives the WLAN interface */ ++&sdio2 { ++ pinctrl-0 = <&sdio2_30_pins>; ++ pinctrl-names = "default"; ++ bus-width = <4>; ++ vmmc-supply = <&wl_on_reg>; ++ sd-uhs-ddr50; ++ non-removable; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ wifi: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ local-mac-address = [00 00 00 00 00 00]; ++ }; ++}; ++ ++&rpivid { ++ status = "okay"; ++}; ++ ++&pinctrl { ++ spi10_gpio2: spi10_gpio2 { ++ function = "vc_spi0"; ++ pins = "gpio2", "gpio3", "gpio4"; ++ bias-disable; ++ }; ++ ++ spi10_cs_gpio1: spi10_cs_gpio1 { ++ function = "gpio"; ++ pins = "gpio1"; ++ bias-pull-up; ++ }; ++}; ++ ++spi10_pins: &spi10_gpio2 {}; ++spi10_cs_pins: &spi10_cs_gpio1 {}; ++ ++&spi10 { ++ pinctrl-names = "default"; ++ cs-gpios = <&gio 1 1>; ++ pinctrl-0 = <&spi10_pins &spi10_cs_pins>; ++ ++ spidev10: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <20000000>; ++ status = "okay"; ++ }; ++}; ++ ++// ============================================= ++// Board specific stuff here ++ ++&gio_aon { ++ // Don't use GIO_AON as an interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ /delete-property/ interrupt-controller; ++}; ++ ++&main_aon_irq { ++ // Don't use the MAIN_AON_IRQ interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ status = "disabled"; ++}; ++ ++&rp1_pwm1 { ++ status = "disabled"; ++ pinctrl-0 = <&rp1_pwm1_gpio45>; ++ pinctrl-names = "default"; ++}; ++ ++&thermal_trips { ++ cpu_tepid: cpu-tepid { ++ temperature = <50000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_warm: cpu-warm { ++ temperature = <60000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_hot: cpu-hot { ++ temperature = <67500>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_vhot: cpu-vhot { ++ temperature = <75000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++}; ++ ++&cooling_maps { ++ tepid { ++ trip = <&cpu_tepid>; ++ cooling-device = <&fan 1 1>; ++ }; ++ ++ warm { ++ trip = <&cpu_warm>; ++ cooling-device = <&fan 2 2>; ++ }; ++ ++ hot { ++ trip = <&cpu_hot>; ++ cooling-device = <&fan 3 3>; ++ }; ++ ++ vhot { ++ trip = <&cpu_vhot>; ++ cooling-device = <&fan 4 4>; ++ }; ++ ++ melt { ++ trip = <&cpu_crit>; ++ cooling-device = <&fan 4 4>; ++ }; ++}; ++ ++&gio { ++ // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank ++ // to reduce the clutter in gpioinfo/pinctrl ++ brcm,gpio-bank-widths = <32 4>; ++ ++ gpio-line-names = ++ "-", // GPIO_000 ++ "2712_BOOT_CS_N", // GPIO_001 ++ "2712_BOOT_MISO", // GPIO_002 ++ "2712_BOOT_MOSI", // GPIO_003 ++ "2712_BOOT_SCLK", // GPIO_004 ++ "-", // GPIO_005 ++ "-", // GPIO_006 ++ "-", // GPIO_007 ++ "-", // GPIO_008 ++ "-", // GPIO_009 ++ "-", // GPIO_010 ++ "-", // GPIO_011 ++ "-", // GPIO_012 ++ "-", // GPIO_013 ++ "PCIE_SDA", // GPIO_014 ++ "PCIE_SCL", // GPIO_015 ++ "-", // GPIO_016 ++ "-", // GPIO_017 ++ "-", // GPIO_018 ++ "-", // GPIO_019 ++ "PWR_GPIO", // GPIO_020 ++ "2712_G21_FS", // GPIO_021 ++ "-", // GPIO_022 ++ "-", // GPIO_023 ++ "BT_RTS", // GPIO_024 ++ "BT_CTS", // GPIO_025 ++ "BT_TXD", // GPIO_026 ++ "BT_RXD", // GPIO_027 ++ "WL_ON", // GPIO_028 ++ "BT_ON", // GPIO_029 ++ "WIFI_SDIO_CLK", // GPIO_030 ++ "WIFI_SDIO_CMD", // GPIO_031 ++ "WIFI_SDIO_D0", // GPIO_032 ++ "WIFI_SDIO_D1", // GPIO_033 ++ "WIFI_SDIO_D2", // GPIO_034 ++ "WIFI_SDIO_D3"; // GPIO_035 ++}; ++ ++&gio_aon { ++ gpio-line-names = ++ "RP1_SDA", // AON_GPIO_00 ++ "RP1_SCL", // AON_GPIO_01 ++ "RP1_RUN", // AON_GPIO_02 ++ "SD_IOVDD_SEL", // AON_GPIO_03 ++ "SD_PWR_ON", // AON_GPIO_04 ++ "SD_CDET_N", // AON_GPIO_05 ++ "SD_FLG_N", // AON_GPIO_06 ++ "-", // AON_GPIO_07 ++ "2712_WAKE", // AON_GPIO_08 ++ "2712_STAT_LED", // AON_GPIO_09 ++ "-", // AON_GPIO_10 ++ "-", // AON_GPIO_11 ++ "PMIC_INT", // AON_GPIO_12 ++ "UART_TX_FS", // AON_GPIO_13 ++ "UART_RX_FS", // AON_GPIO_14 ++ "-", // AON_GPIO_15 ++ "-", // AON_GPIO_16 ++ ++ // Pad bank0 out to 32 entries ++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ++ ++ "HDMI0_SCL", // AON_SGPIO_00 ++ "HDMI0_SDA", // AON_SGPIO_01 ++ "HDMI1_SCL", // AON_SGPIO_02 ++ "HDMI1_SDA", // AON_SGPIO_03 ++ "PMIC_SCL", // AON_SGPIO_04 ++ "PMIC_SDA"; // AON_SGPIO_05 ++ ++ rp1_run_hog { ++ gpio-hog; ++ gpios = <2 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "RP1 RUN pin"; ++ }; ++}; ++ ++&rp1_gpio { ++ gpio-line-names = ++ "ID_SD", // GPIO0 ++ "ID_SC", // GPIO1 ++ "PIN3", // GPIO2 ++ "PIN5", // GPIO3 ++ "PIN7", // GPIO4 ++ "PIN29", // GPIO5 ++ "PIN31", // GPIO6 ++ "PIN26", // GPIO7 ++ "PIN24", // GPIO8 ++ "PIN21", // GPIO9 ++ "PIN19", // GPIO10 ++ "PIN23", // GPIO11 ++ "PIN32", // GPIO12 ++ "PIN33", // GPIO13 ++ "PIN8", // GPIO14 ++ "PIN10", // GPIO15 ++ "PIN36", // GPIO16 ++ "PIN11", // GPIO17 ++ "PIN12", // GPIO18 ++ "PIN35", // GPIO19 ++ "PIN38", // GPIO20 ++ "PIN40", // GPIO21 ++ "PIN15", // GPIO22 ++ "PIN16", // GPIO23 ++ "PIN18", // GPIO24 ++ "PIN22", // GPIO25 ++ "PIN37", // GPIO26 ++ "PIN13", // GPIO27 ++ ++ "PCIE_RP1_WAKE", // GPIO28 ++ "FAN_TACH", // GPIO29 ++ "HOST_SDA", // GPIO30 ++ "HOST_SCL", // GPIO31 ++ "ETH_RST_N", // GPIO32 ++ "-", // GPIO33 ++ ++ "CD0_IO0_MICCLK", // GPIO34 ++ "CD0_IO0_MICDAT0", // GPIO35 ++ "RP1_PCIE_CLKREQ_N", // GPIO36 ++ "-", // GPIO37 ++ "CD0_SDA", // GPIO38 ++ "CD0_SCL", // GPIO39 ++ "CD1_SDA", // GPIO40 ++ "CD1_SCL", // GPIO41 ++ "USB_VBUS_EN", // GPIO42 ++ "USB_OC_N", // GPIO43 ++ "RP1_STAT_LED", // GPIO44 ++ "FAN_PWM", // GPIO45 ++ "CD1_IO0_MICCLK", // GPIO46 ++ "2712_WAKE", // GPIO47 ++ "CD1_IO1_MICDAT1", // GPIO48 ++ "EN_MAX_USB_CUR", // GPIO49 ++ "-", // GPIO50 ++ "-", // GPIO51 ++ "-", // GPIO52 ++ "-"; // GPIO53 ++ ++ usb_vbus_pins: usb_vbus_pins { ++ function = "vbus1"; ++ pins = "gpio42", "gpio43"; ++ }; ++}; ++ ++/ { ++ aliases: aliases { ++ blconfig = &blconfig; ++ bluetooth = &bluetooth; ++ console = &uart10; ++ ethernet0 = &rp1_eth; ++ wifi0 = &wifi; ++ fb = &fb; ++ mailbox = &mailbox; ++ mmc0 = &sdio1; ++ uart0 = &uart0; ++ uart1 = &uart1; ++ uart2 = &uart2; ++ uart3 = &uart3; ++ uart4 = &uart4; ++ uart10 = &uart10; ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ serial10 = &uart10; ++ i2c = &i2c_arm; ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ i2c2 = &i2c2; ++ i2c3 = &i2c3; ++ i2c4 = &i2c4; ++ i2c5 = &i2c5; ++ i2c6 = &i2c6; ++ i2c10 = &i2c_rp1boot; ++ // Bit-bashed i2c_gpios start at 10 ++ spi0 = &spi0; ++ spi1 = &spi1; ++ spi2 = &spi2; ++ spi3 = &spi3; ++ spi4 = &spi4; ++ spi5 = &spi5; ++ spi10 = &spi10; ++ gpio0 = &gpio; ++ gpio1 = &gio; ++ gpio2 = &gio_aon; ++ gpio3 = &pinctrl; ++ gpio4 = &pinctrl_aon; ++ usb0 = &rp1_usb0; ++ usb1 = &rp1_usb1; ++ }; ++ ++ __overrides__ { ++ bdaddr = <&bluetooth>, "local-bd-address["; ++ button_debounce = <&pwr_key>, "debounce-interval:0"; ++ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status"; ++ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0; ++ i2c0 = <&i2c0>, "status"; ++ i2c1 = <&i2c1>, "status"; ++ i2c = <&i2c1>, "status"; ++ i2c_arm = <&i2c_arm>, "status"; ++ i2c_vc = <&i2c_vc>, "status"; ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status"; ++ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status"; ++ i2c0_baudrate = <&i2c0>, "clock-frequency:0"; ++ i2c1_baudrate = <&i2c1>, "clock-frequency:0"; ++ i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; ++ nvme = <&pciex1>, "status"; ++ pciex1 = <&pciex1>, "status"; ++ pciex1_gen = <&pciex1> , "max-link-speed:0"; ++ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; ++ random = <&random>, "status"; ++ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; ++ spi = <&spi0>, "status"; ++ suspend = <&pwr_key>, "linux,code:0=205"; ++ uart0 = <&uart0>, "status"; ++ wifiaddr = <&wifi>, "local-mac-address["; ++ ++ act_led_activelow = <&act_led>, "active-low?"; ++ act_led_trigger = <&act_led>, "linux,default-trigger"; ++ pwr_led_activelow = <&pwr_led>, "gpios:8"; ++ pwr_led_trigger = <&pwr_led>, "linux,default-trigger"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/bcm2712-rpi.dtsi +@@ -0,0 +1,281 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++ ++&soc { ++ firmware: firmware { ++ compatible = "raspberrypi,bcm2835-firmware", "simple-mfd"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ mboxes = <&mailbox>; ++ dma-ranges; ++ ++ firmware_clocks: clocks { ++ compatible = "raspberrypi,firmware-clocks"; ++ #clock-cells = <1>; ++ }; ++ ++ reset: reset { ++ compatible = "raspberrypi,firmware-reset"; ++ #reset-cells = <1>; ++ }; ++ ++ vcio: vcio { ++ compatible = "raspberrypi,vcio"; ++ }; ++ }; ++ ++ power: power { ++ compatible = "raspberrypi,bcm2835-power"; ++ firmware = <&firmware>; ++ #power-domain-cells = <1>; ++ }; ++ ++ fb: fb { ++ compatible = "brcm,bcm2708-fb"; ++ firmware = <&firmware>; ++ status = "okay"; ++ }; ++ ++ rpi_rtc: rpi_rtc { ++ compatible = "raspberrypi,rpi-rtc"; ++ firmware = <&firmware>; ++ status = "okay"; ++ trickle-charge-microvolt = <0>; ++ }; ++ ++ /* Define these notional regulators for use by overlays, etc. */ ++ vdd_3v3_reg: fixedregulator_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-always-on; ++ regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <3300000>; ++ regulator-name = "3v3"; ++ }; ++ ++ vdd_5v0_reg: fixedregulator_5v0 { ++ compatible = "regulator-fixed"; ++ regulator-always-on; ++ regulator-max-microvolt = <5000000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-name = "5v0"; ++ }; ++}; ++ ++/ { ++ __overrides__ { ++ arm_freq; ++ }; ++}; ++ ++pciex1: &pcie1 { }; ++pciex4: &pcie2 { }; ++ ++&dma32 { ++ /* The VPU firmware uses DMA channel 11 for VCHIQ */ ++ brcm,dma-channel-mask = <0x03f>; ++}; ++ ++&dma40 { ++ /* The VPU firmware DMA channel 11 for VCHIQ */ ++ brcm,dma-channel-mask = <0x07c0>; ++}; ++ ++&hdmi0 { ++ dmas = <&dma40 (10|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; ++ ++&hdmi1 { ++ dmas = <&dma40 (17|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; ++ ++&spi10 { ++ dmas = <&dma40 6>, <&dma40 7>; ++ dma-names = "tx", "rx"; ++}; ++ ++&usb { ++ power-domains = <&power RPI_POWER_DOMAIN_USB>; ++}; ++ ++&rmem { ++ /* ++ * RPi4's co-processor will copy the board's bootloader configuration ++ * into memory for the OS to consume. It'll also update this node with ++ * its placement information. ++ */ ++ blconfig: nvram@0 { ++ compatible = "raspberrypi,bootloader-config", "nvmem-rmem"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x0 0x0 0x0>; ++ no-map; ++ status = "disabled"; ++ }; ++}; ++ ++&rp1_adc { ++ status = "okay"; ++}; ++ ++/* Add some gpiomem nodes to make the devices accessible to userspace. ++ * /dev/gpiomem should expose the registers for the interface with DT alias ++ * gpio. ++ */ ++ ++&rp1 { ++ gpiomem@d0000 { ++ /* Export IO_BANKs, RIO_BANKs and PADS_BANKs to userspace */ ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0xc0 0x400d0000 0x0 0x30000>; ++ chardev-name = "gpiomem0"; ++ }; ++}; ++ ++&soc { ++ gpiomem@7d508500 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d508500 0x40>; ++ chardev-name = "gpiomem1"; ++ }; ++ ++ gpiomem@7d517c00 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d517c00 0x40>; ++ chardev-name = "gpiomem2"; ++ }; ++ ++ gpiomem@7d504100 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d504100 0x20>; ++ chardev-name = "gpiomem3"; ++ }; ++ ++ gpiomem@7d510700 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d510700 0x20>; ++ chardev-name = "gpiomem4"; ++ }; ++}; ++ ++i2c0: &rp1_i2c0 { }; ++i2c1: &rp1_i2c1 { }; ++i2c2: &rp1_i2c2 { }; ++i2c3: &rp1_i2c3 { }; ++i2c4: &rp1_i2c4 { }; ++i2c5: &rp1_i2c5 { }; ++i2c6: &rp1_i2c6 { }; ++i2s: &rp1_i2s0 { }; ++i2s_clk_producer: &rp1_i2s0 { }; ++i2s_clk_consumer: &rp1_i2s1 { }; ++pwm0: &rp1_pwm0 { }; ++pwm1: &rp1_pwm1 { }; ++pwm: &pwm0 { }; ++spi0: &rp1_spi0 { }; ++spi1: &rp1_spi1 { }; ++spi2: &rp1_spi2 { }; ++spi3: &rp1_spi3 { }; ++spi4: &rp1_spi4 { }; ++spi5: &rp1_spi5 { }; ++ ++uart0_pins: &rp1_uart0_14_15 {}; ++uart0_ctsrts_pins: &rp1_uart0_ctsrts_16_17 {}; ++uart0: &rp1_uart0 { ++ pinctrl-0 = <&uart0_pins>; ++}; ++ ++uart1_pins: &rp1_uart1_0_1 {}; ++uart1_ctsrts_pins: &rp1_uart1_ctsrts_2_3 {}; ++uart1: &rp1_uart1 { }; ++ ++uart2_pins: &rp1_uart2_4_5 {}; ++uart2_ctsrts_pins: &rp1_uart2_ctsrts_6_7 {}; ++uart2: &rp1_uart2 { }; ++ ++uart3_pins: &rp1_uart3_8_9 {}; ++uart3_ctsrts_pins: &rp1_uart3_ctsrts_10_11 {}; ++uart3: &rp1_uart3 { }; ++ ++uart4_pins: &rp1_uart4_12_13 {}; ++uart4_ctsrts_pins: &rp1_uart4_ctsrts_14_15 {}; ++uart4: &rp1_uart4 { }; ++ ++i2c_vc: &i2c0 { // This is pins 27,28 on the header (not MIPI) ++ pinctrl-0 = <&rp1_i2c0_0_1>; ++ pinctrl-names = "default"; ++}; ++ ++i2c_arm: &i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2c1_2_3>; ++}; ++ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2c2_4_5>; ++}; ++ ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2c3_6_7>; ++}; ++ ++&i2s_clk_producer { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2s0_18_21>; ++}; ++ ++&i2s_clk_consumer { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2s1_18_21>; ++}; ++ ++spi0_pins: &rp1_spi0_gpio9 {}; ++spi0_cs_pins: &rp1_spi0_cs_gpio7 {}; ++ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>; ++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>; ++ ++ spidev0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ }; ++ ++ spidev1: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ }; ++}; ++ ++spi2_pins: &rp1_spi2_gpio1 {}; ++&spi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi2_pins>; ++}; ++ ++spi3_pins: &rp1_spi3_gpio5 {}; ++&spi3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi3_pins>; ++}; ++ ++spi4_pins: &rp1_spi4_gpio9 {}; ++&spi4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi4_pins>; ++}; ++ ++spi5_pins: &rp1_spi5_gpio13 {}; ++&spi5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi5_pins>; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/bcm2712.dtsi +@@ -0,0 +1,1287 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++#include ++ ++/ { ++ compatible = "brcm,bcm2712", "brcm,bcm2711"; ++ model = "BCM2712"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ interrupt-parent = <&gicv2>; ++ ++ rmem: reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges; ++ ++ atf@0 { ++ reg = <0x0 0x0 0x80000>; ++ no-map; ++ }; ++ ++ cma: linux,cma { ++ compatible = "shared-dma-pool"; ++ size = <0x4000000>; /* 64MB */ ++ reusable; ++ linux,cma-default; ++ ++ /* ++ * arm64 reserves the CMA by default somewhere in ++ * ZONE_DMA32, that's not good enough for the BCM2711 ++ * as some devices can only address the lower 1G of ++ * memory (ZONE_DMA). ++ */ ++ alloc-ranges = <0x0 0x00000000 0x40000000>; ++ }; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <2000>; ++ polling-delay = <1000>; ++ coefficients = <(-550) 450000>; ++ thermal-sensors = <&thermal>; ++ ++ thermal_trips: trips { ++ cpu_crit: cpu-crit { ++ temperature = <110000>; ++ hysteresis = <0>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling_maps: cooling-maps { ++ }; ++ }; ++ }; ++ ++ clk_27MHz: clk-27M { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <27000000>; ++ clock-output-names = "27MHz-clock"; ++ }; ++ ++ clk_108MHz: clk-108M { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <108000000>; ++ clock-output-names = "108MHz-clock"; ++ }; ++ ++ hvs: hvs@107c580000 { ++ compatible = "brcm,bcm2712-hvs"; ++ reg = <0x10 0x7c580000 0x1a000>; ++ interrupt-parent = <&disp_intr>; ++ interrupts = <2>, <9>, <16>; ++ interrupt-names = "ch0-eof", "ch1-eof", "ch2-eof"; ++ //iommus = <&iommu4>; ++ status = "disabled"; ++ }; ++ ++ soc: soc { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ranges = <0x7c000000 0x10 0x7c000000 0x04000000>; ++ /* Emulate a contiguous 30-bit address range for DMA */ ++ dma-ranges = <0xc0000000 0x00 0x00000000 0x40000000>, ++ <0x7c000000 0x10 0x7c000000 0x04000000>; ++ ++ system_timer: timer@7c003000 { ++ compatible = "brcm,bcm2835-system-timer"; ++ reg = <0x7c003000 0x1000>; ++ interrupts = , ++ , ++ , ++ ; ++ clock-frequency = <1000000>; ++ }; ++ ++ firmwarekms: firmwarekms@7d503000 { ++ compatible = "raspberrypi,rpi-firmware-kms"; ++ /* SUN_L2 interrupt reg */ ++ reg = <0x7d503000 0x18>; ++ interrupt-parent = <&cpu_l2_irq>; ++ interrupts = <19>; ++ brcm,firmware = <&firmware>; ++ status = "disabled"; ++ }; ++ ++ mailbox: mailbox@7c013880 { ++ compatible = "brcm,bcm2835-mbox"; ++ reg = <0x7c013880 0x40>; ++ interrupts = ; ++ #mbox-cells = <0>; ++ }; ++ ++ pixelvalve0: pixelvalve@7c410000 { ++ compatible = "brcm,bcm2712-pixelvalve0"; ++ reg = <0x7c410000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ pixelvalve1: pixelvalve@7c411000 { ++ compatible = "brcm,bcm2712-pixelvalve1"; ++ reg = <0x7c411000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ usb: usb@7c480000 { ++ compatible = "brcm,bcm2835-usb"; ++ reg = <0x7c480000 0x10000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk_usb>; ++ clock-names = "otg"; ++ phys = <&usbphy>; ++ phy-names = "usb2-phy"; ++ status = "disabled"; ++ }; ++ ++ mop: mop@7c500000 { ++ compatible = "brcm,bcm2712-mop"; ++ reg = <0x7c500000 0x20>; ++ interrupt-parent = <&disp_intr>; ++ interrupts = <1>; ++ status = "disabled"; ++ }; ++ ++ moplet: moplet@7c501000 { ++ compatible = "brcm,bcm2712-moplet"; ++ reg = <0x7c501000 0x20>; ++ interrupt-parent = <&disp_intr>; ++ interrupts = <0>; ++ status = "disabled"; ++ }; ++ ++ disp_intr: interrupt-controller@7c502000 { ++ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; ++ reg = <0x7c502000 0x30>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ dvp: clock@7c700000 { ++ compatible = "brcm,brcm2711-dvp"; ++ reg = <0x7c700000 0x10>; ++ clocks = <&clk_108MHz>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ /* ++ * This node is the provider for the enable-method for ++ * bringing up secondary cores. ++ */ ++ local_intc: local_intc@7cd00000 { ++ compatible = "brcm,bcm2836-l1-intc"; ++ reg = <0x7cd00000 0x100>; ++ }; ++ ++ uart0: serial@7d001000 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001000 0x200>; ++ interrupts = ; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@7d001400 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001400 0x200>; ++ interrupts = ; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@7d001600 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001600 0x200>; ++ interrupts = ; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@7d001800 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001800 0x200>; ++ interrupts = ; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@7d001a00 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001a00 0x200>; ++ interrupts = ; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ sdhost: mmc@7d002000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7d002000 0x100>; ++ //interrupts = ; ++ clocks = <&clk_vpu>; ++ status = "disabled"; ++ }; ++ ++ i2s: i2s@7d003000 { ++ compatible = "brcm,bcm2835-i2s"; ++ reg = <0x7d003000 0x24>; ++ //clocks = <&cprman BCM2835_CLOCK_PCM>; ++ status = "disabled"; ++ }; ++ ++ spi0: spi@7d004000 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004000 0x200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ num-cs = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi3: spi@7d004600 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004600 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi4: spi@7d004800 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004800 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi5: spi@7d004a00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004a00 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi6: spi@7d004c00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004c00 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c0: i2c@7d005000 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005000 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@7d005600 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005600 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@7d005800 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005800 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c5: i2c@7d005a00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005a00 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c6: i2c@7d005c00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005c00 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c8: i2c@7d005e00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005e00 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ pwm0: pwm@7d00c000 { ++ compatible = "brcm,bcm2835-pwm"; ++ reg = <0x7d00c000 0x28>; ++ assigned-clock-rates = <10000000>; ++ #pwm-cells = <2>; ++ status = "disabled"; ++ }; ++ ++ pwm1: pwm@7d00c800 { ++ compatible = "brcm,bcm2835-pwm"; ++ reg = <0x7d00c800 0x28>; ++ assigned-clock-rates = <10000000>; ++ #pwm-cells = <2>; ++ status = "disabled"; ++ }; ++ ++ pm: watchdog@7d200000 { ++ compatible = "brcm,bcm2712-pm"; ++ reg = <0x7d200000 0x308>; ++ reg-names = "pm"; ++ #power-domain-cells = <1>; ++ #reset-cells = <1>; ++ //clocks = <&cprman BCM2835_CLOCK_V3D>, ++ // <&cprman BCM2835_CLOCK_PERI_IMAGE>, ++ // <&cprman BCM2835_CLOCK_H264>, ++ // <&cprman BCM2835_CLOCK_ISP>; ++ clock-names = "v3d", "peri_image", "h264", "isp"; ++ system-power-controller; ++ }; ++ ++ cprman: cprman@7d202000 { ++ compatible = "brcm,bcm2711-cprman"; ++ reg = <0x7d202000 0x2000>; ++ #clock-cells = <1>; ++ ++ /* CPRMAN derives almost everything from the ++ * platform's oscillator. However, the DSI ++ * pixel clocks come from the DSI analog PHY. ++ */ ++ clocks = <&clk_osc>; ++ status = "disabled"; ++ }; ++ ++ random: rng@7d208000 { ++ compatible = "brcm,bcm2711-rng200"; ++ reg = <0x7d208000 0x28>; ++ status = "okay"; ++ }; ++ ++ cpu_l2_irq: intc@7d503000 { ++ compatible = "brcm,l2-intc"; ++ reg = <0x7d503000 0x18>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ pinctrl: pinctrl@7d504100 { ++ compatible = "brcm,bcm2712-pinctrl"; ++ reg = <0x7d504100 0x30>; ++ ++ uarta_24_pins: uarta_24_pins { ++ pin_rts { ++ function = "uart0"; ++ pins = "gpio24"; ++ bias-disable; ++ }; ++ pin_cts { ++ function = "uart0"; ++ pins = "gpio25"; ++ bias-pull-up; ++ }; ++ pin_txd { ++ function = "uart0"; ++ pins = "gpio26"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart0"; ++ pins = "gpio27"; ++ bias-pull-up; ++ }; ++ }; ++ ++ sdio2_30_pins: sdio2_30_pins { ++ pin_clk { ++ function = "sd2"; ++ pins = "gpio30"; ++ bias-disable; ++ }; ++ pin_cmd { ++ function = "sd2"; ++ pins = "gpio31"; ++ bias-pull-up; ++ }; ++ pins_dat { ++ function = "sd2"; ++ pins = "gpio32", "gpio33", "gpio34", "gpio35"; ++ bias-pull-up; ++ }; ++ }; ++ }; ++ ++ ddc0: i2c@7d508200 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d508200 0x58>; ++ interrupt-parent = <&bsc_irq>; ++ interrupts = <1>; ++ clock-frequency = <200000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ ddc1: i2c@7d508280 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d508280 0x58>; ++ interrupt-parent = <&bsc_irq>; ++ interrupts = <2>; ++ clock-frequency = <200000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ bscd: i2c@7d508300 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d508300 0x58>; ++ interrupt-parent = <&bsc_irq>; ++ interrupts = <0>; ++ clock-frequency = <200000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ bsc_irq: intc@7d508380 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d508380 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ main_irq: intc@7d508400 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d508400 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ gio: gpio@7d508500 { ++ compatible = "brcm,brcmstb-gpio"; ++ reg = <0x7d508500 0x40>; ++ interrupt-parent = <&main_irq>; ++ interrupts = <0>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,gpio-bank-widths = <32 22>; ++ brcm,gpio-direct; ++ }; ++ ++ uarta: serial@7d50c000 { ++ compatible = "brcm,bcm7271-uart"; ++ reg = <0x7d50c000 0x20>; ++ reg-names = "uart"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ interrupts = ; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ uartb: serial@7d50d000 { ++ compatible = "brcm,bcm7271-uart"; ++ reg = <0x7d50d000 0x20>; ++ reg-names = "uart"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ interrupts = ; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ uartc: serial@7d50e000 { ++ compatible = "brcm,bcm7271-uart"; ++ reg = <0x7d50e000 0x20>; ++ reg-names = "uart"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ interrupts = ; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ aon_intr: interrupt-controller@7d510600 { ++ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; ++ reg = <0x7d510600 0x30>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ pinctrl_aon: pinctrl@7d510700 { ++ compatible = "brcm,bcm2712-aon-pinctrl"; ++ reg = <0x7d510700 0x20>; ++ ++ i2c3_m4_agpio0_pins: i2c3_m4_agpio0_pins { ++ function = "vc_i2c3"; ++ pins = "aon_gpio0", "aon_gpio1"; ++ bias-pull-up; ++ }; ++ ++ bsc_m1_agpio13_pins: bsc_m1_agpio13_pins { ++ function = "bsc_m1"; ++ pins = "aon_gpio13", "aon_gpio14"; ++ bias-pull-up; ++ }; ++ ++ bsc_pmu_sgpio4_pins: bsc_pmu_sgpio4_pins { ++ function = "avs_pmu_bsc"; ++ pins = "aon_sgpio4", "aon_sgpio5"; ++ }; ++ ++ bsc_m2_sgpio4_pins: bsc_m2_sgpio4_pins { ++ function = "bsc_m2"; ++ pins = "aon_sgpio4", "aon_sgpio5"; ++ }; ++ ++ pwm_aon_agpio1_pins: pwm_aon_agpio1_pins { ++ function = "aon_pwm"; ++ pins = "aon_gpio1", "aon_gpio2"; ++ }; ++ ++ pwm_aon_agpio4_pins: pwm_aon_agpio4_pins { ++ function = "vc_pwm0"; ++ pins = "aon_gpio4", "aon_gpio5"; ++ }; ++ ++ pwm_aon_agpio7_pins: pwm_aon_agpio7_pins { ++ function = "aon_pwm"; ++ pins = "aon_gpio7", "aon_gpio9"; ++ }; ++ }; ++ ++ intc@7d517000 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517000 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ bscc: i2c@7d517a00 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d517a00 0x58>; ++ interrupt-parent = <&bsc_aon_irq>; ++ interrupts = <0>; ++ clock-frequency = <200000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ pwm_aon: pwm@7d517a80 { ++ compatible = "brcm,bcm7038-pwm"; ++ reg = <0x7d517a80 0x28>; ++ #pwm-cells = <2>; ++ clocks = <&clk_27MHz>; ++ }; ++ ++ main_aon_irq: intc@7d517ac0 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517ac0 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ bsc_aon_irq: intc@7d517b00 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517b00 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ gio_aon: gpio@7d517c00 { ++ compatible = "brcm,brcmstb-gpio"; ++ reg = <0x7d517c00 0x40>; ++ interrupt-parent = <&main_aon_irq>; ++ interrupts = <0>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,gpio-bank-widths = <17 6>; ++ brcm,gpio-direct; ++ }; ++ ++ avs_monitor: avs-monitor@7d542000 { ++ compatible = "brcm,bcm2711-avs-monitor", ++ "syscon", "simple-mfd"; ++ reg = <0x7d542000 0xf00>; ++ status = "okay"; ++ ++ thermal: thermal { ++ compatible = "brcm,bcm2711-thermal"; ++ #thermal-sensor-cells = <0>; ++ }; ++ }; ++ ++ bsc_pmu: i2c@7d544000 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d544000 0x58>; ++ interrupt-parent = <&bsc_aon_irq>; ++ interrupts = <1>; ++ clock-frequency = <200000>; ++ status = "disabled"; ++ }; ++ ++ hdmi0: hdmi@7ef00700 { ++ compatible = "brcm,bcm2712-hdmi0"; ++ reg = <0x7c701400 0x300>, ++ <0x7c701000 0x200>, ++ <0x7c701d00 0x300>, ++ <0x7c702000 0x80>, ++ <0x7c703800 0x200>, ++ <0x7c704000 0x800>, ++ <0x7c700100 0x80>, ++ <0x7d510800 0x100>, ++ <0x7c720000 0x100>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd"; ++ resets = <&dvp 1>; ++ interrupt-parent = <&aon_intr>; ++ interrupts = <1>, <2>, <3>, ++ <7>, <8>; ++ interrupt-names = "cec-tx", "cec-rx", "cec-low", ++ "hpd-connected", "hpd-removed"; ++ ddc = <&ddc0>; ++ dmas = <&dma32 10>; ++ dma-names = "audio-rx"; ++ status = "disabled"; ++ }; ++ ++ hdmi1: hdmi@7ef05700 { ++ compatible = "brcm,bcm2712-hdmi1"; ++ reg = <0x7c706400 0x300>, ++ <0x7c706000 0x200>, ++ <0x7c706d00 0x300>, ++ <0x7c707000 0x80>, ++ <0x7c708800 0x200>, ++ <0x7c709000 0x800>, ++ <0x7c700180 0x80>, ++ <0x7d511000 0x100>, ++ <0x7c720000 0x100>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd"; ++ ddc = <&ddc1>; ++ resets = <&dvp 2>; ++ interrupt-parent = <&aon_intr>; ++ interrupts = <11>, <12>, <13>, ++ <14>, <15>; ++ interrupt-names = "cec-tx", "cec-rx", "cec-low", ++ "hpd-connected", "hpd-removed"; ++ dmas = <&dma32 17>; ++ dma-names = "audio-rx"; ++ status = "disabled"; ++ }; ++ ++ sound: sound { ++ }; ++ }; ++ ++ arm-pmu { ++ compatible = "arm,cortex-a76-pmu"; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ /* This only applies to the ARMv7 stub */ ++ arm,cpu-registers-not-fw-configured; ++ }; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x000>; ++ enable-method = "psci"; ++ next-level-cache = <&l2_cache>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x100>; ++ enable-method = "psci"; ++ next-level-cache = <&l2_cache>; ++ }; ++ ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x200>; ++ enable-method = "psci"; ++ next-level-cache = <&l2_cache>; ++ }; ++ ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x300>; ++ enable-method = "psci"; ++ next-level-cache = <&l2_cache>; ++ }; ++ ++ l2_cache: l2-cache { ++ compatible = "cache"; ++ next-level-cache = <&l3_cache>; ++ }; ++ ++ l3_cache: l3-cache { ++ compatible = "cache"; ++ }; ++ }; ++ ++ psci { ++ method = "smc"; ++ compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; ++ cpu_on = <0xc4000003>; ++ cpu_suspend = <0xc4000001>; ++ cpu_off = <0x84000002>; ++ }; ++ ++ axi: axi { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>, ++ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>, ++ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>, ++ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>, ++ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>; ++ ++ dma-ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>, ++ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>, ++ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>, ++ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>, ++ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>; ++ ++ vc4: gpu { ++ compatible = "brcm,bcm2712-vc6"; ++ }; ++ ++ iommu2: iommu@5100 { ++ /* IOMMU2 for PISP-BE, HEVC; and (unused) H264 accelerators */ ++ compatible = "brcm,bcm2712-iommu"; ++ reg = <0x10 0x5100 0x0 0x80>; ++ cache = <&iommuc>; ++ #iommu-cells = <0>; ++ }; ++ ++ iommu4: iommu@5200 { ++ /* IOMMU4 for HVS, MPL/TXP; and (unused) Unicam, PISP-FE, MiniBVN */ ++ compatible = "brcm,bcm2712-iommu"; ++ reg = <0x10 0x5200 0x0 0x80>; ++ cache = <&iommuc>; ++ #iommu-cells = <0>; ++ #interconnect-cells = <0>; ++ }; ++ ++ iommu5: iommu@5280 { ++ /* IOMMU5 for PCIe2 (RP1); and (unused) BSTM */ ++ compatible = "brcm,bcm2712-iommu"; ++ reg = <0x10 0x5280 0x0 0x80>; ++ cache = <&iommuc>; ++ #iommu-cells = <0>; ++ dma-iova-offset = <0x10 0x00000000>; // HACK for RP1 masters over PCIe ++ }; ++ ++ iommuc: iommuc@5b00 { ++ compatible = "brcm,bcm2712-iommuc"; ++ reg = <0x10 0x5b00 0x0 0x80>; ++ }; ++ ++ dma32: dma@10000 { ++ compatible = "brcm,bcm2712-dma"; ++ reg = <0x10 0x00010000 0 0x600>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ ; ++ interrupt-names = "dma0", ++ "dma1", ++ "dma2", ++ "dma3", ++ "dma4", ++ "dma5"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x0035>; ++ }; ++ ++ dma40: dma@10600 { ++ compatible = "brcm,bcm2712-dma"; ++ reg = <0x10 0x00010600 0 0x600>; ++ interrupts = ++ , /* dma4 6 */ ++ , /* dma4 7 */ ++ , /* dma4 8 */ ++ , /* dma4 9 */ ++ , /* dma4 10 */ ++ ; /* dma4 11 */ ++ interrupt-names = "dma6", ++ "dma7", ++ "dma8", ++ "dma9", ++ "dma10", ++ "dma11"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x0fc0>; ++ }; ++ ++ // Single-lane Gen3 PCIe ++ // Outbound window at 0x14_000000-0x17_ffffff ++ pcie0: pcie@100000 { ++ compatible = "brcm,bcm2712-pcie"; ++ reg = <0x10 0x00100000 0x0 0x9310>; ++ device_type = "pci"; ++ max-link-speed = <2>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ /* ++ * Unused interrupts: ++ * 208: AER ++ * 215: NMI ++ * 216: PME ++ */ ++ interrupt-parent = <&gicv2>; ++ interrupts = , ++ ; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 209 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &gicv2 GIC_SPI 210 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &gicv2 GIC_SPI 211 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &gicv2 GIC_SPI 212 ++ IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&bcm_reset 5>, <&bcm_reset 42>, <&pcie_rescal>; ++ reset-names = "swinit", "bridge", "rescal"; ++ msi-controller; ++ msi-parent = <&pcie0>; ++ ++ ranges = <0x02000000 0x00 0x00000000 ++ 0x17 0x00000000 ++ 0x0 0xfffffffc>, ++ <0x43000000 0x04 0x00000000 ++ 0x14 0x00000000 ++ 0x3 0x00000000>; ++ ++ dma-ranges = <0x43000000 0x10 0x00000000 ++ 0x00 0x00000000 ++ 0x10 0x00000000>; ++ ++ status = "disabled"; ++ }; ++ ++ // Single-lane Gen3 PCIe ++ // Outbound window at 0x18_000000-0x1b_ffffff ++ pcie1: pcie@110000 { ++ compatible = "brcm,bcm2712-pcie"; ++ reg = <0x10 0x00110000 0x0 0x9310>; ++ device_type = "pci"; ++ max-link-speed = <2>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ /* ++ * Unused interrupts: ++ * 218: AER ++ * 225: NMI ++ * 226: PME ++ */ ++ interrupt-parent = <&gicv2>; ++ interrupts = , ++ ; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 219 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &gicv2 GIC_SPI 220 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &gicv2 GIC_SPI 221 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &gicv2 GIC_SPI 222 ++ IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&bcm_reset 7>, <&bcm_reset 43>, <&pcie_rescal>; ++ reset-names = "swinit", "bridge", "rescal"; ++ msi-controller; ++ msi-parent = <&mip1>; ++ ++ ranges = <0x02000000 0x00 0x00000000 ++ 0x1b 0x00000000 ++ 0x00 0xfffffffc>, ++ <0x43000000 0x04 0x00000000 ++ 0x18 0x00000000 ++ 0x03 0x00000000>; ++ ++ dma-ranges = <0x03000000 0x10 0x00000000 ++ 0x00 0x00000000 ++ 0x10 0x00000000>; ++ ++ brcm,enable-l1ss; ++ status = "disabled"; ++ }; ++ ++ pcie_rescal: reset-controller@119500 { ++ compatible = "brcm,bcm7216-pcie-sata-rescal"; ++ reg = <0x10 0x00119500 0x0 0x10>; ++ #reset-cells = <0>; ++ }; ++ ++ // Quad-lane Gen3 PCIe ++ // Outbound window at 0x1c_000000-0x1f_ffffff ++ pcie2: pcie@120000 { ++ compatible = "brcm,bcm2712-pcie"; ++ reg = <0x10 0x00120000 0x0 0x9310>; ++ device_type = "pci"; ++ max-link-speed = <2>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ /* ++ * Unused interrupts: ++ * 228: AER ++ * 235: NMI ++ * 236: PME ++ */ ++ interrupt-parent = <&gicv2>; ++ interrupts = , ++ ; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 229 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &gicv2 GIC_SPI 230 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &gicv2 GIC_SPI 231 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &gicv2 GIC_SPI 232 ++ IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&bcm_reset 32>, <&bcm_reset 44>, <&pcie_rescal>; ++ reset-names = "swinit", "bridge", "rescal"; ++ msi-controller; ++ msi-parent = <&mip0>; ++ ++ // ~4GB, 32-bit, not-prefetchable at PCIe 00_00000000 ++ ranges = <0x02000000 0x00 0x00000000 ++ 0x1f 0x00000000 ++ 0x0 0xfffffffc>, ++ // 12GB, 64-bit, prefetchable at PCIe 04_00000000 ++ <0x43000000 0x04 0x00000000 ++ 0x1c 0x00000000 ++ 0x03 0x00000000>; ++ ++ // 64GB system RAM space at PCIe 10_00000000 ++ dma-ranges = <0x02000000 0x00 0x00000000 ++ 0x1f 0x00000000 ++ 0x00 0x00400000>, ++ <0x43000000 0x10 0x00000000 ++ 0x00 0x00000000 ++ 0x10 0x00000000>; ++ ++ brcm,enable-mps-rcb; ++ brcm,enable-l1ss; ++ status = "disabled"; ++ }; ++ ++ mip0: msi-controller@130000 { ++ compatible = "brcm,bcm2712-mip-intc"; ++ reg = <0x10 0x00130000 0x0 0xc0>; ++ msi-controller; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,msi-base-spi = <128>; ++ brcm,msi-num-spis = <64>; ++ brcm,msi-offset = <0>; ++ brcm,msi-pci-addr = <0xff 0xfffff000>; ++ }; ++ ++ mip1: msi-controller@131000 { ++ compatible = "brcm,bcm2712-mip-intc"; ++ reg = <0x10 0x00131000 0x0 0xc0>; ++ msi-controller; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,msi-base-spi = <247>; ++ /* Actually 20 total, but the others are ++ * both sparse and non-consecutive */ ++ brcm,msi-num-spis = <8>; ++ brcm,msi-offset = <8>; ++ brcm,msi-pci-addr = <0xff 0xffffe000>; ++ }; ++ ++ genet: ethernet@1300000 { ++ compatible = "brcm,bcm2711-genet-v5"; ++ reg = <0x10 0x01300000 0x0 0x20010>; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ interrupts = , ++ ; ++ status = "disabled"; ++ phy-mode = "rgmii"; ++ fixed-link = <0x0 0x1 0x3e8 0x0 0x0>; ++ phy-speed = <0x3e8>; ++ phy-id = <0x101>; ++ phy-type = <0x6>; ++ local-mac-address = [ 00 10 18 d8 45 de ]; ++ device_type = "network"; ++ ++ genet_mdio: mdio@e14 { ++ compatible = "brcm,genet-mdio-v5"; ++ reg = <0xe14 0x8>; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ }; ++ }; ++ ++ syscon_piarbctl: syscon@400018 { ++ compatible = "brcm,syscon-piarbctl", "syscon", "simple-mfd"; ++ reg = <0x10 0x00400018 0x0 0x18>; ++ }; ++ ++ rpivid: codec@800000 { ++ compatible = "raspberrypi,rpivid-vid-decoder"; ++ reg = <0x10 0x00800000 0x0 0x10000>, /* HEVC */ ++ <0x10 0x00840000 0x0 0x1000>; /* INTC */ ++ reg-names = "hevc", ++ "intc"; ++ ++ interrupts = ; ++ ++ clocks = <&firmware_clocks 11>; ++ clock-names = "hevc"; ++ status = "disabled"; ++ }; ++ ++ sdio1: mmc@fff000 { ++ compatible = "brcm,bcm2712-sdhci"; ++ reg = <0x10 0x00fff000 0x0 0x260>, ++ <0x10 0x00fff400 0x0 0x200>, ++ <0x10 0x015040b0 0x0 0x4>, // Bus isolation control ++ <0x10 0x015200f0 0x0 0x24>; // LCPLL control misc0-8 ++ reg-names = "host", "cfg", "busisol", "lcpll"; ++ interrupts = ; ++ clocks = <&clk_emmc2>; ++ sdhci-caps-mask = <0x0000C000 0x0>; ++ sdhci-caps = <0x0 0x0>; ++ supports-cqe; ++ mmc-ddr-3_3v; ++ }; ++ ++ sdio2: mmc@1100000 { ++ compatible = "brcm,bcm2712-sdhci"; ++ reg = <0x10 0x01100000 0x0 0x260>, ++ <0x10 0x01100400 0x0 0x200>; ++ reg-names = "host", "cfg"; ++ interrupts = ; ++ clocks = <&clk_emmc2>; ++ sdhci-caps-mask = <0x0000C000 0x0>; ++ sdhci-caps = <0x0 0x0>; ++ supports-cqe; ++ mmc-ddr-3_3v; ++ status = "disabled"; ++ }; ++ ++ sdio0: mmc@1108000 { ++ compatible = "brcm,bcm2711-emmc2"; ++ reg = <0x10 0x01108000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&clk_emmc2>; ++ mmc-ddr-3_3v; ++ status = "disabled"; ++ }; ++ ++ bcm_reset: reset-controller@1504318 { ++ compatible = "brcm,brcmstb-reset"; ++ reg = <0x10 0x01504318 0x0 0x30>; ++ #reset-cells = <1>; ++ }; ++ ++ v3d: v3d@2000000 { ++ compatible = "brcm,2712-v3d"; ++ reg = <0x10 0x02000000 0x0 0x4000>, ++ <0x10 0x02008000 0x0 0x6000>; ++ reg-names = "hub", "core0"; ++ ++ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; ++ resets = <&pm BCM2835_RESET_V3D>; ++ clocks = <&firmware_clocks 5>; ++ clocks-names = "v3d"; ++ interrupts = , ++ ; ++ status = "disabled"; ++ }; ++ ++ gicv2: interrupt-controller@7fff9000 { ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ compatible = "arm,gic-400"; ++ reg = <0x10 0x7fff9000 0x0 0x1000>, ++ <0x10 0x7fffa000 0x0 0x2000>, ++ <0x10 0x7fffc000 0x0 0x2000>, ++ <0x10 0x7fffe000 0x0 0x2000>; ++ interrupts = ; ++ }; ++ ++ pisp_be: pisp_be@880000 { ++ compatible = "raspberrypi,pispbe"; ++ reg = <0x10 0x00880000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&firmware_clocks 7>; ++ clocks-names = "isp_be"; ++ status = "okay"; ++ iommus = <&iommu2>; ++ }; ++ }; ++ ++ clocks { ++ /* The oscillator is the root of the clock tree. */ ++ clk_osc: clk-osc { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "osc"; ++ clock-frequency = <54000000>; ++ }; ++ ++ clk_usb: clk-usb { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "otg"; ++ clock-frequency = <480000000>; ++ }; ++ ++ clk_vpu: clk_vpu { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <750000000>; ++ clock-output-names = "vpu-clock"; ++ }; ++ ++ clk_uart: clk_uart { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <9216000>; ++ clock-output-names = "uart-clock"; ++ }; ++ ++ clk_emmc2: clk_emmc2 { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <54000000>; ++ clock-output-names = "emmc2-clock"; ++ }; ++ }; ++ ++ usbphy: phy { ++ compatible = "usb-nop-xceiv"; ++ #phy-cells = <0>; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -49,8 +49,10 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + dionaudio-loco.dtbo \ + dionaudio-loco-v2.dtbo \ + disable-bt.dtbo \ ++ disable-bt-pi5.dtbo \ + disable-emmc2.dtbo \ + disable-wifi.dtbo \ ++ disable-wifi-pi5.dtbo \ + dpi18.dtbo \ + dpi18cpadhi.dtbo \ + dpi24.dtbo \ +@@ -106,8 +108,12 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + i2c-rtc-gpio.dtbo \ + i2c-sensor.dtbo \ + i2c0.dtbo \ ++ i2c0-pi5.dtbo \ + i2c1.dtbo \ ++ i2c1-pi5.dtbo \ ++ i2c2-pi5.dtbo \ + i2c3.dtbo \ ++ i2c3-pi5.dtbo \ + i2c4.dtbo \ + i2c5.dtbo \ + i2c6.dtbo \ +@@ -150,10 +156,15 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + media-center.dtbo \ + merus-amp.dtbo \ + midi-uart0.dtbo \ ++ midi-uart0-pi5.dtbo \ + midi-uart1.dtbo \ ++ midi-uart1-pi5.dtbo \ + midi-uart2.dtbo \ ++ midi-uart2-pi5.dtbo \ + midi-uart3.dtbo \ ++ midi-uart3-pi5.dtbo \ + midi-uart4.dtbo \ ++ midi-uart4-pi5.dtbo \ + midi-uart5.dtbo \ + minipitft13.dtbo \ + miniuart-bt.dtbo \ +@@ -231,14 +242,20 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + spi1-2cs.dtbo \ + spi1-3cs.dtbo \ + spi2-1cs.dtbo \ ++ spi2-1cs-pi5.dtbo \ + spi2-2cs.dtbo \ ++ spi2-2cs-pi5.dtbo \ + spi2-3cs.dtbo \ + spi3-1cs.dtbo \ ++ spi3-1cs-pi5.dtbo \ + spi3-2cs.dtbo \ ++ spi3-2cs-pi5.dtbo \ + spi4-1cs.dtbo \ + spi4-2cs.dtbo \ + spi5-1cs.dtbo \ ++ spi5-1cs-pi5.dtbo \ + spi5-2cs.dtbo \ ++ spi5-2cs-pi5.dtbo \ + spi6-1cs.dtbo \ + spi6-2cs.dtbo \ + ssd1306.dtbo \ +@@ -253,10 +270,15 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + tpm-slb9670.dtbo \ + tpm-slb9673.dtbo \ + uart0.dtbo \ ++ uart0-pi5.dtbo \ + uart1.dtbo \ ++ uart1-pi5.dtbo \ + uart2.dtbo \ ++ uart2-pi5.dtbo \ + uart3.dtbo \ ++ uart3-pi5.dtbo \ + uart4.dtbo \ ++ uart4-pi5.dtbo \ + uart5.dtbo \ + udrc.dtbo \ + ugreen-dabboard.dtbo \ +@@ -276,6 +298,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + vc4-kms-kippah-7inch.dtbo \ + vc4-kms-v3d.dtbo \ + vc4-kms-v3d-pi4.dtbo \ ++ vc4-kms-v3d-pi5.dtbo \ + vc4-kms-vga666.dtbo \ + vga666.dtbo \ + vl805.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -151,6 +151,9 @@ Params: + bdaddr=06:05:04:03:02:01 + will set the BDADDR to 01:02:03:04:05:06. + ++ button_debounce Set the debounce delay (in ms) on the power/ ++ shutdown button (default 50ms) ++ + cam0_reg Enables CAM 0 regulator. + Only required on CM1 & 3. + +@@ -167,6 +170,9 @@ Params: + Default of GPIO expander 5 on CM4, but override + switches to normal GPIO. + ++ cooling_fan Enables the Pi 5 cooling fan (enabled ++ automatically by the firmware) ++ + eee Enable Energy Efficient Ethernet support for + compatible devices (default "on"). See also + "tx_lpi_timer". Pi3B+ only. +@@ -206,23 +212,29 @@ Params: + hdmi Set to "off" to disable the HDMI interface + (default "on") + ++ i2c An alias for i2c_arm ++ + i2c_arm Set to "on" to enable the ARM's i2c interface + (default "off") + ++ i2c_arm_baudrate Set the baudrate of the ARM's i2c interface ++ (default "100000") ++ ++ i2c_baudrate An alias for i2c_arm_baudrate ++ ++ i2c_csi_dsi Set to "on" to enable the i2c_csi_dsi interface ++ ++ i2c_csi_dsi0 Set to "on" to enable the i2c_csi_dsi0 interface ++ ++ i2c_csi_dsi1 Set to "on" to enable the i2c_csi_dsi1 interface ++ + i2c_vc Set to "on" to enable the i2c interface + usually reserved for the VideoCore processor + (default "off") + +- i2c An alias for i2c_arm +- +- i2c_arm_baudrate Set the baudrate of the ARM's i2c interface +- (default "100000") +- + i2c_vc_baudrate Set the baudrate of the VideoCore i2c interface + (default "100000") + +- i2c_baudrate An alias for i2c_arm_baudrate +- + i2s Set to "on" to enable the i2s interface + (default "off") + +@@ -237,11 +249,23 @@ Params: + krnbt_baudrate Set the baudrate of the PL011 UART when used + with krnbt=on + ++ nvme Alias for "pciex1" (2712 only) ++ + pcie Set to "off" to disable the PCIe interface + (default "on") + (2711 only, but not applicable on CM4S) + N.B. USB-A ports on 4B are subsequently disabled + ++ pciex1 Set to "on" to enable the external PCIe link ++ (2712 only, default "off") ++ ++ pciex1_gen Sets the PCIe "GEN"/speed for the external PCIe ++ link (2712 only, default "2") ++ ++ pciex1_no_l0s Set to "on" to disable ASPM L0s on the external ++ PCIe link for devices that have broken ++ implementations (2712 only, default "off") ++ + spi Set to "on" to enable the spi interfaces + (default "off") + +@@ -252,6 +276,11 @@ Params: + random Set to "on" to enable the hardware random + number generator (default "on") + ++ rtc_bbat_vchg Set the RTC backup battery charging voltage in ++ microvolts. If set to 0 or not specified, the ++ trickle charger is disabled. ++ (2712 only, default "0") ++ + sd Set to "off" to disable the SD card (or eMMC on + non-lite SKU of CM4). + (default "on") +@@ -276,18 +305,30 @@ Params: + sdio_overclock Clock (in MHz) to use when the MMC framework + requests 50MHz for the SDIO/WLAN interface. + ++ suspend Make the power button trigger a suspend rather ++ than a power-off (2712 only, default "off") ++ + tx_lpi_timer Set the delay in microseconds between going idle + and entering the low power state (default 600). + Requires EEE to be enabled - see "eee". + + uart0 Set to "off" to disable uart0 (default "on") + ++ uart0_console Move the kernel boot console to UART0 on pins ++ 6, 8 and 10 of the 40-way header (2712 only, ++ default "off") ++ + uart1 Set to "on" or "off" to enable or disable uart1 + (default varies) + + watchdog Set to "on" to enable the hardware watchdog + (default "off") + ++ wifiaddr Set an alternative WiFi MAC address. ++ The value should be a 6-byte hexadecimal value, ++ with or without colon separators, written in the ++ natural (big-endian) order. ++ + act_led_trigger Choose which activity the LED tracks. + Use "heartbeat" for a nice load indicator. + (default "mmc") +@@ -919,14 +960,16 @@ Params: 24db_digital_gain Allow ga + + + Name: disable-bt +-Info: Disable onboard Bluetooth on Pi 3B, 3B+, 3A+, 4B and Zero W, restoring +- UART0/ttyAMA0 over GPIOs 14 & 15. +- N.B. To disable the systemd service that initialises the modem so it +- doesn't use the UART, use 'sudo systemctl disable hciuart'. ++Info: Disable onboard Bluetooth on Bluetooth-capable Raspberry Pis. On Pis ++ prior to Pi 5 this restores UART0/ttyAMA0 over GPIOs 14 & 15. + Load: dtoverlay=disable-bt + Params: + + ++Name: disable-bt-pi5 ++Info: See disable-bt ++ ++ + Name: disable-emmc2 + Info: Disable EMMC2 controller on BCM2711. + The allows the onboard EMMC storage on Compute Module 4 to be disabled +@@ -936,11 +979,15 @@ Params: + + + Name: disable-wifi +-Info: Disable onboard WLAN on Pi 3B, 3B+, 3A+, 4B and Zero W. ++Info: Disable onboard WLAN on WiFi-capable Raspberry Pis. + Load: dtoverlay=disable-wifi + Params: + + ++Name: disable-wifi-pi5 ++Info: See disable-wifi ++ ++ + Name: dpi18 + Info: Overlay for a generic 18-bit DPI display + This uses GPIOs 0-21 (so no I2C, uart etc.), and activates the output +@@ -2233,6 +2280,15 @@ Info: Deprecated, legacy version of i2 + Load: + + ++Name: i2c0-pi5 ++Info: Enable i2c0 (Pi 5 only) ++Load: dtoverlay=i2c0-pi5,= ++Params: pins_0_1 Use GPIOs 0 and 1 (default) ++ pins_8_9 Use GPIOs 8 and 9 ++ baudrate Set the baudrate for the interface (default ++ "100000") ++ ++ + Name: i2c1 + Info: Change i2c1 pin usage. Not all pin combinations are usable on all + platforms - platforms other then Compute Modules can only use this +@@ -2249,6 +2305,24 @@ Info: Deprecated, legacy version of i2 + Load: + + ++Name: i2c1-pi5 ++Info: Enable i2c1 (Pi 5 only) ++Load: dtoverlay=i2c1-pi5,= ++Params: pins_2_3 Use GPIOs 2 and 3 (default) ++ pins_10_11 Use GPIOs 10 and 11 ++ baudrate Set the baudrate for the interface (default ++ "100000") ++ ++ ++Name: i2c2-pi5 ++Info: Enable i2c2 (Pi 5 only) ++Load: dtoverlay=i2c2-pi5,= ++Params: pins_4_5 Use GPIOs 4 and 5 (default) ++ pins_12_13 Use GPIOs 12 and 13 ++ baudrate Set the baudrate for the interface (default ++ "100000") ++ ++ + Name: i2c3 + Info: Enable the i2c3 bus. BCM2711 only. + Load: dtoverlay=i2c3, +@@ -2258,6 +2332,16 @@ Params: pins_2_3 Use GPIO + "100000") + + ++Name: i2c3-pi5 ++Info: Enable i2c3 (Pi 5 only) ++Load: dtoverlay=i2c3-pi5,= ++Params: pins_6_7 Use GPIOs 6 and 7 (default) ++ pins_14_15 Use GPIOs 14 and 15 ++ pins_22_23 Use GPIOs 22 and 23 ++ baudrate Set the baudrate for the interface (default ++ "100000") ++ ++ + Name: i2c4 + Info: Enable the i2c4 bus. BCM2711 only. + Load: dtoverlay=i2c4, +@@ -2869,6 +2953,10 @@ Load: dtoverlay=midi-uart0 + Params: + + ++Name: midi-uart0-pi5 ++Info: See midi-uart0 (this is the Pi 5 version) ++ ++ + Name: midi-uart1 + Info: Configures UART1 (ttyS0) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI +@@ -2876,29 +2964,45 @@ Load: dtoverlay=midi-uart1 + Params: + + ++Name: midi-uart1-pi5 ++Info: See midi-uart1 (this is the Pi 5 version) ++ ++ + Name: midi-uart2 +-Info: Configures UART2 (ttyAMA1) so that a requested 38.4kbaud actually gets ++Info: Configures UART2 (ttyAMA2) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI + Load: dtoverlay=midi-uart2 + Params: + + ++Name: midi-uart2-pi5 ++Info: See midi-uart2 (this is the Pi 5 version) ++ ++ + Name: midi-uart3 +-Info: Configures UART3 (ttyAMA2) so that a requested 38.4kbaud actually gets ++Info: Configures UART3 (ttyAMA3) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI + Load: dtoverlay=midi-uart3 + Params: + + ++Name: midi-uart3-pi5 ++Info: See midi-uart3 (this is the Pi 5 version) ++ ++ + Name: midi-uart4 +-Info: Configures UART4 (ttyAMA3) so that a requested 38.4kbaud actually gets ++Info: Configures UART4 (ttyAMA4) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI + Load: dtoverlay=midi-uart4 + Params: + + ++Name: midi-uart4-pi5 ++Info: See midi-uart4 (this is the Pi 5 version) ++ ++ + Name: midi-uart5 +-Info: Configures UART5 (ttyAMA4) so that a requested 38.4kbaud actually gets ++Info: Configures UART5 (ttyAMA5) so that a requested 38.4kbaud actually gets + 31.25kbaud, the frequency required for MIDI + Load: dtoverlay=midi-uart5 + Params: +@@ -3921,105 +4025,131 @@ Name: spi1-1cs + Info: Enables spi1 with a single chip select (CS) line and associated spidev + dev node. The gpio pin number for the CS line and spidev device node + creation are configurable. +- N.B.: spi1 is only accessible on devices with a 40pin header, eg: +- A+, B+, Zero and PI2 B; as well as the Compute Module. ++ N.B.: spi1 is not accessible on old Pis without a 40-pin header. + Load: dtoverlay=spi1-1cs,= + Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI1_CE0). +- cs0_spidev Set to 'disabled' to stop the creation of a ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.0 (default +- is 'okay' or enabled). ++ is 'on' or enabled). + + + Name: spi1-2cs + Info: Enables spi1 with two chip select (CS) lines and associated spidev + dev nodes. The gpio pin numbers for the CS lines and spidev device node + creation are configurable. +- N.B.: spi1 is only accessible on devices with a 40pin header, eg: +- A+, B+, Zero and PI2 B; as well as the Compute Module. ++ N.B.: spi1 is not accessible on old Pis without a 40-pin header. + Load: dtoverlay=spi1-2cs,= + Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI1_CE0). + cs1_pin GPIO pin for CS1 (default 17 - BCM SPI1_CE1). +- cs0_spidev Set to 'disabled' to stop the creation of a ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.0 (default +- is 'okay' or enabled). +- cs1_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.1 (default +- is 'okay' or enabled). ++ is 'on' or enabled). + + + Name: spi1-3cs + Info: Enables spi1 with three chip select (CS) lines and associated spidev + dev nodes. The gpio pin numbers for the CS lines and spidev device node + creation are configurable. +- N.B.: spi1 is only accessible on devices with a 40pin header, eg: +- A+, B+, Zero and PI2 B; as well as the Compute Module. ++ N.B.: spi1 is not accessible on old Pis without a 40-pin header. + Load: dtoverlay=spi1-3cs,= + Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI1_CE0). + cs1_pin GPIO pin for CS1 (default 17 - BCM SPI1_CE1). + cs2_pin GPIO pin for CS2 (default 16 - BCM SPI1_CE2). +- cs0_spidev Set to 'disabled' to stop the creation of a ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.0 (default +- is 'okay' or enabled). +- cs1_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.1 (default +- is 'okay' or enabled). +- cs2_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs2_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev1.2 (default +- is 'okay' or enabled). ++ is 'on' or enabled). + + + Name: spi2-1cs +-Info: Enables spi2 with a single chip select (CS) line and associated spidev +- dev node. The gpio pin number for the CS line and spidev device node +- creation are configurable. +- N.B.: spi2 is only accessible with the Compute Module. ++Info: Enables spi2 on GPIOs 40-42 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. spi2-2cs-pi5 is ++ substituted on a Pi 5. ++ N.B.: spi2 is only accessible with the Compute Module or Pi 5. + Load: dtoverlay=spi2-1cs,= + Params: cs0_pin GPIO pin for CS0 (default 43 - BCM SPI2_CE0). +- cs0_spidev Set to 'disabled' to stop the creation of a ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.0 (default +- is 'okay' or enabled). ++ is 'on' or enabled). ++ ++ ++Name: spi2-1cs-pi5 ++Info: Enables spi2 on GPIOs 1-3 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. Pi 5 only. ++Load: dtoverlay=spi2-1cs-pi5,= ++Params: cs0_pin GPIO pin for CS0 (default 0). ++ cs0_spidev Set to 'off' to stop the creation of a ++ userspace device node /dev/spidev2.0 (default ++ is 'on' or enabled). + + + Name: spi2-2cs +-Info: Enables spi2 with two chip select (CS) lines and associated spidev +- dev nodes. The gpio pin numbers for the CS lines and spidev device node +- creation are configurable. +- N.B.: spi2 is only accessible with the Compute Module. ++Info: Enables spi2 on GPIOs 40-42 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. spi2-2cs-pi5 is ++ substituted on a Pi 5. ++ N.B.: spi2 is only accessible with the Compute Module or Pi 5. + Load: dtoverlay=spi2-2cs,= + Params: cs0_pin GPIO pin for CS0 (default 43 - BCM SPI2_CE0). + cs1_pin GPIO pin for CS1 (default 44 - BCM SPI2_CE1). +- cs0_spidev Set to 'disabled' to stop the creation of a ++ cs0_spidev Set to 'off' to stop the creation of a ++ userspace device node /dev/spidev2.0 (default ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a ++ userspace device node /dev/spidev2.1 (default ++ is 'on' or enabled). ++ ++ ++Name: spi2-2cs-pi5 ++Info: Enables spi2 on GPIOs 1-3 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. Pi 5 only. ++Load: dtoverlay=spi2-2cs-pi5,= ++Params: cs0_pin GPIO pin for CS0 (default 0). ++ cs1_pin GPIO pin for CS1 (default 24). ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.0 (default +- is 'okay' or enabled). +- cs1_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.1 (default +- is 'okay' or enabled). ++ is 'on' or enabled). + + + Name: spi2-3cs +-Info: Enables spi2 with three chip select (CS) lines and associated spidev +- dev nodes. The gpio pin numbers for the CS lines and spidev device node +- creation are configurable. +- N.B.: spi2 is only accessible with the Compute Module. ++Info: Enables spi2 on GPIOs 40-42 with three chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. ++ N.B.: spi2 is only accessible with the Compute Module or Pi 5. + Load: dtoverlay=spi2-3cs,= + Params: cs0_pin GPIO pin for CS0 (default 43 - BCM SPI2_CE0). + cs1_pin GPIO pin for CS1 (default 44 - BCM SPI2_CE1). + cs2_pin GPIO pin for CS2 (default 45 - BCM SPI2_CE2). +- cs0_spidev Set to 'disabled' to stop the creation of a ++ cs0_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.0 (default +- is 'okay' or enabled). +- cs1_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.1 (default +- is 'okay' or enabled). +- cs2_spidev Set to 'disabled' to stop the creation of a ++ is 'on' or enabled). ++ cs2_spidev Set to 'off' to stop the creation of a + userspace device node /dev/spidev2.2 (default +- is 'okay' or enabled). ++ is 'on' or enabled). + + + Name: spi3-1cs +-Info: Enables spi3 with a single chip select (CS) line and associated spidev +- dev node. The gpio pin number for the CS line and spidev device node +- creation are configurable. BCM2711 only. ++Info: Enables spi3 on GPIOs 1-3 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. BCM2711 only, ++ spi3-1cs-pi5 is substituted on Pi 5. + Load: dtoverlay=spi3-1cs,= + Params: cs0_pin GPIO pin for CS0 (default 0 - BCM SPI3_CE0). + cs0_spidev Set to 'off' to prevent the creation of a +@@ -4027,10 +4157,22 @@ Params: cs0_pin GPIO pin + is 'on' or enabled). + + ++Name: spi3-1cs-pi5 ++Info: Enables spi3 on GPIOs 5-7 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. Pi 5 only. ++Load: dtoverlay=spi3-1cs-pi5,= ++Params: cs0_pin GPIO pin for CS0 (default 4). ++ cs0_spidev Set to 'off' to prevent the creation of a ++ userspace device node /dev/spidev3.0 (default ++ is 'on' or enabled). ++ ++ + Name: spi3-2cs +-Info: Enables spi3 with two chip select (CS) lines and associated spidev +- dev nodes. The gpio pin numbers for the CS lines and spidev device node +- creation are configurable. BCM2711 only. ++Info: Enables spi3 on GPIO2 1-3 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. BCM2711 only, ++ spi3-2cs-pi5 is substituted on Pi 5. + Load: dtoverlay=spi3-2cs,= + Params: cs0_pin GPIO pin for CS0 (default 0 - BCM SPI3_CE0). + cs1_pin GPIO pin for CS1 (default 24 - BCM SPI3_CE1). +@@ -4042,10 +4184,25 @@ Params: cs0_pin GPIO pin + is 'on' or enabled). + + ++Name: spi3-2cs-pi5 ++Info: Enables spi3 on GPIOs 5-7 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. Pi 5 only. ++Load: dtoverlay=spi3-2cs-pi5,= ++Params: cs0_pin GPIO pin for CS0 (default 4). ++ cs1_pin GPIO pin for CS1 (default 25). ++ cs0_spidev Set to 'off' to prevent the creation of a ++ userspace device node /dev/spidev3.0 (default ++ is 'on' or enabled). ++ cs1_spidev Set to 'off' to prevent the creation of a ++ userspace device node /dev/spidev3.1 (default ++ is 'on' or enabled). ++ ++ + Name: spi4-1cs +-Info: Enables spi4 with a single chip select (CS) line and associated spidev +- dev node. The gpio pin number for the CS line and spidev device node +- creation are configurable. BCM2711 only. ++Info: Enables spi4 on GPIOs 5-7 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin number for the CS line and ++ spidev device node creation are configurable. BCM2711 only. + Load: dtoverlay=spi4-1cs,= + Params: cs0_pin GPIO pin for CS0 (default 4 - BCM SPI4_CE0). + cs0_spidev Set to 'off' to prevent the creation of a +@@ -4054,9 +4211,9 @@ Params: cs0_pin GPIO pin + + + Name: spi4-2cs +-Info: Enables spi4 with two chip select (CS) lines and associated spidev +- dev nodes. The gpio pin numbers for the CS lines and spidev device node +- creation are configurable. BCM2711 only. ++Info: Enables spi4 on GPIOs 5-6 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. BCM2711 only. + Load: dtoverlay=spi4-2cs,= + Params: cs0_pin GPIO pin for CS0 (default 4 - BCM SPI4_CE0). + cs1_pin GPIO pin for CS1 (default 25 - BCM SPI4_CE1). +@@ -4069,23 +4226,27 @@ Params: cs0_pin GPIO pin + + + Name: spi5-1cs +-Info: Enables spi5 with a single chip select (CS) line and associated spidev +- dev node. The gpio pin numbers for the CS lines and spidev device node +- creation are configurable. BCM2711 only. ++Info: Enables spi5 on GPIOs 13-15 with a single chip select (CS) line and ++ associated spidev dev node. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. BCM2711 and Pi 5. + Load: dtoverlay=spi5-1cs,= +-Params: cs0_pin GPIO pin for CS0 (default 12 - BCM SPI5_CE0). ++Params: cs0_pin GPIO pin for CS0 (default 12). + cs0_spidev Set to 'off' to prevent the creation of a + userspace device node /dev/spidev5.0 (default + is 'on' or enabled). + + ++Name: spi5-1cs-pi5 ++Info: See spi5-1cs ++ ++ + Name: spi5-2cs +-Info: Enables spi5 with two chip select (CS) lines and associated spidev +- dev nodes. The gpio pin numbers for the CS lines and spidev device node +- creation are configurable. BCM2711 only. ++Info: Enables spi5 on GPIOs 13-15 with two chip select (CS) lines and ++ associated spidev dev nodes. The gpio pin numbers for the CS lines and ++ spidev device node creation are configurable. BCM2711 and Pi 5. + Load: dtoverlay=spi5-2cs,= +-Params: cs0_pin GPIO pin for CS0 (default 12 - BCM SPI5_CE0). +- cs1_pin GPIO pin for CS1 (default 26 - BCM SPI5_CE1). ++Params: cs0_pin GPIO pin for CS0 (default 12). ++ cs1_pin GPIO pin for CS1 (default 26). + cs0_spidev Set to 'off' to prevent the creation of a + userspace device node /dev/spidev5.0 (default + is 'on' or enabled). +@@ -4094,6 +4255,10 @@ Params: cs0_pin GPIO pin + is 'on' or enabled). + + ++Name: spi5-2cs-pi5 ++Info: See spi5-2cs ++ ++ + Name: spi6-1cs + Info: Enables spi6 with a single chip select (CS) line and associated spidev + dev node. The gpio pin number for the CS line and spidev device node +@@ -4296,6 +4461,12 @@ Params: txd0_pin GPIO pin + 7(Alt3) for 32&33, 6(Alt2) for 36&37 + + ++Name: uart0-pi5 ++Info: Enable uart 0 on GPIOs 14-15. Pi 5 only. ++Load: dtoverlay=uart0-pi5, ++Params: ctsrts Enable CTS/RTS on GPIOs 16-17 (default off) ++ ++ + Name: uart1 + Info: Change the pin usage of uart1 + Load: dtoverlay=uart1,= +@@ -4304,24 +4475,48 @@ Params: txd1_pin GPIO pin + rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15) + + ++Name: uart1-pi5 ++Info: Enable uart 1 on GPIOs 0-1. Pi 5 only. ++Load: dtoverlay=uart1-pi5, ++Params: ctsrts Enable CTS/RTS on GPIOs 2-3 (default off) ++ ++ + Name: uart2 + Info: Enable uart 2 on GPIOs 0-3. BCM2711 only. + Load: dtoverlay=uart2, + Params: ctsrts Enable CTS/RTS on GPIOs 2-3 (default off) + + ++Name: uart2-pi5 ++Info: Enable uart 2 on GPIOs 4-5. Pi 5 only. ++Load: dtoverlay=uart2-pi5, ++Params: ctsrts Enable CTS/RTS on GPIOs 6-7 (default off) ++ ++ + Name: uart3 + Info: Enable uart 3 on GPIOs 4-7. BCM2711 only. + Load: dtoverlay=uart3, + Params: ctsrts Enable CTS/RTS on GPIOs 6-7 (default off) + + ++Name: uart3-pi5 ++Info: Enable uart 3 on GPIOs 8-9. Pi 5 only. ++Load: dtoverlay=uart3-pi5, ++Params: ctsrts Enable CTS/RTS on GPIOs 10-11 (default off) ++ ++ + Name: uart4 + Info: Enable uart 4 on GPIOs 8-11. BCM2711 only. + Load: dtoverlay=uart4, + Params: ctsrts Enable CTS/RTS on GPIOs 10-11 (default off) + + ++Name: uart4-pi5 ++Info: Enable uart 4 on GPIOs 12-13. Pi 5 only. ++Load: dtoverlay=uart4-pi5, ++Params: ctsrts Enable CTS/RTS on GPIOs 14-15 (default off) ++ ++ + Name: uart5 + Info: Enable uart 5 on GPIOs 12-15. BCM2711 only. + Load: dtoverlay=uart5, +@@ -4530,6 +4725,8 @@ Params: sizex Touchscr + invy Touchscreen inverted y axis + swapxy Touchscreen swapped x y axis + disable_touch Disables the touch screen overlay driver ++ dsi0 Use DSI0 and i2c_csi_dsi0 (rather than ++ the default DSI1 and i2c_csi_dsi). + + + Name: vc4-kms-dsi-lt070me05000 +@@ -4579,6 +4776,8 @@ Params: 2_8_inch 2.8" 480 + invx Touchscreen inverted x axis + invy Touchscreen inverted y axis + swapxy Touchscreen swapped x y axis ++ dsi0 Use DSI0 and i2c_csi_dsi0 (rather than ++ the default DSI1 and i2c_csi_dsi). + + + Name: vc4-kms-kippah-7inch +@@ -4633,6 +4832,9 @@ Params: cma-512 CMA is 5 + nohdmi1 Disable HDMI 1 output + + ++Name: vc4-kms-v3d-pi5 ++Info: See vc4-kms-v3d-pi4 (this is the Pi 5 version) ++ + + Name: vc4-kms-vga666 + Info: Enable the VGA666 (resistor ladder ADC) for the vc4-kms-v3d driver. +--- a/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts +@@ -23,7 +23,7 @@ + }; + + fragment@1 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -33,7 +33,7 @@ + target = <&sound>; + __overlay__ { + compatible = "adi,adau1977-adc"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts ++++ b/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts +@@ -5,7 +5,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -37,7 +37,7 @@ + "PDM_DAT", "Microphone Jack"; + status = "okay"; + simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + dailink0_slave: simple-audio-card,codec { + sound-dai = <&adau7002_codec>; +--- a/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -38,7 +38,7 @@ + card_name = "Akkordion"; + dai_name = "IQaudIO DAC"; + dai_stream_name = "IQaudIO DAC HiFi"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts +@@ -18,8 +18,8 @@ + }; + }; + +- fragment@1 { +- target = <&i2s>; ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -46,7 +46,7 @@ + target = <&sound>; + boss_dac: __overlay__ { + compatible = "allo,boss-dac"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + mute-gpios = <&gpio 6 1>; + status = "okay"; + }; +@@ -54,6 +54,8 @@ + + __overrides__ { + 24db_digital_gain = <&boss_dac>,"allo,24db_digital_gain?"; +- slave = <&boss_dac>,"allo,slave?"; ++ slave = <&boss_dac>,"allo,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&boss_dac>,"i2s-controller:0=",<&i2s_clk_producer>; + }; + }; +--- a/arch/arm/boot/dts/overlays/allo-boss2-dac-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/allo-boss2-dac-audio-overlay.dts +@@ -8,7 +8,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; +--- a/arch/arm/boot/dts/overlays/allo-digione-overlay.dts ++++ b/arch/arm/boot/dts/overlays/allo-digione-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -35,7 +35,7 @@ + target = <&sound>; + __overlay__ { + compatible = "allo,allo-digione"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + clock44-gpio = <&gpio 5 0>; + clock48-gpio = <&gpio 6 0>; +--- a/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts +@@ -9,7 +9,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; +--- a/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts +@@ -16,7 +16,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -42,7 +42,7 @@ + target = <&sound>; + piano_dac: __overlay__ { + compatible = "allo,piano-dac"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -41,7 +41,7 @@ + piano_dac: __overlay__ { + compatible = "allo,piano-dac-plus"; + audio-codec = <&allo_pcm5122_4c &allo_pcm5122_4d>; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + mute1-gpios = <&gpio 6 1>; + mute2-gpios = <&gpio 25 1>; + status = "okay"; +--- a/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts +@@ -16,7 +16,7 @@ + format = "i2s"; + + p_cpu_dai: cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; +@@ -40,7 +40,7 @@ + }; + + fragment@2 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; +--- a/arch/arm/boot/dts/overlays/arducam-64mp-overlay.dts ++++ b/arch/arm/boot/dts/overlays/arducam-64mp-overlay.dts +@@ -67,7 +67,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&cam_node>, "clocks:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/arducam-pivariety-overlay.dts ++++ b/arch/arm/boot/dts/overlays/arducam-pivariety-overlay.dts +@@ -85,7 +85,7 @@ + rotation = <&arducam_pivariety>,"rotation:0"; + orientation = <&arducam_pivariety>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&arducam_pivariety>, "clocks:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts ++++ b/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -48,7 +48,7 @@ + mult-gpios = <&gpio 27 0>, <&gpio 22 0>, <&gpio 23 0>, + <&gpio 24 0>; + reset-gpios = <&gpio 5 0>; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + codec = <&cs42448>; + status = "okay"; + }; +--- a/arch/arm/boot/dts/overlays/audioinjector-bare-i2s-overlay.dts ++++ b/arch/arm/boot/dts/overlays/audioinjector-bare-i2s-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -27,7 +27,7 @@ + target = <&sound>; + __overlay__ { + compatible = "simple-audio-card"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + + simple-audio-card,name = "audioinjector-bare"; +@@ -37,7 +37,7 @@ + simple-audio-card,frame-master = <&dailink0_master>; + + dailink0_master: simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; +--- a/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts ++++ b/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -47,7 +47,7 @@ + snd: __overlay__ { + compatible = "ai,audioinjector-isolated-soundcard"; + mute-gpios = <&gpio 17 0>; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + codec = <&cs4272>; + status = "okay"; + }; +--- a/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts ++++ b/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -33,7 +33,7 @@ + target = <&sound>; + __overlay__ { + compatible = "simple-audio-card"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + + simple-audio-card,name = "audioinjector-ultra"; +@@ -57,7 +57,7 @@ + simple-audio-card,frame-master = <&sound_master>; + + simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_consumer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; +--- a/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -32,7 +32,7 @@ + target = <&sound>; + __overlay__ { + compatible = "ai,audioinjector-pi-soundcard"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts ++++ b/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts +@@ -8,7 +8,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -75,7 +75,7 @@ + target = <&sound>; + __overlay__ { + compatible = "as,audiosense-pi"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/chipdip-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/chipdip-dac-overlay.dts +@@ -9,7 +9,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -32,7 +32,7 @@ + target = <&sound>; + __overlay__ { + compatible = "chipdip,chipdip-dac"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + sr0-gpios = <&gpio 5 0>; + sr1-gpios = <&gpio 6 0>; + sr2-gpios = <&gpio 12 0>; +--- a/arch/arm/boot/dts/overlays/cirrus-wm5102-overlay.dts ++++ b/arch/arm/boot/dts/overlays/cirrus-wm5102-overlay.dts +@@ -9,7 +9,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -165,7 +165,7 @@ + target = <&sound>; + __overlay__ { + compatible = "wlf,rpi-cirrus"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/dacberry400-overlay.dts ++++ b/arch/arm/boot/dts/overlays/dacberry400-overlay.dts +@@ -5,7 +5,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -62,7 +62,7 @@ + target = <&sound>; + __overlay__ { + compatible = "osaelectronics,dacberry400"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/dionaudio-kiwi-overlay.dts ++++ b/arch/arm/boot/dts/overlays/dionaudio-kiwi-overlay.dts +@@ -11,7 +11,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -32,7 +32,7 @@ + target = <&sound>; + __overlay__ { + compatible = "dionaudio,dionaudio-kiwi"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts ++++ b/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts +@@ -11,7 +11,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -32,7 +32,7 @@ + target = <&sound>; + __overlay__ { + compatible = "dionaudio,loco-pcm5242-tpa3118"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts ++++ b/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts +@@ -15,13 +15,13 @@ + target = <&sound>; + frag0: __overlay__ { + compatible = "dionaudio,dionaudio-loco-v2"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; + + fragment@1 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/disable-bt-pi5-overlay.dts +@@ -0,0 +1,17 @@ ++/dts-v1/; ++/plugin/; ++ ++/* Disable Bluetooth */ ++ ++#include ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&bluetooth>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/disable-wifi-pi5-overlay.dts +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&sdio2>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/draws-overlay.dts ++++ b/arch/arm/boot/dts/overlays/draws-overlay.dts +@@ -9,7 +9,7 @@ + / { + compatible = "brcm,bcm2835"; + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -131,7 +131,7 @@ + target = <&sound>; + snd: __overlay__ { + compatible = "simple-audio-card"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + + simple-audio-card,name = "draws"; +@@ -153,7 +153,7 @@ + "Line Out", "LOL"; + + dailink0_master: simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + + simple-audio-card,codec { +--- a/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts ++++ b/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts +@@ -25,21 +25,21 @@ + }; + + __overrides__ { +- i2c0 = <&frag13>,"target:0=",<&i2c0>; +- i2c1 = <&frag13>, "target?=0", +- <&frag13>, "target-path=i2c1", ++ i2c0 = <&ts_i2c_frag>,"target:0=",<&i2c0>; ++ i2c1 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c1", + <0>,"-0-1"; +- i2c3 = <&frag13>, "target?=0", +- <&frag13>, "target-path=i2c3", ++ i2c3 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c3", + <0>,"-0-1"; +- i2c4 = <&frag13>, "target?=0", +- <&frag13>, "target-path=i2c4", ++ i2c4 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c4", + <0>,"-0-1"; +- i2c5 = <&frag13>, "target?=0", +- <&frag13>, "target-path=i2c5", ++ i2c5 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c5", + <0>,"-0-1"; +- i2c6 = <&frag13>, "target?=0", +- <&frag13>, "target-path=i2c6", ++ i2c6 = <&ts_i2c_frag>, "target?=0", ++ <&ts_i2c_frag>, "target-path=i2c6", + <0>,"-0-1"; + addr = <&ft5406>,"reg:0"; + }; +--- a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi ++++ b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi +@@ -37,7 +37,7 @@ + }; + }; + +- frag13: fragment@13 { ++ ts_i2c_frag: fragment@13 { + target = <&i2c_csi_dsi>; + i2cbus: __overlay__ { + status = "okay"; +--- a/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts +@@ -53,7 +53,7 @@ + }; + + fragment@3 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -63,7 +63,7 @@ + target = <&sound>; + __overlay__ { + compatible = "fe-pi,fe-pi-audio"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/ghost-amp-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ghost-amp-overlay.dts +@@ -14,7 +14,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -43,7 +43,7 @@ + target = <&sound>; + iqaudio_dac: __overlay__ { + compatible = "iqaudio,iqaudio-dac"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + mute-gpios = <& 0 0>; + iqaudio-dac,auto-mute-amp; + status = "okay"; +--- a/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts ++++ b/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -42,7 +42,7 @@ + target = <&sound>; + __overlay__ { + compatible = "googlevoicehat,googlevoicehat-soundcard"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -32,7 +32,7 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-amp"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts +@@ -15,8 +15,8 @@ + }; + }; + +- fragment@1 { +- target = <&i2s>; ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -46,7 +46,7 @@ + target = <&sound>; + hifiberry_dacplus: __overlay__ { + compatible = "hifiberry,hifiberry-dacplus"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + mute-gpio = <&gpio 4 0>; + reset-gpio = <&gpio 17 0x11>; +@@ -56,7 +56,10 @@ + __overrides__ { + 24db_digital_gain = + <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?"; +- slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?"; ++ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&hifiberry_dacplus>,"i2s-controller:0=",<&i2s_clk_producer>; ++ + leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?"; + mute_ext_ctl = <&hifiberry_dacplus>,"hifiberry-dacplus,mute_ext_ctl:0"; + auto_mute = <&hifiberry_dacplus>,"hifiberry-dacplus,auto_mute?"; +--- a/arch/arm/boot/dts/overlays/hifiberry-amp3-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-amp3-overlay.dts +@@ -10,7 +10,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -50,7 +50,7 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-amp3"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -27,7 +27,7 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-dac"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +@@ -15,8 +15,8 @@ + }; + }; + +- fragment@1 { +- target = <&i2s>; ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -51,7 +51,7 @@ + target = <&sound>; + hifiberry_dacplus: __overlay__ { + compatible = "hifiberry,hifiberry-dacplus"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +@@ -59,7 +59,10 @@ + __overrides__ { + 24db_digital_gain = + <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?"; +- slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?"; ++ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&hifiberry_dacplus>,"i2s-controller:0=",<&i2s_clk_producer>; ++ + leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?"; + }; + }; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts +@@ -15,8 +15,8 @@ + }; + }; + +- fragment@1 { +- target = <&i2s>; ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -58,7 +58,7 @@ + target = <&sound>; + hifiberry_dacplusadc: __overlay__ { + compatible = "hifiberry,hifiberry-dacplusadc"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +@@ -66,7 +66,9 @@ + __overrides__ { + 24db_digital_gain = + <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?"; +- slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?"; ++ slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&hifiberry_dacplusadc>,"i2s-controller:0=",<&i2s_clk_producer>; + leds_off = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,leds_off?"; + }; + }; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts +@@ -15,8 +15,8 @@ + }; + }; + +- fragment@1 { +- target = <&i2s>; ++ frag1: fragment@1 { ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -56,7 +56,7 @@ + hifiberry_dacplusadcpro: __overlay__ { + compatible = "hifiberry,hifiberry-dacplusadcpro"; + audio-codec = <&hb_dac &hb_adc>; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +@@ -64,7 +64,9 @@ + __overrides__ { + 24db_digital_gain = + <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?"; +- slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?"; ++ slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?", ++ <&frag1>,"target:0=",<&i2s_clk_producer>, ++ <&hifiberry_dacplusadcpro>,"i2s-controller:0=",<&i2s_clk_producer>; + leds_off = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,leds_off?"; + }; + }; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -27,7 +27,7 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts +@@ -8,7 +8,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -84,7 +84,7 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-dacplushd"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + clocks = <&pll 0>; + reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>; + status = "okay"; +--- a/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -34,7 +34,7 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-digi"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -34,7 +34,7 @@ + target = <&sound>; + __overlay__ { + compatible = "hifiberry,hifiberry-digi"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + clock44-gpio = <&gpio 5 0>; + clock48-gpio = <&gpio 6 0>; +--- a/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts +@@ -9,13 +9,13 @@ + target = <&sound>; + frag0: __overlay__ { + compatible = "audiophonics,i-sabre-q2m"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; + + fragment@1 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c0-pi5-overlay.dts +@@ -0,0 +1,34 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c0>; ++ frag0: __overlay__ { ++ status = "okay"; ++ clock-frequency = <100000>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&frag0>; ++ __overlay__ { ++ pinctrl-0 = <&rp1_i2c0_0_1>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&frag0>; ++ __dormant__ { ++ pinctrl-0 = <&rp1_i2c0_8_9>; ++ }; ++ }; ++ ++ __overrides__ { ++ pins_0_1 = <0>,"+1-2"; ++ pins_8_9 = <0>,"-1+2"; ++ baudrate = <&frag0>, "clock-frequency:0"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c1-pi5-overlay.dts +@@ -0,0 +1,34 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c1>; ++ frag0: __overlay__ { ++ status = "okay"; ++ clock-frequency = <100000>; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&frag0>; ++ __overlay__ { ++ pinctrl-0 = <&rp1_i2c1_2_3>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&frag0>; ++ __dormant__ { ++ pinctrl-0 = <&rp1_i2c1_10_11>; ++ }; ++ }; ++ ++ __overrides__ { ++ pins_2_3 = <0>,"+1-2"; ++ pins_10_11 = <0>,"-1+2"; ++ baudrate = <&frag0>, "clock-frequency:0"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c2-pi5-overlay.dts +@@ -0,0 +1,21 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c2>; ++ frag0: __overlay__ { ++ status = "okay"; ++ clock-frequency = <100000>; ++ pinctrl-0 = <&rp1_i2c2_4_5>; ++ }; ++ }; ++ ++ __overrides__ { ++ pins_4_5 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c2_4_5>; ++ pins_12_13 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c2_12_13>; ++ baudrate = <&frag0>, "clock-frequency:0"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c3-pi5-overlay.dts +@@ -0,0 +1,22 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c3>; ++ frag0: __overlay__ { ++ status = "okay"; ++ clock-frequency = <100000>; ++ pinctrl-0 = <&rp1_i2c3_6_7>; ++ }; ++ }; ++ ++ __overrides__ { ++ pins_6_7 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c3_6_7>; ++ pins_14_15 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c3_14_15>; ++ pins_22_23 = <&frag0>,"pinctrl-0:0=", <&rp1_i2c3_22_23>; ++ baudrate = <&frag0>, "clock-frequency:0"; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/i2s-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2s-dac-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -27,7 +27,7 @@ + target = <&sound>; + __overlay__ { + compatible = "rpi,rpi-dac"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/imx219-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts +@@ -69,7 +69,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&cam_node>, "clocks:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/imx258-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx258-overlay.dts +@@ -110,7 +110,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <®_frag>, "target:0=",<&cam0_reg>, +--- a/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi ++++ b/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi +@@ -95,7 +95,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&cam_node>, "clocks:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/imx296-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx296-overlay.dts +@@ -94,7 +94,7 @@ + rotation = <&imx296>,"rotation:0"; + orientation = <&imx296>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&imx296>, "clocks:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi ++++ b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi +@@ -65,7 +65,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <®_frag>, "target:0=",<&cam0_reg>, +--- a/arch/arm/boot/dts/overlays/imx519-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx519-overlay.dts +@@ -69,7 +69,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&cam_node>, "clocks:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/imx708-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx708-overlay.dts +@@ -79,12 +79,12 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <®_frag>, "target:0=",<&cam0_reg>, + <&cam_node>, "clocks:0=",<&cam0_clk>, +- <&cam_node>, "VANA1-supply:0=",<&cam0_reg>, ++ <&cam_node>, "vana1-supply:0=",<&cam0_reg>, + <&vcm_node>, "VDD-supply:0=",<&cam0_reg>; + vcm = <&vcm_node>, "status", + <0>, "=4"; +--- a/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -32,7 +32,7 @@ + target = <&sound>; + iqaudio_dac: __overlay__ { + compatible = "iqaudio,iqaudio-codec"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -35,7 +35,7 @@ + target = <&sound>; + frag2: __overlay__ { + compatible = "iqaudio,iqaudio-dac"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -35,7 +35,7 @@ + target = <&sound>; + iqaudio_dac: __overlay__ { + compatible = "iqaudio,iqaudio-dac"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + mute-gpios = <&gpio 22 0>; + status = "okay"; + }; +--- a/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -34,7 +34,7 @@ + target = <&sound>; + wm8804_digi: __overlay__ { + compatible = "iqaudio,wm8804-digi"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/irs1125-overlay.dts ++++ b/arch/arm/boot/dts/overlays/irs1125-overlay.dts +@@ -82,7 +82,7 @@ + + __overrides__ { + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&irs1125>, "clocks:0=",<&cam0_clk>; +--- a/arch/arm/boot/dts/overlays/justboom-both-overlay.dts ++++ b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts +@@ -7,7 +7,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -54,7 +54,7 @@ + target = <&sound>; + frag3: __overlay__ { + compatible = "justboom,justboom-both"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -35,7 +35,7 @@ + target = <&sound>; + frag2: __overlay__ { + compatible = "justboom,justboom-dac"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts ++++ b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -34,7 +34,7 @@ + target = <&sound>; + __overlay__ { + compatible = "justboom,justboom-digi"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/max98357a-overlay.dts ++++ b/arch/arm/boot/dts/overlays/max98357a-overlay.dts +@@ -12,7 +12,7 @@ + + /* Enable I2S */ + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -52,7 +52,7 @@ + simple-audio-card,name = "MAX98357A"; + status = "okay"; + simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + simple-audio-card,codec { + sound-dai = <&max98357a_dac>; +@@ -69,7 +69,7 @@ + simple-audio-card,name = "MAX98357A"; + status = "okay"; + simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + simple-audio-card,codec { + sound-dai = <&max98357a_nsd>; +--- a/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -32,7 +32,7 @@ + target = <&sound>; + __overlay__ { + compatible = "simple-audio-card"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + + simple-audio-card,name = "mbed-DAC"; +@@ -52,7 +52,7 @@ + simple-audio-card,format = "i2s"; + + simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + + sound_master: simple-audio-card,codec { +--- a/arch/arm/boot/dts/overlays/merus-amp-overlay.dts ++++ b/arch/arm/boot/dts/overlays/merus-amp-overlay.dts +@@ -9,7 +9,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -52,7 +52,7 @@ + target = <&sound>; + __overlay__ { + compatible = "merus,merus-amp"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + }; + }; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart0-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk0 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart0_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart0>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart1-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk1 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart1_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart1>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart2-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk2 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart2_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart2>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart3-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk3 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart3_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart3>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/midi-uart4-pi5-overlay.dts +@@ -0,0 +1,35 @@ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/* ++ * Fake a higher clock rate to get a larger divisor, and thereby a lower ++ * baudrate. The real clock is 100MHz, which we scale so that requesting ++ * 38.4kHz results in an actual 31.25kHz. ++ * ++ * 100000000*38400/31250 = 122880000 ++ */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ midi_clk: midi_clk4 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "uart4_pclk"; ++ clock-frequency = <122880000>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&uart4>; ++ __overlay__ { ++ clocks = <&midi_clk &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ }; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/ov2311-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ov2311-overlay.dts +@@ -60,7 +60,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&cam_node>, "clocks:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts +@@ -72,7 +72,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <®_frag>, "target:0=",<&cam0_reg>, + <&clk_frag>, "target:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/ov7251-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ov7251-overlay.dts +@@ -60,7 +60,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&cam_node>, "clocks:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/ov9281-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ov9281-overlay.dts +@@ -61,7 +61,7 @@ + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&cam_node>, "clocks:0=",<&cam0_clk>, +--- a/arch/arm/boot/dts/overlays/overlay_map.dts ++++ b/arch/arm/boot/dts/overlays/overlay_map.dts +@@ -1,32 +1,100 @@ + /dts-v1/; + + / { ++ audremap { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ balena-fin { ++ bcm2835; ++ bcm2711; ++ }; ++ + bmp085_i2c-sensor { + deprecated = "use i2c-sensor,bmp085"; + }; + ++ cm-swap-i2c0 { ++ bcm2835; ++ bcm2711; ++ }; ++ + cutiepi-panel { + bcm2711; + }; + ++ disable-bt { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "disable-bt-pi5"; ++ }; ++ ++ disable-bt-pi5 { ++ bcm2712; ++ }; ++ + disable-emmc2 { + bcm2711; + }; + ++ disable-wifi { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "disable-wifi-pi5"; ++ }; ++ ++ disable-wifi-pi5 { ++ bcm2712; ++ }; ++ + highperi { + bcm2711; + }; + ++ i2c0 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "i2c0-pi5"; ++ }; ++ + i2c0-bcm2708 { + deprecated = "use i2c0"; + }; + ++ i2c0-pi5 { ++ bcm2712; ++ }; ++ ++ i2c1 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "i2c1-pi5"; ++ }; ++ + i2c1-bcm2708 { + deprecated = "use i2c1"; + }; + ++ i2c1-pi5 { ++ bcm2712; ++ }; ++ ++ i2c2 { ++ bcm2712 = "i2c2-pi5"; ++ }; ++ ++ i2c2-pi5 { ++ bcm2712; ++ }; ++ + i2c3 { + bcm2711; ++ bcm2712 = "i2c3-pi5"; ++ }; ++ ++ i2c3-pi5 { ++ bcm2712; + }; + + i2c4 { +@@ -41,26 +109,76 @@ + bcm2711; + }; + ++ i2s-gpio28-31 { ++ bcm2835; ++ bcm2711; ++ }; ++ + lirc-rpi { + deprecated = "use gpio-ir"; + }; + ++ midi-uart0 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "midi-uart0-pi5"; ++ }; ++ ++ midi-uart0-pi5 { ++ bcm2712; ++ }; ++ ++ midi-uart1 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "midi-uart1-pi5"; ++ }; ++ ++ midi-uart1-pi5 { ++ bcm2712; ++ }; ++ + midi-uart2 { + bcm2711; ++ bcm2712 = "midi-uart2-pi5"; ++ }; ++ ++ midi-uart2-pi5 { ++ bcm2712; + }; + + midi-uart3 { + bcm2711; ++ bcm2712 = "midi-uart3-pi5"; ++ }; ++ ++ midi-uart3-pi5 { ++ bcm2712; + }; + + midi-uart4 { + bcm2711; ++ bcm2712 = "midi-uart4-pi5"; ++ }; ++ ++ midi-uart4-pi5 { ++ bcm2712; + }; + + midi-uart5 { + bcm2711; + }; + ++ miniuart-bt { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ mmc { ++ bcm2835; ++ bcm2711; ++ }; ++ + mpu6050 { + deprecated = "use i2c-sensor,mpu6050"; + }; +@@ -118,6 +236,16 @@ + deprecated = "no longer necessary"; + }; + ++ sdhost { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ sdio { ++ bcm2835; ++ bcm2711; ++ }; ++ + sdio-1bit { + deprecated = "use sdio,bus_width=1,gpios_22_25"; + }; +@@ -126,6 +254,21 @@ + deprecated = "use 'dtparam=sd_poll_once' etc."; + }; + ++ smi { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ smi-dev { ++ bcm2835; ++ bcm2711; ++ }; ++ ++ smi-nand { ++ bcm2835; ++ bcm2711; ++ }; ++ + spi0-cs { + renamed = "spi0-2cs"; + }; +@@ -134,12 +277,42 @@ + deprecated = "no longer necessary"; + }; + ++ spi2-1cs { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "spi2-1cs-pi5"; ++ }; ++ ++ spi2-1cs-pi5 { ++ bcm2712; ++ }; ++ ++ spi2-2cs { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "spi2-2cs-pi5"; ++ }; ++ ++ spi2-2cs-pi5 { ++ bcm2712; ++ }; ++ + spi3-1cs { + bcm2711; ++ bcm2712 = "spi3-1cs-pi5"; ++ }; ++ ++ spi3-1cs-pi5 { ++ bcm2712; + }; + + spi3-2cs { + bcm2711; ++ bcm2712 = "spi3-2cs-pi5"; ++ }; ++ ++ spi3-2cs-pi5 { ++ bcm2712; + }; + + spi4-1cs { +@@ -152,10 +325,20 @@ + + spi5-1cs { + bcm2711; ++ bcm2712 = "spi5-1cs-pi5"; ++ }; ++ ++ spi5-1cs-pi5 { ++ bcm2712; + }; + + spi5-2cs { + bcm2711; ++ bcm2712 = "spi5-2cs-pi5"; ++ }; ++ ++ spi5-2cs-pi5 { ++ bcm2712; + }; + + spi6-1cs { +@@ -166,16 +349,51 @@ + bcm2711; + }; + ++ uart0 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "uart0-pi5"; ++ }; ++ ++ uart0-pi5 { ++ bcm2712; ++ }; ++ ++ uart1 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "uart1-pi5"; ++ }; ++ ++ uart1-pi5 { ++ bcm2712; ++ }; ++ + uart2 { + bcm2711; ++ bcm2712 = "uart2-pi5"; ++ }; ++ ++ uart2-pi5 { ++ bcm2712; + }; + + uart3 { + bcm2711; ++ bcm2712 = "uart3-pi5"; ++ }; ++ ++ uart3-pi5 { ++ bcm2712; + }; + + uart4 { + bcm2711; ++ bcm2712 = "uart4-pi5"; ++ }; ++ ++ uart4-pi5 { ++ bcm2712; + }; + + uart5 { +@@ -198,10 +416,12 @@ + vc4-fkms-v3d { + bcm2835; + bcm2711 = "vc4-fkms-v3d-pi4"; ++ bcm2712 = "vc4-fkms-v3d-pi4"; + }; + + vc4-fkms-v3d-pi4 { + bcm2711; ++ bcm2712; + }; + + vc4-kms-dpi-at056tn53v1 { +@@ -211,10 +431,16 @@ + vc4-kms-v3d { + bcm2835; + bcm2711 = "vc4-kms-v3d-pi4"; ++ bcm2712 = "vc4-kms-v3d-pi5"; + }; + + vc4-kms-v3d-pi4 { + bcm2711; ++ bcm2712 = "vc4-kms-v3d-pi5"; ++ }; ++ ++ vc4-kms-v3d-pi5 { ++ bcm2712; + }; + + vl805 { +--- a/arch/arm/boot/dts/overlays/pibell-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pibell-overlay.dts +@@ -24,7 +24,7 @@ + }; + + fragment@1 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; +@@ -43,7 +43,7 @@ + format = "i2s"; + + r_cpu_dai: cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + + /* example TDM slot configuration + dai-tdm-slot-num = <2>; +@@ -60,7 +60,7 @@ + format = "i2s"; + + p_cpu_dai: cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + + /* example TDM slot configuration + dai-tdm-slot-num = <2>; +--- a/arch/arm/boot/dts/overlays/pifi-40-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pifi-40-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -42,7 +42,7 @@ + pifi_40: __overlay__ { + compatible = "pifi,pifi-40"; + audio-codec = <&tas5711l &tas5711r>; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + pdn-gpios = <&gpio 23 1>; + status = "okay"; + }; +--- a/arch/arm/boot/dts/overlays/pifi-dac-hd-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pifi-dac-hd-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -38,7 +38,7 @@ + simple-audio-card,dai-link@1 { + format = "i2s"; + cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + codec { + sound-dai = <&pcm5142>; +--- a/arch/arm/boot/dts/overlays/pifi-dac-zero-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pifi-dac-zero-overlay.dts +@@ -16,7 +16,7 @@ + format = "i2s"; + + cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; +@@ -40,7 +40,7 @@ + }; + + fragment@2 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; +--- a/arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -34,7 +34,7 @@ + target = <&sound>; + __overlay__ { + compatible = "pifi,pifi-mini-210"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + + status = "okay"; + }; +--- a/arch/arm/boot/dts/overlays/pisound-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pisound-overlay.dts +@@ -75,7 +75,7 @@ + target = <&sound>; + __overlay__ { + compatible = "blokaslabs,pisound"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + + pinctrl-names = "default"; +@@ -108,7 +108,7 @@ + }; + + fragment@7 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +--- a/arch/arm/boot/dts/overlays/proto-codec-overlay.dts ++++ b/arch/arm/boot/dts/overlays/proto-codec-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -32,7 +32,7 @@ + target = <&sound>; + __overlay__ { + compatible = "rpi,rpi-proto"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- a/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -42,7 +42,7 @@ + target = <&sound>; + __overlay__ { + compatible = "rra,digidac1-soundcard"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + }; + }; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi2-1cs-pi5-overlay.dts +@@ -0,0 +1,33 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi2>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 0 1>; ++ status = "okay"; ++ ++ spidev2_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs0_spidev = <&spidev2_0>,"status"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi2-2cs-pi5-overlay.dts +@@ -0,0 +1,44 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi2>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 0 1>, <&gpio 24 1>; ++ status = "okay"; ++ ++ spidev2_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ ++ spidev2_1: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs1_pin = <&frag1>,"cs-gpios:16"; ++ cs0_spidev = <&spidev2_0>,"status"; ++ cs1_spidev = <&spidev2_1>,"status"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi3-1cs-pi5-overlay.dts +@@ -0,0 +1,33 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi3>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 4 1>; ++ status = "okay"; ++ ++ spidev3_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs0_spidev = <&spidev3_0>,"status"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi3-2cs-pi5-overlay.dts +@@ -0,0 +1,44 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi3>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 4 1>, <&gpio 25 1>; ++ status = "okay"; ++ ++ spidev3_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ ++ spidev3_1: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs1_pin = <&frag1>,"cs-gpios:16"; ++ cs0_spidev = <&spidev3_0>,"status"; ++ cs1_spidev = <&spidev3_1>,"status"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi5-1cs-pi5-overlay.dts +@@ -0,0 +1,33 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi5>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 12 1>; ++ status = "okay"; ++ ++ spidev5_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs0_spidev = <&spidev5_0>,"status"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/spi5-2cs-pi5-overlay.dts +@@ -0,0 +1,44 @@ ++/dts-v1/; ++/plugin/; ++ ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&spi5>; ++ frag1: __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs-gpios = <&gpio 12 1>, <&gpio 26 1>; ++ status = "okay"; ++ ++ spidev5_0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ ++ spidev5_1: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ cs0_pin = <&frag1>,"cs-gpios:4"; ++ cs1_pin = <&frag1>,"cs-gpios:16"; ++ cs0_spidev = <&spidev5_0>,"status"; ++ cs1_spidev = <&spidev5_1>,"status"; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts ++++ b/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts +@@ -9,7 +9,7 @@ + target = <&sound>; + __overlay__ { + compatible = "simple-audio-card"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_consumer>; + status = "okay"; + + simple-audio-card,name = "SuperAudioBoard"; +@@ -32,7 +32,7 @@ + simple-audio-card,frame-master = <&sound_master>; + + simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_consumer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; +@@ -45,7 +45,7 @@ + }; + + fragment@1 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +--- a/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts +@@ -8,7 +8,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -31,16 +31,16 @@ + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,name = "tc358743"; +- simple-audio-card,bitclock-master = <&dailink0_slave>; +- simple-audio-card,frame-master = <&dailink0_slave>; ++ simple-audio-card,bitclock-master = <&dailink0_master>; ++ simple-audio-card,frame-master = <&dailink0_master>; + status = "okay"; + + simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_consumer>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + }; +- dailink0_slave: simple-audio-card,codec { ++ dailink0_master: simple-audio-card,codec { + sound-dai = <&tc358743_codec>; + }; + }; +--- a/arch/arm/boot/dts/overlays/tc358743-overlay.dts ++++ b/arch/arm/boot/dts/overlays/tc358743-overlay.dts +@@ -101,7 +101,7 @@ + 4lane = <0>, "-2+3-7+8"; + link-frequency = <&tc358743_0>,"link-frequencies#0"; + media-controller = <&csi>,"brcm,media-controller?"; +- cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&tc358743>, "clocks:0=",<&cam0_clk>; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart0-pi5-overlay.dts +@@ -0,0 +1,17 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart0>; ++ frag0: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart0_ctsrts_pins>; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart1-pi5-overlay.dts +@@ -0,0 +1,17 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart1>; ++ frag0: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart1_ctsrts_pins>; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart2-pi5-overlay.dts +@@ -0,0 +1,17 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart2>; ++ frag0: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart2_ctsrts_pins>; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart3-pi5-overlay.dts +@@ -0,0 +1,17 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart3>; ++ frag0: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart3_ctsrts_pins>; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/uart4-pi5-overlay.dts +@@ -0,0 +1,17 @@ ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&uart4>; ++ frag0: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ ctsrts = <&frag0>,"pinctrl-0:4=",<&uart4_ctsrts_pins>; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/udrc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/udrc-overlay.dts +@@ -9,7 +9,7 @@ + / { + compatible = "brcm,bcm2835"; + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + clocks = <&clocks BCM2835_CLOCK_PCM>; + clock-names = "pcm"; +@@ -71,7 +71,7 @@ + target = <&sound>; + snd: __overlay__ { + compatible = "simple-audio-card"; +- i2s-controller = <&i2s>; ++ i2s-controller = <&i2s_clk_producer>; + status = "okay"; + + simple-audio-card,name = "udrc"; +@@ -93,7 +93,7 @@ + "Line Out", "LOL"; + + dailink0_master: simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + + simple-audio-card,codec { +--- a/arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_consumer>; + __overlay__ { + status = "okay"; + }; +@@ -29,14 +29,14 @@ + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,name = "dabboard"; +- simple-audio-card,bitclock-master = <&dailink0_slave>; +- simple-audio-card,frame-master = <&dailink0_slave>; ++ simple-audio-card,bitclock-master = <&dailink0_master>; ++ simple-audio-card,frame-master = <&dailink0_master>; + simple-audio-card,widgets = "Microphone", "Microphone Jack"; + status = "okay"; + simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_consumer>; + }; +- dailink0_slave: simple-audio-card,codec { ++ dailink0_master: simple-audio-card,codec { + #sound-dai-cells = <0>; + sound-dai = <&dmic_codec>; + }; +--- a/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts +@@ -37,4 +37,10 @@ + status = "okay"; + }; + }; ++ fragment@5 { ++ target-path = "/chosen"; ++ __overlay__ { ++ bootargs = "clk_ignore_unused"; ++ }; ++ }; + }; +--- a/arch/arm/boot/dts/overlays/vc4-fkms-v3d-pi4-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-pi4-overlay.dts +@@ -41,4 +41,10 @@ + status = "okay"; + }; + }; ++ fragment@5 { ++ target-path = "/chosen"; ++ __overlay__ { ++ bootargs = "clk_ignore_unused"; ++ }; ++ }; + }; +--- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts +@@ -11,7 +11,7 @@ + / { + /* No compatible as it will have come from edt-ft5406.dtsi */ + +- fragment@0 { ++ dsi_frag: fragment@0 { + target = <&dsi1>; + __overlay__ { + #address-cells = <1>; +@@ -51,8 +51,8 @@ + fragment@1 { + target-path = "/"; + __overlay__ { +- panel_disp1: panel_disp1@0 { +- reg = <0>; ++ panel_disp: panel_disp@1 { ++ reg = <1>; + compatible = "raspberrypi,7inch-dsi", "simple-panel"; + backlight = <®_display>; + power-supply = <®_display>; +@@ -64,8 +64,8 @@ + }; + }; + +- reg_bridge: reg_bridge@0 { +- reg = <0>; ++ reg_bridge: reg_bridge@1 { ++ reg = <1>; + compatible = "regulator-fixed"; + regulator-name = "bridge_reg"; + gpio = <®_display 0 0>; +@@ -75,7 +75,7 @@ + }; + }; + +- fragment@2 { ++ i2c_frag: fragment@2 { + target = <&i2c_csi_dsi>; + __overlay__ { + #address-cells = <1>; +@@ -113,6 +113,12 @@ + }; + + __overrides__ { ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, ++ <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&ts_i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&panel_disp>, "reg:0=0", ++ <®_bridge>, "reg:0=0", ++ <®_bridge>, "regulator-name=bridge_reg_0"; + disable_touch = <0>, "-10-11-12"; + }; + }; +--- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts +@@ -9,7 +9,7 @@ + / { + compatible = "brcm,bcm2835"; + +- fragment@0 { ++ dsi_frag: fragment@0 { + target = <&dsi1>; + __overlay__ { + #address-cells = <1>; +@@ -29,7 +29,7 @@ + }; + }; + +- frag2: fragment@2 { ++ i2c_frag: fragment@2 { + target = <&i2c_csi_dsi>; + __overlay__ { + #address-cells = <1>; +@@ -112,12 +112,14 @@ + <&touch>, "touchscreen-size-y:0=1480", + <&touch>, "touchscreen-inverted-x?", + <&touch>, "touchscreen-swapped-x-y?"; +- i2c1 = <&frag2>, "target:0=",<&i2c1>, ++ i2c1 = <&i2c_frag>, "target:0=",<&i2c1>, + <0>, "-3-4+5"; + disable_touch = <&touch>, "status=disabled"; + rotation = <&panel>, "rotation:0"; + invx = <&touch>,"touchscreen-inverted-x?"; + invy = <&touch>,"touchscreen-inverted-y?"; + swapxy = <&touch>,"touchscreen-swapped-x-y?"; ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, ++ <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>; + }; + }; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts +@@ -0,0 +1,147 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include "cma-overlay.dts" ++ ++&frag0 { ++ size = <((320-4)*1024*1024)>; ++}; ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@1 { ++ target = <&fb>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&aon_intr>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&ddc0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&ddc1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&hdmi0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@6 { ++ target = <&hdmi1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@7 { ++ target = <&hvs>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@8 { ++ target = <&mop>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@9 { ++ target = <&moplet>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@10 { ++ target = <&pixelvalve0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@11 { ++ target = <&pixelvalve1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@12 { ++ target = <&v3d>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@13 { ++ target = <&vec>; ++ frag13: __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@14 { ++ target = <&hdmi0>; ++ __dormant__ { ++ dmas; ++ }; ++ }; ++ ++ fragment@15 { ++ target = <&hdmi1>; ++ __dormant__ { ++ dmas; ++ }; ++ }; ++ ++ fragment@16 { ++ target = <&disp_intr>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@17 { ++ target = <&vc4>; ++ __overlay__ { ++ /* IOMMU attaches here, where we allocate DMA buffers */ ++ iommus = <&iommu4>; ++ }; ++ }; ++ ++ __overrides__ { ++ audio = <0>,"!14"; ++ audio1 = <0>,"!15"; ++ noaudio = <0>,"=14", <0>,"=15"; ++ composite = <0>, "!3", ++ <0>, "!4", ++ <0>, "!5", ++ <0>, "!6", ++ <0>, "!10", ++ <0>, "!11", ++ <&frag13>, "status"; ++ nohdmi0 = <0>, "-3-5-10"; ++ nohdmi1 = <0>, "-4-6-11"; ++ nohdmi = <0>, "-3-4-5-6-10-11"; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts +@@ -94,7 +94,14 @@ + }; + }; + ++ fragment@5 { ++ target = <&i2c_vc>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { +- ddc = <0>,"=2", <0>,"=3", <0>,"=4"; ++ ddc = <0>,"=2", <0>,"=3", <0>,"=4", <0>,"=5"; + }; + }; +--- a/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts ++++ b/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2s>; ++ target = <&i2s_clk_producer>; + __overlay__ { + status = "okay"; + }; +@@ -65,7 +65,7 @@ + "RINPUT2", "Mic Jack"; + + simple-audio-card,cpu { +- sound-dai = <&i2s>; ++ sound-dai = <&i2s_clk_producer>; + }; + dailink0_slave: simple-audio-card,codec { + sound-dai = <&wm8960>; +--- /dev/null ++++ b/arch/arm/boot/dts/rp1.dtsi +@@ -0,0 +1,1168 @@ ++#include ++#include ++#include ++ ++&rp1_target { ++ rp1: rp1 { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ #interrupt-cells = <2>; ++ interrupt-controller; ++ interrupt-parent = <&rp1>; ++ ++ // ranges and dma-ranges must be provided by the includer ++ ++ rp1_clocks: clocks@18000 { ++ compatible = "raspberrypi,rp1-clocks"; ++ #clock-cells = <1>; ++ reg = <0xc0 0x40018000 0x0 0x10038>; ++ clocks = <&clk_xosc>; ++ ++ assigned-clocks = <&rp1_clocks RP1_PLL_SYS_CORE>, ++ <&rp1_clocks RP1_PLL_AUDIO_CORE>, ++ // RP1_PLL_VIDEO_CORE and dividers are now managed by VEC,DPI drivers ++ <&rp1_clocks RP1_PLL_SYS>, ++ <&rp1_clocks RP1_PLL_SYS_SEC>, ++ <&rp1_clocks RP1_PLL_AUDIO>, ++ <&rp1_clocks RP1_PLL_AUDIO_SEC>, ++ <&rp1_clocks RP1_CLK_SYS>, ++ <&rp1_clocks RP1_PLL_SYS_PRI_PH>, ++ // RP1_CLK_SLOW_SYS is used for the frequency counter (FC0) ++ <&rp1_clocks RP1_CLK_SLOW_SYS>, ++ <&rp1_clocks RP1_CLK_SDIO_TIMER>, ++ <&rp1_clocks RP1_CLK_SDIO_ALT_SRC>, ++ <&rp1_clocks RP1_CLK_ETH_TSU>; ++ ++ assigned-clock-rates = <1000000000>, // RP1_PLL_SYS_CORE ++ <1536000000>, // RP1_PLL_AUDIO_CORE ++ <200000000>, // RP1_PLL_SYS ++ <125000000>, // RP1_PLL_SYS_SEC ++ <61440000>, // RP1_PLL_AUDIO ++ <192000000>, // RP1_PLL_AUDIO_SEC ++ <200000000>, // RP1_CLK_SYS ++ <100000000>, // RP1_PLL_SYS_PRI_PH ++ // Must match the XOSC frequency ++ <50000000>, // RP1_CLK_SLOW_SYS ++ <1000000>, // RP1_CLK_SDIO_TIMER ++ <200000000>, // RP1_CLK_SDIO_ALT_SRC ++ <50000000>; // RP1_CLK_ETH_TSU ++ }; ++ ++ rp1_uart0: serial@30000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40030000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ dmas = <&rp1_dma RP1_DMA_UART0_TX>, ++ <&rp1_dma RP1_DMA_UART0_RX>; ++ dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart1: serial@34000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40034000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART1_TX>, ++ // <&rp1_dma RP1_DMA_UART1_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart2: serial@38000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40038000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART2_TX>, ++ // <&rp1_dma RP1_DMA_UART2_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart3: serial@3c000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x4003c000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART3_TX>, ++ // <&rp1_dma RP1_DMA_UART3_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart4: serial@40000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40040000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART4_TX>, ++ // <&rp1_dma RP1_DMA_UART4_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart5: serial@44000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40044000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART5_TX>, ++ // <&rp1_dma RP1_DMA_UART5_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_spi8: spi@4c000 { ++ reg = <0xc0 0x4004c000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI8_TX>, ++ <&rp1_dma RP1_DMA_SPI8_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi0: spi@50000 { ++ reg = <0xc0 0x40050000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI0_TX>, ++ <&rp1_dma RP1_DMA_SPI0_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi1: spi@54000 { ++ reg = <0xc0 0x40054000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <0>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI1_TX>, ++ <&rp1_dma RP1_DMA_SPI1_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi2: spi@58000 { ++ reg = <0xc0 0x40058000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI2_TX>, ++ <&rp1_dma RP1_DMA_SPI2_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi3: spi@5c000 { ++ reg = <0xc0 0x4005c000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI3_TX>, ++ <&rp1_dma RP1_DMA_SPI3_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ // SPI4 is a target/slave interface ++ rp1_spi4: spi@60000 { ++ reg = <0xc0 0x40060000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <0>; ++ #size-cells = <0>; ++ num-cs = <1>; ++ spi-slave; ++ dmas = <&rp1_dma RP1_DMA_SPI4_TX>, ++ <&rp1_dma RP1_DMA_SPI4_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ ++ slave { ++ compatible = "spidev"; ++ spi-max-frequency = <1000000>; ++ }; ++ }; ++ ++ rp1_spi5: spi@64000 { ++ reg = <0xc0 0x40064000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI5_TX>, ++ <&rp1_dma RP1_DMA_SPI5_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ // SPI7 is a target/slave interface ++ rp1_spi7: spi@6c000 { ++ reg = <0xc0 0x4006c000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <0>; ++ #size-cells = <0>; ++ num-cs = <1>; ++ spi-slave; ++ dmas = <&rp1_dma RP1_DMA_SPI7_TX>, ++ <&rp1_dma RP1_DMA_SPI7_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ ++ slave { ++ compatible = "spidev"; ++ spi-max-frequency = <1000000>; ++ }; ++ }; ++ ++ rp1_i2c0: i2c@70000 { ++ reg = <0xc0 0x40070000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c1: i2c@74000 { ++ reg = <0xc0 0x40074000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c2: i2c@78000 { ++ reg = <0xc0 0x40078000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c3: i2c@7c000 { ++ reg = <0xc0 0x4007c000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c4: i2c@80000 { ++ reg = <0xc0 0x40080000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c5: i2c@84000 { ++ reg = <0xc0 0x40084000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c6: i2c@88000 { ++ reg = <0xc0 0x40088000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ status = "disabled"; ++ }; ++ ++ rp1_pwm0: pwm@98000 { ++ compatible = "raspberrypi,rp1-pwm"; ++ reg = <0xc0 0x40098000 0x0 0x100>; ++ #pwm-cells = <3>; ++ clocks = <&rp1_clocks RP1_CLK_PWM0>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_PWM0>; ++ assigned-clock-rates = <6144000>; ++ status = "disabled"; ++ }; ++ ++ rp1_pwm1: pwm@9c000 { ++ compatible = "raspberrypi,rp1-pwm"; ++ reg = <0xc0 0x4009c000 0x0 0x100>; ++ #pwm-cells = <3>; ++ clocks = <&rp1_clocks RP1_CLK_PWM1>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>; ++ assigned-clock-rates = <6144000>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2s0: i2s@a0000 { ++ reg = <0xc0 0x400a0000 0x0 0x1000>; ++ compatible = "snps,designware-i2s"; ++ // Providing an interrupt disables DMA ++ // interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_I2S>; ++ clock-names = "i2sclk"; ++ #sound-dai-cells = <0>; ++ dmas = <&rp1_dma RP1_DMA_I2S0_TX>,<&rp1_dma RP1_DMA_I2S0_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_i2s1: i2s@a4000 { ++ reg = <0xc0 0x400a4000 0x0 0x1000>; ++ compatible = "snps,designware-i2s"; ++ // Providing an interrupt disables DMA ++ // interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_I2S>; ++ clock-names = "i2sclk"; ++ #sound-dai-cells = <0>; ++ dmas = <&rp1_dma RP1_DMA_I2S1_TX>,<&rp1_dma RP1_DMA_I2S1_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_i2s2: i2s@a8000 { ++ reg = <0xc0 0x400a8000 0x0 0x1000>; ++ compatible = "snps,designware-i2s"; ++ // Providing an interrupt disables DMA ++ // interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_I2S>; ++ status = "disabled"; ++ }; ++ ++ rp1_sdio_clk0: sdio_clk0@b0004 { ++ compatible = "raspberrypi,rp1-sdio-clk"; ++ reg = <0xc0 0x400b0004 0x0 0x1c>; ++ clocks = <&sdio_src &sdhci_core>; ++ clock-names = "src", "base"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_sdio_clk1: sdio_clk1@b4004 { ++ compatible = "raspberrypi,rp1-sdio-clk"; ++ reg = <0xc0 0x400b4004 0x0 0x1c>; ++ clocks = <&sdio_src &sdhci_core>; ++ clock-names = "src", "base"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_adc: adc@c8000 { ++ compatible = "raspberrypi,rp1-adc"; ++ reg = <0xc0 0x400c8000 0x0 0x4000>; ++ clocks = <&rp1_clocks RP1_CLK_ADC>; ++ clock-names = "adcclk"; ++ #clock-cells = <0>; ++ vref-supply = <&rp1_vdd_3v3>; ++ status = "disabled"; ++ }; ++ ++ rp1_gpio: gpio@d0000 { ++ reg = <0xc0 0x400d0000 0x0 0xc000>, ++ <0xc0 0x400e0000 0x0 0xc000>, ++ <0xc0 0x400f0000 0x0 0xc000>; ++ compatible = "raspberrypi,rp1-gpio"; ++ interrupts = , ++ , ++ ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ ++ rp1_uart0_14_15: rp1_uart0_14_15 { ++ pin_txd { ++ function = "uart0"; ++ pins = "gpio14"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart0"; ++ pins = "gpio15"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart0_ctsrts_16_17: rp1_uart0_ctsrts_16_17 { ++ pin_cts { ++ function = "uart0"; ++ pins = "gpio16"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart0"; ++ pins = "gpio17"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart1_0_1: rp1_uart1_0_1 { ++ pin_txd { ++ function = "uart1"; ++ pins = "gpio0"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart1"; ++ pins = "gpio1"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart1_ctsrts_2_3: rp1_uart1_ctsrts_2_3 { ++ pin_cts { ++ function = "uart1"; ++ pins = "gpio2"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart1"; ++ pins = "gpio3"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart2_4_5: rp1_uart2_4_5 { ++ pin_txd { ++ function = "uart2"; ++ pins = "gpio4"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart2"; ++ pins = "gpio5"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart2_ctsrts_6_7: rp1_uart2_ctsrts_6_7 { ++ pin_cts { ++ function = "uart2"; ++ pins = "gpio6"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart2"; ++ pins = "gpio7"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart3_8_9: rp1_uart3_8_9 { ++ pin_txd { ++ function = "uart3"; ++ pins = "gpio8"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart3"; ++ pins = "gpio9"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart3_ctsrts_10_11: rp1_uart3_ctsrts_10_11 { ++ pin_cts { ++ function = "uart3"; ++ pins = "gpio10"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart3"; ++ pins = "gpio11"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart4_12_13: rp1_uart4_12_13 { ++ pin_txd { ++ function = "uart4"; ++ pins = "gpio12"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart4"; ++ pins = "gpio13"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart4_ctsrts_14_15: rp1_uart4_ctsrts_14_15 { ++ pin_cts { ++ function = "uart4"; ++ pins = "gpio14"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart4"; ++ pins = "gpio15"; ++ bias-disable; ++ }; ++ }; ++ ++ rp1_sdio0_22_27: rp1_sdio0_22_27 { ++ pin_clk { ++ function = "sd0"; ++ pins = "gpio22"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pin_cmd { ++ function = "sd0"; ++ pins = "gpio23"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pins_dat { ++ function = "sd0"; ++ pins = "gpio24", "gpio25", "gpio26", "gpio27"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ }; ++ ++ rp1_sdio1_28_33: rp1_sdio1_28_33 { ++ pin_clk { ++ function = "sd1"; ++ pins = "gpio28"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pin_cmd { ++ function = "sd1"; ++ pins = "gpio29"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pins_dat { ++ function = "sd1"; ++ pins = "gpio30", "gpio31", "gpio32", "gpio33"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ }; ++ ++ rp1_i2s0_18_21: rp1_i2s0_18_21 { ++ function = "i2s0"; ++ pins = "gpio18", "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ ++ rp1_i2s1_18_21: rp1_i2s1_18_21 { ++ function = "i2s1"; ++ pins = "gpio18", "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ ++ rp1_i2c4_34_35: rp1_i2c4_34_35 { ++ function = "i2c4"; ++ pins = "gpio34", "gpio35"; ++ bias-pull-up; ++ }; ++ rp1_i2c6_38_39: rp1_i2c6_38_39 { ++ function = "i2c6"; ++ pins = "gpio38", "gpio39"; ++ bias-pull-up; ++ }; ++ rp1_i2c4_40_41: rp1_i2c4_40_41 { ++ function = "i2c4"; ++ pins = "gpio40", "gpio41"; ++ bias-pull-up; ++ }; ++ rp1_i2c5_44_45: rp1_i2c5_44_45 { ++ function = "i2c5"; ++ pins = "gpio44", "gpio45"; ++ bias-pull-up; ++ }; ++ rp1_i2c0_0_1: rp1_i2c0_0_1 { ++ function = "i2c0"; ++ pins = "gpio0", "gpio1"; ++ bias-pull-up; ++ }; ++ rp1_i2c0_8_9: rp1_i2c0_8_9 { ++ function = "i2c0"; ++ pins = "gpio8", "gpio9"; ++ bias-pull-up; ++ }; ++ rp1_i2c1_2_3: rp1_i2c1_2_3 { ++ function = "i2c1"; ++ pins = "gpio2", "gpio3"; ++ bias-pull-up; ++ }; ++ rp1_i2c1_10_11: rp1_i2c1_10_11 { ++ function = "i2c1"; ++ pins = "gpio10", "gpio11"; ++ bias-pull-up; ++ }; ++ rp1_i2c2_4_5: rp1_i2c2_4_5 { ++ function = "i2c2"; ++ pins = "gpio4", "gpio5"; ++ bias-pull-up; ++ }; ++ rp1_i2c2_12_13: rp1_i2c2_12_13 { ++ function = "i2c2"; ++ pins = "gpio12", "gpio13"; ++ bias-pull-up; ++ }; ++ rp1_i2c3_6_7: rp1_i2c3_6_7 { ++ function = "i2c3"; ++ pins = "gpio6", "gpio7"; ++ bias-pull-up; ++ }; ++ rp1_i2c3_14_15: rp1_i2c3_14_15 { ++ function = "i2c3"; ++ pins = "gpio14", "gpio15"; ++ bias-pull-up; ++ }; ++ rp1_i2c3_22_23: rp1_i2c3_22_23 { ++ function = "i2c3"; ++ pins = "gpio22", "gpio23"; ++ bias-pull-up; ++ }; ++ ++ // DPI mappings with HSYNC,VSYNC but without PIXCLK,DE ++ rp1_dpi_16bit_gpio2: rp1_dpi_16bit_gpio2 { /* Mode 2, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio10", "gpio11", "gpio12", "gpio13", ++ "gpio14", "gpio15", "gpio16", "gpio17", ++ "gpio18", "gpio19"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_cpadhi_gpio2: rp1_dpi_16bit_cpadhi_gpio2 { /* Mode 3 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_pad666_gpio2: rp1_dpi_16bit_pad666_gpio2 { /* Mode 4 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", ++ "gpio5", "gpio6", "gpio7", "gpio8", ++ "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio21", "gpio22", "gpio23", "gpio24", ++ "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_gpio2: rp1_dpi_18bit_gpio2 { /* Mode 5, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio10", "gpio11", "gpio12", "gpio13", ++ "gpio14", "gpio15", "gpio16", "gpio17", ++ "gpio18", "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_cpadhi_gpio2: rp1_dpi_18bit_cpadhi_gpio2 { /* Mode 6 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_24bit_gpio2: rp1_dpi_24bit_gpio2 { /* Mode 7 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio10", "gpio11", "gpio12", "gpio13", ++ "gpio14", "gpio15", "gpio16", "gpio17", ++ "gpio18", "gpio19", "gpio20", "gpio21", ++ "gpio22", "gpio23", "gpio24", "gpio25", ++ "gpio26", "gpio27"; ++ bias-disable; ++ }; ++ rp1_dpi_hvsync: rp1_dpi_hvsync { /* Sync only, for use with int VDAC */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3"; ++ bias-disable; ++ }; ++ ++ // More DPI mappings, including PIXCLK,DE on GPIOs 0,1 ++ rp1_dpi_16bit_gpio0: rp1_dpi_16bit_gpio0 { /* Mode 2, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", "gpio10", "gpio11", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", "gpio18", "gpio19"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_cpadhi_gpio0: rp1_dpi_16bit_cpadhi_gpio0 { /* Mode 3 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_pad666_gpio0: rp1_dpi_16bit_pad666_gpio0 { /* Mode 4 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio5", "gpio6", "gpio7", "gpio8", ++ "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio21", "gpio22", "gpio23", "gpio24", ++ "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_gpio0: rp1_dpi_18bit_gpio0 { /* Mode 5, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", "gpio10", "gpio11", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", "gpio18", "gpio19", ++ "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_cpadhi_gpio0: rp1_dpi_18bit_cpadhi_gpio0 { /* Mode 6 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_24bit_gpio0: rp1_dpi_24bit_gpio0 { /* Mode 7 -- All GPIOs used! */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", "gpio10", "gpio11", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", "gpio18", "gpio19", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25", "gpio26", "gpio27"; ++ bias-disable; ++ }; ++ ++ rp1_pwm1_gpio45: rp1_pwm1_gpio45 { ++ function = "pwm1"; ++ pins = "gpio45"; ++ bias-pull-down; ++ }; ++ ++ rp1_spi0_gpio9: rp1_spi0_gpio9 { ++ function = "spi0"; ++ pins = "gpio9", "gpio10", "gpio11"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi0_cs_gpio7: rp1_spi0_cs_gpio7 { ++ function = "spi0"; ++ pins = "gpio7", "gpio8"; ++ bias-pull-up; ++ }; ++ ++ rp1_spi1_gpio19: rp1_spi1_gpio19 { ++ function = "spi1"; ++ pins = "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi2_gpio1: rp1_spi2_gpio1 { ++ function = "spi2"; ++ pins = "gpio1", "gpio2", "gpio3"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi3_gpio5: rp1_spi3_gpio5 { ++ function = "spi3"; ++ pins = "gpio5", "gpio6", "gpio7"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi4_gpio9: rp1_spi4_gpio9 { ++ function = "spi4"; ++ pins = "gpio9", "gpio10", "gpio11"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi5_gpio13: rp1_spi5_gpio13 { ++ function = "spi5"; ++ pins = "gpio13", "gpio14", "gpio15"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi8_gpio49: rp1_spi8_gpio49 { ++ function = "spi8"; ++ pins = "gpio49", "gpio50", "gpio51"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi8_cs_gpio52: rp1_spi8_cs_gpio52 { ++ function = "spi0"; ++ pins = "gpio52", "gpio53"; ++ bias-pull-up; ++ }; ++ }; ++ ++ rp1_eth: ethernet@100000 { ++ reg = <0xc0 0x40100000 0x0 0x4000>; ++ compatible = "cdns,macb"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupts = ; ++ clocks = <&macb_pclk &macb_hclk &rp1_clocks RP1_CLK_ETH_TSU>; ++ clock-names = "pclk", "hclk", "tsu_clk"; ++ phy-mode = "rgmii-id"; ++ cdns,aw2w-max-pipe = /bits/ 8 <8>; ++ cdns,ar2r-max-pipe = /bits/ 8 <8>; ++ cdns,use-aw2b-fill; ++ local-mac-address = [00 00 00 00 00 00]; ++ status = "disabled"; ++ }; ++ ++ rp1_csi0: csi@110000 { ++ compatible = "raspberrypi,rp1-cfe"; ++ reg = <0xc0 0x40110000 0x0 0x100>, // CSI2 DMA address ++ <0xc0 0x40114000 0x0 0x100>, // PHY/CSI Host address ++ <0xc0 0x40120000 0x0 0x100>, // MIPI CFG address ++ <0xc0 0x40124000 0x0 0x1000>; // PiSP FE address ++ ++ // interrupts must match rp1_pisp_fe setup ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>; ++ assigned-clock-rates = <25000000>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_csi1: csi@128000 { ++ compatible = "raspberrypi,rp1-cfe"; ++ reg = <0xc0 0x40128000 0x0 0x100>, // CSI2 DMA address ++ <0xc0 0x4012c000 0x0 0x100>, // PHY/CSI Host address ++ <0xc0 0x40138000 0x0 0x100>, // MIPI CFG address ++ <0xc0 0x4013c000 0x0 0x1000>; // PiSP FE address ++ ++ // interrupts must match rp1_pisp_fe setup ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; ++ assigned-clock-rates = <25000000>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_mmc0: mmc@180000 { ++ reg = <0xc0 0x40180000 0x0 0x100>; ++ compatible = "snps,dwcmshc-sdhci"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core ++ &rp1_clocks RP1_CLK_SDIO_TIMER ++ &rp1_sdio_clk0>; ++ clock-names = "bus", "core", "timeout", "sdio"; ++ /* Bank 0 VDDIO is fixed */ ++ no-1-8-v; ++ bus-width = <4>; ++ vmmc-supply = <&rp1_vdd_3v3>; ++ broken-cd; ++ status = "disabled"; ++ }; ++ ++ rp1_mmc1: mmc@184000 { ++ reg = <0xc0 0x40184000 0x0 0x100>; ++ compatible = "snps,dwcmshc-sdhci"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core ++ &rp1_clocks RP1_CLK_SDIO_TIMER ++ &rp1_sdio_clk1>; ++ clock-names = "bus", "core", "timeout", "sdio"; ++ bus-width = <4>; ++ vmmc-supply = <&rp1_vdd_3v3>; ++ /* Nerf SDR speeds */ ++ sdhci-caps-mask = <0x3 0x0>; ++ broken-cd; ++ status = "disabled"; ++ }; ++ ++ rp1_dma: dma@188000 { ++ reg = <0xc0 0x40188000 0x0 0x1000>; ++ compatible = "snps,axi-dma-1.01a"; ++ interrupts = ; ++ clocks = <&sdhci_core &rp1_clocks RP1_CLK_SYS>; ++ clock-names = "core-clk", "cfgr-clk"; ++ ++ #dma-cells = <1>; ++ dma-channels = <8>; ++ snps,dma-masters = <1>; ++ snps,dma-targets = <64>; ++ snps,data-width = <4>; // (8 << 4) == 128 bits ++ snps,block-size = <0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000>; ++ snps,priority = <0 1 2 3 4 5 6 7>; ++ snps,axi-max-burst-len = <8>; ++ status = "disabled"; ++ }; ++ ++ rp1_usb0: usb@200000 { ++ reg = <0xc0 0x40200000 0x0 0x100000>; ++ compatible = "snps,dwc3"; ++ dr_mode = "host"; ++ usb3-lpm-capable; ++ snps,axi-pipe-limit = /bits/ 8 <8>; ++ snps,dis_rxdet_inp3_quirk; ++ snps,tx-max-burst-prd = <8>; ++ snps,tx-thr-num-pkt-prd = <2>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ rp1_usb1: usb@300000 { ++ reg = <0xc0 0x40300000 0x0 0x100000>; ++ compatible = "snps,dwc3"; ++ dr_mode = "host"; ++ usb3-lpm-capable; ++ snps,axi-pipe-limit = /bits/ 8 <8>; ++ snps,dis_rxdet_inp3_quirk; ++ snps,tx-max-burst-prd = <8>; ++ snps,tx-thr-num-pkt-prd = <2>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ rp1_dsi0: dsi@110000 { ++ compatible = "raspberrypi,rp1dsi"; ++ status = "disabled"; ++ reg = <0xc0 0x40118000 0x0 0x1000>, // MIPI0 DSI DMA (ArgonDPI) ++ <0xc0 0x4011c000 0x0 0x1000>, // MIPI0 DSI Host (SNPS) ++ <0xc0 0x40120000 0x0 0x1000>; // MIPI0 CFG ++ ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>, // required, config bus clock ++ <&rp1_clocks RP1_CLK_MIPI0_DPI>, // required, pixel clock ++ <&clksrc_mipi0_dsi_byteclk>, // internal, parent for divide ++ <&clk_xosc>; // hardwired to DSI "refclk" ++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>, ++ <&rp1_clocks RP1_CLK_MIPI0_DPI>; ++ assigned-clock-rates = <25000000>; ++ assigned-clock-parents = <0>, <&clksrc_mipi0_dsi_byteclk>; ++ }; ++ ++ rp1_dsi1: dsi@128000 { ++ compatible = "raspberrypi,rp1dsi"; ++ status = "disabled"; ++ reg = <0xc0 0x40130000 0x0 0x1000>, // MIPI1 DSI DMA (ArgonDPI) ++ <0xc0 0x40134000 0x0 0x1000>, // MIPI1 DSI Host (SNPS) ++ <0xc0 0x40138000 0x0 0x1000>; // MIPI1 CFG ++ ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, // required, config bus clock ++ <&rp1_clocks RP1_CLK_MIPI1_DPI>, // required, pixel clock ++ <&clksrc_mipi1_dsi_byteclk>, // internal, parent for divide ++ <&clk_xosc>; // hardwired to DSI "refclk" ++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, ++ <&rp1_clocks RP1_CLK_MIPI1_DPI>; ++ assigned-clock-rates = <25000000>; ++ assigned-clock-parents = <0>, <&clksrc_mipi1_dsi_byteclk>; ++ }; ++ ++ /* VEC and DPI both need to control PLL_VIDEO and cannot work together; */ ++ /* config.txt should enable one or other using dtparam=vec or an overlay. */ ++ rp1_vec: vec@144000 { ++ compatible = "raspberrypi,rp1vec"; ++ status = "disabled"; ++ reg = <0xc0 0x40144000 0x0 0x1000>, // VIDEO_OUT_VEC ++ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG ++ ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_VEC>; ++ ++ assigned-clocks = <&rp1_clocks RP1_PLL_VIDEO_CORE>, ++ <&rp1_clocks RP1_PLL_VIDEO_SEC>, ++ <&rp1_clocks RP1_CLK_VEC>; ++ assigned-clock-rates = <1188000000>, ++ <108000000>, ++ <108000000>; ++ assigned-clock-parents = <0>, ++ <&rp1_clocks RP1_PLL_VIDEO_CORE>, ++ <&rp1_clocks RP1_PLL_VIDEO_SEC>; ++ }; ++ ++ rp1_dpi: dpi@148000 { ++ compatible = "raspberrypi,rp1dpi"; ++ status = "disabled"; ++ reg = <0xc0 0x40148000 0x0 0x1000>, // VIDEO_OUT DPI ++ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG ++ ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_DPI>, // DPI pixel clock ++ <&rp1_clocks RP1_PLL_VIDEO>, // PLL primary divider, and ++ <&rp1_clocks RP1_PLL_VIDEO_CORE>; // VCO, which we also control ++ clock-names = "dpiclk", "plldiv", "pllcore"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_DPI>; ++ assigned-clock-parents = <&rp1_clocks RP1_PLL_VIDEO>; ++ }; ++ }; ++}; ++ ++&clocks { ++ clk_xosc: clk_xosc { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "xosc"; ++ clock-frequency = <50000000>; ++ }; ++ macb_pclk: macb_pclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "pclk"; ++ clock-frequency = <200000000>; ++ }; ++ macb_hclk: macb_hclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "hclk"; ++ clock-frequency = <200000000>; ++ }; ++ sdio_src: sdio_src { ++ // 400 MHz on FPGA. PLL sys VCO on asic ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "src"; ++ clock-frequency = <1000000000>; ++ }; ++ sdhci_core: sdhci_core { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "core"; ++ clock-frequency = <50000000>; ++ }; ++ clksrc_mipi0_dsi_byteclk: clksrc_mipi0_dsi_byteclk { ++ // This clock is synthesized by MIPI0 D-PHY, when DSI is running. ++ // Its frequency is not known a priori (until a panel driver attaches) ++ // so assign a made-up frequency of 72MHz so it can be divided for DPI. ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "clksrc_mipi0_dsi_byteclk"; ++ clock-frequency = <72000000>; ++ }; ++ clksrc_mipi1_dsi_byteclk: clksrc_mipi1_dsi_byteclk { ++ // This clock is synthesized by MIPI1 D-PHY, when DSI is running. ++ // Its frequency is not known a priori (until a panel driver attaches) ++ // so assign a made-up frequency of 72MHz so it can be divided for DPI. ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "clksrc_mipi1_dsi_byteclk"; ++ clock-frequency = <72000000>; ++ }; ++}; ++ ++/ { ++ rp1_vdd_3v3: rp1_vdd_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++}; +--- a/arch/arm64/boot/dts/broadcom/Makefile ++++ b/arch/arm64/boot/dts/broadcom/Makefile +@@ -16,6 +16,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rp + dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-cm3.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-cm4.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-cm4s.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-5-b.dtb + + subdir-y += bcmbca + subdir-y += northstar2 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +@@ -0,0 +1 @@ ++#include "../../../../arm/boot/dts/bcm2712-rpi-5-b.dts" diff --git a/target/linux/bcm27xx/patches-6.1/950-0855-gpio_brcmstb-Allow-to-build-for-ARCH_BCM2835.patch b/target/linux/bcm27xx/patches-6.1/950-0855-gpio_brcmstb-Allow-to-build-for-ARCH_BCM2835.patch new file mode 100644 index 0000000000..7e39ac8abf --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0855-gpio_brcmstb-Allow-to-build-for-ARCH_BCM2835.patch @@ -0,0 +1,282 @@ +From fa18902ee1e53ad391a455a01be3ab2ea1c5af5f Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Fri, 21 May 2021 12:33:38 +0100 +Subject: [PATCH] gpio_brcmstb: Allow to build for ARCH_BCM2835 + +gpio-brcmstb: Report the correct bank width + +gpio: brcmstb: Use bank address as gpiochip label + +If the path to the device node is used as gpiochip label then +gpio-brcmstb instances with multiple banks end up with duplicated +names. Instead, use a combination of the driver name with the physical +address of the bank, which is both unique and helpful for devmem +debugging. + +Signed-off-by: Phil Elwell + +gpio: mmio: Add DIRECT mode for shared access + +The generic MMIO GPIO library uses shadow registers for efficiency, +but this breaks attempts by raspi-gpio to change other GPIOs in the +same bank. Add a DIRECT mode that makes fewer assumptions about the +existing register contents, but note that genuinely simultaneous +accesses are likely to lose updates. + +Signed-off-by: Phil Elwell + +gpio: brcmstb: Don't always clear interrupt mask + +If the GPIO controller is not being used as an interrupt source +leave the interrupt mask register alone. On BCM2712 it might be used +to generate interrupts to the VPU firmware, and on other devices it +doesn't matter since no interrupts will be generated. + +Signed-off-by: Phil Elwell +--- + drivers/gpio/Kconfig | 2 +- + drivers/gpio/gpio-brcmstb.c | 14 ++-- + drivers/gpio/gpio-mmio.c | 124 ++++++++++++++++++++++++++++++++++-- + include/linux/gpio/driver.h | 1 + + 4 files changed, 131 insertions(+), 10 deletions(-) + +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -203,7 +203,7 @@ config GPIO_BCM_VIRT + config GPIO_BRCMSTB + tristate "BRCMSTB GPIO support" + default y if (ARCH_BRCMSTB || BMIPS_GENERIC) +- depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST) ++ depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM2835 || COMPILE_TEST) + select GPIO_GENERIC + select IRQ_DOMAIN + help +--- a/drivers/gpio/gpio-brcmstb.c ++++ b/drivers/gpio/gpio-brcmstb.c +@@ -640,6 +640,8 @@ static int brcmstb_gpio_probe(struct pla + #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN) + flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER; + #endif ++ if (of_property_read_bool(np, "brcm,gpio-direct")) ++ flags |= BGPIOF_REG_DIRECT; + + of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p, + bank_width) { +@@ -689,7 +691,9 @@ static int brcmstb_gpio_probe(struct pla + } + + gc->owner = THIS_MODULE; +- gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); ++ gc->label = devm_kasprintf(dev, GFP_KERNEL, "gpio-brcmstb@%zx", ++ (size_t)res->start + ++ GIO_BANK_OFF(bank->id, 0)); + if (!gc->label) { + err = -ENOMEM; + goto fail; +@@ -698,7 +702,7 @@ static int brcmstb_gpio_probe(struct pla + gc->of_gpio_n_cells = 2; + gc->of_xlate = brcmstb_gpio_of_xlate; + /* not all ngpio lines are valid, will use bank width later */ +- gc->ngpio = MAX_GPIO_PER_BANK; ++ gc->ngpio = bank_width; + gc->offset = bank->id * MAX_GPIO_PER_BANK; + if (priv->parent_irq > 0) + gc->to_irq = brcmstb_gpio_to_irq; +@@ -707,8 +711,10 @@ static int brcmstb_gpio_probe(struct pla + * Mask all interrupts by default, since wakeup interrupts may + * be retained from S5 cold boot + */ +- need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); +- gc->write_reg(reg_base + GIO_MASK(bank->id), 0); ++ if (priv->parent_irq > 0) { ++ need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); ++ gc->write_reg(reg_base + GIO_MASK(bank->id), 0); ++ } + + err = gpiochip_add_data(gc, bank); + if (err) { +--- a/drivers/gpio/gpio-mmio.c ++++ b/drivers/gpio/gpio-mmio.c +@@ -232,6 +232,25 @@ static void bgpio_set(struct gpio_chip * + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); + } + ++static void bgpio_set_direct(struct gpio_chip *gc, unsigned int gpio, int val) ++{ ++ unsigned long mask = bgpio_line2mask(gc, gpio); ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ gc->bgpio_data = gc->read_reg(gc->reg_dat); ++ ++ if (val) ++ gc->bgpio_data |= mask; ++ else ++ gc->bgpio_data &= ~mask; ++ ++ gc->write_reg(gc->reg_dat, gc->bgpio_data); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++} ++ + static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio, + int val) + { +@@ -324,6 +343,27 @@ static void bgpio_set_multiple_with_clea + gc->write_reg(gc->reg_clr, clear_mask); + } + ++static void bgpio_set_multiple_direct(struct gpio_chip *gc, ++ unsigned long *mask, ++ unsigned long *bits) ++{ ++ unsigned long flags; ++ unsigned long set_mask, clear_mask; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); ++ ++ gc->bgpio_data = gc->read_reg(gc->reg_dat); ++ ++ gc->bgpio_data |= set_mask; ++ gc->bgpio_data &= ~clear_mask; ++ ++ gc->write_reg(gc->reg_dat, gc->bgpio_data); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++} ++ + static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) + { + return 0; +@@ -361,6 +401,29 @@ static int bgpio_dir_in(struct gpio_chip + return 0; + } + ++static int bgpio_dir_in_direct(struct gpio_chip *gc, unsigned int gpio) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ if (gc->reg_dir_in) ++ gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in); ++ if (gc->reg_dir_out) ++ gc->bgpio_dir = gc->read_reg(gc->reg_dir_out); ++ ++ gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); ++ ++ if (gc->reg_dir_in) ++ gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); ++ if (gc->reg_dir_out) ++ gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++ ++ return 0; ++} ++ + static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) + { + /* Return 0 if output, 1 if input */ +@@ -399,6 +462,28 @@ static void bgpio_dir_out(struct gpio_ch + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); + } + ++static void bgpio_dir_out_direct(struct gpio_chip *gc, unsigned int gpio, ++ int val) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ++ ++ if (gc->reg_dir_in) ++ gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in); ++ if (gc->reg_dir_out) ++ gc->bgpio_dir = gc->read_reg(gc->reg_dir_out); ++ ++ gc->bgpio_dir |= bgpio_line2mask(gc, gpio); ++ ++ if (gc->reg_dir_in) ++ gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); ++ if (gc->reg_dir_out) ++ gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); ++ ++ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); ++} ++ + static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, + int val) + { +@@ -415,6 +500,22 @@ static int bgpio_dir_out_val_first(struc + return 0; + } + ++static int bgpio_dir_out_dir_first_direct(struct gpio_chip *gc, ++ unsigned int gpio, int val) ++{ ++ bgpio_dir_out_direct(gc, gpio, val); ++ gc->set(gc, gpio, val); ++ return 0; ++} ++ ++static int bgpio_dir_out_val_first_direct(struct gpio_chip *gc, ++ unsigned int gpio, int val) ++{ ++ gc->set(gc, gpio, val); ++ bgpio_dir_out_direct(gc, gpio, val); ++ return 0; ++} ++ + static int bgpio_setup_accessors(struct device *dev, + struct gpio_chip *gc, + bool byte_be) +@@ -508,6 +609,9 @@ static int bgpio_setup_io(struct gpio_ch + } else if (flags & BGPIOF_NO_OUTPUT) { + gc->set = bgpio_set_none; + gc->set_multiple = NULL; ++ } else if (flags & BGPIOF_REG_DIRECT) { ++ gc->set = bgpio_set_direct; ++ gc->set_multiple = bgpio_set_multiple_direct; + } else { + gc->set = bgpio_set; + gc->set_multiple = bgpio_set_multiple; +@@ -544,11 +648,21 @@ static int bgpio_setup_direction(struct + if (dirout || dirin) { + gc->reg_dir_out = dirout; + gc->reg_dir_in = dirin; +- if (flags & BGPIOF_NO_SET_ON_INPUT) +- gc->direction_output = bgpio_dir_out_dir_first; +- else +- gc->direction_output = bgpio_dir_out_val_first; +- gc->direction_input = bgpio_dir_in; ++ if (flags & BGPIOF_REG_DIRECT) { ++ if (flags & BGPIOF_NO_SET_ON_INPUT) ++ gc->direction_output = ++ bgpio_dir_out_dir_first_direct; ++ else ++ gc->direction_output = ++ bgpio_dir_out_val_first_direct; ++ gc->direction_input = bgpio_dir_in_direct; ++ } else { ++ if (flags & BGPIOF_NO_SET_ON_INPUT) ++ gc->direction_output = bgpio_dir_out_dir_first; ++ else ++ gc->direction_output = bgpio_dir_out_val_first; ++ gc->direction_input = bgpio_dir_in; ++ } + gc->get_direction = bgpio_get_dir; + } else { + if (flags & BGPIOF_NO_OUTPUT) +--- a/include/linux/gpio/driver.h ++++ b/include/linux/gpio/driver.h +@@ -690,6 +690,7 @@ int bgpio_init(struct gpio_chip *gc, str + #define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */ + #define BGPIOF_NO_OUTPUT BIT(5) /* only input */ + #define BGPIOF_NO_SET_ON_INPUT BIT(6) ++#define BGPIOF_REG_DIRECT BIT(7) /* ignore shadow registers */ + + int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq); diff --git a/target/linux/bcm27xx/patches-6.1/950-0856-Allow-RESET_BRCMSTB-on-ARCH_BCM2835.patch b/target/linux/bcm27xx/patches-6.1/950-0856-Allow-RESET_BRCMSTB-on-ARCH_BCM2835.patch new file mode 100644 index 0000000000..7e0886d7e6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0856-Allow-RESET_BRCMSTB-on-ARCH_BCM2835.patch @@ -0,0 +1,20 @@ +From 22ae3b2ee3293278e647877b269a5aebad3f077d Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 27 May 2021 11:46:30 +0100 +Subject: [PATCH] Allow RESET_BRCMSTB on ARCH_BCM2835 + +--- + drivers/reset/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -51,7 +51,7 @@ config RESET_BERLIN + + config RESET_BRCMSTB + tristate "Broadcom STB reset controller" +- depends on ARCH_BRCMSTB || COMPILE_TEST ++ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST + default ARCH_BRCMSTB + help + This enables the reset controller driver for Broadcom STB SoCs using diff --git a/target/linux/bcm27xx/patches-6.1/950-0857-pinctrl-bcm2712-pinctrl-pinconf-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0857-pinctrl-bcm2712-pinctrl-pinconf-driver.patch new file mode 100644 index 0000000000..429c3e2fd2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0857-pinctrl-bcm2712-pinctrl-pinconf-driver.patch @@ -0,0 +1,1324 @@ +From af7e60a33f0b5ce84bffb69ba084ba1edd180195 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 9 Jun 2021 15:48:28 +0100 +Subject: [PATCH] pinctrl: bcm2712 pinctrl/pinconf driver + +pinctrl: bcm2712: Reject invalid pulls + +Reject attempts to set pulls on aon-sgpios, and fix pull shift +values. + +pinctrl: bcm2712: Add 7712 support, fix 2712 count + +Signed-off-by: Phil Elwell + +pinctrl-bcm2712: add EMMC pins so pulls can be set + +These pins have pad controls but not mux controls. They look enough like +GPIOs to squeeze in at the end of the list though. + +pinctrl: bcm2712: correct BCM2712C0 AON_GPIO pad pull control offset + +Signed-off-by: Jonathan Bell + +pinctrl: bcm2712: on C0 the regular GPIO pad control register moves too + +Signed-off-by: Jonathan Bell + +pinctrl: bcm2712: Implement (partially) pinconf_get + +Signed-off-by: Phil Elwell + +pinctrl: bcm2712: Convert to generic pinconf + +Remove the legacy brcm,* pin configuration support and replace it with +a proper generic pinconf interface, using named functions instead of +alt function numbers. This is nicer for users, less error-prone, and +immune to some of the C0->D0 changes. + +Signed-off-by: Phil Elwell + +pinctrl: bcm2712: Remove vestigial pull parameter + +Now the legacy brcm, pinconf parameters are no longer supported, this +custom pin config parameter is not needed. + +Signed-off-by: Phil Elwell + +pinctrl: bcm2712: Guard against bad func numbers + +Signed-off-by: Phil Elwell + +pinctrl: bcm2712: A better attempt at D0 support + +The BCM2712D0 sparse pinctrl maps play havoc with the old GPIO_REGS +macro, so make the bit positions explicit. And delete the unwanted +GPIO and pinmux declarations on D0. + +Note that a Pi 5 with D0 requires a separate DTS file with "bcm2712d0" +compatible strings. + +Signed-off-by: Phil Elwell + +pinctrl: bcm2712: Delete base register constants + +BCM2712D0 deletes many GPIOs and their associated mux and pad bits, +so much so that the offsets to the start of the pad control registers +changes. Remove the constant offsets from the *GPIO_REGS macros, +compensating by adjusting the per-GPIO values. + +Signed-off-by: Phil Elwell +--- + drivers/pinctrl/bcm/Kconfig | 9 + + drivers/pinctrl/bcm/Makefile | 1 + + drivers/pinctrl/bcm/pinctrl-bcm2712.c | 1216 +++++++++++++++++++++++++ + 3 files changed, 1226 insertions(+) + create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm2712.c + +--- a/drivers/pinctrl/bcm/Kconfig ++++ b/drivers/pinctrl/bcm/Kconfig +@@ -3,6 +3,15 @@ + # Broadcom pinctrl drivers + # + ++config PINCTRL_BCM2712 ++ bool "Broadcom BCM2712 PINCONF driver" ++ depends on OF && (ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST) ++ select PINMUX ++ select PINCONF ++ select GENERIC_PINCONF ++ help ++ Say Y here to enable the Broadcom BCM2835 GPIO driver. ++ + config PINCTRL_BCM281XX + bool "Broadcom BCM281xx pinctrl driver" + depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST) +--- a/drivers/pinctrl/bcm/Makefile ++++ b/drivers/pinctrl/bcm/Makefile +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + # Broadcom pinctrl support + ++obj-$(CONFIG_PINCTRL_BCM2712) += pinctrl-bcm2712.o + obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o + obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o + obj-$(CONFIG_PINCTRL_BCM4908) += pinctrl-bcm4908.o +--- /dev/null ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2712.c +@@ -0,0 +1,1216 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Driver for Broadcom BCM2712 GPIO units (pinctrl only) ++ * ++ * Copyright (C) 2021-3 Raspberry Pi Ltd. ++ * Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren ++ * ++ * Based heavily on the BCM2835 GPIO & pinctrl driver, which was inspired by: ++ * pinctrl-nomadik.c, please see original file for copyright information ++ * pinctrl-tegra.c, please see original file for copyright information ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MODULE_NAME "pinctrl-bcm2712" ++ ++/* Register offsets */ ++ ++#define BCM2712_PULL_NONE 0 ++#define BCM2712_PULL_DOWN 1 ++#define BCM2712_PULL_UP 2 ++#define BCM2712_PULL_MASK 0x3 ++ ++#define BCM2712_FSEL_COUNT 9 ++#define BCM2712_FSEL_MASK 0xf ++ ++#define FUNC(f) \ ++ [func_##f] = #f ++#define PIN(i, f1, f2, f3, f4, f5, f6, f7, f8) \ ++ [i] = { \ ++ .funcs = { \ ++ func_##f1, \ ++ func_##f2, \ ++ func_##f3, \ ++ func_##f4, \ ++ func_##f5, \ ++ func_##f6, \ ++ func_##f7, \ ++ func_##f8, \ ++ }, \ ++ } ++ ++#define REG_BIT_INVALID 0xffff ++ ++#define BIT_TO_REG(b) (((b) >> 5) << 2) ++#define BIT_TO_SHIFT(b) ((b) & 0x1f) ++ ++#define GPIO_REGS(n, mr, mb, pr, pb) \ ++ [n] = { ((mr)*4)*8 + (mb)*4, ((pr)*4)*8 + (pb)*2 } ++ ++#define EMMC_REGS(n, r, b) \ ++ [n] = { 0, ((r)*4)*8 + (b)*2 } ++ ++#define AGPIO_REGS(n, mr, mb, pr, pb) \ ++ [n] = { ((mr)*4)*8 + (mb)*4, ((pr)*4)*8 + (pb)*2 } ++ ++#define SGPIO_REGS(n, mr, mb) \ ++ [n+32] = { ((mr)*4)*8 + (mb)*4, REG_BIT_INVALID } ++ ++#define GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a) ++#define AGPIO_PIN(a) PINCTRL_PIN(a, "aon_gpio" #a) ++#define SGPIO_PIN(a) PINCTRL_PIN(a+32, "aon_sgpio" #a) ++ ++struct pin_regs { ++ u16 mux_bit; ++ u16 pad_bit; ++}; ++ ++struct bcm2712_pinctrl { ++ struct device *dev; ++ void __iomem *base; ++ struct pinctrl_dev *pctl_dev; ++ struct pinctrl_desc pctl_desc; ++ const struct pin_regs *pin_regs; ++ const struct bcm2712_pin_funcs *pin_funcs; ++ const char *const *gpio_groups; ++ struct pinctrl_gpio_range gpio_range; ++ spinlock_t lock; ++}; ++ ++struct bcm_plat_data { ++ const struct pinctrl_desc *pctl_desc; ++ const struct pinctrl_gpio_range *gpio_range; ++ const struct pin_regs *pin_regs; ++ const struct bcm2712_pin_funcs *pin_funcs; ++}; ++ ++struct bcm2712_pin_funcs { ++ u8 funcs[BCM2712_FSEL_COUNT - 1]; ++}; ++ ++enum bcm2712_funcs { ++ func_gpio, ++ func_alt1, ++ func_alt2, ++ func_alt3, ++ func_alt4, ++ func_alt5, ++ func_alt6, ++ func_alt7, ++ func_alt8, ++ func_aon_cpu_standbyb, ++ func_aon_fp_4sec_resetb, ++ func_aon_gpclk, ++ func_aon_pwm, ++ func_arm_jtag, ++ func_aud_fs_clk0, ++ func_avs_pmu_bsc, ++ func_bsc_m0, ++ func_bsc_m1, ++ func_bsc_m2, ++ func_bsc_m3, ++ func_clk_observe, ++ func_ctl_hdmi_5v, ++ func_enet0, ++ func_enet0_mii, ++ func_enet0_rgmii, ++ func_ext_sc_clk, ++ func_fl0, ++ func_fl1, ++ func_gpclk0, ++ func_gpclk1, ++ func_gpclk2, ++ func_hdmi_tx0_auto_i2c, ++ func_hdmi_tx0_bsc, ++ func_hdmi_tx1_auto_i2c, ++ func_hdmi_tx1_bsc, ++ func_i2s_in, ++ func_i2s_out, ++ func_ir_in, ++ func_mtsif, ++ func_mtsif_alt, ++ func_mtsif_alt1, ++ func_pdm, ++ func_pkt, ++ func_pm_led_out, ++ func_sc0, ++ func_sd0, ++ func_sd2, ++ func_sd_card_a, ++ func_sd_card_b, ++ func_sd_card_c, ++ func_sd_card_d, ++ func_sd_card_e, ++ func_sd_card_f, ++ func_sd_card_g, ++ func_spdif_out, ++ func_spi_m, ++ func_spi_s, ++ func_sr_edm_sense, ++ func_te0, ++ func_te1, ++ func_tsio, ++ func_uart0, ++ func_uart1, ++ func_uart2, ++ func_usb_pwr, ++ func_usb_vbus, ++ func_uui, ++ func_vc_i2c0, ++ func_vc_i2c3, ++ func_vc_i2c4, ++ func_vc_i2c5, ++ func_vc_i2csl, ++ func_vc_pcm, ++ func_vc_pwm0, ++ func_vc_pwm1, ++ func_vc_spi0, ++ func_vc_spi3, ++ func_vc_spi4, ++ func_vc_spi5, ++ func_vc_uart0, ++ func_vc_uart2, ++ func_vc_uart3, ++ func_vc_uart4, ++ func__, ++ func_count = func__ ++}; ++ ++static const struct pin_regs bcm2712_c0_gpio_pin_regs[] = { ++ GPIO_REGS(0, 0, 0, 7, 7), ++ GPIO_REGS(1, 0, 1, 7, 8), ++ GPIO_REGS(2, 0, 2, 7, 9), ++ GPIO_REGS(3, 0, 3, 7, 10), ++ GPIO_REGS(4, 0, 4, 7, 11), ++ GPIO_REGS(5, 0, 5, 7, 12), ++ GPIO_REGS(6, 0, 6, 7, 13), ++ GPIO_REGS(7, 0, 7, 7, 14), ++ GPIO_REGS(8, 1, 0, 8, 0), ++ GPIO_REGS(9, 1, 1, 8, 1), ++ GPIO_REGS(10, 1, 2, 8, 2), ++ GPIO_REGS(11, 1, 3, 8, 3), ++ GPIO_REGS(12, 1, 4, 8, 4), ++ GPIO_REGS(13, 1, 5, 8, 5), ++ GPIO_REGS(14, 1, 6, 8, 6), ++ GPIO_REGS(15, 1, 7, 8, 7), ++ GPIO_REGS(16, 2, 0, 8, 8), ++ GPIO_REGS(17, 2, 1, 8, 9), ++ GPIO_REGS(18, 2, 2, 8, 10), ++ GPIO_REGS(19, 2, 3, 8, 11), ++ GPIO_REGS(20, 2, 4, 8, 12), ++ GPIO_REGS(21, 2, 5, 8, 13), ++ GPIO_REGS(22, 2, 6, 8, 14), ++ GPIO_REGS(23, 2, 7, 9, 0), ++ GPIO_REGS(24, 3, 0, 9, 1), ++ GPIO_REGS(25, 3, 1, 9, 2), ++ GPIO_REGS(26, 3, 2, 9, 3), ++ GPIO_REGS(27, 3, 3, 9, 4), ++ GPIO_REGS(28, 3, 4, 9, 5), ++ GPIO_REGS(29, 3, 5, 9, 6), ++ GPIO_REGS(30, 3, 6, 9, 7), ++ GPIO_REGS(31, 3, 7, 9, 8), ++ GPIO_REGS(32, 4, 0, 9, 9), ++ GPIO_REGS(33, 4, 1, 9, 10), ++ GPIO_REGS(34, 4, 2, 9, 11), ++ GPIO_REGS(35, 4, 3, 9, 12), ++ GPIO_REGS(36, 4, 4, 9, 13), ++ GPIO_REGS(37, 4, 5, 9, 14), ++ GPIO_REGS(38, 4, 6, 10, 0), ++ GPIO_REGS(39, 4, 7, 10, 1), ++ GPIO_REGS(40, 5, 0, 10, 2), ++ GPIO_REGS(41, 5, 1, 10, 3), ++ GPIO_REGS(42, 5, 2, 10, 4), ++ GPIO_REGS(43, 5, 3, 10, 5), ++ GPIO_REGS(44, 5, 4, 10, 6), ++ GPIO_REGS(45, 5, 5, 10, 7), ++ GPIO_REGS(46, 5, 6, 10, 8), ++ GPIO_REGS(47, 5, 7, 10, 9), ++ GPIO_REGS(48, 6, 0, 10, 10), ++ GPIO_REGS(49, 6, 1, 10, 11), ++ GPIO_REGS(50, 6, 2, 10, 12), ++ GPIO_REGS(51, 6, 3, 10, 13), ++ GPIO_REGS(52, 6, 4, 10, 14), ++ GPIO_REGS(53, 6, 5, 11, 0), ++ EMMC_REGS(54, 11, 1), /* EMMC_CMD */ ++ EMMC_REGS(55, 11, 2), /* EMMC_DS */ ++ EMMC_REGS(56, 11, 3), /* EMMC_CLK */ ++ EMMC_REGS(57, 11, 4), /* EMMC_DAT0 */ ++ EMMC_REGS(58, 11, 5), /* EMMC_DAT1 */ ++ EMMC_REGS(59, 11, 6), /* EMMC_DAT2 */ ++ EMMC_REGS(60, 11, 7), /* EMMC_DAT3 */ ++ EMMC_REGS(61, 11, 8), /* EMMC_DAT4 */ ++ EMMC_REGS(62, 11, 9), /* EMMC_DAT5 */ ++ EMMC_REGS(63, 11, 10), /* EMMC_DAT6 */ ++ EMMC_REGS(64, 11, 11), /* EMMC_DAT7 */ ++}; ++ ++static struct pin_regs bcm2712_c0_aon_gpio_pin_regs[] = { ++ AGPIO_REGS(0, 3, 0, 6, 10), ++ AGPIO_REGS(1, 3, 1, 6, 11), ++ AGPIO_REGS(2, 3, 2, 6, 12), ++ AGPIO_REGS(3, 3, 3, 6, 13), ++ AGPIO_REGS(4, 3, 4, 6, 14), ++ AGPIO_REGS(5, 3, 5, 7, 0), ++ AGPIO_REGS(6, 3, 6, 7, 1), ++ AGPIO_REGS(7, 3, 7, 7, 2), ++ AGPIO_REGS(8, 4, 0, 7, 3), ++ AGPIO_REGS(9, 4, 1, 7, 4), ++ AGPIO_REGS(10, 4, 2, 7, 5), ++ AGPIO_REGS(11, 4, 3, 7, 6), ++ AGPIO_REGS(12, 4, 4, 7, 7), ++ AGPIO_REGS(13, 4, 5, 7, 8), ++ AGPIO_REGS(14, 4, 6, 7, 9), ++ AGPIO_REGS(15, 4, 7, 7, 10), ++ AGPIO_REGS(16, 5, 0, 7, 11), ++ SGPIO_REGS(0, 0, 0), ++ SGPIO_REGS(1, 0, 1), ++ SGPIO_REGS(2, 0, 2), ++ SGPIO_REGS(3, 0, 3), ++ SGPIO_REGS(4, 1, 0), ++ SGPIO_REGS(5, 2, 0), ++}; ++ ++static const struct pinctrl_pin_desc bcm2712_c0_gpio_pins[] = { ++ GPIO_PIN(0), ++ GPIO_PIN(1), ++ GPIO_PIN(2), ++ GPIO_PIN(3), ++ GPIO_PIN(4), ++ GPIO_PIN(5), ++ GPIO_PIN(6), ++ GPIO_PIN(7), ++ GPIO_PIN(8), ++ GPIO_PIN(9), ++ GPIO_PIN(10), ++ GPIO_PIN(11), ++ GPIO_PIN(12), ++ GPIO_PIN(13), ++ GPIO_PIN(14), ++ GPIO_PIN(15), ++ GPIO_PIN(16), ++ GPIO_PIN(17), ++ GPIO_PIN(18), ++ GPIO_PIN(19), ++ GPIO_PIN(20), ++ GPIO_PIN(21), ++ GPIO_PIN(22), ++ GPIO_PIN(23), ++ GPIO_PIN(24), ++ GPIO_PIN(25), ++ GPIO_PIN(26), ++ GPIO_PIN(27), ++ GPIO_PIN(28), ++ GPIO_PIN(29), ++ GPIO_PIN(30), ++ GPIO_PIN(31), ++ GPIO_PIN(32), ++ GPIO_PIN(33), ++ GPIO_PIN(34), ++ GPIO_PIN(35), ++ GPIO_PIN(36), ++ GPIO_PIN(37), ++ GPIO_PIN(38), ++ GPIO_PIN(39), ++ GPIO_PIN(40), ++ GPIO_PIN(41), ++ GPIO_PIN(42), ++ GPIO_PIN(43), ++ GPIO_PIN(44), ++ GPIO_PIN(45), ++ GPIO_PIN(46), ++ GPIO_PIN(47), ++ GPIO_PIN(48), ++ GPIO_PIN(49), ++ GPIO_PIN(50), ++ GPIO_PIN(51), ++ GPIO_PIN(52), ++ GPIO_PIN(53), ++ PINCTRL_PIN(54, "emmc_cmd"), ++ PINCTRL_PIN(55, "emmc_ds"), ++ PINCTRL_PIN(56, "emmc_clk"), ++ PINCTRL_PIN(57, "emmc_dat0"), ++ PINCTRL_PIN(58, "emmc_dat1"), ++ PINCTRL_PIN(59, "emmc_dat2"), ++ PINCTRL_PIN(60, "emmc_dat3"), ++ PINCTRL_PIN(61, "emmc_dat4"), ++ PINCTRL_PIN(62, "emmc_dat5"), ++ PINCTRL_PIN(63, "emmc_dat6"), ++ PINCTRL_PIN(64, "emmc_dat7"), ++}; ++ ++static struct pinctrl_pin_desc bcm2712_c0_aon_gpio_pins[] = { ++ AGPIO_PIN(0), ++ AGPIO_PIN(1), ++ AGPIO_PIN(2), ++ AGPIO_PIN(3), ++ AGPIO_PIN(4), ++ AGPIO_PIN(5), ++ AGPIO_PIN(6), ++ AGPIO_PIN(7), ++ AGPIO_PIN(8), ++ AGPIO_PIN(9), ++ AGPIO_PIN(10), ++ AGPIO_PIN(11), ++ AGPIO_PIN(12), ++ AGPIO_PIN(13), ++ AGPIO_PIN(14), ++ AGPIO_PIN(15), ++ AGPIO_PIN(16), ++ SGPIO_PIN(0), ++ SGPIO_PIN(1), ++ SGPIO_PIN(2), ++ SGPIO_PIN(3), ++ SGPIO_PIN(4), ++ SGPIO_PIN(5), ++}; ++ ++static const struct pin_regs bcm2712_d0_gpio_pin_regs[] = { ++ GPIO_REGS(1, 0, 0, 4, 5), ++ GPIO_REGS(2, 0, 1, 4, 6), ++ GPIO_REGS(3, 0, 2, 4, 7), ++ GPIO_REGS(4, 0, 3, 4, 8), ++ GPIO_REGS(10, 0, 4, 4, 9), ++ GPIO_REGS(11, 0, 5, 4, 10), ++ GPIO_REGS(12, 0, 6, 4, 11), ++ GPIO_REGS(13, 0, 7, 4, 12), ++ GPIO_REGS(14, 1, 0, 4, 13), ++ GPIO_REGS(15, 1, 1, 4, 14), ++ GPIO_REGS(18, 1, 2, 5, 0), ++ GPIO_REGS(19, 1, 3, 5, 1), ++ GPIO_REGS(20, 1, 4, 5, 2), ++ GPIO_REGS(21, 1, 5, 5, 3), ++ GPIO_REGS(22, 1, 6, 5, 4), ++ GPIO_REGS(23, 1, 7, 5, 5), ++ GPIO_REGS(24, 2, 0, 5, 6), ++ GPIO_REGS(25, 2, 1, 5, 7), ++ GPIO_REGS(26, 2, 2, 5, 8), ++ GPIO_REGS(27, 2, 3, 5, 9), ++ GPIO_REGS(28, 2, 4, 5, 10), ++ GPIO_REGS(29, 2, 5, 5, 11), ++ GPIO_REGS(30, 2, 6, 5, 12), ++ GPIO_REGS(31, 2, 7, 5, 13), ++ GPIO_REGS(32, 3, 0, 5, 14), ++ GPIO_REGS(33, 3, 1, 6, 0), ++ GPIO_REGS(34, 3, 2, 6, 1), ++ GPIO_REGS(35, 3, 3, 6, 2), ++}; ++ ++static struct pin_regs bcm2712_d0_aon_gpio_pin_regs[] = { ++ AGPIO_REGS(0, 3, 0, 5, 9), ++ AGPIO_REGS(1, 3, 1, 5, 10), ++ AGPIO_REGS(2, 3, 2, 5, 11), ++ AGPIO_REGS(3, 3, 3, 5, 12), ++ AGPIO_REGS(4, 3, 4, 5, 13), ++ AGPIO_REGS(5, 3, 5, 5, 14), ++ AGPIO_REGS(6, 3, 6, 6, 0), ++ AGPIO_REGS(8, 3, 7, 6, 1), ++ AGPIO_REGS(9, 4, 0, 6, 2), ++ AGPIO_REGS(12, 4, 1, 6, 3), ++ AGPIO_REGS(13, 4, 2, 6, 4), ++ AGPIO_REGS(14, 4, 3, 6, 5), ++ SGPIO_REGS(0, 0, 0), ++ SGPIO_REGS(1, 0, 1), ++ SGPIO_REGS(2, 0, 2), ++ SGPIO_REGS(3, 0, 3), ++ SGPIO_REGS(4, 1, 0), ++ SGPIO_REGS(5, 2, 0), ++}; ++ ++static const struct pinctrl_pin_desc bcm2712_d0_gpio_pins[] = { ++ GPIO_PIN(1), ++ GPIO_PIN(2), ++ GPIO_PIN(3), ++ GPIO_PIN(4), ++ GPIO_PIN(10), ++ GPIO_PIN(11), ++ GPIO_PIN(12), ++ GPIO_PIN(13), ++ GPIO_PIN(14), ++ GPIO_PIN(15), ++ GPIO_PIN(18), ++ GPIO_PIN(19), ++ GPIO_PIN(20), ++ GPIO_PIN(21), ++ GPIO_PIN(22), ++ GPIO_PIN(23), ++ GPIO_PIN(24), ++ GPIO_PIN(25), ++ GPIO_PIN(26), ++ GPIO_PIN(27), ++ GPIO_PIN(28), ++ GPIO_PIN(29), ++ GPIO_PIN(30), ++ GPIO_PIN(31), ++ GPIO_PIN(32), ++ GPIO_PIN(33), ++ GPIO_PIN(34), ++ GPIO_PIN(35), ++}; ++ ++static struct pinctrl_pin_desc bcm2712_d0_aon_gpio_pins[] = { ++ AGPIO_PIN(0), ++ AGPIO_PIN(1), ++ AGPIO_PIN(2), ++ AGPIO_PIN(3), ++ AGPIO_PIN(4), ++ AGPIO_PIN(5), ++ AGPIO_PIN(6), ++ AGPIO_PIN(8), ++ AGPIO_PIN(9), ++ AGPIO_PIN(12), ++ AGPIO_PIN(13), ++ AGPIO_PIN(14), ++ SGPIO_PIN(0), ++ SGPIO_PIN(1), ++ SGPIO_PIN(2), ++ SGPIO_PIN(3), ++ SGPIO_PIN(4), ++ SGPIO_PIN(5), ++}; ++ ++static const char * const bcm2712_func_names[] = { ++ FUNC(gpio), ++ FUNC(alt1), ++ FUNC(alt2), ++ FUNC(alt3), ++ FUNC(alt4), ++ FUNC(alt5), ++ FUNC(alt6), ++ FUNC(alt7), ++ FUNC(alt8), ++ FUNC(aon_cpu_standbyb), ++ FUNC(aon_fp_4sec_resetb), ++ FUNC(aon_gpclk), ++ FUNC(aon_pwm), ++ FUNC(arm_jtag), ++ FUNC(aud_fs_clk0), ++ FUNC(avs_pmu_bsc), ++ FUNC(bsc_m0), ++ FUNC(bsc_m1), ++ FUNC(bsc_m2), ++ FUNC(bsc_m3), ++ FUNC(clk_observe), ++ FUNC(ctl_hdmi_5v), ++ FUNC(enet0), ++ FUNC(enet0_mii), ++ FUNC(enet0_rgmii), ++ FUNC(ext_sc_clk), ++ FUNC(fl0), ++ FUNC(fl1), ++ FUNC(gpclk0), ++ FUNC(gpclk1), ++ FUNC(gpclk2), ++ FUNC(hdmi_tx0_auto_i2c), ++ FUNC(hdmi_tx0_bsc), ++ FUNC(hdmi_tx1_auto_i2c), ++ FUNC(hdmi_tx1_bsc), ++ FUNC(i2s_in), ++ FUNC(i2s_out), ++ FUNC(ir_in), ++ FUNC(mtsif), ++ FUNC(mtsif_alt), ++ FUNC(mtsif_alt1), ++ FUNC(pdm), ++ FUNC(pkt), ++ FUNC(pm_led_out), ++ FUNC(sc0), ++ FUNC(sd0), ++ FUNC(sd2), ++ FUNC(sd_card_a), ++ FUNC(sd_card_b), ++ FUNC(sd_card_c), ++ FUNC(sd_card_d), ++ FUNC(sd_card_e), ++ FUNC(sd_card_f), ++ FUNC(sd_card_g), ++ FUNC(spdif_out), ++ FUNC(spi_m), ++ FUNC(spi_s), ++ FUNC(sr_edm_sense), ++ FUNC(te0), ++ FUNC(te1), ++ FUNC(tsio), ++ FUNC(uart0), ++ FUNC(uart1), ++ FUNC(uart2), ++ FUNC(usb_pwr), ++ FUNC(usb_vbus), ++ FUNC(uui), ++ FUNC(vc_i2c0), ++ FUNC(vc_i2c3), ++ FUNC(vc_i2c4), ++ FUNC(vc_i2c5), ++ FUNC(vc_i2csl), ++ FUNC(vc_pcm), ++ FUNC(vc_pwm0), ++ FUNC(vc_pwm1), ++ FUNC(vc_spi0), ++ FUNC(vc_spi3), ++ FUNC(vc_spi4), ++ FUNC(vc_spi5), ++ FUNC(vc_uart0), ++ FUNC(vc_uart2), ++ FUNC(vc_uart3), ++ FUNC(vc_uart4), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_c0_aon_gpio_pin_funcs[] = { ++ PIN(0, ir_in, vc_spi0, vc_uart3, vc_i2c3, te0, vc_i2c0, _, _), ++ PIN(1, vc_pwm0, vc_spi0, vc_uart3, vc_i2c3, te1, aon_pwm, vc_i2c0, vc_pwm1), ++ PIN(2, vc_pwm0, vc_spi0, vc_uart3, ctl_hdmi_5v, fl0, aon_pwm, ir_in, vc_pwm1), ++ PIN(3, ir_in, vc_spi0, vc_uart3, aon_fp_4sec_resetb, fl1, sd_card_g, aon_gpclk, _), ++ PIN(4, gpclk0, vc_spi0, vc_i2csl, aon_gpclk, pm_led_out, aon_pwm, sd_card_g, vc_pwm0), ++ PIN(5, gpclk1, ir_in, vc_i2csl, clk_observe, aon_pwm, sd_card_g, vc_pwm0, _), ++ PIN(6, uart1, vc_uart4, gpclk2, ctl_hdmi_5v, vc_uart0, vc_spi3, _, _), ++ PIN(7, uart1, vc_uart4, gpclk0, aon_pwm, vc_uart0, vc_spi3, _, _), ++ PIN(8, uart1, vc_uart4, vc_i2csl, ctl_hdmi_5v, vc_uart0, vc_spi3, _, _), ++ PIN(9, uart1, vc_uart4, vc_i2csl, aon_pwm, vc_uart0, vc_spi3, _, _), ++ PIN(10, tsio, ctl_hdmi_5v, sc0, spdif_out, vc_spi5, usb_pwr, aon_gpclk, sd_card_f), ++ PIN(11, tsio, uart0, sc0, aud_fs_clk0, vc_spi5, usb_vbus, vc_uart2, sd_card_f), ++ PIN(12, tsio, uart0, vc_uart0, tsio, vc_spi5, usb_pwr, vc_uart2, sd_card_f), ++ PIN(13, bsc_m1, uart0, vc_uart0, uui, vc_spi5, arm_jtag, vc_uart2, vc_i2c3), ++ PIN(14, bsc_m1, uart0, vc_uart0, uui, vc_spi5, arm_jtag, vc_uart2, vc_i2c3), ++ PIN(15, ir_in, aon_fp_4sec_resetb, vc_uart0, pm_led_out, ctl_hdmi_5v, aon_pwm, aon_gpclk, _), ++ PIN(16, aon_cpu_standbyb, gpclk0, pm_led_out, ctl_hdmi_5v, vc_pwm0, usb_pwr, aud_fs_clk0, _), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_c0_aon_sgpio_pin_funcs[] = { ++ PIN(0, hdmi_tx0_bsc, hdmi_tx0_auto_i2c, bsc_m0, vc_i2c0, _, _, _, _), ++ PIN(1, hdmi_tx0_bsc, hdmi_tx0_auto_i2c, bsc_m0, vc_i2c0, _, _, _, _), ++ PIN(2, hdmi_tx1_bsc, hdmi_tx1_auto_i2c, bsc_m1, vc_i2c4, ctl_hdmi_5v, _, _, _), ++ PIN(3, hdmi_tx1_bsc, hdmi_tx1_auto_i2c, bsc_m1, vc_i2c4, _, _, _, _), ++ PIN(4, avs_pmu_bsc, bsc_m2, vc_i2c5, ctl_hdmi_5v, _, _, _, _), ++ PIN(5, avs_pmu_bsc, bsc_m2, vc_i2c5, _, _, _, _, _), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_c0_gpio_pin_funcs[] = { ++ PIN(0, bsc_m3, vc_i2c0, gpclk0, enet0, vc_pwm1, vc_spi0, ir_in, _), ++ PIN(1, bsc_m3, vc_i2c0, gpclk1, enet0, vc_pwm1, sr_edm_sense, vc_spi0, vc_uart3), ++ PIN(2, pdm, i2s_in, gpclk2, vc_spi4, pkt, vc_spi0, vc_uart3, _), ++ PIN(3, pdm, i2s_in, vc_spi4, pkt, vc_spi0, vc_uart3, _, _), ++ PIN(4, pdm, i2s_in, arm_jtag, vc_spi4, pkt, vc_spi0, vc_uart3, _), ++ PIN(5, pdm, vc_i2c3, arm_jtag, sd_card_e, vc_spi4, pkt, vc_pcm, vc_i2c5), ++ PIN(6, pdm, vc_i2c3, arm_jtag, sd_card_e, vc_spi4, pkt, vc_pcm, vc_i2c5), ++ PIN(7, i2s_out, spdif_out, arm_jtag, sd_card_e, vc_i2c3, enet0_rgmii, vc_pcm, vc_spi4), ++ PIN(8, i2s_out, aud_fs_clk0, arm_jtag, sd_card_e, vc_i2c3, enet0_mii, vc_pcm, vc_spi4), ++ PIN(9, i2s_out, aud_fs_clk0, arm_jtag, sd_card_e, enet0_mii, sd_card_c, vc_spi4, _), ++ PIN(10, bsc_m3, mtsif_alt1, i2s_in, i2s_out, vc_spi5, enet0_mii, sd_card_c, vc_spi4), ++ PIN(11, bsc_m3, mtsif_alt1, i2s_in, i2s_out, vc_spi5, enet0_mii, sd_card_c, vc_spi4), ++ PIN(12, spi_s, mtsif_alt1, i2s_in, i2s_out, vc_spi5, vc_i2csl, sd0, sd_card_d), ++ PIN(13, spi_s, mtsif_alt1, i2s_out, usb_vbus, vc_spi5, vc_i2csl, sd0, sd_card_d), ++ PIN(14, spi_s, vc_i2csl, enet0_rgmii, arm_jtag, vc_spi5, vc_pwm0, vc_i2c4, sd_card_d), ++ PIN(15, spi_s, vc_i2csl, vc_spi3, arm_jtag, vc_pwm0, vc_i2c4, gpclk0, _), ++ PIN(16, sd_card_b, i2s_out, vc_spi3, i2s_in, sd0, enet0_rgmii, gpclk1, _), ++ PIN(17, sd_card_b, i2s_out, vc_spi3, i2s_in, ext_sc_clk, sd0, enet0_rgmii, gpclk2), ++ PIN(18, sd_card_b, i2s_out, vc_spi3, i2s_in, sd0, enet0_rgmii, vc_pwm1, _), ++ PIN(19, sd_card_b, usb_pwr, vc_spi3, pkt, spdif_out, sd0, ir_in, vc_pwm1), ++ PIN(20, sd_card_b, uui, vc_uart0, arm_jtag, uart2, usb_pwr, vc_pcm, vc_uart4), ++ PIN(21, usb_pwr, uui, vc_uart0, arm_jtag, uart2, sd_card_b, vc_pcm, vc_uart4), ++ PIN(22, usb_pwr, enet0, vc_uart0, mtsif, uart2, usb_vbus, vc_pcm, vc_i2c5), ++ PIN(23, usb_vbus, enet0, vc_uart0, mtsif, uart2, i2s_out, vc_pcm, vc_i2c5), ++ PIN(24, mtsif, pkt, uart0, enet0_rgmii, enet0_rgmii, vc_i2c4, vc_uart3, _), ++ PIN(25, mtsif, pkt, sc0, uart0, enet0_rgmii, enet0_rgmii, vc_i2c4, vc_uart3), ++ PIN(26, mtsif, pkt, sc0, uart0, enet0_rgmii, vc_uart4, vc_spi5, _), ++ PIN(27, mtsif, pkt, sc0, uart0, enet0_rgmii, vc_uart4, vc_spi5, _), ++ PIN(28, mtsif, pkt, sc0, enet0_rgmii, vc_uart4, vc_spi5, _, _), ++ PIN(29, mtsif, pkt, sc0, enet0_rgmii, vc_uart4, vc_spi5, _, _), ++ PIN(30, mtsif, pkt, sc0, sd2, enet0_rgmii, gpclk0, vc_pwm0, _), ++ PIN(31, mtsif, pkt, sc0, sd2, enet0_rgmii, vc_spi3, vc_pwm0, _), ++ PIN(32, mtsif, pkt, sc0, sd2, enet0_rgmii, vc_spi3, vc_uart3, _), ++ PIN(33, mtsif, pkt, sd2, enet0_rgmii, vc_spi3, vc_uart3, _, _), ++ PIN(34, mtsif, pkt, ext_sc_clk, sd2, enet0_rgmii, vc_spi3, vc_i2c5, _), ++ PIN(35, mtsif, pkt, sd2, enet0_rgmii, vc_spi3, vc_i2c5, _, _), ++ PIN(36, sd0, mtsif, sc0, i2s_in, vc_uart3, vc_uart2, _, _), ++ PIN(37, sd0, mtsif, sc0, vc_spi0, i2s_in, vc_uart3, vc_uart2, _), ++ PIN(38, sd0, mtsif_alt, sc0, vc_spi0, i2s_in, vc_uart3, vc_uart2, _), ++ PIN(39, sd0, mtsif_alt, sc0, vc_spi0, vc_uart3, vc_uart2, _, _), ++ PIN(40, sd0, mtsif_alt, sc0, vc_spi0, bsc_m3, _, _, _), ++ PIN(41, sd0, mtsif_alt, sc0, vc_spi0, bsc_m3, _, _, _), ++ PIN(42, vc_spi0, mtsif_alt, vc_i2c0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), ++ PIN(43, vc_spi0, mtsif_alt, vc_i2c0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), ++ PIN(44, vc_spi0, mtsif_alt, enet0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), ++ PIN(45, vc_spi0, mtsif_alt, enet0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), ++ PIN(46, vc_spi0, mtsif_alt, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m, _), ++ PIN(47, enet0, mtsif_alt, i2s_out, mtsif_alt1, arm_jtag, _, _, _), ++ PIN(48, sc0, usb_pwr, spdif_out, mtsif, _, _, _, _), ++ PIN(49, sc0, usb_pwr, aud_fs_clk0, mtsif, _, _, _, _), ++ PIN(50, sc0, usb_vbus, sc0, _, _, _, _, _), ++ PIN(51, sc0, enet0, sc0, sr_edm_sense, _, _, _, _), ++ PIN(52, sc0, enet0, vc_pwm1, _, _, _, _, _), ++ PIN(53, sc0, enet0_rgmii, ext_sc_clk, _, _, _, _, _), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_d0_aon_gpio_pin_funcs[] = { ++ PIN(0, ir_in, vc_spi0, vc_uart0, vc_i2c3, uart0, vc_i2c0, _, _), ++ PIN(1, vc_pwm0, vc_spi0, vc_uart0, vc_i2c3, uart0, aon_pwm, vc_i2c0, vc_pwm1), ++ PIN(2, vc_pwm0, vc_spi0, vc_uart0, ctl_hdmi_5v, uart0, aon_pwm, ir_in, vc_pwm1), ++ PIN(3, ir_in, vc_spi0, vc_uart0, uart0, sd_card_g, aon_gpclk, _, _), ++ PIN(4, gpclk0, vc_spi0, pm_led_out, aon_pwm, sd_card_g, vc_pwm0, _, _), ++ PIN(5, gpclk1, ir_in, aon_pwm, sd_card_g, vc_pwm0, _, _, _), ++ PIN(6, uart1, vc_uart2, ctl_hdmi_5v, gpclk2, vc_spi3, _, _, _), ++ PIN(7, _, _, _, _, _, _, _, _), ++ PIN(8, uart1, vc_uart2, ctl_hdmi_5v, vc_spi0, vc_spi3, _, _, _), ++ PIN(9, uart1, vc_uart2, vc_uart0, aon_pwm, vc_spi0, vc_uart2, vc_spi3, _), ++ PIN(10, _, _, _, _, _, _, _, _), ++ PIN(11, _, _, _, _, _, _, _, _), ++ PIN(12, uart1, vc_uart2, vc_uart0, vc_spi0, usb_pwr, vc_uart2, vc_spi3, _), ++ PIN(13, bsc_m1, vc_uart0, uui, vc_spi0, arm_jtag, vc_uart2, vc_i2c3, _), ++ PIN(14, bsc_m1, aon_gpclk, vc_uart0, uui, vc_spi0, arm_jtag, vc_uart2, vc_i2c3), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_d0_aon_sgpio_pin_funcs[] = { ++ PIN(0, hdmi_tx0_bsc, hdmi_tx0_auto_i2c, bsc_m0, vc_i2c0, _, _, _, _), ++ PIN(1, hdmi_tx0_bsc, hdmi_tx0_auto_i2c, bsc_m0, vc_i2c0, _, _, _, _), ++ PIN(2, hdmi_tx1_bsc, hdmi_tx1_auto_i2c, bsc_m1, vc_i2c0, ctl_hdmi_5v, _, _, _), ++ PIN(3, hdmi_tx1_bsc, hdmi_tx1_auto_i2c, bsc_m1, vc_i2c0, _, _, _, _), ++ PIN(4, avs_pmu_bsc, bsc_m2, vc_i2c3, ctl_hdmi_5v, _, _, _, _), ++ PIN(5, avs_pmu_bsc, bsc_m2, vc_i2c3, _, _, _, _, _), ++}; ++ ++static const struct bcm2712_pin_funcs bcm2712_d0_gpio_pin_funcs[] = { ++ PIN(1, vc_i2c0, usb_pwr, gpclk0, sd_card_e, vc_spi3, sr_edm_sense, vc_spi0, vc_uart0), ++ PIN(2, vc_i2c0, usb_pwr, gpclk1, sd_card_e, vc_spi3, clk_observe, vc_spi0, vc_uart0), ++ PIN(3, vc_i2c3, usb_vbus, gpclk2, sd_card_e, vc_spi3, vc_spi0, vc_uart0, _), ++ PIN(4, vc_i2c3, vc_pwm1, vc_spi3, sd_card_e, vc_spi3, vc_spi0, vc_uart0, _), ++ PIN(10, bsc_m3, vc_pwm1, vc_spi3, sd_card_e, vc_spi3, gpclk0, _, _), ++ PIN(11, bsc_m3, vc_spi3, clk_observe, sd_card_c, gpclk1, _, _, _), ++ PIN(12, spi_s, vc_spi3, sd_card_c, sd_card_d, _, _, _, _), ++ PIN(13, spi_s, vc_spi3, sd_card_c, sd_card_d, _, _, _, _), ++ PIN(14, spi_s, uui, arm_jtag, vc_pwm0, vc_i2c0, sd_card_d, _, _), ++ PIN(15, spi_s, uui, arm_jtag, vc_pwm0, vc_i2c0, gpclk0, _, _), ++ PIN(18, sd_card_f, vc_pwm1, _, _, _, _, _, _), ++ PIN(19, sd_card_f, usb_pwr, vc_pwm1, _, _, _, _, _), ++ PIN(20, vc_i2c3, uui, vc_uart0, arm_jtag, vc_uart2, _, _, _), ++ PIN(21, vc_i2c3, uui, vc_uart0, arm_jtag, vc_uart2, _, _, _), ++ PIN(22, sd_card_f, vc_uart0, vc_i2c3, _, _, _, _, _), ++ PIN(23, vc_uart0, vc_i2c3, _, _, _, _, _, _), ++ PIN(24, sd_card_b, vc_spi0, arm_jtag, uart0, usb_pwr, vc_uart2, vc_uart0, _), ++ PIN(25, sd_card_b, vc_spi0, arm_jtag, uart0, usb_pwr, vc_uart2, vc_uart0, _), ++ PIN(26, sd_card_b, vc_spi0, arm_jtag, uart0, usb_vbus, vc_uart2, vc_spi0, _), ++ PIN(27, sd_card_b, vc_spi0, arm_jtag, uart0, vc_uart2, vc_spi0, _, _), ++ PIN(28, sd_card_b, vc_spi0, arm_jtag, vc_i2c0, vc_spi0, _, _, _), ++ PIN(29, arm_jtag, vc_i2c0, vc_spi0, _, _, _, _, _), ++ PIN(30, sd2, gpclk0, vc_pwm0, _, _, _, _, _), ++ PIN(31, sd2, vc_spi3, vc_pwm0, _, _, _, _, _), ++ PIN(32, sd2, vc_spi3, vc_uart3, _, _, _, _, _), ++ PIN(33, sd2, vc_spi3, vc_uart3, _, _, _, _, _), ++ PIN(34, sd2, vc_spi3, vc_i2c5, _, _, _, _, _), ++ PIN(35, sd2, vc_spi3, vc_i2c5, _, _, _, _, _), ++}; ++ ++static inline u32 bcm2712_reg_rd(struct bcm2712_pinctrl *pc, unsigned reg) ++{ ++ return readl(pc->base + reg); ++} ++ ++static inline void bcm2712_reg_wr(struct bcm2712_pinctrl *pc, unsigned reg, ++ u32 val) ++{ ++ writel(val, pc->base + reg); ++} ++ ++static enum bcm2712_funcs bcm2712_pinctrl_fsel_get( ++ struct bcm2712_pinctrl *pc, unsigned pin) ++{ ++ u32 bit = pc->pin_regs[pin].mux_bit; ++ enum bcm2712_funcs func; ++ int fsel; ++ u32 val; ++ ++ if (!bit) ++ return func_gpio; ++ ++ val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); ++ fsel = (val >> BIT_TO_SHIFT(bit)) & BCM2712_FSEL_MASK; ++ func = pc->pin_funcs[pin].funcs[fsel]; ++ if (func >= func_count) ++ func = (enum bcm2712_funcs)fsel; ++ ++ dev_dbg(pc->dev, "get %04x: %08x (%u => %s)\n", ++ BIT_TO_REG(bit), val, pin, ++ bcm2712_func_names[func]); ++ ++ return func; ++} ++ ++static void bcm2712_pinctrl_fsel_set( ++ struct bcm2712_pinctrl *pc, unsigned pin, ++ enum bcm2712_funcs func) ++{ ++ u32 bit = pc->pin_regs[pin].mux_bit, val; ++ const u8 *pin_funcs; ++ unsigned long flags; ++ int fsel; ++ int cur; ++ int i; ++ ++ if (!bit || func >= func_count) ++ return; ++ ++ fsel = BCM2712_FSEL_COUNT; ++ ++ if (func >= BCM2712_FSEL_COUNT) { ++ /* Convert to an fsel number */ ++ pin_funcs = pc->pin_funcs[pin].funcs; ++ for (i = 1; i < BCM2712_FSEL_COUNT; i++) { ++ if (pin_funcs[i - 1] == func) { ++ fsel = i; ++ break; ++ } ++ } ++ } else { ++ fsel = (enum bcm2712_funcs)func; ++ } ++ if (fsel >= BCM2712_FSEL_COUNT) ++ return; ++ ++ spin_lock_irqsave(&pc->lock, flags); ++ ++ val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); ++ cur = (val >> BIT_TO_SHIFT(bit)) & BCM2712_FSEL_MASK; ++ ++ dev_dbg(pc->dev, "read %04x: %08x (%u => %s)\n", ++ BIT_TO_REG(bit), val, pin, ++ bcm2712_func_names[cur]); ++ ++ if (cur != fsel) { ++ val &= ~(BCM2712_FSEL_MASK << BIT_TO_SHIFT(bit)); ++ val |= fsel << BIT_TO_SHIFT(bit); ++ ++ dev_dbg(pc->dev, "write %04x: %08x (%u <= %s)\n", ++ BIT_TO_REG(bit), val, pin, ++ bcm2712_func_names[fsel]); ++ bcm2712_reg_wr(pc, BIT_TO_REG(bit), val); ++ } ++ ++ spin_unlock_irqrestore(&pc->lock, flags); ++} ++ ++static int bcm2712_pctl_get_groups_count(struct pinctrl_dev *pctldev) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ return pc->pctl_desc.npins; ++} ++ ++static const char *bcm2712_pctl_get_group_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ return pc->gpio_groups[selector]; ++} ++ ++static int bcm2712_pctl_get_group_pins(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const unsigned **pins, ++ unsigned *num_pins) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ *pins = &pc->pctl_desc.pins[selector].number; ++ *num_pins = 1; ++ ++ return 0; ++} ++ ++static void bcm2712_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, ++ struct seq_file *s, ++ unsigned offset) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ enum bcm2712_funcs fsel = bcm2712_pinctrl_fsel_get(pc, offset); ++ const char *fname = bcm2712_func_names[fsel]; ++ ++ seq_printf(s, "function %s", fname); ++} ++ ++static void bcm2712_pctl_dt_free_map(struct pinctrl_dev *pctldev, ++ struct pinctrl_map *maps, unsigned num_maps) ++{ ++ int i; ++ ++ for (i = 0; i < num_maps; i++) ++ if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN) ++ kfree(maps[i].data.configs.configs); ++ ++ kfree(maps); ++} ++ ++static const struct pinctrl_ops bcm2712_pctl_ops = { ++ .get_groups_count = bcm2712_pctl_get_groups_count, ++ .get_group_name = bcm2712_pctl_get_group_name, ++ .get_group_pins = bcm2712_pctl_get_group_pins, ++ .pin_dbg_show = bcm2712_pctl_pin_dbg_show, ++ .dt_node_to_map = pinconf_generic_dt_node_to_map_all, ++ .dt_free_map = bcm2712_pctl_dt_free_map, ++}; ++ ++static int bcm2712_pmx_free(struct pinctrl_dev *pctldev, ++ unsigned offset) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ /* disable by setting to GPIO */ ++ bcm2712_pinctrl_fsel_set(pc, offset, func_gpio); ++ return 0; ++} ++ ++static int bcm2712_pmx_get_functions_count(struct pinctrl_dev *pctldev) ++{ ++ return func_count; ++} ++ ++static const char *bcm2712_pmx_get_function_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ return (selector < func_count) ? bcm2712_func_names[selector] : NULL; ++} ++ ++static int bcm2712_pmx_get_function_groups(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const char * const **groups, ++ unsigned * const num_groups) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ /* every pin can do every function */ ++ *groups = pc->gpio_groups; ++ *num_groups = pc->pctl_desc.npins; ++ ++ return 0; ++} ++ ++static int bcm2712_pmx_set(struct pinctrl_dev *pctldev, ++ unsigned func_selector, ++ unsigned group_selector) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ bcm2712_pinctrl_fsel_set(pc, group_selector, func_selector); ++ ++ return 0; ++} ++static int bcm2712_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned pin) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ bcm2712_pinctrl_fsel_set(pc, pin, func_gpio); ++ ++ return 0; ++} ++ ++static void bcm2712_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned offset) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ /* disable by setting to GPIO */ ++ bcm2712_pinctrl_fsel_set(pc, offset, func_gpio); ++} ++ ++static const struct pinmux_ops bcm2712_pmx_ops = { ++ .free = bcm2712_pmx_free, ++ .get_functions_count = bcm2712_pmx_get_functions_count, ++ .get_function_name = bcm2712_pmx_get_function_name, ++ .get_function_groups = bcm2712_pmx_get_function_groups, ++ .set_mux = bcm2712_pmx_set, ++ .gpio_request_enable = bcm2712_pmx_gpio_request_enable, ++ .gpio_disable_free = bcm2712_pmx_gpio_disable_free, ++}; ++ ++static unsigned int bcm2712_pull_config_get(struct bcm2712_pinctrl *pc, ++ unsigned int pin) ++{ ++ u32 bit = pc->pin_regs[pin].pad_bit, val; ++ ++ if (unlikely(bit == REG_BIT_INVALID)) ++ return BCM2712_PULL_NONE; ++ ++ val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); ++ return (val >> BIT_TO_SHIFT(bit)) & BCM2712_PULL_MASK; ++} ++ ++static void bcm2712_pull_config_set(struct bcm2712_pinctrl *pc, ++ unsigned int pin, unsigned int arg) ++{ ++ u32 bit = pc->pin_regs[pin].pad_bit, val; ++ unsigned long flags; ++ ++ if (unlikely(bit == REG_BIT_INVALID)) { ++ dev_warn(pc->dev, "can't set pulls for %s\n", pc->gpio_groups[pin]); ++ return; ++ } ++ ++ spin_lock_irqsave(&pc->lock, flags); ++ ++ val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); ++ val &= ~(BCM2712_PULL_MASK << BIT_TO_SHIFT(bit)); ++ val |= (arg << BIT_TO_SHIFT(bit)); ++ bcm2712_reg_wr(pc, BIT_TO_REG(bit), val); ++ ++ spin_unlock_irqrestore(&pc->lock, flags); ++} ++ ++static int bcm2712_pinconf_get(struct pinctrl_dev *pctldev, ++ unsigned pin, unsigned long *config) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ enum pin_config_param param = pinconf_to_config_param(*config); ++ u32 arg; ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ arg = (bcm2712_pull_config_get(pc, pin) == BCM2712_PULL_NONE); ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ arg = (bcm2712_pull_config_get(pc, pin) == BCM2712_PULL_DOWN); ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ arg = (bcm2712_pull_config_get(pc, pin) == BCM2712_PULL_UP); ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ ++ *config = pinconf_to_config_packed(param, arg); ++ ++ return -ENOTSUPP; ++} ++ ++static int bcm2712_pinconf_set(struct pinctrl_dev *pctldev, ++ unsigned int pin, unsigned long *configs, ++ unsigned int num_configs) ++{ ++ struct bcm2712_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ u32 param, arg; ++ int i; ++ ++ for (i = 0; i < num_configs; i++) { ++ param = pinconf_to_config_param(configs[i]); ++ arg = pinconf_to_config_argument(configs[i]); ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ bcm2712_pull_config_set(pc, pin, BCM2712_PULL_NONE); ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ bcm2712_pull_config_set(pc, pin, BCM2712_PULL_DOWN); ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ bcm2712_pull_config_set(pc, pin, BCM2712_PULL_UP); ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ } /* for each config */ ++ ++ return 0; ++} ++ ++static const struct pinconf_ops bcm2712_pinconf_ops = { ++ .is_generic = true, ++ .pin_config_get = bcm2712_pinconf_get, ++ .pin_config_set = bcm2712_pinconf_set, ++}; ++ ++static const struct pinctrl_desc bcm2712_c0_pinctrl_desc = { ++ .name = "pinctrl-bcm2712", ++ .pins = bcm2712_c0_gpio_pins, ++ .npins = ARRAY_SIZE(bcm2712_c0_gpio_pins), ++ .pctlops = &bcm2712_pctl_ops, ++ .pmxops = &bcm2712_pmx_ops, ++ .confops = &bcm2712_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct pinctrl_desc bcm2712_c0_aon_pinctrl_desc = { ++ .name = "aon-pinctrl-bcm2712", ++ .pins = bcm2712_c0_aon_gpio_pins, ++ .npins = ARRAY_SIZE(bcm2712_c0_aon_gpio_pins), ++ .pctlops = &bcm2712_pctl_ops, ++ .pmxops = &bcm2712_pmx_ops, ++ .confops = &bcm2712_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct pinctrl_desc bcm2712_d0_pinctrl_desc = { ++ .name = "pinctrl-bcm2712", ++ .pins = bcm2712_d0_gpio_pins, ++ .npins = ARRAY_SIZE(bcm2712_d0_gpio_pins), ++ .pctlops = &bcm2712_pctl_ops, ++ .pmxops = &bcm2712_pmx_ops, ++ .confops = &bcm2712_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct pinctrl_desc bcm2712_d0_aon_pinctrl_desc = { ++ .name = "aon-pinctrl-bcm2712", ++ .pins = bcm2712_d0_aon_gpio_pins, ++ .npins = ARRAY_SIZE(bcm2712_d0_aon_gpio_pins), ++ .pctlops = &bcm2712_pctl_ops, ++ .pmxops = &bcm2712_pmx_ops, ++ .confops = &bcm2712_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct pinctrl_gpio_range bcm2712_c0_pinctrl_gpio_range = { ++ .name = "pinctrl-bcm2712", ++ .npins = ARRAY_SIZE(bcm2712_c0_gpio_pins), ++}; ++ ++static const struct pinctrl_gpio_range bcm2712_c0_aon_pinctrl_gpio_range = { ++ .name = "aon-pinctrl-bcm2712", ++ .npins = ARRAY_SIZE(bcm2712_c0_aon_gpio_pins), ++}; ++ ++static const struct pinctrl_gpio_range bcm2712_d0_pinctrl_gpio_range = { ++ .name = "pinctrl-bcm2712", ++ .npins = ARRAY_SIZE(bcm2712_d0_gpio_pins), ++}; ++ ++static const struct pinctrl_gpio_range bcm2712_d0_aon_pinctrl_gpio_range = { ++ .name = "aon-pinctrl-bcm2712", ++ .npins = ARRAY_SIZE(bcm2712_d0_aon_gpio_pins), ++}; ++ ++static const struct bcm_plat_data bcm2712_c0_plat_data = { ++ .pctl_desc = &bcm2712_c0_pinctrl_desc, ++ .gpio_range = &bcm2712_c0_pinctrl_gpio_range, ++ .pin_regs = bcm2712_c0_gpio_pin_regs, ++ .pin_funcs = bcm2712_c0_gpio_pin_funcs, ++}; ++ ++static const struct bcm_plat_data bcm2712_c0_aon_plat_data = { ++ .pctl_desc = &bcm2712_c0_aon_pinctrl_desc, ++ .gpio_range = &bcm2712_c0_aon_pinctrl_gpio_range, ++ .pin_regs = bcm2712_c0_aon_gpio_pin_regs, ++ .pin_funcs = bcm2712_c0_aon_gpio_pin_funcs, ++}; ++ ++static const struct bcm_plat_data bcm2712_d0_plat_data = { ++ .pctl_desc = &bcm2712_d0_pinctrl_desc, ++ .gpio_range = &bcm2712_d0_pinctrl_gpio_range, ++ .pin_regs = bcm2712_d0_gpio_pin_regs, ++ .pin_funcs = bcm2712_d0_gpio_pin_funcs, ++}; ++ ++static const struct bcm_plat_data bcm2712_d0_aon_plat_data = { ++ .pctl_desc = &bcm2712_d0_aon_pinctrl_desc, ++ .gpio_range = &bcm2712_d0_aon_pinctrl_gpio_range, ++ .pin_regs = bcm2712_d0_aon_gpio_pin_regs, ++ .pin_funcs = bcm2712_d0_aon_gpio_pin_funcs, ++}; ++ ++static const struct of_device_id bcm2712_pinctrl_match[] = { ++ { ++ .compatible = "brcm,bcm2712-pinctrl", ++ .data = &bcm2712_c0_plat_data, ++ }, ++ { ++ .compatible = "brcm,bcm2712-aon-pinctrl", ++ .data = &bcm2712_c0_aon_plat_data, ++ }, ++ ++ { ++ .compatible = "brcm,bcm2712c0-pinctrl", ++ .data = &bcm2712_c0_plat_data, ++ }, ++ { ++ .compatible = "brcm,bcm2712c0-aon-pinctrl", ++ .data = &bcm2712_c0_aon_plat_data, ++ }, ++ ++ { ++ .compatible = "brcm,bcm2712d0-pinctrl", ++ .data = &bcm2712_d0_plat_data, ++ }, ++ { ++ .compatible = "brcm,bcm2712d0-aon-pinctrl", ++ .data = &bcm2712_d0_aon_plat_data, ++ }, ++ {} ++}; ++ ++static int bcm2712_pinctrl_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ const struct bcm_plat_data *pdata; ++ const struct of_device_id *match; ++ struct bcm2712_pinctrl *pc; ++ const char **names; ++ int num_pins, i; ++ ++ match = of_match_node(bcm2712_pinctrl_match, np); ++ if (!match) ++ return -EINVAL; ++ pdata = match->data; ++ ++ pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); ++ if (!pc) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, pc); ++ pc->dev = dev; ++ spin_lock_init(&pc->lock); ++ ++ pc->base = devm_of_iomap(dev, np, 0, NULL); ++ if (IS_ERR(pc->base)) { ++ dev_err(dev, "could not get IO memory\n"); ++ return PTR_ERR(pc->base); ++ } ++ ++ pc->pctl_desc = *pdata->pctl_desc; ++ num_pins = pc->pctl_desc.npins; ++ names = devm_kmalloc_array(dev, num_pins, sizeof(const char *), ++ GFP_KERNEL); ++ if (!names) ++ return -ENOMEM; ++ for (i = 0; i < num_pins; i++) ++ names[i] = pc->pctl_desc.pins[i].name; ++ pc->gpio_groups = names; ++ pc->pin_regs = pdata->pin_regs; ++ pc->pin_funcs = pdata->pin_funcs; ++ pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc); ++ if (IS_ERR(pc->pctl_dev)) ++ return PTR_ERR(pc->pctl_dev); ++ ++ pc->gpio_range = *pdata->gpio_range; ++ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); ++ ++ return 0; ++} ++ ++static struct platform_driver bcm2712_pinctrl_driver = { ++ .probe = bcm2712_pinctrl_probe, ++ .driver = { ++ .name = MODULE_NAME, ++ .of_match_table = bcm2712_pinctrl_match, ++ .suppress_bind_attrs = true, ++ }, ++}; ++builtin_platform_driver(bcm2712_pinctrl_driver); diff --git a/target/linux/bcm27xx/patches-6.1/950-0859-mmc-brcmstb-add-support-for-BCM2712.patch b/target/linux/bcm27xx/patches-6.1/950-0859-mmc-brcmstb-add-support-for-BCM2712.patch new file mode 100644 index 0000000000..05d403a63e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0859-mmc-brcmstb-add-support-for-BCM2712.patch @@ -0,0 +1,498 @@ +From b627647c4500d39cb026924b608841fdf4d4d7e9 Mon Sep 17 00:00:00 2001 +From: Ulf Hansson +Date: Thu, 29 Oct 2020 09:57:16 +0800 +Subject: [PATCH] mmc: brcmstb: add support for BCM2712 + +BCM2712 has an SD Express capable SDHCI implementation and uses +the SDIO CFG register block present on other STB chips. + +Add plumbing for SD Express handover and BCM2712-specific functions. + +Due to the common bus infrastructure between BCM2711 and BCM2712, +the driver also needs to implement 32-bit IO accessors. + +mmc: brcmstb: override card presence if broken-cd is set + +Not just if the card is declared as nonremovable. + +sdhci: brcmstb: align SD express switchover with SD spec v8.00 + +Part 1 of the Physical specification, figure 3-24, details the switch +sequence for cards initially probed as SD. Add a missing check for DAT2 +level after switching VDD2 on. + +sdhci: brcmstb: clean up SD Express probe and error handling + +Refactor to avoid spurious error messages in dmesg if the requisite SD +Express DT nodes aren't present. + +Signed-off-by: Jonathan Bell + +mmc: sdhci-brcmstb: only use the delay line PHY for tuneable speeds + +The MMC core has a 200MHz core clock which allows the use of DDR50 and +below without incremental phase tuning. SDR50/SDR104 and the EMMC HS200 +speeds require tuning. + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/host/Kconfig | 2 + + drivers/mmc/host/sdhci-brcmstb.c | 356 +++++++++++++++++++++++++++++++ + 2 files changed, 358 insertions(+) + +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -1082,7 +1082,9 @@ config MMC_SDHCI_BRCMSTB + tristate "Broadcom SDIO/SD/MMC support" + depends on ARCH_BRCMSTB || BMIPS_GENERIC + depends on MMC_SDHCI_PLTFM ++ select MMC_SDHCI_IO_ACCESSORS + select MMC_CQHCI ++ select OF_DYNAMIC + default y + help + This selects support for the SDIO/SD/MMC Host Controller on +--- a/drivers/mmc/host/sdhci-brcmstb.c ++++ b/drivers/mmc/host/sdhci-brcmstb.c +@@ -11,6 +11,8 @@ + #include + #include + #include ++#include ++#include + + #include "sdhci-cqhci.h" + #include "sdhci-pltfm.h" +@@ -26,18 +28,43 @@ + + #define BRCMSTB_PRIV_FLAGS_HAS_CQE BIT(0) + #define BRCMSTB_PRIV_FLAGS_GATE_CLOCK BIT(1) ++#define BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS BIT(2) + + #define SDHCI_ARASAN_CQE_BASE_ADDR 0x200 + ++#define SDIO_CFG_CTRL 0x0 ++#define SDIO_CFG_CTRL_SDCD_N_TEST_EN BIT(31) ++#define SDIO_CFG_CTRL_SDCD_N_TEST_LEV BIT(30) ++ ++#define SDIO_CFG_SD_PIN_SEL 0x44 ++#define SDIO_CFG_SD_PIN_SEL_MASK 0x3 ++#define SDIO_CFG_SD_PIN_SEL_CARD BIT(1) ++ ++#define SDIO_CFG_MAX_50MHZ_MODE 0x1ac ++#define SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE BIT(31) ++#define SDIO_CFG_MAX_50MHZ_MODE_ENABLE BIT(0) ++ + struct sdhci_brcmstb_priv { + void __iomem *cfg_regs; + unsigned int flags; + struct clk *base_clk; + u32 base_freq_hz; ++ u32 shadow_cmd; ++ u32 shadow_blk; ++ bool is_cmd_shadowed; ++ bool is_blk_shadowed; ++ struct regulator *sde_1v8; ++ struct device_node *sde_pcie; ++ void *__iomem sde_ioaddr; ++ void *__iomem sde_ioaddr2; ++ struct pinctrl *pinctrl; ++ struct pinctrl_state *pins_default; ++ struct pinctrl_state *pins_sdex; + }; + + struct brcmstb_match_priv { + void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios); ++ void (*cfginit)(struct sdhci_host *host); + struct sdhci_ops *ops; + const unsigned int flags; + }; +@@ -94,6 +121,124 @@ static void sdhci_brcmstb_set_clock(stru + sdhci_enable_clk(host, clk); + } + ++#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) ++ ++static inline u32 sdhci_brcmstb_32only_readl(struct sdhci_host *host, int reg) ++{ ++ u32 val = readl(host->ioaddr + reg); ++ ++ pr_debug("%s: readl [0x%02x] 0x%08x\n", ++ mmc_hostname(host->mmc), reg, val); ++ return val; ++} ++ ++static u16 sdhci_brcmstb_32only_readw(struct sdhci_host *host, int reg) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host); ++ u32 val; ++ u16 word; ++ ++ if ((reg == SDHCI_TRANSFER_MODE) && brcmstb_priv->is_cmd_shadowed) { ++ /* Get the saved transfer mode */ ++ val = brcmstb_priv->shadow_cmd; ++ } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && ++ brcmstb_priv->is_blk_shadowed) { ++ /* Get the saved block info */ ++ val = brcmstb_priv->shadow_blk; ++ } else { ++ val = sdhci_brcmstb_32only_readl(host, (reg & ~3)); ++ } ++ word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; ++ return word; ++} ++ ++static u8 sdhci_brcmstb_32only_readb(struct sdhci_host *host, int reg) ++{ ++ u32 val = sdhci_brcmstb_32only_readl(host, (reg & ~3)); ++ u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff; ++ return byte; ++} ++ ++static inline void sdhci_brcmstb_32only_writel(struct sdhci_host *host, u32 val, int reg) ++{ ++ pr_debug("%s: writel [0x%02x] 0x%08x\n", ++ mmc_hostname(host->mmc), reg, val); ++ ++ writel(val, host->ioaddr + reg); ++} ++ ++/* ++ * BCM2712 unfortunately carries with it a perennial bug with the SD controller ++ * register interface present on previous chips (2711/2709/2708). Accesses must ++ * be dword-sized and a read-modify-write cycle to the 32-bit registers ++ * containing the COMMAND, TRANSFER_MODE, BLOCK_SIZE and BLOCK_COUNT registers ++ * tramples the upper/lower 16 bits of data written. BCM2712 does not seem to ++ * need the extreme delay between each write as on previous chips, just the ++ * serialisation of writes to these registers in a single 32-bit operation. ++ */ ++static void sdhci_brcmstb_32only_writew(struct sdhci_host *host, u16 val, int reg) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host); ++ u32 word_shift = REG_OFFSET_IN_BITS(reg); ++ u32 mask = 0xffff << word_shift; ++ u32 oldval, newval; ++ ++ if (reg == SDHCI_COMMAND) { ++ /* Write the block now as we are issuing a command */ ++ if (brcmstb_priv->is_blk_shadowed) { ++ sdhci_brcmstb_32only_writel(host, brcmstb_priv->shadow_blk, ++ SDHCI_BLOCK_SIZE); ++ brcmstb_priv->is_blk_shadowed = false; ++ } ++ oldval = brcmstb_priv->shadow_cmd; ++ brcmstb_priv->is_cmd_shadowed = false; ++ } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && ++ brcmstb_priv->is_blk_shadowed) { ++ /* Block size and count are stored in shadow reg */ ++ oldval = brcmstb_priv->shadow_blk; ++ } else { ++ /* Read reg, all other registers are not shadowed */ ++ oldval = sdhci_brcmstb_32only_readl(host, (reg & ~3)); ++ } ++ newval = (oldval & ~mask) | (val << word_shift); ++ ++ if (reg == SDHCI_TRANSFER_MODE) { ++ /* Save the transfer mode until the command is issued */ ++ brcmstb_priv->shadow_cmd = newval; ++ brcmstb_priv->is_cmd_shadowed = true; ++ } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { ++ /* Save the block info until the command is issued */ ++ brcmstb_priv->shadow_blk = newval; ++ brcmstb_priv->is_blk_shadowed = true; ++ } else { ++ /* Command or other regular 32-bit write */ ++ sdhci_brcmstb_32only_writel(host, newval, reg & ~3); ++ } ++} ++ ++static void sdhci_brcmstb_32only_writeb(struct sdhci_host *host, u8 val, int reg) ++{ ++ u32 oldval = sdhci_brcmstb_32only_readl(host, (reg & ~3)); ++ u32 byte_shift = REG_OFFSET_IN_BITS(reg); ++ u32 mask = 0xff << byte_shift; ++ u32 newval = (oldval & ~mask) | (val << byte_shift); ++ ++ sdhci_brcmstb_32only_writel(host, newval, reg & ~3); ++} ++ ++static void sdhci_brcmstb_set_power(struct sdhci_host *host, unsigned char mode, ++ unsigned short vdd) ++{ ++ if (!IS_ERR(host->mmc->supply.vmmc)) { ++ struct mmc_host *mmc = host->mmc; ++ ++ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); ++ } ++ sdhci_set_power_noreg(host, mode, vdd); ++} ++ + static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) + { +@@ -123,6 +268,146 @@ static void sdhci_brcmstb_set_uhs_signal + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + } + ++static void sdhci_brcmstb_cfginit_2712(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host); ++ bool want_dll = false; ++ u32 uhs_mask = (MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104); ++ u32 hsemmc_mask = (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS200_1_2V_SDR | ++ MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V); ++ u32 reg; ++ ++ if (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)) { ++ if((host->mmc->caps & uhs_mask) || (host->mmc->caps2 & hsemmc_mask)) ++ want_dll = true; ++ } ++ ++ /* ++ * If we want a speed that requires tuning, ++ * then select the delay line PHY as the clock source. ++ */ ++ if (want_dll) { ++ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE); ++ reg &= ~SDIO_CFG_MAX_50MHZ_MODE_ENABLE; ++ reg |= SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE; ++ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE); ++ } ++ ++ if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || ++ (host->mmc->caps & MMC_CAP_NEEDS_POLL)) { ++ /* Force presence */ ++ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_CTRL); ++ reg &= ~SDIO_CFG_CTRL_SDCD_N_TEST_LEV; ++ reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN; ++ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CTRL); ++ } else { ++ /* Enable card detection line */ ++ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL); ++ reg &= ~SDIO_CFG_SD_PIN_SEL_MASK; ++ reg |= SDIO_CFG_SD_PIN_SEL_CARD; ++ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL); ++ } ++} ++ ++static int bcm2712_init_sd_express(struct sdhci_host *host, struct mmc_ios *ios) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host); ++ struct device *dev = host->mmc->parent; ++ u32 ctrl_val; ++ u32 present_state; ++ int ret; ++ ++ if (!brcmstb_priv->sde_ioaddr || !brcmstb_priv->sde_ioaddr2) ++ return -EINVAL; ++ ++ if (!brcmstb_priv->pinctrl) ++ return -EINVAL; ++ ++ /* Turn off the SD clock first */ ++ sdhci_set_clock(host, 0); ++ ++ /* Disable SD DAT0-3 pulls */ ++ pinctrl_select_state(brcmstb_priv->pinctrl, brcmstb_priv->pins_sdex); ++ ++ ctrl_val = readl(brcmstb_priv->sde_ioaddr); ++ dev_dbg(dev, "ctrl_val 1 %08x\n", ctrl_val); ++ ++ /* Tri-state the SD pins */ ++ ctrl_val |= 0x1ff8; ++ writel(ctrl_val, brcmstb_priv->sde_ioaddr); ++ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr)); ++ /* Let voltages settle */ ++ udelay(100); ++ ++ /* Enable the PCIe sideband pins */ ++ ctrl_val &= ~0x6000; ++ writel(ctrl_val, brcmstb_priv->sde_ioaddr); ++ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr)); ++ /* Let voltages settle */ ++ udelay(100); ++ ++ /* Turn on the 1v8 VDD2 regulator */ ++ ret = regulator_enable(brcmstb_priv->sde_1v8); ++ if (ret) ++ return ret; ++ ++ /* Wait for Tpvcrl */ ++ msleep(1); ++ ++ /* Sample DAT2 (CLKREQ#) - if low, card is in PCIe mode */ ++ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); ++ present_state = (present_state & SDHCI_DATA_LVL_MASK) >> SDHCI_DATA_LVL_SHIFT; ++ dev_dbg(dev, "state = 0x%08x\n", present_state); ++ ++ if (present_state & BIT(2)) { ++ dev_err(dev, "DAT2 still high, abandoning SDex switch\n"); ++ return -ENODEV; ++ } ++ ++ /* Turn on the LCPLL PTEST mux */ ++ ctrl_val = readl(brcmstb_priv->sde_ioaddr2 + 20); // misc5 ++ ctrl_val &= ~(0x7 << 7); ++ ctrl_val |= 3 << 7; ++ writel(ctrl_val, brcmstb_priv->sde_ioaddr2 + 20); ++ dev_dbg(dev, "misc 5->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2 + 20)); ++ ++ /* PTEST diff driver enable */ ++ ctrl_val = readl(brcmstb_priv->sde_ioaddr2); ++ ctrl_val |= BIT(21); ++ writel(ctrl_val, brcmstb_priv->sde_ioaddr2); ++ ++ dev_dbg(dev, "misc 0->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2)); ++ ++ /* Wait for more than the minimum Tpvpgl time */ ++ msleep(100); ++ ++ if (brcmstb_priv->sde_pcie) { ++ struct of_changeset changeset; ++ static struct property okay_property = { ++ .name = "status", ++ .value = "okay", ++ .length = 5, ++ }; ++ ++ /* Enable the pcie controller */ ++ of_changeset_init(&changeset); ++ ret = of_changeset_update_property(&changeset, ++ brcmstb_priv->sde_pcie, ++ &okay_property); ++ if (ret) { ++ dev_err(dev, "%s: failed to update property - %d\n", __func__, ++ ret); ++ return -ENODEV; ++ } ++ ret = of_changeset_apply(&changeset); ++ } ++ ++ dev_dbg(dev, "%s -> %d\n", __func__, ret); ++ return ret; ++} ++ + static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc) + { + sdhci_dumpregs(mmc_priv(mmc)); +@@ -155,6 +440,21 @@ static struct sdhci_ops sdhci_brcmstb_op + .set_uhs_signaling = sdhci_set_uhs_signaling, + }; + ++static struct sdhci_ops sdhci_brcmstb_ops_2712 = { ++ .read_l = sdhci_brcmstb_32only_readl, ++ .read_w = sdhci_brcmstb_32only_readw, ++ .read_b = sdhci_brcmstb_32only_readb, ++ .write_l = sdhci_brcmstb_32only_writel, ++ .write_w = sdhci_brcmstb_32only_writew, ++ .write_b = sdhci_brcmstb_32only_writeb, ++ .set_clock = sdhci_set_clock, ++ .set_power = sdhci_brcmstb_set_power, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++ .init_sd_express = bcm2712_init_sd_express, ++}; ++ + static struct sdhci_ops sdhci_brcmstb_ops_7216 = { + .set_clock = sdhci_brcmstb_set_clock, + .set_bus_width = sdhci_set_bus_width, +@@ -179,10 +479,16 @@ static const struct brcmstb_match_priv m + .ops = &sdhci_brcmstb_ops_7216, + }; + ++static const struct brcmstb_match_priv match_priv_2712 = { ++ .cfginit = sdhci_brcmstb_cfginit_2712, ++ .ops = &sdhci_brcmstb_ops_2712, ++}; ++ + static const struct of_device_id sdhci_brcm_of_match[] = { + { .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 }, + { .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 }, + { .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 }, ++ { .compatible = "brcm,bcm2712-sdhci", .data = &match_priv_2712 }, + {}, + }; + +@@ -256,6 +562,7 @@ static int sdhci_brcmstb_probe(struct pl + u32 actual_clock_mhz; + struct sdhci_host *host; + struct resource *iomem; ++ bool no_pinctrl = false; + struct clk *clk; + struct clk *base_clk = NULL; + int res; +@@ -290,6 +597,11 @@ static int sdhci_brcmstb_probe(struct pl + match_priv->ops->irq = sdhci_brcmstb_cqhci_irq; + } + ++ priv->sde_pcie = of_parse_phandle(pdev->dev.of_node, ++ "sde-pcie", 0); ++ if (priv->sde_pcie) ++ priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS; ++ + /* Map in the non-standard CFG registers */ + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->cfg_regs = devm_ioremap_resource(&pdev->dev, iomem); +@@ -303,6 +615,43 @@ static int sdhci_brcmstb_probe(struct pl + if (res) + goto err; + ++ priv->sde_1v8 = devm_regulator_get_optional(&pdev->dev, "sde-1v8"); ++ if (IS_ERR(priv->sde_1v8)) ++ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS; ++ ++ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ if (iomem) { ++ priv->sde_ioaddr = devm_ioremap_resource(&pdev->dev, iomem); ++ if (IS_ERR(priv->sde_ioaddr)) ++ priv->sde_ioaddr = NULL; ++ } ++ ++ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 3); ++ if (iomem) { ++ priv->sde_ioaddr2 = devm_ioremap_resource(&pdev->dev, iomem); ++ if (IS_ERR(priv->sde_ioaddr2)) ++ priv->sde_ioaddr = NULL; ++ } ++ ++ priv->pinctrl = devm_pinctrl_get(&pdev->dev); ++ if (IS_ERR(priv->pinctrl)) { ++ no_pinctrl = true; ++ } ++ priv->pins_default = pinctrl_lookup_state(priv->pinctrl, "default"); ++ if (IS_ERR(priv->pins_default)) { ++ dev_dbg(&pdev->dev, "No pinctrl default state\n"); ++ no_pinctrl = true; ++ } ++ priv->pins_sdex = pinctrl_lookup_state(priv->pinctrl, "sd-express"); ++ if (IS_ERR(priv->pins_sdex)) { ++ dev_dbg(&pdev->dev, "No pinctrl sd-express state\n"); ++ no_pinctrl = true; ++ } ++ if (no_pinctrl || !priv->sde_ioaddr || !priv->sde_ioaddr2) { ++ priv->pinctrl = NULL; ++ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS; ++ } ++ + /* + * Automatic clock gating does not work for SD cards that may + * voltage switch so only enable it for non-removable devices. +@@ -319,6 +668,13 @@ static int sdhci_brcmstb_probe(struct pl + (host->mmc->caps2 & MMC_CAP2_HS400_ES)) + host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es; + ++ if (host->ops->init_sd_express && ++ (priv->flags & BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS)) ++ host->mmc->caps2 |= MMC_CAP2_SD_EXP; ++ ++ if(match_priv->cfginit) ++ match_priv->cfginit(host); ++ + /* + * Supply the existing CAPS, but clear the UHS modes. This + * will allow these modes to be specified by device tree diff --git a/target/linux/bcm27xx/patches-6.1/950-0860-sdhci-Add-SD-Express-hook.patch b/target/linux/bcm27xx/patches-6.1/950-0860-sdhci-Add-SD-Express-hook.patch new file mode 100644 index 0000000000..1aea0b3bcd --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0860-sdhci-Add-SD-Express-hook.patch @@ -0,0 +1,90 @@ +From 9564939f1a92e5f9807461539de28c50e5bee440 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 6 Jul 2021 09:45:36 +0100 +Subject: [PATCH] sdhci: Add SD Express hook + +sdhci: remove PYA0_INTR_BUG quirk. Add quirks to disable some of the higher SDR speeds at 1.8v. +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 5 ++++- + drivers/mmc/host/sdhci.c | 19 +++++++++++++++++++ + drivers/mmc/host/sdhci.h | 6 ++++++ + 3 files changed, 29 insertions(+), 1 deletion(-) + +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -363,7 +363,10 @@ static const struct sdhci_pltfm_data sdh + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +- SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, ++ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | ++ SDHCI_QUIRK2_NO_SDR50 | ++ SDHCI_QUIRK2_NO_SDR104 | ++ SDHCI_QUIRK2_NO_SDR25, + }; + + static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -3071,6 +3071,15 @@ static void sdhci_card_event(struct mmc_ + spin_unlock_irqrestore(&host->lock, flags); + } + ++static int sdhci_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ ++ if (!host->ops->init_sd_express) ++ return -EOPNOTSUPP; ++ return host->ops->init_sd_express(host, ios); ++} ++ + static const struct mmc_host_ops sdhci_ops = { + .request = sdhci_request, + .post_req = sdhci_post_req, +@@ -3086,6 +3095,7 @@ static const struct mmc_host_ops sdhci_o + .execute_tuning = sdhci_execute_tuning, + .card_event = sdhci_card_event, + .card_busy = sdhci_card_busy, ++ .init_sd_express = sdhci_init_sd_express, + }; + + /*****************************************************************************\ +@@ -4605,6 +4615,15 @@ int sdhci_setup_host(struct sdhci_host * + !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) + mmc->caps |= MMC_CAP_UHS_DDR50; + ++ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR25) ++ mmc->caps &= ~MMC_CAP_UHS_SDR25; ++ ++ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR50) ++ mmc->caps &= ~MMC_CAP_UHS_SDR50; ++ ++ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR104) ++ mmc->caps &= ~MMC_CAP_UHS_SDR104; ++ + /* Does the host need tuning for SDR50? */ + if (host->caps1 & SDHCI_USE_SDR50_TUNING) + host->flags |= SDHCI_SDR50_NEEDS_TUNING; +--- a/drivers/mmc/host/sdhci.h ++++ b/drivers/mmc/host/sdhci.h +@@ -481,6 +481,11 @@ struct sdhci_host { + /* Issue CMD and DATA reset together */ + #define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19) + ++/* Quirks to ignore a speed if a that speed is unreliable */ ++#define SDHCI_QUIRK2_NO_SDR25 (1<<19) ++#define SDHCI_QUIRK2_NO_SDR50 (1<<20) ++#define SDHCI_QUIRK2_NO_SDR104 (1<<21) ++ + int irq; /* Device IRQ */ + void __iomem *ioaddr; /* Mapped address */ + phys_addr_t mapbase; /* physical address base */ +@@ -663,6 +668,7 @@ struct sdhci_ops { + void (*request_done)(struct sdhci_host *host, + struct mmc_request *mrq); + void (*dump_vendor_regs)(struct sdhci_host *host); ++ int (*init_sd_express)(struct sdhci_host *host, struct mmc_ios *ios); + }; + + #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS diff --git a/target/linux/bcm27xx/patches-6.1/950-0861-Add-new-pispbe-driver-though-not-yet-the-Makesfiles-.patch b/target/linux/bcm27xx/patches-6.1/950-0861-Add-new-pispbe-driver-though-not-yet-the-Makesfiles-.patch new file mode 100644 index 0000000000..2ac7b7830c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0861-Add-new-pispbe-driver-though-not-yet-the-Makesfiles-.patch @@ -0,0 +1,3788 @@ +From ce14be51d71bf39893786d380cbb82e81d2a10d5 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Wed, 14 Jul 2021 09:32:49 +0100 +Subject: [PATCH] Add new "pispbe" driver (though not yet the Makesfiles or DT + required to use it) + +media: bcm2712: Initial commit of the PiSP BE driver + +Signed-off-by: Naushir Patuck + +media: bcm2712_pisp_be: PiSP driver updates. + +- Start registering video nodes from /dev/video20 +- Formatting fixes +- Define MODULE_DEVICE_TABLE() to probe correctly + +Signed-off-by: Naushir Patuck + +media: pisp_be: Improve image format support + +Add a new format table that lists the V4L2 format enums and their properties. +Keep the exising 'RPBP' format to support the userland verification tools. +This format requires userland to fill all plane properties. Standard V4L2 +formats will derive these properties from the format table. + +Signed-off-by: Naushir Patuck + +media: pisp_be: Advertise the meta output format explictily. + +Signed-off-by: Naushir Patuck + +drivers: pisp_be: Various updates and cleanups + +- Switch to a single node group for now. +- Add a node description table to simplify node handling. +- Switch HoG output to V4L2_CAP_META_CAPTURE type. +- Use string descriptions for node names in logging messages. + +Signed-off-by: Naushir Patuck + +pisp_be: Updates for libcamera usage: + +- Remove indexes from device entity names +- Add enumframesize and enumfmts ioctls +- Add default format to all nodes. + +Signed-off-by: Naushir Patuck + +v4l2: pisp_be: Move format definitions into v4l2 core + +Signed-off-by: Naushir Patuck + +media: raspberrypi: Move PiSP common headers to a single location + +Signed-off-by: Naushir Patuck + +media: raspberrypi: Remove old pispbe driver. + +This is now supersede by the driver in drivers/media/platform/raspberrypi/ + +Signed-off-by: Naushir Patuck + +PISP-BE Driver: Automate buffer-cycling for TDN and Stitch state. +Remove "tdn-input" and "stitch-input" nodes altogether (the output +nodes must still be opened and REQBUFS called with 1 or 2 buffers). +Also, a bit of tidying of buffer address handling and locking. + +PISP-BE driver: Turn debug level right down to reduce overly-chatty messages + +media: bcm2712: Depend on CONFIG_PM + +Depend on CONFIG_PM as the driver uses the runtime_pm infrastructure. + +Signed-off-by: Jacopo Mondi + +drivers: media: pisp_be: Move BE driver to a raspberrypi directory + +Move the pisp_be driver from drivers/media/platform/raspberrypi/ to +drivers/media/platform/raspberrypi/pisp_be/. This seems the accepted +convention in the drivers/media/platform/ directory structure. + +Also rename the driver module from bcm2712_pisp_be to pisp_be. + +Signed-off-by: Naushir Patuck + +pisp_be: Updates for libcamera streaming: + +- Add some required v4l2 formats +- Add buf_prepare ioctl +- Set plane offsets correctly before reprogramming + +pisp_be: Reduce logging verbosity + +Signed-off-by: Naushir Patuck + +pisp_be: Add buffer timestamps + +While at it, remove duplicate code when checking if the HW has completed +multiple jobs. + +Signed-off-by: Naushir Patuck + +pisp_be: Remove queue size allocation constraint + +PISP-BE driver: Fix ISR to handle multiple done/start events. + +PISP-BE: Fix variable-name shadowing bugette + +PISP-BE: Support for two node groups. Reorganize the driver. + +To support 2 concurrent libcamera applications, we need 2 node groups, +need to allow multiple opens of each node (because libcamera does this) +and create a separate media device per group (to support file-locking). + +This triggered significant rearrangement of the driver. Some calls +that we formerly intercepted have been delegated back to v4l2/vb2. +Logging changes arising from multiple v4l2_dev. Refactored probe() +and initialization. Avoid dynamically-allocated entity name strings. + +drivers: media: pisp_be: Add vidioc_enum_fmt_meta_out + +This was missing in the struct v4l2_ioctl_ops definition. + +Signed-off-by: Naushir Patuck + +drivers: media: pispe_be: Add Bayer compressed formats + +Add PiSP Bayer compressed formats to the list of supported pixel formats +for the PiSP backend driver. + +Signed-off-by: Naushir Patuck + +drivers: meida: pisp_be: Fix overflow in plane size calculations + +The calculations for buffer plane sizes can overflow because of the +plane factor shift. Fix this by using u64 integers for the calculations. + +Signed-off-by: Naushir Patuck + +drivers: media: pisp_be: Use 0P3 for plane factors + +Use less precision for the plane factors to avoid any nasty overflows. + +Signed-off-by: Naushir Patuck + +media: pisp: Checkpatch and coding style fixups + +Signed-off-by: Dave Stevenson + +media: pisp_be: More coding style fixups + +media: platform: bcm2712: pisp_be: Fix crash when buffer format not set + +Signed-off-by: Nick Hollinghurst + +media: platform: bcm2712: pisp_be: Allow non-SRGB colour spaces on RGB outputs + +Allow colour spaces other than SRGB when the output format in question +is an RGB output. This commit merely ports over existing changes from +the vc4 ISP driver. + +Signed-off-by: David Plowman + +media: platform: bcm2712: Tweak list of BE supported image formats + +Remove RGB565 and 10- and 12-bit packed raw formats, which ISP-BE +can't support for input or output. Add NV12M and NV21M which it can. +(I didn't bother adding YUV422P, which apparently is not widely used.) + +Signed-off-by: Nick Hollinghurst + +pisp_be: Fill the hardware revision in the media entity struct + +This can be used by userland to determine the hardware capabilities. + +Signed-off-by: Naushir Patuck + +bcm2712: Use BIT() macro + +Use the BIT() macro instead of plain bit shifting. + +Signed-off-by: Jacopo Mondi + +bcm2712: Invert condition in pispbe_schedule_internal() + +Return earlier and save one indentation level + +Signed-off-by: Jacopo Mondi + +bcm2712: Invert condition in for loop + +Save one indentation level by continuing if the node is not streaming. + +Signed-off-by: Jacopo Mondi + +bcm2712: Do not declare a local variable + +There already is a truct pispbe_node *node in the function scope. + +Signed-off-by: Jacopo Mondi + +bcm21712: Siplify pispbe_schedule_one() + +A little more verbose but easier to follow ? + +Signed-off-by: Jacopo Mondi + +bcm2712: Rename pispbe_schedule_all() to pispbe_schedule_any() + +The pispbe_schedule_all() function name is misleading, as the function +schedule a single job from any of the node groups. Rename it. + +Signed-off-by: Jacopo Mondi + +media: platform: bcm2712: Remove buffer auto-cycling from ISP-BE + +Previously, the ISP-BE driver tried to automate "ping pong" buffers +for TDN and HDR state, but did not fully conceal them from users. + +The automation has been removed: there are now separate output and +capture queues for each of TDN and Stitch, which must be managed by +user code (DMABUFs may be used to circulate buffers between queues). + +Signed-off-by: Nick Hollinghurst + +drivers: media: pisp_be: Cache BE config buffer vaddr + +When programming a new job, we access at the config buffer, possibly +from ISR context. So fetch and the virtual address when queuing the +buffer. + +Signed-off-by: Naushir Patuck + +drivers: media: pisp_be: Remove all traces of ctrls and request API + +These APIs are not (and will not) be used by the driver, so remove them. + +Signed-off-by: Naushir Patuck + +media: bcm2712: Replace v4l2_dbg with dev_dbg + +Replace the v4l2 debug helpers with the device debug once, which are +preferred. + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Remove of_match_ptr() + +The of_match_ptr() usage could cause a compiler warning if +CONFIG_OF is not enabled, as the pispbe_of_match variable would +result unused. + +As the of_match_table field of struct platform_driver exists +unconditionally, drop of_match_ptr() to avoid a warning. + +Signed-off-by: Jacopo Mondi + +drivers: media: pispbe: Add local config buffer DMA allocation + +When initialiasing the driver, allocate a number of tiles + config +structures used for storing hardware config internally in the driver. + +Signed-off-by: Naushir Patuck + +drivers: media: pispbe: Use local config buffers + +Store a copy of the config + tiles buffer locally when the buffer gets +queued. This resolves the security issue where a userland process may +modify the config buffer after it has been queued. + +Signed-off-by: Naushir Patuck + +drivers: media: pispbe: Validate config buffers + +Perform a basic config validation on the device output nodes to ensure +the buffer size and stride values do not result in a buffer overrun. + +Signed-off-by: Naushir Patuck + +media: bcm2712: Rework probe sequence order + +Rework the probe sequence to: +1) Use dev_err_probe() when failing to get clocks +2) Disable clock on error path +3) Disable the node groups if they have been enabled and + propagate the error up + +Also disable clocks in the remove() function. + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Use pm_runtime_ops + +Introduce usage of runtime resume and suspend operations. + +The diver only uses a single clock source which is enable/disabled +at resume and suspend time. + +Implement file open and release operations to control enablement of +the clock provider. + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Demote info message + +Demote info message about clock enablement to dev_dbg() + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Move pm_runtime calls to streamon/streamoff + +Move the calls to pm_runtime_resume_and_get() and pm_runtime_put() +to the streamon and streamoff ioctl handlers. + +Remove custom handlers for the open and close file operations and use +the framework provided helpers. + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Use pm_runtime_autosuspend() + +Use the _autosuspend() version of runtime_pm_put() in order to avoid +resuming and suspending the peripheral in between streaming sessions +closely apart one from the other. + +Signed-off-by: Jacopo Mondi + +drivers: media: pisp_be: Conditionally check buffers when preparing jobs + +When preparing a job, check the global enables in the config structure +to see if the Output0/1, Tdn and Stitch blocks are enabled, and only +test for a buffer queued if they are. + +This will allow userland to control the outputs selectively without +disabling/re-enabling the respective device nodes. + +Signed-off-by: Naushir Patuck + +media: bcm2712: Rework media controller registration + +The current implementation register the v4l2_device and the video +devices first, then creates the media controller and manually registers +entities there. + +Rework the registration procedure to first create the v4l2_device and +register the media_device with it. Then create the video nodes which +gets automatically registered in the media graph by the core. + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Create v4l2_subdev for ISP entity + +Create a v4l2 subdevice to represent the PISPBE ISP entity. + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Fix v4l2-compliance warn on QUERYCAP + +Fix: + +warn: v4l2-compliance.cpp(669): media bus_info +'platform:1000880000.pisp_be' differs from V4L2 bus_info +'platform:pispbe' + +by populating the driver caps bus_info by using dev_name(). + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Fix v4l2-compliance warn on invalid pixfmt + +The V4L2 API for the TRY_FMT/S_FMT ioctl allows the ioctl handler to +return an error code only in specific conditions. If an invalid pixel +format is supplied it should be adjusted instead of an error being +returned. + +Albeit, v4l2-compliance treats this situation as a warning and not as +an error because the behaviour has been discussed in length in the past. + +warn: v4l2-test-formats.cpp(794): TRY_FMT cannot handle an invalid pixelformat. +warn: v4l2-test-formats.cpp(795): This may or may not be a problem. For more information see: +warn: v4l2-test-formats.cpp(796): http://www.mail-archive.com/linux-media@vger.kernel.org/msg56550.html +VIDIOC_TRY_FMT returned -1 (Invalid argument) + +Regardless of the warning vs failure decision, adjust the try_format() +function implementation to use V4L2_PIX_FMT_YUV420M as default pixel +format if the supplied one is invalid. + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Fix v4l2-compliance warn on HOG pix format + +The try_format() implementation for the HOG video device node returns +an error if the supplied pixel format is not correct. + +As per the video device output and capture video nodes, this contradicts +the V4L2 specification even if it is treated as a warning by +v4l2-compliance. + +Fix this by forcing the buffer pixel format and size to the default +supported one. While at here, use the BIT() macro in the format +initialization function. + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Fix formats enumeration + +Right now a single implementation of enum_fmt() is used for all nodes +in a group. This means that all the BE supported formats are listed for +all the nodes. This is incorrect as the meta capture and output node +formats should be restricted, and the meta formats should not be +enumerated for video output and capture devices. + +Fix this by restricting the enumeration of META formats to the config +and hog nodes. Split out from the list of supported_formats the +V4L2_META_FMT_RPI_BE_CFG which is only used for the meta_out node, while +V4L2_PIX_FMT_RPI_BE is kept in the list of supported_formats as it can +be used as an opaque format for both meta_cap, video_cap and video_out +nodes. + +Signed-off-by: Jacopo Mondi + +media: bcm2712: Minor fixes to support PiSP regression tests + +Allow RGB input, not just Bayer (but only of those at once); +Allow Wallpaper image formats. XXX They are not yet size-checked; +Set "chicken bits" to test BURST_TRIM and AXI AWID/BID variation. +Convert some v4l2_err() to dev_err() + +Signed-off-by: Nick Hollinghurst + +drivers: media: pisp_be: Use the maximum number of config buffers + +Set PISP_BE_NUM_CONFIG_BUFFERS the the maximum number of possible +buffers. In the worst case, this overallocates config buffers, but +given their size, it's not too much of a problem. + +Signed-off-by: Naushir Patuck + +media: pisp_be: Fix extra PM runtime put + +vidioc_streamoff callback can be called even if vidioc_streamon was +never called. The driver currently does PM runtime get/put in these +callbacks, which may lead to a put without a matching get. + +Fix this by moving the PM runtime get/put to vb2_ops's start_streaming & +stop_streaming, which the framework makes sure won't get extra calls. + +Signed-off-by: Tomi Valkeinen + +drivers: media: pisp_be: Don't report V4L2_PIX_FMT_RPI_BE format + +This is an internal opaque format, not to be reported in enum_fmt. + +Signed-off-by: Naushir Patuck +--- + drivers/media/platform/Kconfig | 1 + + drivers/media/platform/Makefile | 1 + + drivers/media/platform/raspberrypi/Kconfig | 5 + + drivers/media/platform/raspberrypi/Makefile | 3 + + .../platform/raspberrypi/pisp_be/Kconfig | 12 + + .../platform/raspberrypi/pisp_be/Makefile | 6 + + .../platform/raspberrypi/pisp_be/pisp_be.c | 1985 +++++++++++++++++ + .../raspberrypi/pisp_be/pisp_be_config.h | 533 +++++ + .../raspberrypi/pisp_be/pisp_be_formats.h | 469 ++++ + drivers/media/v4l2-core/v4l2-ioctl.c | 2 + + include/media/raspberrypi/pisp_common.h | 65 + + include/media/raspberrypi/pisp_types.h | 144 ++ + include/uapi/linux/videodev2.h | 6 + + 13 files changed, 3232 insertions(+) + create mode 100644 drivers/media/platform/raspberrypi/Kconfig + create mode 100644 drivers/media/platform/raspberrypi/Makefile + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/Kconfig + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/Makefile + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be.c + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h + create mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h + create mode 100644 include/media/raspberrypi/pisp_common.h + create mode 100644 include/media/raspberrypi/pisp_types.h + +--- a/drivers/media/platform/Kconfig ++++ b/drivers/media/platform/Kconfig +@@ -76,6 +76,7 @@ source "drivers/media/platform/mediatek/ + source "drivers/media/platform/nvidia/Kconfig" + source "drivers/media/platform/nxp/Kconfig" + source "drivers/media/platform/qcom/Kconfig" ++source "drivers/media/platform/raspberrypi/Kconfig" + source "drivers/media/platform/renesas/Kconfig" + source "drivers/media/platform/rockchip/Kconfig" + source "drivers/media/platform/samsung/Kconfig" +--- a/drivers/media/platform/Makefile ++++ b/drivers/media/platform/Makefile +@@ -19,6 +19,7 @@ obj-y += mediatek/ + obj-y += nvidia/ + obj-y += nxp/ + obj-y += qcom/ ++obj-y += raspberrypi/ + obj-y += renesas/ + obj-y += rockchip/ + obj-y += samsung/ +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/Kconfig +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++comment "Raspberry Pi media platform drivers" ++ ++source "drivers/media/platform/raspberrypi/pisp_be/Kconfig" +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++obj-y += pisp_be/ +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/Kconfig +@@ -0,0 +1,12 @@ ++config VIDEO_RASPBERRYPI_PISP_BE ++ tristate "Raspberry Pi PiSP Backend (BE) ISP driver" ++ depends on VIDEO_DEV && PM ++ select VIDEO_V4L2_SUBDEV_API ++ select MEDIA_CONTROLLER ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_FWNODE ++ help ++ Say Y here to enable support for the PiSP Backend (BE) ISP driver. ++ ++ To compile this driver as a module, choose M here. The module will be ++ called pisp-be. +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for Raspberry Pi PiSP Backend driver ++# ++pisp-be-objs := pisp_be.o ++obj-$(CONFIG_VIDEO_RASPBERRYPI_PISP_BE) += pisp-be.o +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c +@@ -0,0 +1,1985 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * PiSP Back End driver. ++ * Copyright (c) 2021-2022 Raspberry Pi Limited. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pisp_be_config.h" ++#include "pisp_be_formats.h" ++ ++MODULE_DESCRIPTION("PiSP Back End driver"); ++MODULE_AUTHOR("David Plowman "); ++MODULE_AUTHOR("Nick Hollinghurst "); ++MODULE_LICENSE("GPL v2"); ++ ++/* Offset to use when registering the /dev/videoX node */ ++#define PISPBE_VIDEO_NODE_OFFSET 20 ++ ++/* Maximum number of config buffers possible */ ++#define PISP_BE_NUM_CONFIG_BUFFERS VB2_MAX_FRAME ++ ++/* ++ * We want to support 2 independent instances allowing 2 simultaneous users ++ * of the ISP-BE (of course they share hardware, platform resources and mutex). ++ * Each such instance comprises a group of device nodes representing input ++ * and output queues, and a media controller device node to describe them. ++ */ ++#define PISPBE_NUM_NODE_GROUPS 2 ++ ++#define PISPBE_NAME "pispbe" ++ ++/* Some ISP-BE registers */ ++#define PISP_BE_VERSION_OFFSET (0x0) ++#define PISP_BE_CONTROL_OFFSET (0x4) ++#define PISP_BE_TILE_ADDR_LO_OFFSET (0x8) ++#define PISP_BE_TILE_ADDR_HI_OFFSET (0xc) ++#define PISP_BE_STATUS_OFFSET (0x10) ++#define PISP_BE_BATCH_STATUS_OFFSET (0x14) ++#define PISP_BE_INTERRUPT_EN_OFFSET (0x18) ++#define PISP_BE_INTERRUPT_STATUS_OFFSET (0x1c) ++#define PISP_BE_AXI_OFFSET (0x20) ++#define PISP_BE_CONFIG_BASE_OFFSET (0x40) ++#define PISP_BE_IO_INPUT_ADDR0_LO_OFFSET (PISP_BE_CONFIG_BASE_OFFSET) ++#define PISP_BE_GLOBAL_BAYER_ENABLE_OFFSET (PISP_BE_CONFIG_BASE_OFFSET + 0x70) ++#define PISP_BE_GLOBAL_RGB_ENABLE_OFFSET (PISP_BE_CONFIG_BASE_OFFSET + 0x74) ++#define N_HW_ADDRESSES 14 ++#define N_HW_ENABLES 2 ++ ++#define PISP_BE_VERSION_2712C1 0x02252700 ++#define PISP_BE_VERSION_MINOR_BITS 0xF ++ ++/* ++ * This maps our nodes onto the inputs/outputs of the actual PiSP Back End. ++ * Be wary of the word "OUTPUT" which is used ambiguously here. In a V4L2 ++ * context it means an input to the hardware (source image or metadata). ++ * Elsewhere it means an output from the hardware. ++ */ ++enum node_ids { ++ MAIN_INPUT_NODE, ++ TDN_INPUT_NODE, ++ STITCH_INPUT_NODE, ++ HOG_OUTPUT_NODE, ++ OUTPUT0_NODE, ++ OUTPUT1_NODE, ++ TDN_OUTPUT_NODE, ++ STITCH_OUTPUT_NODE, ++ CONFIG_NODE, ++ PISPBE_NUM_NODES ++}; ++ ++struct node_description { ++ const char *ent_name; ++ enum v4l2_buf_type buf_type; ++ unsigned int caps; ++}; ++ ++static const struct node_description node_desc[PISPBE_NUM_NODES] = { ++ /* MAIN_INPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-input", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ++ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE, ++ }, ++ /* TDN_INPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-tdn_input", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ++ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE, ++ }, ++ /* STITCH_INPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-stitch_input", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ++ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE, ++ }, ++ /* HOG_OUTPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-hog_output", ++ .buf_type = V4L2_BUF_TYPE_META_CAPTURE, ++ .caps = V4L2_CAP_META_CAPTURE, ++ }, ++ /* OUTPUT0_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-output0", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE, ++ }, ++ /* OUTPUT1_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-output1", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE, ++ }, ++ /* TDN_OUTPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-tdn_output", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE, ++ }, ++ /* STITCH_OUTPUT_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-stitch_output", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE, ++ }, ++ /* CONFIG_NODE */ ++ { ++ .ent_name = PISPBE_NAME "-config", ++ .buf_type = V4L2_BUF_TYPE_META_OUTPUT, ++ .caps = V4L2_CAP_META_OUTPUT, ++ } ++}; ++ ++#define NODE_DESC_IS_OUTPUT(desc) ( \ ++ ((desc)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \ ++ ((desc)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) || \ ++ ((desc)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) ++ ++#define NODE_IS_META(node) ( \ ++ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_META_CAPTURE)) ++#define NODE_IS_OUTPUT(node) ( \ ++ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) ++#define NODE_IS_CAPTURE(node) ( \ ++ ((node)->buf_type == V4L2_BUF_TYPE_META_CAPTURE) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) ++#define NODE_IS_MPLANE(node) ( \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) || \ ++ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) ++ ++/* ++ * Structure to describe a single node /dev/video which represents a single ++ * input or output queue to the PiSP Back End device. ++ */ ++struct pispbe_node { ++ unsigned int id; ++ int vfl_dir; ++ enum v4l2_buf_type buf_type; ++ struct video_device vfd; ++ struct media_pad pad; ++ struct media_intf_devnode *intf_devnode; ++ struct media_link *intf_link; ++ struct pispbe_node_group *node_group; ++ struct mutex node_lock; ++ struct mutex queue_lock; ++ spinlock_t ready_lock; ++ struct list_head ready_queue; ++ struct vb2_queue queue; ++ struct v4l2_format format; ++ const struct pisp_be_format *pisp_format; ++}; ++ ++/* For logging only, use the entity name with "pispbe" and separator removed */ ++#define NODE_NAME(node) \ ++ (node_desc[(node)->id].ent_name + sizeof(PISPBE_NAME)) ++#define NODE_GET_V4L2(node) ((node)->node_group->v4l2_dev) ++ ++/* ++ * Node group structure, which comprises all the input and output nodes that a ++ * single PiSP client will need, along with its own v4l2 and media devices. ++ */ ++struct pispbe_node_group { ++ unsigned int id; ++ struct v4l2_device v4l2_dev; ++ struct v4l2_subdev sd; ++ struct pispbe_dev *pispbe; ++ struct media_device mdev; ++ struct pispbe_node node[PISPBE_NUM_NODES]; ++ u32 streaming_map; /* bitmap of which nodes are streaming */ ++ struct media_pad pad[PISPBE_NUM_NODES]; /* output pads first */ ++ struct pisp_be_tiles_config *config; ++ dma_addr_t config_dma_addr; ++}; ++ ++/* Records details of the jobs currently running or queued on the h/w. */ ++struct pispbe_job { ++ struct pispbe_node_group *node_group; ++ /* ++ * An array of buffer pointers - remember it's source buffers first, ++ * then captures, then metadata last. ++ */ ++ struct pispbe_buffer *buf[PISPBE_NUM_NODES]; ++}; ++ ++/* ++ * Structure representing the entire PiSP Back End device, comprising several ++ * node groups which share platform resources and a mutex for the actual HW. ++ */ ++struct pispbe_dev { ++ struct device *dev; ++ struct pispbe_node_group node_group[PISPBE_NUM_NODE_GROUPS]; ++ int hw_busy; /* non-zero if a job is queued or is being started */ ++ struct pispbe_job queued_job, running_job; ++ void __iomem *be_reg_base; ++ struct clk *clk; ++ int irq; ++ u32 hw_version; ++ u8 done, started; ++ spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */ ++}; ++ ++static inline u32 read_reg(struct pispbe_dev *pispbe, unsigned int offset) ++{ ++ return readl(pispbe->be_reg_base + offset); ++} ++ ++static inline void write_reg(struct pispbe_dev *pispbe, unsigned int offset, ++ u32 val) ++{ ++ writel(val, pispbe->be_reg_base + offset); ++} ++ ++/* Check and initialize hardware. */ ++static int hw_init(struct pispbe_dev *pispbe) ++{ ++ u32 u; ++ ++ /* Check the HW is present and has a known version */ ++ u = read_reg(pispbe, PISP_BE_VERSION_OFFSET); ++ dev_info(pispbe->dev, "pispbe_probe: HW version: 0x%08x", u); ++ pispbe->hw_version = u; ++ if ((u & ~PISP_BE_VERSION_MINOR_BITS) != PISP_BE_VERSION_2712C1) ++ return -ENODEV; ++ ++ /* Clear leftover interrupts */ ++ write_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET, 0xFFFFFFFFu); ++ u = read_reg(pispbe, PISP_BE_BATCH_STATUS_OFFSET); ++ dev_info(pispbe->dev, "pispbe_probe: BatchStatus: 0x%08x", u); ++ pispbe->done = (uint8_t)u; ++ pispbe->started = (uint8_t)(u >> 8); ++ u = read_reg(pispbe, PISP_BE_STATUS_OFFSET); ++ dev_info(pispbe->dev, "pispbe_probe: Status: 0x%08x", u); ++ if (u != 0 || pispbe->done != pispbe->started) { ++ dev_err(pispbe->dev, "pispbe_probe: HW is stuck or busy\n"); ++ return -EBUSY; ++ } ++ /* ++ * AXI QOS=0, CACHE=4'b0010, PROT=3'b011 ++ * Also set "chicken bits" 22:20 which enable sub-64-byte bursts ++ * and AXI AWID/BID variability (on versions which support this). ++ */ ++ write_reg(pispbe, PISP_BE_AXI_OFFSET, 0x32703200u); ++ ++ /* Enable both interrupt flags */ ++ write_reg(pispbe, PISP_BE_INTERRUPT_EN_OFFSET, 0x00000003u); ++ return 0; ++} ++ ++/* ++ * Queue a job to the h/w. If the h/w is idle it will begin immediately. ++ * Caller must ensure it is "safe to queue", i.e. we don't already have a ++ * queued, unstarted job. ++ */ ++static void hw_queue_job(struct pispbe_dev *pispbe, ++ dma_addr_t hw_dma_addrs[N_HW_ADDRESSES], ++ u32 hw_enables[N_HW_ENABLES], ++ struct pisp_be_config *config, dma_addr_t tiles, ++ unsigned int num_tiles) ++{ ++ unsigned int begin, end; ++ unsigned int u; ++ ++ if (read_reg(pispbe, PISP_BE_STATUS_OFFSET) & 1) ++ dev_err(pispbe->dev, "ERROR: not safe to queue new job!\n"); ++ ++ /* ++ * Write configuration to hardware. DMA addresses and enable flags ++ * are passed separately, because the driver needs to sanitize them, ++ * and we don't want to modify (or be vulnerable to modifications of) ++ * the mmap'd buffer. ++ */ ++ for (u = 0; u < N_HW_ADDRESSES; ++u) { ++ write_reg(pispbe, PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u, ++ (u32)(hw_dma_addrs[u])); ++ write_reg(pispbe, PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u + 4, ++ (u32)(hw_dma_addrs[u] >> 32)); ++ } ++ write_reg(pispbe, PISP_BE_GLOBAL_BAYER_ENABLE_OFFSET, hw_enables[0]); ++ write_reg(pispbe, PISP_BE_GLOBAL_RGB_ENABLE_OFFSET, hw_enables[1]); ++ ++ /* ++ * Everything else is as supplied by the user. XXX Buffer sizes not ++ * checked! ++ */ ++ begin = offsetof(struct pisp_be_config, global.bayer_order) / ++ sizeof(u32); ++ end = offsetof(struct pisp_be_config, axi) / sizeof(u32); ++ for (u = begin; u < end; u++) { ++ unsigned int val = ((u32 *)config)[u]; ++ ++ write_reg(pispbe, PISP_BE_CONFIG_BASE_OFFSET + 4 * u, val); ++ } ++ ++ /* Read back the addresses -- an error here could be fatal */ ++ for (u = 0; u < N_HW_ADDRESSES; ++u) { ++ unsigned int offset = PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u; ++ u64 along = read_reg(pispbe, offset); ++ ++ along += ((u64)read_reg(pispbe, offset + 4)) << 32; ++ if (along != (u64)(hw_dma_addrs[u])) { ++ dev_err(pispbe->dev, ++ "ISP BE config error: check if ISP RAMs enabled?\n"); ++ return; ++ } ++ } ++ ++ /* ++ * Write tile pointer to hardware. XXX Tile offsets and sizes not ++ * checked (and even if checked, the user could subsequently modify ++ * them)! ++ */ ++ write_reg(pispbe, PISP_BE_TILE_ADDR_LO_OFFSET, (u32)tiles); ++ write_reg(pispbe, PISP_BE_TILE_ADDR_HI_OFFSET, (u32)(tiles >> 32)); ++ ++ /* Enqueue the job */ ++ write_reg(pispbe, PISP_BE_CONTROL_OFFSET, 3 + 65536 * num_tiles); ++} ++ ++struct pispbe_buffer { ++ struct vb2_v4l2_buffer vb; ++ struct list_head ready_list; ++ unsigned int config_index; ++}; ++ ++static int get_addr_3(dma_addr_t addr[3], struct pispbe_buffer *buf, ++ struct pispbe_node *node) ++{ ++ unsigned int num_planes = node->format.fmt.pix_mp.num_planes; ++ unsigned int plane_factor = 0; ++ unsigned int size; ++ unsigned int p; ++ ++ if (!buf || !node->pisp_format) ++ return 0; ++ ++ WARN_ON(!NODE_IS_MPLANE(node)); ++ ++ /* ++ * Determine the base plane size. This will not be the same ++ * as node->format.fmt.pix_mp.plane_fmt[0].sizeimage for a single ++ * plane buffer in an mplane format. ++ */ ++ size = node->format.fmt.pix_mp.plane_fmt[0].bytesperline * ++ node->format.fmt.pix_mp.height; ++ ++ for (p = 0; p < num_planes && p < 3; p++) { ++ addr[p] = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, p); ++ plane_factor += node->pisp_format->plane_factor[p]; ++ } ++ ++ for (; p < MAX_PLANES && node->pisp_format->plane_factor[p]; p++) { ++ /* ++ * Calculate the address offset of this plane as needed ++ * by the hardware. This is specifically for non-mplane ++ * buffer formats, where there are 3 image planes, e.g. ++ * for the V4L2_PIX_FMT_YUV420 format. ++ */ ++ addr[p] = addr[0] + ((size * plane_factor) >> 3); ++ plane_factor += node->pisp_format->plane_factor[p]; ++ } ++ ++ return num_planes; ++} ++ ++static dma_addr_t get_addr(struct pispbe_buffer *buf) ++{ ++ if (buf) ++ return vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ return 0; ++} ++ ++static void ++fixup_addrs_enables(dma_addr_t addrs[N_HW_ADDRESSES], ++ u32 hw_enables[N_HW_ENABLES], ++ struct pisp_be_tiles_config *config, ++ struct pispbe_buffer *buf[PISPBE_NUM_NODES], ++ struct pispbe_node_group *node_group) ++{ ++ int ret, i; ++ ++ /* Take a copy of the "enable" bitmaps so we can modify them. */ ++ hw_enables[0] = config->config.global.bayer_enables; ++ hw_enables[1] = config->config.global.rgb_enables; ++ ++ /* ++ * Main input first. There are 3 address pointers, corresponding to up ++ * to 3 planes. ++ */ ++ ret = get_addr_3(addrs, buf[MAIN_INPUT_NODE], ++ &node_group->node[MAIN_INPUT_NODE]); ++ if (ret <= 0) { ++ /* ++ * This shouldn't happen; pispbe_schedule_internal should insist ++ * on an input. ++ */ ++ dev_warn(node_group->pispbe->dev, ++ "ISP-BE missing input\n"); ++ hw_enables[0] = 0; ++ hw_enables[1] = 0; ++ return; ++ } ++ ++ /* ++ * Now TDN/Stitch inputs and outputs. These are single-plane and only ++ * used with Bayer input. Input enables must match the requirements ++ * of the processing stages, otherwise the hardware can lock up! ++ */ ++ if (hw_enables[0] & PISP_BE_BAYER_ENABLE_INPUT) { ++ addrs[3] = get_addr(buf[TDN_INPUT_NODE]); ++ if (addrs[3] == 0 || ++ !(hw_enables[0] & PISP_BE_BAYER_ENABLE_TDN_INPUT) || ++ !(hw_enables[0] & PISP_BE_BAYER_ENABLE_TDN) || ++ (config->config.tdn.reset & 1)) { ++ hw_enables[0] &= ~(PISP_BE_BAYER_ENABLE_TDN_INPUT | ++ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS); ++ if (!(config->config.tdn.reset & 1)) ++ hw_enables[0] &= ~PISP_BE_BAYER_ENABLE_TDN; ++ } ++ ++ addrs[4] = get_addr(buf[STITCH_INPUT_NODE]); ++ if (addrs[4] == 0 || ++ !(hw_enables[0] & PISP_BE_BAYER_ENABLE_STITCH_INPUT) || ++ !(hw_enables[0] & PISP_BE_BAYER_ENABLE_STITCH)) { ++ hw_enables[0] &= ++ ~(PISP_BE_BAYER_ENABLE_STITCH_INPUT | ++ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS | ++ PISP_BE_BAYER_ENABLE_STITCH); ++ } ++ ++ addrs[5] = get_addr(buf[TDN_OUTPUT_NODE]); ++ if (addrs[5] == 0) ++ hw_enables[0] &= ~(PISP_BE_BAYER_ENABLE_TDN_COMPRESS | ++ PISP_BE_BAYER_ENABLE_TDN_OUTPUT); ++ ++ addrs[6] = get_addr(buf[STITCH_OUTPUT_NODE]); ++ if (addrs[6] == 0) ++ hw_enables[0] &= ++ ~(PISP_BE_BAYER_ENABLE_STITCH_COMPRESS | ++ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT); ++ } else { ++ /* No Bayer input? Disable entire Bayer pipe (else lockup) */ ++ hw_enables[0] = 0; ++ } ++ ++ /* Main image output channels. */ ++ for (i = 0; i < PISP_BACK_END_NUM_OUTPUTS; i++) { ++ ret = get_addr_3(addrs + 7 + 3 * i, buf[OUTPUT0_NODE + i], ++ &node_group->node[OUTPUT0_NODE + i]); ++ if (ret <= 0) ++ hw_enables[1] &= ~(PISP_BE_RGB_ENABLE_OUTPUT0 << i); ++ } ++ ++ /* HoG output (always single plane). */ ++ addrs[13] = get_addr(buf[HOG_OUTPUT_NODE]); ++ if (addrs[13] == 0) ++ hw_enables[1] &= ~PISP_BE_RGB_ENABLE_HOG; ++} ++ ++/* ++ * Internal function. Called from pispbe_schedule_one/all. Returns non-zero if ++ * we started a job. ++ * ++ * Warning: needs to be called with hw_lock taken, and releases it if it ++ * schedules a job. ++ */ ++static int pispbe_schedule_internal(struct pispbe_node_group *node_group, ++ unsigned long flags) ++{ ++ struct pisp_be_tiles_config *config_tiles_buffer; ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ struct pispbe_buffer *buf[PISPBE_NUM_NODES]; ++ dma_addr_t hw_dma_addrs[N_HW_ADDRESSES]; ++ dma_addr_t tiles; ++ u32 hw_enables[N_HW_ENABLES]; ++ struct pispbe_node *node; ++ unsigned long flags1; ++ unsigned int config_index; ++ int i; ++ ++ /* ++ * To schedule a job, we need all streaming nodes (apart from Output0, ++ * Output1, Tdn and Stitch) to have a buffer ready, which must ++ * include at least a config buffer and a main input image. ++ * ++ * For Output0, Output1, Tdn and Stitch, a buffer only needs to be ++ * available if the blocks are enabled in the config. ++ * ++ * (Note that streaming_map is protected by hw_lock, which is held.) ++ */ ++ if (((BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)) & ++ node_group->streaming_map) != ++ (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE))) { ++ dev_dbg(pispbe->dev, "Nothing to do\n"); ++ return 0; ++ } ++ ++ node = &node_group->node[CONFIG_NODE]; ++ spin_lock_irqsave(&node->ready_lock, flags1); ++ buf[CONFIG_NODE] = ++ list_first_entry_or_null(&node->ready_queue, struct pispbe_buffer, ++ ready_list); ++ spin_unlock_irqrestore(&node->ready_lock, flags1); ++ ++ /* Exit early if no config buffer has been queued. */ ++ if (!buf[CONFIG_NODE]) ++ return 0; ++ ++ config_index = buf[CONFIG_NODE]->vb.vb2_buf.index; ++ config_tiles_buffer = &node_group->config[config_index]; ++ tiles = (dma_addr_t)node_group->config_dma_addr + ++ config_index * sizeof(struct pisp_be_tiles_config) + ++ offsetof(struct pisp_be_tiles_config, tiles); ++ ++ /* remember: srcimages, captures then metadata */ ++ for (i = 0; i < PISPBE_NUM_NODES; i++) { ++ unsigned int bayer_en = ++ config_tiles_buffer->config.global.bayer_enables; ++ unsigned int rgb_en = ++ config_tiles_buffer->config.global.rgb_enables; ++ bool ignore_buffers = false; ++ ++ /* Config node is handled outside the loop above. */ ++ if (i == CONFIG_NODE) ++ continue; ++ ++ buf[i] = NULL; ++ if (!(node_group->streaming_map & BIT(i))) ++ continue; ++ ++ if ((!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT0) && ++ i == OUTPUT0_NODE) || ++ (!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT1) && ++ i == OUTPUT1_NODE) || ++ (!(bayer_en & PISP_BE_BAYER_ENABLE_TDN_INPUT) && ++ i == TDN_INPUT_NODE) || ++ (!(bayer_en & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) && ++ i == TDN_OUTPUT_NODE) || ++ (!(bayer_en & PISP_BE_BAYER_ENABLE_STITCH_INPUT) && ++ i == STITCH_INPUT_NODE) || ++ (!(bayer_en & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) && ++ i == STITCH_OUTPUT_NODE)) { ++ /* ++ * Ignore Output0/Output1/Tdn/Stitch buffer check if the ++ * global enables aren't set for these blocks. If a ++ * buffer has been provided, we dequeue it back to the ++ * user with the other in-use buffers. ++ * ++ */ ++ ignore_buffers = true; ++ } ++ ++ node = &node_group->node[i]; ++ ++ spin_lock_irqsave(&node->ready_lock, flags1); ++ buf[i] = list_first_entry_or_null(&node->ready_queue, ++ struct pispbe_buffer, ++ ready_list); ++ spin_unlock_irqrestore(&node->ready_lock, flags1); ++ if (!buf[i] && !ignore_buffers) { ++ dev_dbg(pispbe->dev, "Nothing to do\n"); ++ return 0; ++ } ++ } ++ ++ /* Pull a buffer from each V4L2 queue to form the queued job */ ++ for (i = 0; i < PISPBE_NUM_NODES; i++) { ++ if (buf[i]) { ++ node = &node_group->node[i]; ++ ++ spin_lock_irqsave(&node->ready_lock, flags1); ++ list_del(&buf[i]->ready_list); ++ spin_unlock_irqrestore(&node->ready_lock, ++ flags1); ++ } ++ pispbe->queued_job.buf[i] = buf[i]; ++ } ++ ++ pispbe->queued_job.node_group = node_group; ++ pispbe->hw_busy = 1; ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ /* ++ * We can kick the job off without the hw_lock, as this can ++ * never run again until hw_busy is cleared, which will happen ++ * only when the following job has been queued. ++ */ ++ dev_dbg(pispbe->dev, "Have buffers - starting hardware\n"); ++ ++ /* Convert buffers to DMA addresses for the hardware */ ++ fixup_addrs_enables(hw_dma_addrs, hw_enables, ++ config_tiles_buffer, buf, node_group); ++ /* ++ * This could be a spot to fill in the ++ * buf[i]->vb.vb2_buf.planes[j].bytesused fields? ++ */ ++ i = config_tiles_buffer->num_tiles; ++ if (i <= 0 || i > PISP_BACK_END_NUM_TILES || ++ !((hw_enables[0] | hw_enables[1]) & ++ PISP_BE_BAYER_ENABLE_INPUT)) { ++ /* ++ * Bad job. We can't let it proceed as it could lock up ++ * the hardware, or worse! ++ * ++ * XXX How to deal with this most cleanly? For now, just ++ * force num_tiles to 0, which causes the H/W to do ++ * something bizarre but survivable. It increments ++ * (started,done) counters by more than 1, but we seem ++ * to survive... ++ */ ++ dev_err(pispbe->dev, "PROBLEM: Bad job"); ++ i = 0; ++ } ++ hw_queue_job(pispbe, hw_dma_addrs, hw_enables, ++ &config_tiles_buffer->config, tiles, i); ++ ++ return 1; ++} ++ ++/* Try and schedule a job for just a single node group. */ ++static void pispbe_schedule_one(struct pispbe_node_group *node_group) ++{ ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ if (pispbe->hw_busy) { ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ return; ++ } ++ ++ /* A non-zero return means the lock was released. */ ++ ret = pispbe_schedule_internal(node_group, flags); ++ if (!ret) ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++} ++ ++/* Try and schedule a job for any of the node groups. */ ++static void pispbe_schedule_any(struct pispbe_dev *pispbe, int clear_hw_busy) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ ++ if (clear_hw_busy) ++ pispbe->hw_busy = 0; ++ if (pispbe->hw_busy == 0) { ++ unsigned int i; ++ ++ for (i = 0; i < PISPBE_NUM_NODE_GROUPS; i++) { ++ /* ++ * A non-zero return from pispbe_schedule_internal means ++ * the lock was released. ++ */ ++ if (pispbe_schedule_internal(&pispbe->node_group[i], ++ flags)) ++ return; ++ } ++ } ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++} ++ ++static void pispbe_isr_jobdone(struct pispbe_dev *pispbe, ++ struct pispbe_job *job) ++{ ++ struct pispbe_buffer **buf = job->buf; ++ u64 ts = ktime_get_ns(); ++ int i; ++ ++ for (i = 0; i < PISPBE_NUM_NODES; i++) { ++ if (buf[i]) { ++ buf[i]->vb.vb2_buf.timestamp = ts; ++ vb2_buffer_done(&buf[i]->vb.vb2_buf, ++ VB2_BUF_STATE_DONE); ++ } ++ } ++} ++ ++static irqreturn_t pispbe_isr(int irq, void *dev) ++{ ++ struct pispbe_dev *pispbe = (struct pispbe_dev *)dev; ++ u8 started, done; ++ int can_queue_another = 0; ++ u32 u; ++ ++ u = read_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET); ++ if (u == 0) ++ return IRQ_NONE; ++ ++ write_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET, u); ++ dev_dbg(pispbe->dev, "Hardware interrupt\n"); ++ u = read_reg(pispbe, PISP_BE_BATCH_STATUS_OFFSET); ++ done = (uint8_t)u; ++ started = (uint8_t)(u >> 8); ++ dev_dbg(pispbe->dev, ++ "H/W started %d done %d, previously started %d done %d\n", ++ (int)started, (int)done, (int)pispbe->started, ++ (int)pispbe->done); ++ ++ /* ++ * Be aware that done can go up by 2 and started by 1 when: a job that ++ * we previously saw "start" now finishes, and we then queued a new job ++ * which we see both start and finish "simultaneously". ++ */ ++ if (pispbe->running_job.node_group && pispbe->done != done) { ++ pispbe_isr_jobdone(pispbe, &pispbe->running_job); ++ memset(&pispbe->running_job, 0, sizeof(pispbe->running_job)); ++ pispbe->done++; ++ dev_dbg(pispbe->dev, "Job done (1)\n"); ++ } ++ ++ if (pispbe->started != started) { ++ pispbe->started++; ++ can_queue_another = 1; ++ dev_dbg(pispbe->dev, "Job started\n"); ++ ++ if (pispbe->done != done && pispbe->queued_job.node_group) { ++ pispbe_isr_jobdone(pispbe, &pispbe->queued_job); ++ pispbe->done++; ++ dev_dbg(pispbe->dev, "Job done (2)\n"); ++ } else { ++ pispbe->running_job = pispbe->queued_job; ++ } ++ ++ memset(&pispbe->queued_job, 0, sizeof(pispbe->queued_job)); ++ } ++ ++ if (pispbe->done != done || pispbe->started != started) { ++ dev_err(pispbe->dev, "PROBLEM: counters not matching!\n"); ++ pispbe->started = started; ++ pispbe->done = done; ++ } ++ ++ /* check if there's more to do before going to sleep */ ++ pispbe_schedule_any(pispbe, can_queue_another); ++ ++ return IRQ_HANDLED; ++} ++ ++static int pisp_be_validate_config(struct pispbe_node_group *node_group, ++ struct pisp_be_tiles_config *config) ++{ ++ u32 bayer_enables = config->config.global.bayer_enables; ++ u32 rgb_enables = config->config.global.rgb_enables; ++ struct device *dev = node_group->pispbe->dev; ++ struct v4l2_format *fmt; ++ unsigned int bpl, size, i, j; ++ ++ if (!(bayer_enables & PISP_BE_BAYER_ENABLE_INPUT) == ++ !(rgb_enables & PISP_BE_RGB_ENABLE_INPUT)) { ++ dev_err(dev, "%s: Not one input enabled\n", __func__); ++ return -EIO; ++ } ++ ++ /* Ensure output config strides and buffer sizes match the V4L2 formats. */ ++ fmt = &node_group->node[TDN_OUTPUT_NODE].format; ++ if (bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) { ++ bpl = config->config.tdn_output_format.stride; ++ size = bpl * config->config.tdn_output_format.height; ++ if (fmt->fmt.pix_mp.plane_fmt[0].bytesperline < bpl) { ++ dev_err(dev, "%s: bpl mismatch on tdn_output\n", ++ __func__); ++ return -EINVAL; ++ } ++ if (fmt->fmt.pix_mp.plane_fmt[0].sizeimage < size) { ++ dev_err(dev, "%s: size mismatch on tdn_output\n", ++ __func__); ++ return -EINVAL; ++ } ++ } ++ ++ fmt = &node_group->node[STITCH_OUTPUT_NODE].format; ++ if (bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) { ++ bpl = config->config.stitch_output_format.stride; ++ size = bpl * config->config.stitch_output_format.height; ++ if (fmt->fmt.pix_mp.plane_fmt[0].bytesperline < bpl) { ++ dev_err(dev, "%s: bpl mismatch on stitch_output\n", ++ __func__); ++ return -EINVAL; ++ } ++ if (fmt->fmt.pix_mp.plane_fmt[0].sizeimage < size) { ++ dev_err(dev, "%s: size mismatch on stitch_output\n", ++ __func__); ++ return -EINVAL; ++ } ++ } ++ ++ for (j = 0; j < PISP_BACK_END_NUM_OUTPUTS; j++) { ++ if (!(rgb_enables & PISP_BE_RGB_ENABLE_OUTPUT(j))) ++ continue; ++ if (config->config.output_format[j].image.format & ++ PISP_IMAGE_FORMAT_WALLPAPER_ROLL) ++ continue; /* TODO: Size checks for wallpaper formats */ ++ ++ fmt = &node_group->node[OUTPUT0_NODE + j].format; ++ for (i = 0; i < fmt->fmt.pix_mp.num_planes; i++) { ++ bpl = !i ? config->config.output_format[j].image.stride ++ : config->config.output_format[j].image.stride2; ++ size = bpl * config->config.output_format[j].image.height; ++ ++ if (config->config.output_format[j].image.format & ++ PISP_IMAGE_FORMAT_SAMPLING_420) ++ size >>= 1; ++ if (fmt->fmt.pix_mp.plane_fmt[i].bytesperline < bpl) { ++ dev_err(dev, "%s: bpl mismatch on output %d\n", ++ __func__, j); ++ return -EINVAL; ++ } ++ if (fmt->fmt.pix_mp.plane_fmt[i].sizeimage < size) { ++ dev_err(dev, "%s: size mismatch on output\n", ++ __func__); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int pispbe_node_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, ++ unsigned int *nplanes, unsigned int sizes[], ++ struct device *alloc_devs[]) ++{ ++ struct pispbe_node *node = vb2_get_drv_priv(q); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ *nplanes = 1; ++ if (NODE_IS_MPLANE(node)) { ++ unsigned int i; ++ ++ *nplanes = node->format.fmt.pix_mp.num_planes; ++ for (i = 0; i < *nplanes; i++) { ++ unsigned int size = ++ node->format.fmt.pix_mp.plane_fmt[i].sizeimage; ++ if (sizes[i] && sizes[i] < size) { ++ dev_err(pispbe->dev, "%s: size %u < %u\n", ++ __func__, sizes[i], size); ++ return -EINVAL; ++ } ++ sizes[i] = size; ++ } ++ } else if (NODE_IS_META(node)) { ++ sizes[0] = node->format.fmt.meta.buffersize; ++ /* ++ * Limit the config node buffer count to the number of internal ++ * buffers allocated. ++ */ ++ if (node->id == CONFIG_NODE) ++ *nbuffers = min_t(unsigned int, *nbuffers, ++ PISP_BE_NUM_CONFIG_BUFFERS); ++ } ++ ++ dev_dbg(pispbe->dev, ++ "Image (or metadata) size %u, nbuffers %u for node %s\n", ++ sizes[0], *nbuffers, NODE_NAME(node)); ++ ++ return 0; ++} ++ ++static int pispbe_node_buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct pispbe_node *node = vb2_get_drv_priv(vb->vb2_queue); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ unsigned long size = 0; ++ unsigned int num_planes = NODE_IS_MPLANE(node) ? ++ node->format.fmt.pix_mp.num_planes : 1; ++ unsigned int i; ++ ++ for (i = 0; i < num_planes; i++) { ++ size = NODE_IS_MPLANE(node) ++ ? node->format.fmt.pix_mp.plane_fmt[i].sizeimage ++ : node->format.fmt.meta.buffersize; ++ ++ if (vb2_plane_size(vb, i) < size) { ++ dev_err(pispbe->dev, ++ "data will not fit into plane %d (%lu < %lu)\n", ++ i, vb2_plane_size(vb, i), size); ++ return -EINVAL; ++ } ++ ++ vb2_set_plane_payload(vb, i, size); ++ } ++ ++ if (node->id == CONFIG_NODE) { ++ void *dst = &node->node_group->config[vb->index]; ++ void *src = vb2_plane_vaddr(vb, 0); ++ ++ memcpy(dst, src, sizeof(struct pisp_be_tiles_config)); ++ return pisp_be_validate_config(node->node_group, dst); ++ } ++ ++ return 0; ++} ++ ++static void pispbe_node_buffer_queue(struct vb2_buffer *buf) ++{ ++ struct vb2_v4l2_buffer *vbuf = ++ container_of(buf, struct vb2_v4l2_buffer, vb2_buf); ++ struct pispbe_buffer *buffer = ++ container_of(vbuf, struct pispbe_buffer, vb); ++ struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue); ++ struct pispbe_node_group *node_group = node->node_group; ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ unsigned long flags; ++ ++ dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); ++ spin_lock_irqsave(&node->ready_lock, flags); ++ list_add_tail(&buffer->ready_list, &node->ready_queue); ++ spin_unlock_irqrestore(&node->ready_lock, flags); ++ ++ /* ++ * Every time we add a buffer, check if there's now some work for the hw ++ * to do, but only for this client. ++ */ ++ pispbe_schedule_one(node_group); ++} ++ ++static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ unsigned long flags; ++ struct pispbe_node *node = vb2_get_drv_priv(q); ++ struct pispbe_node_group *node_group = node->node_group; ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(pispbe->dev); ++ if (ret < 0) ++ return ret; ++ ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ node->node_group->streaming_map |= BIT(node->id); ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n", ++ __func__, NODE_NAME(node), count); ++ dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n", ++ node->node_group->streaming_map); ++ ++ /* Maybe we're ready to run. */ ++ pispbe_schedule_one(node_group); ++ ++ return 0; ++} ++ ++static void pispbe_node_stop_streaming(struct vb2_queue *q) ++{ ++ struct pispbe_node *node = vb2_get_drv_priv(q); ++ struct pispbe_node_group *node_group = node->node_group; ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ struct pispbe_buffer *buf; ++ unsigned long flags; ++ ++ /* ++ * Now this is a bit awkward. In a simple M2M device we could just wait ++ * for all queued jobs to complete, but here there's a risk that a ++ * partial set of buffers was queued and cannot be run. For now, just ++ * cancel all buffers stuck in the "ready queue", then wait for any ++ * running job. ++ * XXX This may return buffers out of order. ++ */ ++ dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ do { ++ unsigned long flags1; ++ ++ spin_lock_irqsave(&node->ready_lock, flags1); ++ buf = list_first_entry_or_null(&node->ready_queue, ++ struct pispbe_buffer, ++ ready_list); ++ if (buf) { ++ list_del(&buf->ready_list); ++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ } ++ spin_unlock_irqrestore(&node->ready_lock, flags1); ++ } while (buf); ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ vb2_wait_for_all_buffers(&node->queue); ++ ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ node_group->streaming_map &= ~BIT(node->id); ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ pm_runtime_mark_last_busy(pispbe->dev); ++ pm_runtime_put_autosuspend(pispbe->dev); ++ ++ dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n", ++ node_group->streaming_map); ++} ++ ++static const struct vb2_ops pispbe_node_queue_ops = { ++ .queue_setup = pispbe_node_queue_setup, ++ .buf_prepare = pispbe_node_buffer_prepare, ++ .buf_queue = pispbe_node_buffer_queue, ++ .start_streaming = pispbe_node_start_streaming, ++ .stop_streaming = pispbe_node_stop_streaming, ++}; ++ ++static const struct v4l2_file_operations pispbe_fops = { ++ .owner = THIS_MODULE, ++ .open = v4l2_fh_open, ++ .release = vb2_fop_release, ++ .poll = vb2_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = vb2_fop_mmap ++}; ++ ++static int pispbe_node_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ strscpy(cap->driver, PISPBE_NAME, sizeof(cap->driver)); ++ strscpy(cap->card, PISPBE_NAME, sizeof(cap->card)); ++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", ++ dev_name(pispbe->dev)); ++ ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | ++ V4L2_CAP_VIDEO_OUTPUT_MPLANE | ++ V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS | ++ V4L2_CAP_META_OUTPUT | V4L2_CAP_META_CAPTURE; ++ cap->device_caps = node->vfd.device_caps; ++ ++ dev_dbg(pispbe->dev, "Caps for node %s: %x and %x (dev %x)\n", ++ NODE_NAME(node), cap->capabilities, cap->device_caps, ++ node->vfd.device_caps); ++ return 0; ++} ++ ++static int pispbe_node_g_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) { ++ dev_err(pispbe->dev, ++ "Cannot get capture fmt for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ *f = node->format; ++ dev_dbg(pispbe->dev, "Get capture format for node %s\n", ++ NODE_NAME(node)); ++ return 0; ++} ++ ++static int pispbe_node_g_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (NODE_IS_CAPTURE(node) || NODE_IS_META(node)) { ++ dev_err(pispbe->dev, ++ "Cannot get capture fmt for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ *f = node->format; ++ dev_dbg(pispbe->dev, "Get output format for node %s\n", ++ NODE_NAME(node)); ++ return 0; ++} ++ ++static int pispbe_node_g_fmt_meta_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) { ++ dev_err(pispbe->dev, ++ "Cannot get capture fmt for meta output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ *f = node->format; ++ dev_dbg(pispbe->dev, "Get output format for meta node %s\n", ++ NODE_NAME(node)); ++ return 0; ++} ++ ++static int pispbe_node_g_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_META(node) || NODE_IS_OUTPUT(node)) { ++ dev_err(pispbe->dev, ++ "Cannot get capture fmt for meta output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ *f = node->format; ++ dev_dbg(pispbe->dev, "Get output format for meta node %s\n", ++ NODE_NAME(node)); ++ return 0; ++} ++ ++static int verify_be_pix_format(const struct v4l2_format *f, ++ struct pispbe_node *node) ++{ ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ unsigned int nplanes = f->fmt.pix_mp.num_planes; ++ unsigned int i; ++ ++ if (f->fmt.pix_mp.width == 0 || f->fmt.pix_mp.height == 0) { ++ dev_err(pispbe->dev, "Details incorrect for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ if (nplanes == 0 || nplanes > MAX_PLANES) { ++ dev_err(pispbe->dev, ++ "Bad number of planes for output node %s, req =%d\n", ++ NODE_NAME(node), nplanes); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < nplanes; i++) { ++ const struct v4l2_plane_pix_format *p; ++ ++ p = &f->fmt.pix_mp.plane_fmt[i]; ++ if (p->bytesperline == 0 || p->sizeimage == 0) { ++ dev_err(pispbe->dev, ++ "Invalid plane %d for output node %s\n", ++ i, NODE_NAME(node)); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct pisp_be_format *find_format(unsigned int fourcc) ++{ ++ const struct pisp_be_format *fmt; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { ++ fmt = &supported_formats[i]; ++ if (fmt->fourcc == fourcc) ++ return fmt; ++ } ++ ++ return NULL; ++} ++ ++static void set_plane_params(struct v4l2_format *f, ++ const struct pisp_be_format *fmt) ++{ ++ unsigned int nplanes = f->fmt.pix_mp.num_planes; ++ unsigned int total_plane_factor = 0; ++ unsigned int i; ++ ++ for (i = 0; i < MAX_PLANES; i++) ++ total_plane_factor += fmt->plane_factor[i]; ++ ++ for (i = 0; i < nplanes; i++) { ++ struct v4l2_plane_pix_format *p = &f->fmt.pix_mp.plane_fmt[i]; ++ unsigned int bpl, plane_size; ++ ++ bpl = (f->fmt.pix_mp.width * fmt->bit_depth) >> 3; ++ bpl = ALIGN(max(p->bytesperline, bpl), fmt->align); ++ ++ plane_size = bpl * f->fmt.pix_mp.height * ++ (nplanes > 1 ? fmt->plane_factor[i] : total_plane_factor); ++ /* ++ * The shift is to divide out the plane_factor fixed point ++ * scaling of 8. ++ */ ++ plane_size = max(p->sizeimage, plane_size >> 3); ++ ++ p->bytesperline = bpl; ++ p->sizeimage = plane_size; ++ } ++} ++ ++static int try_format(struct v4l2_format *f, struct pispbe_node *node) ++{ ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ const struct pisp_be_format *fmt; ++ unsigned int i; ++ bool is_rgb; ++ u32 pixfmt = f->fmt.pix_mp.pixelformat; ++ ++ dev_dbg(pispbe->dev, ++ "%s: [%s] req %ux%u " V4L2_FOURCC_CONV ", planes %d\n", ++ __func__, NODE_NAME(node), f->fmt.pix_mp.width, ++ f->fmt.pix_mp.height, V4L2_FOURCC_CONV_ARGS(pixfmt), ++ f->fmt.pix_mp.num_planes); ++ ++ if (pixfmt == V4L2_PIX_FMT_RPI_BE) ++ return verify_be_pix_format(f, node); ++ ++ fmt = find_format(pixfmt); ++ if (!fmt) ++ fmt = find_format(V4L2_PIX_FMT_YUV420M); ++ ++ f->fmt.pix_mp.pixelformat = fmt->fourcc; ++ f->fmt.pix_mp.num_planes = fmt->num_planes; ++ f->fmt.pix_mp.field = V4L2_FIELD_NONE; ++ f->fmt.pix_mp.width = max(min(f->fmt.pix_mp.width, 65536u), ++ PISP_BACK_END_MIN_TILE_WIDTH); ++ f->fmt.pix_mp.height = max(min(f->fmt.pix_mp.height, 65536u), ++ PISP_BACK_END_MIN_TILE_HEIGHT); ++ ++ /* ++ * Fill in the actual colour space when the requested one was ++ * not supported. This also catches the case when the "default" ++ * colour space was requested (as that's never in the mask). ++ */ ++ if (!(V4L2_COLORSPACE_MASK(f->fmt.pix_mp.colorspace) & fmt->colorspace_mask)) ++ f->fmt.pix_mp.colorspace = fmt->colorspace_default; ++ ++ /* In all cases, we only support the defaults for these: */ ++ f->fmt.pix_mp.ycbcr_enc = ++ V4L2_MAP_YCBCR_ENC_DEFAULT(f->fmt.pix_mp.colorspace); ++ f->fmt.pix_mp.xfer_func = ++ V4L2_MAP_XFER_FUNC_DEFAULT(f->fmt.pix_mp.colorspace); ++ ++ is_rgb = f->fmt.pix_mp.colorspace == V4L2_COLORSPACE_SRGB; ++ f->fmt.pix_mp.quantization = ++ V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, f->fmt.pix_mp.colorspace, ++ f->fmt.pix_mp.ycbcr_enc); ++ ++ /* Set plane size and bytes/line for each plane. */ ++ set_plane_params(f, fmt); ++ ++ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ dev_dbg(pispbe->dev, ++ "%s: [%s] calc plane %d, %ux%u, depth %u, bpl %u size %u\n", ++ __func__, NODE_NAME(node), i, f->fmt.pix_mp.width, ++ f->fmt.pix_mp.height, fmt->bit_depth, ++ f->fmt.pix_mp.plane_fmt[i].bytesperline, ++ f->fmt.pix_mp.plane_fmt[i].sizeimage); ++ } ++ ++ return 0; ++} ++ ++static int pispbe_node_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret; ++ ++ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) { ++ dev_err(pispbe->dev, ++ "Cannot set capture fmt for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ ret = try_format(f, node); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int pispbe_node_try_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret; ++ ++ if (!NODE_IS_OUTPUT(node) || NODE_IS_META(node)) { ++ dev_err(pispbe->dev, ++ "Cannot set capture fmt for output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ ret = try_format(f, node); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int pispbe_node_try_fmt_meta_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) { ++ dev_err(pispbe->dev, ++ "Cannot set capture fmt for meta output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_BE_CFG; ++ f->fmt.meta.buffersize = sizeof(struct pisp_be_tiles_config); ++ ++ return 0; ++} ++ ++static int pispbe_node_try_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (!NODE_IS_META(node) || NODE_IS_OUTPUT(node)) { ++ dev_err(pispbe->dev, ++ "Cannot set capture fmt for meta output node %s\n", ++ NODE_NAME(node)); ++ return -EINVAL; ++ } ++ ++ f->fmt.meta.dataformat = V4L2_PIX_FMT_RPI_BE; ++ if (!f->fmt.meta.buffersize) ++ f->fmt.meta.buffersize = BIT(20); ++ ++ return 0; ++} ++ ++static int pispbe_node_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret = pispbe_node_try_fmt_vid_cap(file, priv, f); ++ ++ if (ret < 0) ++ return ret; ++ ++ node->format = *f; ++ node->pisp_format = find_format(f->fmt.pix_mp.pixelformat); ++ ++ dev_dbg(pispbe->dev, ++ "Set capture format for node %s to " V4L2_FOURCC_CONV "\n", ++ NODE_NAME(node), ++ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat)); ++ return 0; ++} ++ ++static int pispbe_node_s_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret = pispbe_node_try_fmt_vid_out(file, priv, f); ++ ++ if (ret < 0) ++ return ret; ++ ++ node->format = *f; ++ node->pisp_format = find_format(f->fmt.pix_mp.pixelformat); ++ ++ dev_dbg(pispbe->dev, ++ "Set output format for node %s to " V4L2_FOURCC_CONV "\n", ++ NODE_NAME(node), ++ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat)); ++ return 0; ++} ++ ++static int pispbe_node_s_fmt_meta_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret = pispbe_node_try_fmt_meta_out(file, priv, f); ++ ++ if (ret < 0) ++ return ret; ++ ++ node->format = *f; ++ node->pisp_format = &meta_out_supported_formats[0]; ++ ++ dev_dbg(pispbe->dev, ++ "Set output format for meta node %s to " V4L2_FOURCC_CONV "\n", ++ NODE_NAME(node), ++ V4L2_FOURCC_CONV_ARGS(f->fmt.meta.dataformat)); ++ return 0; ++} ++ ++static int pispbe_node_s_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ int ret = pispbe_node_try_fmt_meta_cap(file, priv, f); ++ ++ if (ret < 0) ++ return ret; ++ ++ node->format = *f; ++ node->pisp_format = find_format(f->fmt.meta.dataformat); ++ ++ dev_dbg(pispbe->dev, ++ "Set capture format for meta node %s to " V4L2_FOURCC_CONV "\n", ++ NODE_NAME(node), ++ V4L2_FOURCC_CONV_ARGS(f->fmt.meta.dataformat)); ++ return 0; ++} ++ ++static int pispbe_node_enum_fmt(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ ++ if (f->type != node->queue.type) ++ return -EINVAL; ++ ++ if (NODE_IS_META(node)) { ++ if (f->index) ++ return -EINVAL; ++ ++ if (NODE_IS_OUTPUT(node)) ++ f->pixelformat = V4L2_META_FMT_RPI_BE_CFG; ++ else ++ f->pixelformat = V4L2_PIX_FMT_RPI_BE; ++ f->flags = 0; ++ return 0; ++ } ++ ++ if (f->index >= ARRAY_SIZE(supported_formats)) ++ return -EINVAL; ++ ++ f->pixelformat = supported_formats[f->index].fourcc; ++ f->flags = 0; ++ ++ return 0; ++} ++ ++static int pispbe_enum_framesizes(struct file *file, void *priv, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ if (NODE_IS_META(node) || fsize->index) ++ return -EINVAL; ++ ++ if (!find_format(fsize->pixel_format)) { ++ dev_err(pispbe->dev, "Invalid pixel code: %x\n", ++ fsize->pixel_format); ++ return -EINVAL; ++ } ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; ++ fsize->stepwise.min_width = 32; ++ fsize->stepwise.max_width = 65535; ++ fsize->stepwise.step_width = 2; ++ ++ fsize->stepwise.min_height = 32; ++ fsize->stepwise.max_height = 65535; ++ fsize->stepwise.step_height = 2; ++ ++ return 0; ++} ++ ++static int pispbe_node_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ struct pispbe_dev *pispbe = node->node_group->pispbe; ++ ++ /* Do we need a node->stream_lock mutex? */ ++ ++ dev_dbg(pispbe->dev, "Stream on for node %s\n", NODE_NAME(node)); ++ ++ /* Do we care about the type? Each node has only one queue. */ ++ ++ INIT_LIST_HEAD(&node->ready_queue); ++ ++ /* locking should be handled by the queue->lock? */ ++ return vb2_streamon(&node->queue, type); ++} ++ ++static int pispbe_node_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct pispbe_node *node = video_drvdata(file); ++ ++ return vb2_streamoff(&node->queue, type); ++} ++ ++static const struct v4l2_ioctl_ops pispbe_node_ioctl_ops = { ++ .vidioc_querycap = pispbe_node_querycap, ++ .vidioc_g_fmt_vid_cap_mplane = pispbe_node_g_fmt_vid_cap, ++ .vidioc_g_fmt_vid_out_mplane = pispbe_node_g_fmt_vid_out, ++ .vidioc_g_fmt_meta_out = pispbe_node_g_fmt_meta_out, ++ .vidioc_g_fmt_meta_cap = pispbe_node_g_fmt_meta_cap, ++ .vidioc_try_fmt_vid_cap_mplane = pispbe_node_try_fmt_vid_cap, ++ .vidioc_try_fmt_vid_out_mplane = pispbe_node_try_fmt_vid_out, ++ .vidioc_try_fmt_meta_out = pispbe_node_try_fmt_meta_out, ++ .vidioc_try_fmt_meta_cap = pispbe_node_try_fmt_meta_cap, ++ .vidioc_s_fmt_vid_cap_mplane = pispbe_node_s_fmt_vid_cap, ++ .vidioc_s_fmt_vid_out_mplane = pispbe_node_s_fmt_vid_out, ++ .vidioc_s_fmt_meta_out = pispbe_node_s_fmt_meta_out, ++ .vidioc_s_fmt_meta_cap = pispbe_node_s_fmt_meta_cap, ++ .vidioc_enum_fmt_vid_cap = pispbe_node_enum_fmt, ++ .vidioc_enum_fmt_vid_out = pispbe_node_enum_fmt, ++ .vidioc_enum_fmt_meta_cap = pispbe_node_enum_fmt, ++ .vidioc_enum_fmt_meta_out = pispbe_node_enum_fmt, ++ .vidioc_enum_framesizes = pispbe_enum_framesizes, ++ .vidioc_create_bufs = vb2_ioctl_create_bufs, ++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_streamon = pispbe_node_streamon, ++ .vidioc_streamoff = pispbe_node_streamoff, ++}; ++ ++static const struct video_device pispbe_videodev = { ++ .name = PISPBE_NAME, ++ .vfl_dir = VFL_DIR_M2M, /* gets overwritten */ ++ .fops = &pispbe_fops, ++ .ioctl_ops = &pispbe_node_ioctl_ops, ++ .minor = -1, ++ .release = video_device_release_empty, ++}; ++ ++static void node_set_default_format(struct pispbe_node *node) ++{ ++ if (NODE_IS_META(node) && NODE_IS_OUTPUT(node)) { ++ /* Config node */ ++ struct v4l2_format *f = &node->format; ++ ++ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_BE_CFG; ++ f->fmt.meta.buffersize = sizeof(struct pisp_be_tiles_config); ++ f->type = node->buf_type; ++ } else if (NODE_IS_META(node) && NODE_IS_CAPTURE(node)) { ++ /* HOG output node */ ++ struct v4l2_format *f = &node->format; ++ ++ f->fmt.meta.dataformat = V4L2_PIX_FMT_RPI_BE; ++ f->fmt.meta.buffersize = BIT(20); ++ f->type = node->buf_type; ++ } else { ++ struct v4l2_format f = {0}; ++ ++ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M; ++ f.fmt.pix_mp.width = 1920; ++ f.fmt.pix_mp.height = 1080; ++ f.type = node->buf_type; ++ try_format(&f, node); ++ node->format = f; ++ } ++ ++ node->pisp_format = find_format(node->format.fmt.pix_mp.pixelformat); ++} ++ ++/* ++ * Initialise a struct pispbe_node and register it as /dev/video ++ * to represent one of the PiSP Back End's input or output streams. ++ */ ++static int ++pispbe_init_node(struct pispbe_node_group *node_group, unsigned int id) ++{ ++ bool output = NODE_DESC_IS_OUTPUT(&node_desc[id]); ++ struct pispbe_node *node = &node_group->node[id]; ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ struct media_entity *entity = &node->vfd.entity; ++ struct video_device *vdev = &node->vfd; ++ struct vb2_queue *q = &node->queue; ++ int ret; ++ ++ node->id = id; ++ node->node_group = node_group; ++ node->buf_type = node_desc[id].buf_type; ++ ++ mutex_init(&node->node_lock); ++ mutex_init(&node->queue_lock); ++ INIT_LIST_HEAD(&node->ready_queue); ++ spin_lock_init(&node->ready_lock); ++ ++ node->format.type = node->buf_type; ++ node_set_default_format(node); ++ ++ q->type = node->buf_type; ++ q->io_modes = VB2_MMAP | VB2_DMABUF; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->drv_priv = node; ++ q->ops = &pispbe_node_queue_ops; ++ q->buf_struct_size = sizeof(struct pispbe_buffer); ++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ q->dev = node->node_group->pispbe->dev; ++ /* get V4L2 to handle node->queue locking */ ++ q->lock = &node->queue_lock; ++ ++ ret = vb2_queue_init(q); ++ if (ret < 0) { ++ dev_err(pispbe->dev, "vb2_queue_init failed\n"); ++ return ret; ++ } ++ ++ *vdev = pispbe_videodev; /* default initialization */ ++ strscpy(vdev->name, node_desc[id].ent_name, sizeof(vdev->name)); ++ vdev->v4l2_dev = &node_group->v4l2_dev; ++ vdev->vfl_dir = output ? VFL_DIR_TX : VFL_DIR_RX; ++ /* get V4L2 to serialise our ioctls */ ++ vdev->lock = &node->node_lock; ++ vdev->queue = &node->queue; ++ vdev->device_caps = V4L2_CAP_STREAMING | node_desc[id].caps; ++ ++ node->pad.flags = output ? MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; ++ ret = media_entity_pads_init(entity, 1, &node->pad); ++ if (ret) { ++ dev_err(pispbe->dev, ++ "Failed to register media pads for %s device node\n", ++ NODE_NAME(node)); ++ goto err_unregister_queue; ++ } ++ ++ ret = video_register_device(vdev, VFL_TYPE_VIDEO, ++ PISPBE_VIDEO_NODE_OFFSET); ++ if (ret) { ++ dev_err(pispbe->dev, ++ "Failed to register video %s device node\n", ++ NODE_NAME(node)); ++ goto err_unregister_queue; ++ } ++ video_set_drvdata(vdev, node); ++ ++ if (output) ++ ret = media_create_pad_link(entity, 0, &node_group->sd.entity, ++ id, MEDIA_LNK_FL_IMMUTABLE | ++ MEDIA_LNK_FL_ENABLED); ++ else ++ ret = media_create_pad_link(&node_group->sd.entity, id, entity, ++ 0, MEDIA_LNK_FL_IMMUTABLE | ++ MEDIA_LNK_FL_ENABLED); ++ if (ret) ++ goto err_unregister_video_dev; ++ ++ dev_info(pispbe->dev, ++ "%s device node registered as /dev/video%d\n", ++ NODE_NAME(node), node->vfd.num); ++ return 0; ++ ++err_unregister_video_dev: ++ video_unregister_device(&node->vfd); ++err_unregister_queue: ++ vb2_queue_release(&node->queue); ++ return ret; ++} ++ ++static const struct v4l2_subdev_pad_ops pispbe_pad_ops = { ++ .link_validate = v4l2_subdev_link_validate_default, ++}; ++ ++static const struct v4l2_subdev_ops pispbe_sd_ops = { ++ .pad = &pispbe_pad_ops, ++}; ++ ++static int pispbe_init_subdev(struct pispbe_node_group *node_group) ++{ ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ struct v4l2_subdev *sd = &node_group->sd; ++ unsigned int i; ++ int ret; ++ ++ v4l2_subdev_init(sd, &pispbe_sd_ops); ++ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; ++ sd->owner = THIS_MODULE; ++ sd->dev = pispbe->dev; ++ strscpy(sd->name, PISPBE_NAME, sizeof(sd->name)); ++ ++ for (i = 0; i < PISPBE_NUM_NODES; i++) ++ node_group->pad[i].flags = ++ NODE_DESC_IS_OUTPUT(&node_desc[i]) ? ++ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, PISPBE_NUM_NODES, ++ node_group->pad); ++ if (ret) ++ goto error; ++ ++ ret = v4l2_device_register_subdev(&node_group->v4l2_dev, sd); ++ if (ret) ++ goto error; ++ ++ return 0; ++ ++error: ++ media_entity_cleanup(&sd->entity); ++ return ret; ++} ++ ++static int pispbe_init_group(struct pispbe_dev *pispbe, unsigned int id) ++{ ++ struct pispbe_node_group *node_group = &pispbe->node_group[id]; ++ struct v4l2_device *v4l2_dev; ++ struct media_device *mdev; ++ unsigned int num_registered = 0; ++ int ret; ++ ++ node_group->id = id; ++ node_group->pispbe = pispbe; ++ node_group->streaming_map = 0; ++ ++ dev_info(pispbe->dev, "Register nodes for group %u\n", id); ++ ++ /* Register v4l2_device and media_device */ ++ mdev = &node_group->mdev; ++ mdev->hw_revision = node_group->pispbe->hw_version; ++ mdev->dev = node_group->pispbe->dev; ++ strscpy(mdev->model, PISPBE_NAME, sizeof(mdev->model)); ++ snprintf(mdev->bus_info, sizeof(mdev->bus_info), ++ "platform:%s", dev_name(node_group->pispbe->dev)); ++ media_device_init(mdev); ++ ++ v4l2_dev = &node_group->v4l2_dev; ++ v4l2_dev->mdev = &node_group->mdev; ++ strscpy(v4l2_dev->name, PISPBE_NAME, sizeof(v4l2_dev->name)); ++ ++ ret = v4l2_device_register(pispbe->dev, &node_group->v4l2_dev); ++ if (ret) ++ goto err_media_dev_cleanup; ++ ++ /* Register the PISPBE subdevice. */ ++ ret = pispbe_init_subdev(node_group); ++ if (ret) ++ goto err_unregister_v4l2; ++ ++ /* Create device video nodes */ ++ for (; num_registered < PISPBE_NUM_NODES; num_registered++) { ++ ret = pispbe_init_node(node_group, num_registered); ++ if (ret) ++ goto err_unregister_nodes; ++ } ++ ++ ret = media_device_register(mdev); ++ if (ret) ++ goto err_unregister_nodes; ++ ++ node_group->config = ++ dma_alloc_coherent(pispbe->dev, ++ sizeof(struct pisp_be_tiles_config) * ++ PISP_BE_NUM_CONFIG_BUFFERS, ++ &node_group->config_dma_addr, GFP_KERNEL); ++ if (!node_group->config) { ++ dev_err(pispbe->dev, "Unable to allocate cached config buffers.\n"); ++ ret = -ENOMEM; ++ goto err_unregister_mdev; ++ } ++ ++ return 0; ++ ++err_unregister_mdev: ++ media_device_unregister(mdev); ++err_unregister_nodes: ++ while (num_registered-- > 0) { ++ video_unregister_device(&node_group->node[num_registered].vfd); ++ vb2_queue_release(&node_group->node[num_registered].queue); ++ } ++ v4l2_device_unregister_subdev(&node_group->sd); ++ media_entity_cleanup(&node_group->sd.entity); ++err_unregister_v4l2: ++ v4l2_device_unregister(v4l2_dev); ++err_media_dev_cleanup: ++ media_device_cleanup(mdev); ++ return ret; ++} ++ ++static void pispbe_destroy_node_group(struct pispbe_node_group *node_group) ++{ ++ struct pispbe_dev *pispbe = node_group->pispbe; ++ int i; ++ ++ if (node_group->config) { ++ dma_free_coherent(node_group->pispbe->dev, ++ sizeof(struct pisp_be_tiles_config) * ++ PISP_BE_NUM_CONFIG_BUFFERS, ++ node_group->config, ++ node_group->config_dma_addr); ++ } ++ ++ dev_info(pispbe->dev, "Unregister from media controller\n"); ++ ++ v4l2_device_unregister_subdev(&node_group->sd); ++ media_entity_cleanup(&node_group->sd.entity); ++ media_device_unregister(&node_group->mdev); ++ ++ for (i = PISPBE_NUM_NODES - 1; i >= 0; i--) { ++ video_unregister_device(&node_group->node[i].vfd); ++ vb2_queue_release(&node_group->node[i].queue); ++ } ++ ++ media_device_cleanup(&node_group->mdev); ++ v4l2_device_unregister(&node_group->v4l2_dev); ++} ++ ++static int pispbe_runtime_suspend(struct device *dev) ++{ ++ struct pispbe_dev *pispbe = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(pispbe->clk); ++ ++ return 0; ++} ++ ++static int pispbe_runtime_resume(struct device *dev) ++{ ++ struct pispbe_dev *pispbe = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = clk_prepare_enable(pispbe->clk); ++ if (ret) { ++ dev_err(dev, "Unable to enable clock\n"); ++ return ret; ++ } ++ ++ dev_dbg(dev, "%s: Enabled clock, rate=%lu\n", ++ __func__, clk_get_rate(pispbe->clk)); ++ ++ return 0; ++} ++ ++/* ++ * Probe the ISP-BE hardware block, as a single platform device. ++ * This will instantiate multiple "node groups" each with many device nodes. ++ */ ++static int pispbe_probe(struct platform_device *pdev) ++{ ++ unsigned int num_groups = 0; ++ struct pispbe_dev *pispbe; ++ int ret; ++ ++ pispbe = devm_kzalloc(&pdev->dev, sizeof(*pispbe), GFP_KERNEL); ++ if (!pispbe) ++ return -ENOMEM; ++ ++ dev_set_drvdata(&pdev->dev, pispbe); ++ pispbe->dev = &pdev->dev; ++ platform_set_drvdata(pdev, pispbe); ++ ++ pispbe->be_reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(pispbe->be_reg_base)) { ++ dev_err(&pdev->dev, "Failed to get ISP-BE registers address\n"); ++ return PTR_ERR(pispbe->be_reg_base); ++ } ++ ++ pispbe->irq = platform_get_irq(pdev, 0); ++ if (pispbe->irq <= 0) { ++ dev_err(&pdev->dev, "No IRQ resource\n"); ++ return -EINVAL; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, pispbe->irq, pispbe_isr, 0, ++ PISPBE_NAME, pispbe); ++ if (ret) { ++ dev_err(&pdev->dev, "Unable to request interrupt\n"); ++ return ret; ++ } ++ ++ ret = dma_set_mask_and_coherent(pispbe->dev, DMA_BIT_MASK(36)); ++ if (ret) ++ return ret; ++ ++ pispbe->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(pispbe->clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pispbe->clk), ++ "Failed to get clock"); ++ ++ /* Hardware initialisation */ ++ pm_runtime_set_autosuspend_delay(pispbe->dev, 200); ++ pm_runtime_use_autosuspend(pispbe->dev); ++ pm_runtime_enable(pispbe->dev); ++ ++ ret = pm_runtime_resume_and_get(pispbe->dev); ++ if (ret) ++ goto pm_runtime_disable_err; ++ ++ pispbe->hw_busy = 0; ++ spin_lock_init(&pispbe->hw_lock); ++ ret = hw_init(pispbe); ++ if (ret) ++ goto pm_runtime_put_err; ++ ++ /* ++ * Initialise and register devices for each node_group, including media ++ * device ++ */ ++ for (num_groups = 0; ++ num_groups < PISPBE_NUM_NODE_GROUPS; ++ num_groups++) { ++ ret = pispbe_init_group(pispbe, num_groups); ++ if (ret) ++ goto disable_nodes_err; ++ } ++ ++ pm_runtime_mark_last_busy(pispbe->dev); ++ pm_runtime_put_autosuspend(pispbe->dev); ++ ++ return 0; ++ ++disable_nodes_err: ++ while (num_groups-- > 0) ++ pispbe_destroy_node_group(&pispbe->node_group[num_groups]); ++pm_runtime_put_err: ++ pm_runtime_put(pispbe->dev); ++pm_runtime_disable_err: ++ pm_runtime_dont_use_autosuspend(pispbe->dev); ++ pm_runtime_disable(pispbe->dev); ++ ++ dev_err(&pdev->dev, "%s: returning %d", __func__, ret); ++ ++ return ret; ++} ++ ++static int pispbe_remove(struct platform_device *pdev) ++{ ++ struct pispbe_dev *pispbe = platform_get_drvdata(pdev); ++ int i; ++ ++ for (i = PISPBE_NUM_NODE_GROUPS - 1; i >= 0; i--) ++ pispbe_destroy_node_group(&pispbe->node_group[i]); ++ ++ pm_runtime_dont_use_autosuspend(pispbe->dev); ++ pm_runtime_disable(pispbe->dev); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops pispbe_pm_ops = { ++ SET_RUNTIME_PM_OPS(pispbe_runtime_suspend, pispbe_runtime_resume, NULL) ++}; ++ ++static const struct of_device_id pispbe_of_match[] = { ++ { ++ .compatible = "raspberrypi,pispbe", ++ }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, pispbe_of_match); ++ ++static struct platform_driver pispbe_pdrv = { ++ .probe = pispbe_probe, ++ .remove = pispbe_remove, ++ .driver = { ++ .name = PISPBE_NAME, ++ .of_match_table = pispbe_of_match, ++ .pm = &pispbe_pm_ops, ++ }, ++}; ++ ++module_platform_driver(pispbe_pdrv); +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h +@@ -0,0 +1,533 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * PiSP Back End configuration definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd ++ * ++ */ ++#ifndef _PISP_BE_CONFIG_H_ ++#define _PISP_BE_CONFIG_H_ ++ ++#include ++ ++#include ++ ++/* byte alignment for inputs */ ++#define PISP_BACK_END_INPUT_ALIGN 4u ++/* alignment for compressed inputs */ ++#define PISP_BACK_END_COMPRESSED_ALIGN 8u ++/* minimum required byte alignment for outputs */ ++#define PISP_BACK_END_OUTPUT_MIN_ALIGN 16u ++/* preferred byte alignment for outputs */ ++#define PISP_BACK_END_OUTPUT_MAX_ALIGN 64u ++ ++/* minimum allowed tile width anywhere in the pipeline */ ++#define PISP_BACK_END_MIN_TILE_WIDTH 16u ++/* minimum allowed tile width anywhere in the pipeline */ ++#define PISP_BACK_END_MIN_TILE_HEIGHT 16u ++ ++#define PISP_BACK_END_NUM_OUTPUTS 2 ++#define PISP_BACK_END_HOG_OUTPUT 1 ++ ++#define PISP_BACK_END_NUM_TILES 64 ++ ++enum pisp_be_bayer_enable { ++ PISP_BE_BAYER_ENABLE_INPUT = 0x000001, ++ PISP_BE_BAYER_ENABLE_DECOMPRESS = 0x000002, ++ PISP_BE_BAYER_ENABLE_DPC = 0x000004, ++ PISP_BE_BAYER_ENABLE_GEQ = 0x000008, ++ PISP_BE_BAYER_ENABLE_TDN_INPUT = 0x000010, ++ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS = 0x000020, ++ PISP_BE_BAYER_ENABLE_TDN = 0x000040, ++ PISP_BE_BAYER_ENABLE_TDN_COMPRESS = 0x000080, ++ PISP_BE_BAYER_ENABLE_TDN_OUTPUT = 0x000100, ++ PISP_BE_BAYER_ENABLE_SDN = 0x000200, ++ PISP_BE_BAYER_ENABLE_BLC = 0x000400, ++ PISP_BE_BAYER_ENABLE_STITCH_INPUT = 0x000800, ++ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS = 0x001000, ++ PISP_BE_BAYER_ENABLE_STITCH = 0x002000, ++ PISP_BE_BAYER_ENABLE_STITCH_COMPRESS = 0x004000, ++ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT = 0x008000, ++ PISP_BE_BAYER_ENABLE_WBG = 0x010000, ++ PISP_BE_BAYER_ENABLE_CDN = 0x020000, ++ PISP_BE_BAYER_ENABLE_LSC = 0x040000, ++ PISP_BE_BAYER_ENABLE_TONEMAP = 0x080000, ++ PISP_BE_BAYER_ENABLE_CAC = 0x100000, ++ PISP_BE_BAYER_ENABLE_DEBIN = 0x200000, ++ PISP_BE_BAYER_ENABLE_DEMOSAIC = 0x400000, ++}; ++ ++enum pisp_be_rgb_enable { ++ PISP_BE_RGB_ENABLE_INPUT = 0x000001, ++ PISP_BE_RGB_ENABLE_CCM = 0x000002, ++ PISP_BE_RGB_ENABLE_SAT_CONTROL = 0x000004, ++ PISP_BE_RGB_ENABLE_YCBCR = 0x000008, ++ PISP_BE_RGB_ENABLE_FALSE_COLOUR = 0x000010, ++ PISP_BE_RGB_ENABLE_SHARPEN = 0x000020, ++ /* Preferred colours would occupy 0x000040 */ ++ PISP_BE_RGB_ENABLE_YCBCR_INVERSE = 0x000080, ++ PISP_BE_RGB_ENABLE_GAMMA = 0x000100, ++ PISP_BE_RGB_ENABLE_CSC0 = 0x000200, ++ PISP_BE_RGB_ENABLE_CSC1 = 0x000400, ++ PISP_BE_RGB_ENABLE_DOWNSCALE0 = 0x001000, ++ PISP_BE_RGB_ENABLE_DOWNSCALE1 = 0x002000, ++ PISP_BE_RGB_ENABLE_RESAMPLE0 = 0x008000, ++ PISP_BE_RGB_ENABLE_RESAMPLE1 = 0x010000, ++ PISP_BE_RGB_ENABLE_OUTPUT0 = 0x040000, ++ PISP_BE_RGB_ENABLE_OUTPUT1 = 0x080000, ++ PISP_BE_RGB_ENABLE_HOG = 0x200000 ++}; ++ ++#define PISP_BE_RGB_ENABLE_CSC(i) (PISP_BE_RGB_ENABLE_CSC0 << (i)) ++#define PISP_BE_RGB_ENABLE_DOWNSCALE(i) (PISP_BE_RGB_ENABLE_DOWNSCALE0 << (i)) ++#define PISP_BE_RGB_ENABLE_RESAMPLE(i) (PISP_BE_RGB_ENABLE_RESAMPLE0 << (i)) ++#define PISP_BE_RGB_ENABLE_OUTPUT(i) (PISP_BE_RGB_ENABLE_OUTPUT0 << (i)) ++ ++/* ++ * We use the enable flags to show when blocks are "dirty", but we need some ++ * extra ones too. ++ */ ++enum pisp_be_dirty { ++ PISP_BE_DIRTY_GLOBAL = 0x0001, ++ PISP_BE_DIRTY_SH_FC_COMBINE = 0x0002, ++ PISP_BE_DIRTY_CROP = 0x0004 ++}; ++ ++struct pisp_be_global_config { ++ u32 bayer_enables; ++ u32 rgb_enables; ++ u8 bayer_order; ++ u8 pad[3]; ++}; ++ ++struct pisp_be_input_buffer_config { ++ /* low 32 bits followed by high 32 bits (for each of up to 3 planes) */ ++ u32 addr[3][2]; ++}; ++ ++struct pisp_be_dpc_config { ++ u8 coeff_level; ++ u8 coeff_range; ++ u8 pad; ++#define PISP_BE_DPC_FLAG_FOLDBACK 1 ++ u8 flags; ++}; ++ ++struct pisp_be_geq_config { ++ u16 offset; ++#define PISP_BE_GEQ_SHARPER BIT(15) ++#define PISP_BE_GEQ_SLOPE ((1 << 10) - 1) ++ /* top bit is the "sharper" flag, slope value is bottom 10 bits */ ++ u16 slope_sharper; ++ u16 min; ++ u16 max; ++}; ++ ++struct pisp_be_tdn_input_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr[2]; ++}; ++ ++struct pisp_be_tdn_config { ++ u16 black_level; ++ u16 ratio; ++ u16 noise_constant; ++ u16 noise_slope; ++ u16 threshold; ++ u8 reset; ++ u8 pad; ++}; ++ ++struct pisp_be_tdn_output_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr[2]; ++}; ++ ++struct pisp_be_sdn_config { ++ u16 black_level; ++ u8 leakage; ++ u8 pad; ++ u16 noise_constant; ++ u16 noise_slope; ++ u16 noise_constant2; ++ u16 noise_slope2; ++}; ++ ++struct pisp_be_stitch_input_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr[2]; ++}; ++ ++#define PISP_BE_STITCH_STREAMING_LONG 0x8000 ++#define PISP_BE_STITCH_EXPOSURE_RATIO_MASK 0x7fff ++ ++struct pisp_be_stitch_config { ++ u16 threshold_lo; ++ u8 threshold_diff_power; ++ u8 pad; ++ ++ /* top bit indicates whether streaming input is the long exposure */ ++ u16 exposure_ratio; ++ ++ u8 motion_threshold_256; ++ u8 motion_threshold_recip; ++}; ++ ++struct pisp_be_stitch_output_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr[2]; ++}; ++ ++struct pisp_be_cdn_config { ++ u16 thresh; ++ u8 iir_strength; ++ u8 g_adjust; ++}; ++ ++#define PISP_BE_LSC_LOG_GRID_SIZE 5 ++#define PISP_BE_LSC_GRID_SIZE (1 << PISP_BE_LSC_LOG_GRID_SIZE) ++#define PISP_BE_LSC_STEP_PRECISION 18 ++ ++struct pisp_be_lsc_config { ++ /* (1<<18) / grid_cell_width */ ++ u16 grid_step_x; ++ /* (1<<18) / grid_cell_height */ ++ u16 grid_step_y; ++ /* RGB gains jointly encoded in 32 bits */ ++ u32 lut_packed[PISP_BE_LSC_GRID_SIZE + 1] ++ [PISP_BE_LSC_GRID_SIZE + 1]; ++}; ++ ++struct pisp_be_lsc_extra { ++ u16 offset_x; ++ u16 offset_y; ++}; ++ ++#define PISP_BE_CAC_LOG_GRID_SIZE 3 ++#define PISP_BE_CAC_GRID_SIZE (1 << PISP_BE_CAC_LOG_GRID_SIZE) ++#define PISP_BE_CAC_STEP_PRECISION 20 ++ ++struct pisp_be_cac_config { ++ /* (1<<20) / grid_cell_width */ ++ u16 grid_step_x; ++ /* (1<<20) / grid_cell_height */ ++ u16 grid_step_y; ++ /* [gridy][gridx][rb][xy] */ ++ s8 lut[PISP_BE_CAC_GRID_SIZE + 1][PISP_BE_CAC_GRID_SIZE + 1][2][2]; ++}; ++ ++struct pisp_be_cac_extra { ++ u16 offset_x; ++ u16 offset_y; ++}; ++ ++#define PISP_BE_DEBIN_NUM_COEFFS 4 ++ ++struct pisp_be_debin_config { ++ s8 coeffs[PISP_BE_DEBIN_NUM_COEFFS]; ++ s8 h_enable; ++ s8 v_enable; ++ s8 pad[2]; ++}; ++ ++#define PISP_BE_TONEMAP_LUT_SIZE 64 ++ ++struct pisp_be_tonemap_config { ++ u16 detail_constant; ++ u16 detail_slope; ++ u16 iir_strength; ++ u16 strength; ++ u32 lut[PISP_BE_TONEMAP_LUT_SIZE]; ++}; ++ ++struct pisp_be_demosaic_config { ++ u8 sharper; ++ u8 fc_mode; ++ u8 pad[2]; ++}; ++ ++struct pisp_be_ccm_config { ++ s16 coeffs[9]; ++ u8 pad[2]; ++ s32 offsets[3]; ++}; ++ ++struct pisp_be_sat_control_config { ++ u8 shift_r; ++ u8 shift_g; ++ u8 shift_b; ++ u8 pad; ++}; ++ ++struct pisp_be_false_colour_config { ++ u8 distance; ++ u8 pad[3]; ++}; ++ ++#define PISP_BE_SHARPEN_SIZE 5 ++#define PISP_BE_SHARPEN_FUNC_NUM_POINTS 9 ++ ++struct pisp_be_sharpen_config { ++ s8 kernel0[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ s8 pad0[3]; ++ s8 kernel1[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ s8 pad1[3]; ++ s8 kernel2[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ s8 pad2[3]; ++ s8 kernel3[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ s8 pad3[3]; ++ s8 kernel4[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ s8 pad4[3]; ++ u16 threshold_offset0; ++ u16 threshold_slope0; ++ u16 scale0; ++ u16 pad5; ++ u16 threshold_offset1; ++ u16 threshold_slope1; ++ u16 scale1; ++ u16 pad6; ++ u16 threshold_offset2; ++ u16 threshold_slope2; ++ u16 scale2; ++ u16 pad7; ++ u16 threshold_offset3; ++ u16 threshold_slope3; ++ u16 scale3; ++ u16 pad8; ++ u16 threshold_offset4; ++ u16 threshold_slope4; ++ u16 scale4; ++ u16 pad9; ++ u16 positive_strength; ++ u16 positive_pre_limit; ++ u16 positive_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS]; ++ u16 positive_limit; ++ u16 negative_strength; ++ u16 negative_pre_limit; ++ u16 negative_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS]; ++ u16 negative_limit; ++ u8 enables; ++ u8 white; ++ u8 black; ++ u8 grey; ++}; ++ ++struct pisp_be_sh_fc_combine_config { ++ u8 y_factor; ++ u8 c1_factor; ++ u8 c2_factor; ++ u8 pad; ++}; ++ ++#define PISP_BE_GAMMA_LUT_SIZE 64 ++ ++struct pisp_be_gamma_config { ++ u32 lut[PISP_BE_GAMMA_LUT_SIZE]; ++}; ++ ++struct pisp_be_crop_config { ++ u16 offset_x, offset_y; ++ u16 width, height; ++}; ++ ++#define PISP_BE_RESAMPLE_FILTER_SIZE 96 ++ ++struct pisp_be_resample_config { ++ u16 scale_factor_h, scale_factor_v; ++ s16 coef[PISP_BE_RESAMPLE_FILTER_SIZE]; ++}; ++ ++struct pisp_be_resample_extra { ++ u16 scaled_width; ++ u16 scaled_height; ++ s16 initial_phase_h[3]; ++ s16 initial_phase_v[3]; ++}; ++ ++struct pisp_be_downscale_config { ++ u16 scale_factor_h; ++ u16 scale_factor_v; ++ u16 scale_recip_h; ++ u16 scale_recip_v; ++}; ++ ++struct pisp_be_downscale_extra { ++ u16 scaled_width; ++ u16 scaled_height; ++}; ++ ++struct pisp_be_hog_config { ++ u8 compute_signed; ++ u8 channel_mix[3]; ++ u32 stride; ++}; ++ ++struct pisp_be_axi_config { ++ u8 r_qos; /* Read QoS */ ++ u8 r_cache_prot; /* Read { prot[2:0], cache[3:0] } */ ++ u8 w_qos; /* Write QoS */ ++ u8 w_cache_prot; /* Write { prot[2:0], cache[3:0] } */ ++}; ++ ++enum pisp_be_transform { ++ PISP_BE_TRANSFORM_NONE = 0x0, ++ PISP_BE_TRANSFORM_HFLIP = 0x1, ++ PISP_BE_TRANSFORM_VFLIP = 0x2, ++ PISP_BE_TRANSFORM_ROT180 = ++ (PISP_BE_TRANSFORM_HFLIP | PISP_BE_TRANSFORM_VFLIP) ++}; ++ ++struct pisp_be_output_format_config { ++ struct pisp_image_format_config image; ++ u8 transform; ++ u8 pad[3]; ++ u16 lo; ++ u16 hi; ++ u16 lo2; ++ u16 hi2; ++}; ++ ++struct pisp_be_output_buffer_config { ++ /* low 32 bits followed by high 32 bits (for each of 3 planes) */ ++ u32 addr[3][2]; ++}; ++ ++struct pisp_be_hog_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ u32 addr[2]; ++}; ++ ++struct pisp_be_config { ++ /* I/O configuration: */ ++ struct pisp_be_input_buffer_config input_buffer; ++ struct pisp_be_tdn_input_buffer_config tdn_input_buffer; ++ struct pisp_be_stitch_input_buffer_config stitch_input_buffer; ++ struct pisp_be_tdn_output_buffer_config tdn_output_buffer; ++ struct pisp_be_stitch_output_buffer_config stitch_output_buffer; ++ struct pisp_be_output_buffer_config ++ output_buffer[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_hog_buffer_config hog_buffer; ++ /* Processing configuration: */ ++ struct pisp_be_global_config global; ++ struct pisp_image_format_config input_format; ++ struct pisp_decompress_config decompress; ++ struct pisp_be_dpc_config dpc; ++ struct pisp_be_geq_config geq; ++ struct pisp_image_format_config tdn_input_format; ++ struct pisp_decompress_config tdn_decompress; ++ struct pisp_be_tdn_config tdn; ++ struct pisp_compress_config tdn_compress; ++ struct pisp_image_format_config tdn_output_format; ++ struct pisp_be_sdn_config sdn; ++ struct pisp_bla_config blc; ++ struct pisp_compress_config stitch_compress; ++ struct pisp_image_format_config stitch_output_format; ++ struct pisp_image_format_config stitch_input_format; ++ struct pisp_decompress_config stitch_decompress; ++ struct pisp_be_stitch_config stitch; ++ struct pisp_be_lsc_config lsc; ++ struct pisp_wbg_config wbg; ++ struct pisp_be_cdn_config cdn; ++ struct pisp_be_cac_config cac; ++ struct pisp_be_debin_config debin; ++ struct pisp_be_tonemap_config tonemap; ++ struct pisp_be_demosaic_config demosaic; ++ struct pisp_be_ccm_config ccm; ++ struct pisp_be_sat_control_config sat_control; ++ struct pisp_be_ccm_config ycbcr; ++ struct pisp_be_sharpen_config sharpen; ++ struct pisp_be_false_colour_config false_colour; ++ struct pisp_be_sh_fc_combine_config sh_fc_combine; ++ struct pisp_be_ccm_config ycbcr_inverse; ++ struct pisp_be_gamma_config gamma; ++ struct pisp_be_ccm_config csc[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_downscale_config downscale[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_resample_config resample[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_output_format_config ++ output_format[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_hog_config hog; ++ struct pisp_be_axi_config axi; ++ /* Non-register fields: */ ++ struct pisp_be_lsc_extra lsc_extra; ++ struct pisp_be_cac_extra cac_extra; ++ struct pisp_be_downscale_extra ++ downscale_extra[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_crop_config crop; ++ struct pisp_image_format_config hog_format; ++ u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */ ++ u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */ ++ u32 dirty_flags_extra; /* these use pisp_be_dirty_t */ ++}; ++ ++/* ++ * We also need a tile structure to describe the size of the tiles going ++ * through the pipeline. ++ */ ++ ++enum pisp_tile_edge { ++ PISP_LEFT_EDGE = (1 << 0), ++ PISP_RIGHT_EDGE = (1 << 1), ++ PISP_TOP_EDGE = (1 << 2), ++ PISP_BOTTOM_EDGE = (1 << 3) ++}; ++ ++struct pisp_tile { ++ u8 edge; // enum pisp_tile_edge ++ u8 pad0[3]; ++ // 4 bytes ++ u32 input_addr_offset; ++ u32 input_addr_offset2; ++ u16 input_offset_x; ++ u16 input_offset_y; ++ u16 input_width; ++ u16 input_height; ++ // 20 bytes ++ u32 tdn_input_addr_offset; ++ u32 tdn_output_addr_offset; ++ u32 stitch_input_addr_offset; ++ u32 stitch_output_addr_offset; ++ // 36 bytes ++ u32 lsc_grid_offset_x; ++ u32 lsc_grid_offset_y; ++ // 44 bytes ++ u32 cac_grid_offset_x; ++ u32 cac_grid_offset_y; ++ // 52 bytes ++ u16 crop_x_start[PISP_BACK_END_NUM_OUTPUTS]; ++ u16 crop_x_end[PISP_BACK_END_NUM_OUTPUTS]; ++ u16 crop_y_start[PISP_BACK_END_NUM_OUTPUTS]; ++ u16 crop_y_end[PISP_BACK_END_NUM_OUTPUTS]; ++ // 68 bytes ++ /* Ordering is planes then branches */ ++ u16 downscale_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS]; ++ u16 downscale_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS]; ++ // 92 bytes ++ u16 resample_in_width[PISP_BACK_END_NUM_OUTPUTS]; ++ u16 resample_in_height[PISP_BACK_END_NUM_OUTPUTS]; ++ // 100 bytes ++ /* Ordering is planes then branches */ ++ u16 resample_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS]; ++ u16 resample_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS]; ++ // 124 bytes ++ u16 output_offset_x[PISP_BACK_END_NUM_OUTPUTS]; ++ u16 output_offset_y[PISP_BACK_END_NUM_OUTPUTS]; ++ u16 output_width[PISP_BACK_END_NUM_OUTPUTS]; ++ u16 output_height[PISP_BACK_END_NUM_OUTPUTS]; ++ // 140 bytes ++ u32 output_addr_offset[PISP_BACK_END_NUM_OUTPUTS]; ++ u32 output_addr_offset2[PISP_BACK_END_NUM_OUTPUTS]; ++ // 156 bytes ++ u32 output_hog_addr_offset; ++ // 160 bytes ++}; ++ ++static_assert(sizeof(struct pisp_tile) == 160); ++ ++struct pisp_be_tiles_config { ++ struct pisp_be_config config; ++ struct pisp_tile tiles[PISP_BACK_END_NUM_TILES]; ++ int num_tiles; ++}; ++ ++#endif /* _PISP_BE_CONFIG_H_ */ +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h +@@ -0,0 +1,469 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * PiSP Back End driver image format definitions. ++ * ++ * Copyright (c) 2021 Raspberry Pi Ltd ++ */ ++ ++#ifndef _PISP_BE_FORMATS_ ++#define _PISP_BE_FORMATS_ ++ ++#include ++#include ++ ++#define MAX_PLANES 3 ++#define P3(x) ((x) * 8) ++ ++struct pisp_be_format { ++ unsigned int fourcc; ++ unsigned int align; ++ unsigned int bit_depth; ++ /* 0P3 factor for plane sizing */ ++ unsigned int plane_factor[MAX_PLANES]; ++ unsigned int num_planes; ++ unsigned int colorspace_mask; ++ enum v4l2_colorspace colorspace_default; ++}; ++ ++#define V4L2_COLORSPACE_MASK(colorspace) BIT(colorspace) ++ ++#define V4L2_COLORSPACE_MASK_JPEG V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_JPEG) ++#define V4L2_COLORSPACE_MASK_SMPTE170M V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SMPTE170M) ++#define V4L2_COLORSPACE_MASK_REC709 V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_REC709) ++#define V4L2_COLORSPACE_MASK_SRGB V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SRGB) ++#define V4L2_COLORSPACE_MASK_RAW V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW) ++ ++/* ++ * All three colour spaces JPEG, SMPTE170M and REC709 are fundamentally sRGB ++ * underneath (as near as makes no difference to us), just with different YCbCr ++ * encodings. Therefore the ISP can generate sRGB on its main output and any of ++ * the others on its low resolution output. Applications should, when using both ++ * outputs, program the colour spaces on them to be the same, matching whatever ++ * is requested for the low resolution output, even if the main output is ++ * producing an RGB format. In turn this requires us to allow all these colour ++ * spaces for every YUV/RGB output format. ++ */ ++#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \ ++ V4L2_COLORSPACE_MASK_SRGB | \ ++ V4L2_COLORSPACE_MASK_SMPTE170M | \ ++ V4L2_COLORSPACE_MASK_REC709) ++ ++static const struct pisp_be_format supported_formats[] = { ++ /* Single plane YUV formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_YUV420, ++ /* 128 alignment to ensure U/V planes are 64 byte aligned. */ ++ .align = 128, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.25), P3(0.25) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVU420, ++ /* 128 alignment to ensure U/V planes are 64 byte aligned. */ ++ .align = 128, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.25), P3(0.25) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .align = 32, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .align = 32, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .align = 64, ++ .bit_depth = 16, ++ .plane_factor = { P3(1) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .align = 64, ++ .bit_depth = 16, ++ .plane_factor = { P3(1) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .align = 64, ++ .bit_depth = 16, ++ .plane_factor = { P3(1) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .align = 64, ++ .bit_depth = 16, ++ .plane_factor = { P3(1) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ /* Multiplane YUV formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_YUV420M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.25), P3(0.25) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12M, ++ .align = 32, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5) }, ++ .num_planes = 2, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21M, ++ .align = 32, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5) }, ++ .num_planes = 2, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVU420M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.25), P3(0.25) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YUV422M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5), P3(0.5) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVU422M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5), P3(0.5) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YUV444M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(1), P3(1) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVU444M, ++ .align = 64, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(1), P3(1) }, ++ .num_planes = 3, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, ++ /* RGB formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .align = 32, ++ .bit_depth = 24, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_BGR24, ++ .align = 32, ++ .bit_depth = 24, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_XBGR32, ++ .align = 64, ++ .bit_depth = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGBX32, ++ .align = 64, ++ .bit_depth = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ /* Bayer formats - 8-bit */ ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ /* Bayer formats - 16-bit */ ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ /* Bayer formats unpacked to 16bpp */ ++ /* 10 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB10, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR10, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG10, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG10, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ /* 12 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB12, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR12, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG12, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG12, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ /* 14 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB14, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR14, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG14, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG14, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ /* Bayer formats - 16-bit PiSP Compressed */ ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_BGGR, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_RGGB, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GRBG, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GBRG, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++}; ++ ++static const struct pisp_be_format meta_out_supported_formats[] = { ++ /* Configuration buffer format. */ ++ { ++ .fourcc = V4L2_META_FMT_RPI_BE_CFG, ++ }, ++}; ++ ++#endif /* _PISP_BE_FORMATS_ */ +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1452,6 +1452,7 @@ static void v4l_fill_fmtdesc(struct v4l2 + case V4L2_PIX_FMT_NV12M_10BE_8L128: descr = "10-bit NV12M (8x128 Linear, BE)"; break; + case V4L2_META_FMT_SENSOR_DATA: descr = "Sensor Ancillary Metadata"; break; + case V4L2_META_FMT_BCM2835_ISP_STATS: descr = "BCM2835 ISP Image Statistics"; break; ++ case V4L2_META_FMT_RPI_BE_CFG: descr = "PiSP Config format"; break; + + default: + /* Compressed formats */ +@@ -1503,6 +1504,7 @@ static void v4l_fill_fmtdesc(struct v4l2 + case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break; + case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit Format"; break; + case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break; ++ case V4L2_PIX_FMT_RPI_BE: descr = "PiSP Opaque Format"; break; + default: + if (fmt->description[0]) + return; +--- /dev/null ++++ b/include/media/raspberrypi/pisp_common.h +@@ -0,0 +1,65 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Raspberry Pi PiSP common configuration definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi (Trading) Ltd. ++ * ++ */ ++#ifndef _PISP_COMMON_H_ ++#define _PISP_COMMON_H_ ++ ++#include ++ ++#include "pisp_types.h" ++ ++struct pisp_bla_config { ++ uint16_t black_level_r; ++ uint16_t black_level_gr; ++ uint16_t black_level_gb; ++ uint16_t black_level_b; ++ uint16_t output_black_level; ++ uint8_t pad[2]; ++}; ++ ++struct pisp_wbg_config { ++ uint16_t gain_r; ++ uint16_t gain_g; ++ uint16_t gain_b; ++ uint8_t pad[2]; ++}; ++ ++struct pisp_compress_config { ++ /* value subtracted from incoming data */ ++ uint16_t offset; ++ uint8_t pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ uint8_t mode; ++}; ++ ++struct pisp_decompress_config { ++ /* value added to reconstructed data */ ++ uint16_t offset; ++ uint8_t pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ uint8_t mode; ++}; ++ ++enum pisp_axi_flags { ++ /* round down bursts to end at a 32-byte boundary, to align following bursts */ ++ PISP_AXI_FLAG_ALIGN = 128, ++ /* for FE writer: force WSTRB high, to pad output to 16-byte boundary */ ++ PISP_AXI_FLAG_PAD = 64, ++ /* for FE writer: Use Output FIFO level to trigger "panic" */ ++ PISP_AXI_FLAG_PANIC = 32 ++}; ++ ++struct pisp_axi_config { ++ /* burst length minus one, which must be in the range 0:15; OR'd with flags */ ++ uint8_t maxlen_flags; ++ /* { prot[2:0], cache[3:0] } fields, echoed on AXI bus */ ++ uint8_t cache_prot; ++ /* QoS field(s) (4x4 bits for FE writer; 4 bits for other masters) */ ++ uint16_t qos; ++}; ++ ++#endif /* _PISP_COMMON_H_ */ +--- /dev/null ++++ b/include/media/raspberrypi/pisp_types.h +@@ -0,0 +1,144 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Raspberry Pi PiSP common types. ++ * ++ * Copyright (C) 2021 - Raspberry Pi (Trading) Ltd. ++ * ++ */ ++#ifndef _PISP_TYPES_H_ ++#define _PISP_TYPES_H_ ++ ++/* This definition must match the format description in the hardware exactly! */ ++struct pisp_image_format_config { ++ /* size in pixels */ ++ uint16_t width, height; ++ /* must match struct pisp_image_format below */ ++ uint32_t format; ++ int32_t stride; ++ /* some planar image formats will need a second stride */ ++ int32_t stride2; ++}; ++ ++static_assert(sizeof(struct pisp_image_format_config) == 16); ++ ++enum pisp_bayer_order { ++ /* ++ * Note how bayer_order&1 tells you if G is on the even pixels of the ++ * checkerboard or not, and bayer_order&2 tells you if R is on the even ++ * rows or is swapped with B. Note that if the top (of the 8) bits is ++ * set, this denotes a monochrome or greyscale image, and the lower bits ++ * should all be ignored. ++ */ ++ PISP_BAYER_ORDER_RGGB = 0, ++ PISP_BAYER_ORDER_GBRG = 1, ++ PISP_BAYER_ORDER_BGGR = 2, ++ PISP_BAYER_ORDER_GRBG = 3, ++ PISP_BAYER_ORDER_GREYSCALE = 128 ++}; ++ ++enum pisp_image_format { ++ /* ++ * Precise values are mostly tbd. Generally these will be portmanteau ++ * values comprising bit fields and flags. This format must be shared ++ * throughout the PiSP. ++ */ ++ PISP_IMAGE_FORMAT_BPS_8 = 0x00000000, ++ PISP_IMAGE_FORMAT_BPS_10 = 0x00000001, ++ PISP_IMAGE_FORMAT_BPS_12 = 0x00000002, ++ PISP_IMAGE_FORMAT_BPS_16 = 0x00000003, ++ PISP_IMAGE_FORMAT_BPS_MASK = 0x00000003, ++ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED = 0x00000000, ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR = 0x00000010, ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR = 0x00000020, ++ PISP_IMAGE_FORMAT_PLANARITY_MASK = 0x00000030, ++ ++ PISP_IMAGE_FORMAT_SAMPLING_444 = 0x00000000, ++ PISP_IMAGE_FORMAT_SAMPLING_422 = 0x00000100, ++ PISP_IMAGE_FORMAT_SAMPLING_420 = 0x00000200, ++ PISP_IMAGE_FORMAT_SAMPLING_MASK = 0x00000300, ++ ++ PISP_IMAGE_FORMAT_ORDER_NORMAL = 0x00000000, ++ PISP_IMAGE_FORMAT_ORDER_SWAPPED = 0x00001000, ++ ++ PISP_IMAGE_FORMAT_SHIFT_0 = 0x00000000, ++ PISP_IMAGE_FORMAT_SHIFT_1 = 0x00010000, ++ PISP_IMAGE_FORMAT_SHIFT_2 = 0x00020000, ++ PISP_IMAGE_FORMAT_SHIFT_3 = 0x00030000, ++ PISP_IMAGE_FORMAT_SHIFT_4 = 0x00040000, ++ PISP_IMAGE_FORMAT_SHIFT_5 = 0x00050000, ++ PISP_IMAGE_FORMAT_SHIFT_6 = 0x00060000, ++ PISP_IMAGE_FORMAT_SHIFT_7 = 0x00070000, ++ PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000, ++ PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000, ++ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_3 = 0x03000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MASK = 0x03000000, ++ ++ PISP_IMAGE_FORMAT_HOG_SIGNED = 0x04000000, ++ PISP_IMAGE_FORMAT_HOG_UNSIGNED = 0x08000000, ++ PISP_IMAGE_FORMAT_INTEGRAL_IMAGE = 0x10000000, ++ PISP_IMAGE_FORMAT_WALLPAPER_ROLL = 0x20000000, ++ PISP_IMAGE_FORMAT_THREE_CHANNEL = 0x40000000, ++ ++ /* Lastly a few specific instantiations of the above. */ ++ PISP_IMAGE_FORMAT_SINGLE_16 = PISP_IMAGE_FORMAT_BPS_16, ++ PISP_IMAGE_FORMAT_THREE_16 = ++ PISP_IMAGE_FORMAT_BPS_16 | PISP_IMAGE_FORMAT_THREE_CHANNEL ++}; ++ ++#define PISP_IMAGE_FORMAT_bps_8(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8) ++#define PISP_IMAGE_FORMAT_bps_10(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10) ++#define PISP_IMAGE_FORMAT_bps_12(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12) ++#define PISP_IMAGE_FORMAT_bps_16(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16) ++#define PISP_IMAGE_FORMAT_bps(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) ? \ ++ 8 + (2 << (((fmt)&PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : \ ++ 8) ++#define PISP_IMAGE_FORMAT_shift(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1) ++#define PISP_IMAGE_FORMAT_three_channel(fmt) \ ++ ((fmt)&PISP_IMAGE_FORMAT_THREE_CHANNEL) ++#define PISP_IMAGE_FORMAT_single_channel(fmt) \ ++ (!((fmt)&PISP_IMAGE_FORMAT_THREE_CHANNEL)) ++#define PISP_IMAGE_FORMAT_compressed(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED) ++#define PISP_IMAGE_FORMAT_sampling_444(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_444) ++#define PISP_IMAGE_FORMAT_sampling_422(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_422) ++#define PISP_IMAGE_FORMAT_sampling_420(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_420) ++#define PISP_IMAGE_FORMAT_order_normal(fmt) \ ++ (!((fmt)&PISP_IMAGE_FORMAT_ORDER_SWAPPED)) ++#define PISP_IMAGE_FORMAT_order_swapped(fmt) \ ++ ((fmt)&PISP_IMAGE_FORMAT_ORDER_SWAPPED) ++#define PISP_IMAGE_FORMAT_interleaved(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED) ++#define PISP_IMAGE_FORMAT_semiplanar(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR) ++#define PISP_IMAGE_FORMAT_planar(fmt) \ ++ (((fmt)&PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR) ++#define PISP_IMAGE_FORMAT_wallpaper(fmt) \ ++ ((fmt)&PISP_IMAGE_FORMAT_WALLPAPER_ROLL) ++#define PISP_IMAGE_FORMAT_HOG(fmt) \ ++ ((fmt) & \ ++ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED)) ++ ++#define PISP_WALLPAPER_WIDTH 128 // in bytes ++ ++#endif /* _PISP_TYPES_H_ */ +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -793,6 +793,9 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_IPU3_SGRBG10 v4l2_fourcc('i', 'p', '3', 'G') /* IPU3 packed 10-bit GRBG bayer */ + #define V4L2_PIX_FMT_IPU3_SRGGB10 v4l2_fourcc('i', 'p', '3', 'r') /* IPU3 packed 10-bit RGGB bayer */ + ++/* The pixel format for all our buffers (the precise format is found in the config buffer). */ ++#define V4L2_PIX_FMT_RPI_BE v4l2_fourcc('R', 'P', 'B', 'P') ++ + /* SDR formats - used only for Software Defined Radio devices */ + #define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */ + #define V4L2_SDR_FMT_CU16LE v4l2_fourcc('C', 'U', '1', '6') /* IQ u16le */ +@@ -822,6 +825,9 @@ struct v4l2_pix_format { + #define V4L2_META_FMT_RK_ISP1_PARAMS v4l2_fourcc('R', 'K', '1', 'P') /* Rockchip ISP1 3A Parameters */ + #define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */ + ++/* The metadata format identifier for our configuration buffers. */ ++#define V4L2_META_FMT_RPI_BE_CFG v4l2_fourcc('R', 'P', 'B', 'C') ++ + /* priv field value to indicates that subsequent fields are valid. */ + #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe + diff --git a/target/linux/bcm27xx/patches-6.1/950-0862-irqchip-irq-bcm2712-mip-Support-for-2712-s-MIP.patch b/target/linux/bcm27xx/patches-6.1/950-0862-irqchip-irq-bcm2712-mip-Support-for-2712-s-MIP.patch new file mode 100644 index 0000000000..022a94af1c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0862-irqchip-irq-bcm2712-mip-Support-for-2712-s-MIP.patch @@ -0,0 +1,386 @@ +From 89b748416358e4e04765b9a4f20e1c3d256b9d9e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 28 Jul 2021 11:13:39 +0100 +Subject: [PATCH] irqchip: irq-bcm2712-mip: Support for 2712's MIP + +irqchip: irq-bcm2712-mip: specify bitmap search size as ilog2(N) not N + +Freeing also has the same interface. + +irqchip: irq-bcm2712-mip: Fix build warnings + +Signed-off-by: Phil Elwell + +irqchip: bcm2712-mip: add a quick hack to optionally shift MSI vectors + +There are two MIP peripherals in bcm2712, the first gets a first-class +treatment where 64 consecutive GIC SPIs are assigned to all 64 output +vectors. The second gets an agglomeration of 17 GIC SPIs, but only 8 of +these are consecutive starting at the 8th output vector. + +For now, allow the use of this smaller contiguous range within a larger +whole. + +Signed-off-by: Jonathan Bell +--- + drivers/irqchip/Kconfig | 8 + + drivers/irqchip/Makefile | 1 + + drivers/irqchip/irq-bcm2712-mip.c | 325 ++++++++++++++++++++++++++++++ + 3 files changed, 334 insertions(+) + create mode 100644 drivers/irqchip/irq-bcm2712-mip.c + +--- a/drivers/irqchip/Kconfig ++++ b/drivers/irqchip/Kconfig +@@ -109,6 +109,14 @@ config I8259 + bool + select IRQ_DOMAIN + ++config BCM2712_MIP ++ bool "Broadcom 2712 MSI-X Interrupt Peripheral support" ++ depends on ARM_GIC ++ select GENERIC_IRQ_CHIP ++ select IRQ_DOMAIN ++ help ++ Enable support for the Broadcom BCM2712 MSI-X target peripheral. ++ + config BCM6345_L1_IRQ + bool + select GENERIC_IRQ_CHIP +--- a/drivers/irqchip/Makefile ++++ b/drivers/irqchip/Makefile +@@ -63,6 +63,7 @@ obj-$(CONFIG_XTENSA_MX) += irq-xtensa- + obj-$(CONFIG_XILINX_INTC) += irq-xilinx-intc.o + obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o + obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o ++obj-$(CONFIG_BCM2712_MIP) += irq-bcm2712-mip.o + obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o + obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o + obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o +--- /dev/null ++++ b/drivers/irqchip/irq-bcm2712-mip.c +@@ -0,0 +1,325 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2021 Raspberry Pi Ltd., All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define MIP_INT_RAISED 0x00 ++#define MIP_INT_CLEARED 0x10 ++#define MIP_INT_CFGL_HOST 0x20 ++#define MIP_INT_CFGH_HOST 0x30 ++#define MIP_INT_MASKL_HOST 0x40 ++#define MIP_INT_MASKH_HOST 0x50 ++#define MIP_INT_MASKL_VPU 0x60 ++#define MIP_INT_MASKH_VPU 0x70 ++#define MIP_INT_STATUSL_HOST 0x80 ++#define MIP_INT_STATUSH_HOST 0x90 ++#define MIP_INT_STATUSL_VPU 0xa0 ++#define MIP_INT_STATUSH_VPU 0xb0 ++ ++struct mip_priv { ++ spinlock_t msi_map_lock; ++ spinlock_t hw_lock; ++ void * __iomem base; ++ phys_addr_t msg_addr; ++ u32 msi_base; /* The SGI number that MSIs start */ ++ u32 num_msis; /* The number of SGIs for MSIs */ ++ u32 msi_offset; /* Shift the allocated msi up by N */ ++ unsigned long *msi_map; ++}; ++ ++static void mip_mask_msi_irq(struct irq_data *d) ++{ ++ pci_msi_mask_irq(d); ++ irq_chip_mask_parent(d); ++} ++ ++static void mip_unmask_msi_irq(struct irq_data *d) ++{ ++ pci_msi_unmask_irq(d); ++ irq_chip_unmask_parent(d); ++} ++ ++static void mip_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) ++{ ++ struct mip_priv *priv = irq_data_get_irq_chip_data(d); ++ ++ msg->address_hi = upper_32_bits(priv->msg_addr); ++ msg->address_lo = lower_32_bits(priv->msg_addr); ++ msg->data = d->hwirq; ++} ++ ++// The "bus-specific" irq_chip (the MIP doesn't _have_ to be used with PCIe) ++ ++static struct irq_chip mip_msi_irq_chip = { ++ .name = "MIP-MSI", ++ .irq_unmask = mip_unmask_msi_irq, ++ .irq_mask = mip_mask_msi_irq, ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++}; ++ ++static struct msi_domain_info mip_msi_domain_info = { ++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | ++ MSI_FLAG_PCI_MSIX), ++ .chip = &mip_msi_irq_chip, ++}; ++ ++// The "middle" irq_chip (the hardware control part) ++ ++static struct irq_chip mip_irq_chip = { ++ .name = "MIP", ++ .irq_mask = irq_chip_mask_parent, ++ .irq_unmask = irq_chip_unmask_parent, ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++ .irq_set_type = irq_chip_set_type_parent, ++ .irq_compose_msi_msg = mip_compose_msi_msg, ++}; ++ ++ ++// And a domain to connect it to its parent (the GIC) ++ ++static int mip_irq_domain_alloc(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs, ++ void *args) ++{ ++ struct mip_priv *priv = domain->host_data; ++ struct irq_fwspec fwspec; ++ struct irq_data *irqd; ++ int hwirq, ret, i; ++ ++ spin_lock(&priv->msi_map_lock); ++ ++ hwirq = bitmap_find_free_region(priv->msi_map, priv->num_msis, ilog2(nr_irqs)); ++ ++ spin_unlock(&priv->msi_map_lock); ++ ++ if (hwirq < 0) ++ return -ENOSPC; ++ ++ hwirq += priv->msi_offset; ++ fwspec.fwnode = domain->parent->fwnode; ++ fwspec.param_count = 3; ++ fwspec.param[0] = 0; ++ fwspec.param[1] = hwirq + priv->msi_base; ++ fwspec.param[2] = IRQ_TYPE_EDGE_RISING; ++ ++ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &fwspec); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < nr_irqs; i++) { ++ irqd = irq_domain_get_irq_data(domain->parent, virq + i); ++ irqd->chip->irq_set_type(irqd, IRQ_TYPE_EDGE_RISING); ++ ++ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, ++ &mip_irq_chip, priv); ++ irqd = irq_get_irq_data(virq + i); ++ irqd_set_single_target(irqd); ++ irqd_set_affinity_on_activate(irqd); ++ } ++ ++ return 0; ++} ++ ++static void mip_irq_domain_free(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs) ++{ ++ struct irq_data *d = irq_domain_get_irq_data(domain, virq); ++ struct mip_priv *priv = irq_data_get_irq_chip_data(d); ++ ++ irq_domain_free_irqs_parent(domain, virq, nr_irqs); ++ d->hwirq -= priv->msi_offset; ++ ++ spin_lock(&priv->msi_map_lock); ++ ++ bitmap_release_region(priv->msi_map, d->hwirq, ilog2(nr_irqs)); ++ ++ spin_unlock(&priv->msi_map_lock); ++} ++ ++#if 0 ++static int mip_irq_domain_activate(struct irq_domain *domain, ++ struct irq_data *d, bool reserve) ++{ ++ struct mip_priv *priv = irq_data_get_irq_chip_data(d); ++ unsigned long flags; ++ unsigned int irq = d->hwirq; ++ void *__iomem reg = priv->base + ++ ((irq < 32) ? MIP_INT_MASKL_HOST : MIP_INT_MASKH_HOST); ++ u32 val; ++ ++ spin_lock_irqsave(&priv->hw_lock, flags); ++ val = readl(reg); ++ val &= ~(1 << (irq % 32)); // Clear the mask ++ writel(val, reg); ++ spin_unlock_irqrestore(&priv->hw_lock, flags); ++ return 0; ++} ++ ++static void mip_irq_domain_deactivate(struct irq_domain *domain, ++ struct irq_data *d) ++{ ++ struct mip_priv *priv = irq_data_get_irq_chip_data(d); ++ unsigned long flags; ++ unsigned int irq = d->hwirq - priv->msi_base; ++ void *__iomem reg = priv->base + ++ ((irq < 32) ? MIP_INT_MASKL_HOST : MIP_INT_MASKH_HOST); ++ u32 val; ++ ++ spin_lock_irqsave(&priv->hw_lock, flags); ++ val = readl(reg); ++ val |= (1 << (irq % 32)); // Mask it out ++ writel(val, reg); ++ spin_unlock_irqrestore(&priv->hw_lock, flags); ++} ++#endif ++ ++static const struct irq_domain_ops mip_irq_domain_ops = { ++ .alloc = mip_irq_domain_alloc, ++ .free = mip_irq_domain_free, ++ //.activate = mip_irq_domain_activate, ++ //.deactivate = mip_irq_domain_deactivate, ++}; ++ ++static int mip_init_domains(struct mip_priv *priv, ++ struct device_node *node) ++{ ++ struct irq_domain *middle_domain, *msi_domain, *gic_domain; ++ struct device_node *gic_node; ++ ++ gic_node = of_irq_find_parent(node); ++ if (!gic_node) { ++ pr_err("Failed to find the GIC node\n"); ++ return -ENODEV; ++ } ++ ++ gic_domain = irq_find_host(gic_node); ++ if (!gic_domain) { ++ pr_err("Failed to find the GIC domain\n"); ++ return -ENXIO; ++ } ++ ++ middle_domain = irq_domain_add_tree(NULL, ++ &mip_irq_domain_ops, ++ priv); ++ if (!middle_domain) { ++ pr_err("Failed to create the MIP middle domain\n"); ++ return -ENOMEM; ++ } ++ ++ middle_domain->parent = gic_domain; ++ ++ msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node), ++ &mip_msi_domain_info, ++ middle_domain); ++ if (!msi_domain) { ++ pr_err("Failed to create MSI domain\n"); ++ irq_domain_remove(middle_domain); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int __init mip_of_msi_init(struct device_node *node, ++ struct device_node *parent) ++{ ++ struct mip_priv *priv; ++ struct resource res; ++ int ret; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->msi_map_lock); ++ spin_lock_init(&priv->hw_lock); ++ ++ ret = of_address_to_resource(node, 0, &res); ++ if (ret) { ++ pr_err("Failed to allocate resource\n"); ++ goto err_priv; ++ } ++ ++ if (of_property_read_u32(node, "brcm,msi-base-spi", &priv->msi_base)) { ++ pr_err("Unable to parse MSI base\n"); ++ ret = -EINVAL; ++ goto err_priv; ++ } ++ ++ if (of_property_read_u32(node, "brcm,msi-num-spis", &priv->num_msis)) { ++ pr_err("Unable to parse MSI numbers\n"); ++ ret = -EINVAL; ++ goto err_priv; ++ } ++ ++ if (of_property_read_u32(node, "brcm,msi-offset", &priv->msi_offset)) ++ priv->msi_offset = 0; ++ ++ if (of_property_read_u64(node, "brcm,msi-pci-addr", &priv->msg_addr)) { ++ pr_err("Unable to parse MSI address\n"); ++ ret = -EINVAL; ++ goto err_priv; ++ } ++ ++ priv->base = ioremap(res.start, resource_size(&res)); ++ if (!priv->base) { ++ pr_err("Failed to ioremap regs\n"); ++ ret = -ENOMEM; ++ goto err_priv; ++ } ++ ++ priv->msi_map = kcalloc(BITS_TO_LONGS(priv->num_msis), ++ sizeof(*priv->msi_map), ++ GFP_KERNEL); ++ if (!priv->msi_map) { ++ ret = -ENOMEM; ++ goto err_base; ++ } ++ ++ pr_debug("Registering %d msixs, starting at %d\n", ++ priv->num_msis, priv->msi_base); ++ ++ /* ++ * Begin with all MSI-Xs masked in for the host, masked out for the ++ * VPU, and edge-triggered. ++ */ ++ writel(0, priv->base + MIP_INT_MASKL_HOST); ++ writel(0, priv->base + MIP_INT_MASKH_HOST); ++ writel(~0, priv->base + MIP_INT_MASKL_VPU); ++ writel(~0, priv->base + MIP_INT_MASKH_VPU); ++ writel(~0, priv->base + MIP_INT_CFGL_HOST); ++ writel(~0, priv->base + MIP_INT_CFGH_HOST); ++ ++ ret = mip_init_domains(priv, node); ++ if (ret) { ++ pr_err("Failed to allocate msi_map\n"); ++ goto err_map; ++ } ++ ++ return 0; ++ ++err_map: ++ kfree(priv->msi_map); ++ ++err_base: ++ iounmap(priv->base); ++ ++err_priv: ++ kfree(priv); ++ ++ pr_err("%s: failed - err %d\n", __func__, ret); ++ ++ return ret; ++} ++IRQCHIP_DECLARE(bcm_mip, "brcm,bcm2712-mip-intc", mip_of_msi_init); diff --git a/target/linux/bcm27xx/patches-6.1/950-0863-reset-reset-brcmstb-rescal-Support-shared-use.patch b/target/linux/bcm27xx/patches-6.1/950-0863-reset-reset-brcmstb-rescal-Support-shared-use.patch new file mode 100644 index 0000000000..a4328e5bc7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0863-reset-reset-brcmstb-rescal-Support-shared-use.patch @@ -0,0 +1,47 @@ +From 87b1126181f79fb2558652af0d7fafd9deaab5f3 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 7 Sep 2021 14:49:00 +0100 +Subject: [PATCH] reset: reset-brcmstb-rescal: Support shared use + +reset_control_reset should not be used with shared reset controllers. +Add support for reset_control_assert and _deassert to get the desired +behaviour and avoid ugly warnings in the kernel log. + +Signed-off-by: Phil Elwell +--- + drivers/reset/reset-brcmstb-rescal.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/reset/reset-brcmstb-rescal.c ++++ b/drivers/reset/reset-brcmstb-rescal.c +@@ -20,6 +20,7 @@ struct brcm_rescal_reset { + struct reset_controller_dev rcdev; + }; + ++/* Also doubles a deassert */ + static int brcm_rescal_reset_set(struct reset_controller_dev *rcdev, + unsigned long id) + { +@@ -52,6 +53,13 @@ static int brcm_rescal_reset_set(struct + return 0; + } + ++/* A dummy function - deassert/reset does all the work */ ++static int brcm_rescal_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return 0; ++} ++ + static int brcm_rescal_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) + { +@@ -61,6 +69,8 @@ static int brcm_rescal_reset_xlate(struc + + static const struct reset_control_ops brcm_rescal_reset_ops = { + .reset = brcm_rescal_reset_set, ++ .deassert = brcm_rescal_reset_set, ++ .assert = brcm_rescal_reset_assert, + }; + + static int brcm_rescal_reset_probe(struct platform_device *pdev) diff --git a/target/linux/bcm27xx/patches-6.1/950-0864-net-macb-Also-set-DMA-coherent-mask.patch b/target/linux/bcm27xx/patches-6.1/950-0864-net-macb-Also-set-DMA-coherent-mask.patch new file mode 100644 index 0000000000..88d92fbb20 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0864-net-macb-Also-set-DMA-coherent-mask.patch @@ -0,0 +1,418 @@ +From bd36586dd9e05bde8e23dc3d99771269b48b65f8 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 10 Sep 2021 17:20:45 +0100 +Subject: [PATCH] net: macb: Also set DMA coherent mask + +macb: Add device tree properties that allow configuration of the AXI max pipeline register + +net: macb: add support for ethtool interrupt moderation configuration + +Only global throttling of rx or tx by time quanta is supported. + +Signed-off-by: Jonathan Bell + +macb: add platform device shutdown function. Prevents AXI master over PCIE from hanging when the host is rebooted. + +net: macb: increase polling interval for MDIO completion + +MDIO is a slow bus (single-digit MHz). Polling at 1us intervals +is a bit aggressive, so increase to 100us as the transaction +usually takes 100-200us to complete. + +Signed-off-by: Jonathan Bell + +net: macb: Several patches for RP1 + +64-bit RX fix + +Also set DMA coherent mask + +Add device tree properties that allow configuration of the AXI max +pipeline register + +Add support for ethtool interrupt moderation configuration + +Only global throttling of rx or tx by time quanta is supported. + +Add platform device shutdown function. Prevents AXI master over PCIE +from hanging when the host is rebooted. + +Increase polling interval for MDIO completion + +MDIO is a slow bus (single-digit MHz). Polling at 1us intervals +is a bit aggressive, so increase to 100us as the transaction +usually takes 100-200us to complete. + +Signed-off-by: Jonathan Bell + +net: macb: Support the phy-reset-gpios property + +Allow a PHY to be reset with an optional GPIO. The reset duration can +be specified in milliseconds - the default is 10ms. + +Signed-off-by: Phil Elwell + +drivers: net: macb: close device on driver shutdown + +Fix some suspicious locking and instead call into macb_close, which +deregisters and frees all resources the corresponding macb_open +claimed. + +Signed-off-by: Jonathan Bell + +net: macb: add hack to prevent TX stalls in a quiet system + +See https://github.com/raspberrypi/linux-2712/issues/89 + +There is some critical window during TX where a further write to the +TSTART bit while TX is active does not cause newly queued TX descriptors +to be consumed. + +For now "wait a bit, then try anyway" seems to work. + +Requires further investigation, but this unsticks NFS reliably. + +Signed-off-by: Jonathan Bell + +net: macb: set default interrupt moderation for GEM hardware + +Defaulting to intmod = 0 is antisocial, as the MAC can generate over +130,000 interrupts per second. 50us is a sensible default. + +Signed-off-by: Jonathan Bell +--- + drivers/net/ethernet/cadence/macb.h | 25 ++++ + drivers/net/ethernet/cadence/macb_main.c | 151 ++++++++++++++++++++++- + 2 files changed, 174 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/cadence/macb.h ++++ b/drivers/net/ethernet/cadence/macb.h +@@ -84,6 +84,8 @@ + #define GEM_DMACFG 0x0010 /* DMA Configuration */ + #define GEM_JML 0x0048 /* Jumbo Max Length */ + #define GEM_HS_MAC_CONFIG 0x0050 /* GEM high speed config */ ++#define GEM_AMP 0x0054 /* AXI Max Pipeline */ ++#define GEM_INTMOD 0x005c /* Interrupt moderation */ + #define GEM_HRB 0x0080 /* Hash Bottom */ + #define GEM_HRT 0x0084 /* Hash Top */ + #define GEM_SA1B 0x0088 /* Specific1 Bottom */ +@@ -346,6 +348,21 @@ + #define GEM_ADDR64_OFFSET 30 /* Address bus width - 64b or 32b */ + #define GEM_ADDR64_SIZE 1 + ++/* Bitfields in AMP */ ++#define GEM_AR2R_MAX_PIPE_OFFSET 0 /* Maximum number of outstanding AXI read requests */ ++#define GEM_AR2R_MAX_PIPE_SIZE 8 ++#define GEM_AW2W_MAX_PIPE_OFFSET 8 /* Maximum number of outstanding AXI write requests */ ++#define GEM_AW2W_MAX_PIPE_SIZE 8 ++#define GEM_AW2B_FILL_OFFSET 16 /* Select wether the max AW2W transactions operates between: */ ++#define GEM_AW2B_FILL_AW2W 0 /* 0: the AW to W AXI channel */ ++#define GEM_AW2B_FILL_AW2B 1 /* 1: AW to B channel */ ++#define GEM_AW2B_FILL_SIZE 1 ++ ++/* Bitfields in INTMOD */ ++#define GEM_RX_MODERATION_OFFSET 0 /* RX interrupt moderation */ ++#define GEM_RX_MODERATION_SIZE 8 ++#define GEM_TX_MODERATION_OFFSET 16 /* TX interrupt moderation */ ++#define GEM_TX_MODERATION_SIZE 8 + + /* Bitfields in NSR */ + #define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */ +@@ -798,6 +815,7 @@ + }) + + #define MACB_READ_NSR(bp) macb_readl(bp, NSR) ++#define MACB_READ_TSR(bp) macb_readl(bp, TSR) + + /* struct macb_dma_desc - Hardware DMA descriptor + * @addr: DMA address of data buffer +@@ -1217,6 +1235,7 @@ struct macb_queue { + dma_addr_t tx_ring_dma; + struct work_struct tx_error_task; + bool txubr_pending; ++ bool tx_pending; + struct napi_struct napi_tx; + + dma_addr_t rx_ring_dma; +@@ -1286,9 +1305,15 @@ struct macb { + + u32 caps; + unsigned int dma_burst_length; ++ u8 aw2w_max_pipe; ++ u8 ar2r_max_pipe; ++ bool use_aw2b_fill; + + phy_interface_t phy_interface; + ++ struct gpio_desc *phy_reset_gpio; ++ int phy_reset_ms; ++ + /* AT91RM9200 transmit queue (1 on wire + 1 queued) */ + struct macb_tx_skb rm9200_txq[2]; + unsigned int max_tx_length; +--- a/drivers/net/ethernet/cadence/macb_main.c ++++ b/drivers/net/ethernet/cadence/macb_main.c +@@ -41,6 +41,9 @@ + #include + #include "macb.h" + ++static unsigned int txdelay = 35; ++module_param(txdelay, uint, 0644); ++ + /* This structure is only used for MACB on SiFive FU540 devices */ + struct sifive_fu540_macb_mgmt { + void __iomem *reg; +@@ -336,7 +339,7 @@ static int macb_mdio_wait_for_idle(struc + u32 val; + + return readx_poll_timeout(MACB_READ_NSR, bp, val, val & MACB_BIT(IDLE), +- 1, MACB_MDIO_TIMEOUT); ++ 100, MACB_MDIO_TIMEOUT); + } + + static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +@@ -442,6 +445,19 @@ mdio_pm_exit: + return status; + } + ++static int macb_mdio_reset(struct mii_bus *bus) ++{ ++ struct macb *bp = bus->priv; ++ ++ if (bp->phy_reset_gpio) { ++ gpiod_set_value_cansleep(bp->phy_reset_gpio, 1); ++ msleep(bp->phy_reset_ms); ++ gpiod_set_value_cansleep(bp->phy_reset_gpio, 0); ++ } ++ ++ return 0; ++} ++ + static void macb_init_buffers(struct macb *bp) + { + struct macb_queue *queue; +@@ -915,6 +931,7 @@ static int macb_mii_init(struct macb *bp + bp->mii_bus->name = "MACB_mii_bus"; + bp->mii_bus->read = &macb_mdio_read; + bp->mii_bus->write = &macb_mdio_write; ++ bp->mii_bus->reset = &macb_mdio_reset; + snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + bp->pdev->name, bp->pdev->id); + bp->mii_bus->priv = bp; +@@ -1584,6 +1601,11 @@ static int macb_rx(struct macb_queue *qu + + macb_init_rx_ring(queue); + queue_writel(queue, RBQP, queue->rx_ring_dma); ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ if (bp->hw_dma_cap & HW_DMA_CAP_64B) ++ macb_writel(bp, RBQPH, ++ upper_32_bits(queue->rx_ring_dma)); ++#endif + + macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); + +@@ -1884,8 +1906,9 @@ static irqreturn_t macb_interrupt(int ir + queue_writel(queue, ISR, MACB_BIT(TCOMP) | + MACB_BIT(TXUBR)); + +- if (status & MACB_BIT(TXUBR)) { ++ if (status & MACB_BIT(TXUBR) || queue->tx_pending) { + queue->txubr_pending = true; ++ queue->tx_pending = 0; + wmb(); // ensure softirq can see update + } + +@@ -2332,6 +2355,11 @@ static netdev_tx_t macb_start_xmit(struc + skb_tx_timestamp(skb); + + spin_lock_irq(&bp->lock); ++ ++ /* TSTART write might get dropped, so make the IRQ retrigger a buffer read */ ++ if (macb_readl(bp, TSR) & MACB_BIT(TGO)) ++ queue->tx_pending = 1; ++ + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); + spin_unlock_irq(&bp->lock); + +@@ -2699,6 +2727,37 @@ static void macb_configure_dma(struct ma + } + } + ++static void gem_init_axi(struct macb *bp) ++{ ++ u32 amp; ++ ++ /* AXI pipeline setup - don't touch values unless specified in device ++ * tree. Some hardware could have reset values > 1. ++ */ ++ amp = gem_readl(bp, AMP); ++ ++ if (bp->use_aw2b_fill) ++ amp = GEM_BFINS(AW2B_FILL, bp->use_aw2b_fill, amp); ++ if (bp->aw2w_max_pipe) ++ amp = GEM_BFINS(AW2W_MAX_PIPE, bp->aw2w_max_pipe, amp); ++ if (bp->ar2r_max_pipe) ++ amp = GEM_BFINS(AR2R_MAX_PIPE, bp->ar2r_max_pipe, amp); ++ ++ gem_writel(bp, AMP, amp); ++} ++ ++static void gem_init_intmod(struct macb *bp) ++{ ++ unsigned int throttle; ++ u32 intmod = 0; ++ ++ /* Use sensible interrupt moderation thresholds (50us rx and tx) */ ++ throttle = (1000 * 50) / 800; ++ intmod = GEM_BFINS(TX_MODERATION, throttle, intmod); ++ intmod = GEM_BFINS(RX_MODERATION, throttle, intmod); ++ gem_writel(bp, INTMOD, intmod); ++} ++ + static void macb_init_hw(struct macb *bp) + { + u32 config; +@@ -2727,6 +2786,11 @@ static void macb_init_hw(struct macb *bp + if (bp->caps & MACB_CAPS_JUMBO) + bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; + ++ if (macb_is_gem(bp)) { ++ gem_init_axi(bp); ++ gem_init_intmod(bp); ++ } ++ + macb_configure_dma(bp); + } + +@@ -3072,6 +3136,52 @@ static void gem_get_ethtool_strings(stru + } + } + ++static int gem_set_coalesce(struct net_device *dev, ++ struct ethtool_coalesce *ec, ++ struct kernel_ethtool_coalesce *kernel_coal, ++ struct netlink_ext_ack *extack) ++{ ++ struct macb *bp = netdev_priv(dev); ++ unsigned int tx_throttle; ++ unsigned int rx_throttle; ++ u32 intmod = 0; ++ ++ /* GEM has simple IRQ throttling support. RX and TX interrupts ++ * are separately moderated on 800ns quantums, with no support ++ * for frame coalescing. ++ */ ++ ++ /* Max is 255 * 0.8us = 204us. Zero implies no moderation. */ ++ if (ec->rx_coalesce_usecs > 204 || ec->tx_coalesce_usecs > 204) ++ return -EINVAL; ++ ++ tx_throttle = (1000 * ec->tx_coalesce_usecs) / 800; ++ rx_throttle = (1000 * ec->rx_coalesce_usecs) / 800; ++ ++ intmod = GEM_BFINS(TX_MODERATION, tx_throttle, intmod); ++ intmod = GEM_BFINS(RX_MODERATION, rx_throttle, intmod); ++ ++ gem_writel(bp, INTMOD, intmod); ++ ++ return 0; ++} ++ ++static int gem_get_coalesce(struct net_device *dev, ++ struct ethtool_coalesce *ec, ++ struct kernel_ethtool_coalesce *kernel_coal, ++ struct netlink_ext_ack *extack) ++{ ++ struct macb *bp = netdev_priv(dev); ++ u32 intmod; ++ ++ intmod = gem_readl(bp, INTMOD); ++ ++ ec->tx_coalesce_usecs = (GEM_BFEXT(TX_MODERATION, intmod) * 800) / 1000; ++ ec->rx_coalesce_usecs = (GEM_BFEXT(RX_MODERATION, intmod) * 800) / 1000; ++ ++ return 0; ++} ++ + static struct net_device_stats *macb_get_stats(struct net_device *dev) + { + struct macb *bp = netdev_priv(dev); +@@ -3664,6 +3774,8 @@ static const struct ethtool_ops macb_eth + }; + + static const struct ethtool_ops gem_ethtool_ops = { ++ .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | ++ ETHTOOL_COALESCE_TX_USECS, + .get_regs_len = macb_get_regs_len, + .get_regs = macb_get_regs, + .get_wol = macb_get_wol, +@@ -3673,6 +3785,8 @@ static const struct ethtool_ops gem_etht + .get_ethtool_stats = gem_get_ethtool_stats, + .get_strings = gem_get_ethtool_strings, + .get_sset_count = gem_get_sset_count, ++ .get_coalesce = gem_get_coalesce, ++ .set_coalesce = gem_set_coalesce, + .get_link_ksettings = macb_get_link_ksettings, + .set_link_ksettings = macb_set_link_ksettings, + .get_ringparam = macb_get_ringparam, +@@ -4940,6 +5054,10 @@ static int macb_probe(struct platform_de + + bp->usrio = macb_config->usrio; + ++ device_property_read_u8(&pdev->dev, "cdns,aw2w-max-pipe", &bp->aw2w_max_pipe); ++ device_property_read_u8(&pdev->dev, "cdns,ar2r-max-pipe", &bp->ar2r_max_pipe); ++ bp->use_aw2b_fill = device_property_read_bool(&pdev->dev, "cdns,use-aw2b-fill"); ++ + spin_lock_init(&bp->lock); + + /* setup capabilities */ +@@ -4995,6 +5113,21 @@ static int macb_probe(struct platform_de + else + bp->phy_interface = interface; + ++ /* optional PHY reset-related properties */ ++ bp->phy_reset_gpio = devm_gpiod_get_optional(&pdev->dev, "phy-reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(bp->phy_reset_gpio)) { ++ dev_err(&pdev->dev, "Failed to obtain phy-reset gpio\n"); ++ err = PTR_ERR(bp->phy_reset_gpio); ++ goto err_out_free_netdev; ++ } ++ ++ bp->phy_reset_ms = 10; ++ of_property_read_u32(np, "phy-reset-duration", &bp->phy_reset_ms); ++ /* A sane reset duration should not be longer than 1s */ ++ if (bp->phy_reset_ms > 1000) ++ bp->phy_reset_ms = 1000; ++ + /* IP specific init */ + err = init(pdev); + if (err) +@@ -5071,6 +5204,19 @@ static int macb_remove(struct platform_d + return 0; + } + ++static void macb_shutdown(struct platform_device *pdev) ++{ ++ struct net_device *dev; ++ ++ dev = platform_get_drvdata(pdev); ++ ++ rtnl_lock(); ++ netif_device_detach(dev); ++ if (netif_running(dev)) ++ dev_close(dev); ++ rtnl_unlock(); ++} ++ + static int __maybe_unused macb_suspend(struct device *dev) + { + struct net_device *netdev = dev_get_drvdata(dev); +@@ -5285,6 +5431,7 @@ static const struct dev_pm_ops macb_pm_o + static struct platform_driver macb_driver = { + .probe = macb_probe, + .remove = macb_remove, ++ .shutdown = macb_shutdown, + .driver = { + .name = "macb", + .of_match_table = of_match_ptr(macb_dt_ids), diff --git a/target/linux/bcm27xx/patches-6.1/950-0865-usb-dwc3-Set-DMA-and-coherent-masks-early.patch b/target/linux/bcm27xx/patches-6.1/950-0865-usb-dwc3-Set-DMA-and-coherent-masks-early.patch new file mode 100644 index 0000000000..f6944e226f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0865-usb-dwc3-Set-DMA-and-coherent-masks-early.patch @@ -0,0 +1,384 @@ +From 4ffa5f2c5fc7854683964bb2f2bf23907c18213f Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Mon, 13 Sep 2021 11:14:32 +0100 +Subject: [PATCH] usb: dwc3: Set DMA and coherent masks early + +dwc3 allocates scratch and event buffers in the top-level driver. Hack the +probe function to set the DMA mask before trying to allocate these. + +I think the event buffers are only used in device mode, but the scratch +buffers may be used if core hibernation is enabled. + +usb: dwc3: add support for new DT quirks + +Apply the optional axi-pipe-limit and dis-in-autoretry-quirk properties +during driver probe. + +Signed-off-by: Jonathan Bell + +phy: phy-brcm-usb: Add 2712 support + +usb: dwc3: if the host controller instance number is present in DT, use it + +If two instances of a dwc3 host controller are specified in devicetree, +then the probe order may be arbitrary which results in the device names +swapping on a per-boot basis. + +If a "usb" alias with the instance number is specified, then use +that to construct the device name instead of autogenerating one. + +Signed-off-by: Jonathan Bell + +rp1 dwc3 changes + +drivers: usb: dwc3: allow setting GTXTHRCFG on dwc_usb3.0 hardware + +Equivalent register fields exist in the SuperSpeed Host version of the +hardware, so allow the use of TX thresholds if specified in devicetree. + +Signed-off-by: Jonathan Bell + +drivers: usb: dwc3: remove downstream quirk dis-in-autoretry + +Upstream have unilaterally disabled the feature. + +Partially reverts 6e9142a26ee0fdc3a5adc49ed6cedc0b16ec2ed1 (downstream) + +Signed-off-by: Jonathan Bell +--- + drivers/phy/broadcom/Kconfig | 2 +- + .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 59 +++++++++++++++++++ + drivers/phy/broadcom/phy-brcm-usb-init.h | 2 + + drivers/phy/broadcom/phy-brcm-usb.c | 18 +++++- + drivers/usb/dwc3/core.c | 52 ++++++++++++++++ + drivers/usb/dwc3/core.h | 10 ++++ + drivers/usb/dwc3/host.c | 17 ++++-- + 7 files changed, 153 insertions(+), 7 deletions(-) + +--- a/drivers/phy/broadcom/Kconfig ++++ b/drivers/phy/broadcom/Kconfig +@@ -93,7 +93,7 @@ config PHY_BRCM_SATA + + config PHY_BRCM_USB + tristate "Broadcom STB USB PHY driver" +- depends on ARCH_BCMBCA || ARCH_BRCMSTB || COMPILE_TEST ++ depends on ARCH_BCMBCA || ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST + depends on OF + select GENERIC_PHY + select SOC_BRCMSTB if ARCH_BRCMSTB +--- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c ++++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c +@@ -318,6 +318,36 @@ static void usb_init_common_7216(struct + usb_init_common(params); + } + ++static void usb_init_common_2712(struct brcm_usb_init_params *params) ++{ ++ void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; ++ void __iomem *bdc_ec = params->regs[BRCM_REGS_BDC_EC]; ++ u32 reg; ++ ++ if (params->syscon_piarbctl) ++ syscon_piarbctl_init(params->syscon_piarbctl); ++ ++ USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN); ++ ++ usb_wake_enable_7211b0(params, false); ++ ++ usb_init_common(params); ++ ++ /* ++ * The BDC controller will get occasional failures with ++ * the default "Read Transaction Size" of 6 (1024 bytes). ++ * Set it to 4 (256 bytes). ++ */ ++ if ((params->mode != USB_CTLR_MODE_HOST) && bdc_ec) { ++ reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA); ++ reg &= ~BDC_EC_AXIRDA_RTS_MASK; ++ reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT); ++ brcm_usb_writel(reg, bdc_ec + BDC_EC_AXIRDA); ++ } ++ ++ usb2_eye_fix_7211b0(params); ++} ++ + static void usb_init_xhci(struct brcm_usb_init_params *params) + { + pr_debug("%s\n", __func__); +@@ -363,6 +393,18 @@ static void usb_uninit_common_7211b0(str + + } + ++static void usb_uninit_common_2712(struct brcm_usb_init_params *params) ++{ ++ void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; ++ ++ if (params->wake_enabled) { ++ USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN); ++ usb_wake_enable_7211b0(params, true); ++ } else { ++ USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN); ++ } ++} ++ + static void usb_uninit_xhci(struct brcm_usb_init_params *params) + { + +@@ -417,6 +459,16 @@ static const struct brcm_usb_init_ops bc + .set_dual_select = usb_set_dual_select, + }; + ++static const struct brcm_usb_init_ops bcm2712_ops = { ++ .init_ipp = usb_init_ipp, ++ .init_common = usb_init_common_2712, ++ .init_xhci = usb_init_xhci, ++ .uninit_common = usb_uninit_common_2712, ++ .uninit_xhci = usb_uninit_xhci, ++ .get_dual_select = usb_get_dual_select, ++ .set_dual_select = usb_set_dual_select, ++}; ++ + void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params) + { + +@@ -434,3 +486,10 @@ void brcm_usb_dvr_init_7211b0(struct brc + params->family_name = "7211"; + params->ops = &bcm7211b0_ops; + } ++ ++void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params) ++{ ++ params->family_name = "2712"; ++ params->ops = &bcm2712_ops; ++ params->suspend_with_clocks = true; ++} +--- a/drivers/phy/broadcom/phy-brcm-usb-init.h ++++ b/drivers/phy/broadcom/phy-brcm-usb-init.h +@@ -61,12 +61,14 @@ struct brcm_usb_init_params { + const struct brcm_usb_init_ops *ops; + struct regmap *syscon_piarbctl; + bool wake_enabled; ++ bool suspend_with_clocks; + }; + + void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params); + void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params); + void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params); + void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params); ++void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params); + + static inline u32 brcm_usb_readl(void __iomem *addr) + { +--- a/drivers/phy/broadcom/phy-brcm-usb.c ++++ b/drivers/phy/broadcom/phy-brcm-usb.c +@@ -76,7 +76,7 @@ struct brcm_usb_phy_data { + }; + + static s8 *node_reg_names[BRCM_REGS_MAX] = { +- "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec" ++ "ctrl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec" + }; + + static int brcm_pm_notifier(struct notifier_block *notifier, +@@ -315,6 +315,18 @@ static const struct match_chip_info chip + .optional_reg = BRCM_REGS_BDC_EC, + }; + ++static const struct match_chip_info chip_info_2712 = { ++ .init_func = &brcm_usb_dvr_init_2712, ++ .required_regs = { ++ BRCM_REGS_CTRL, ++ BRCM_REGS_XHCI_EC, ++ BRCM_REGS_XHCI_GBL, ++ BRCM_REGS_USB_MDIO, ++ -1, ++ }, ++ .optional_reg = BRCM_REGS_BDC_EC, ++}; ++ + static const struct match_chip_info chip_info_7445 = { + .init_func = &brcm_usb_dvr_init_7445, + .required_regs = { +@@ -338,6 +350,10 @@ static const struct of_device_id brcm_us + .data = &chip_info_7211b0, + }, + { ++ .compatible = "brcm,bcm2712-usb-phy", ++ .data = &chip_info_2712, ++ }, ++ { + .compatible = "brcm,brcmstb-usb-phy", + .data = &chip_info_7445, + }, +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -1216,6 +1216,24 @@ static void dwc3_config_threshold(struct + } + } + ++static void dwc3_set_axi_pipe_limit(struct dwc3 *dwc) ++{ ++ struct device *dev = dwc->dev; ++ u32 cfg; ++ ++ if (!dwc->axi_pipe_limit) ++ return; ++ if (dwc->axi_pipe_limit > 16) { ++ dev_err(dev, "Invalid axi_pipe_limit property\n"); ++ return; ++ } ++ cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG1); ++ cfg &= ~DWC3_GSBUSCFG1_PIPETRANSLIMIT(15); ++ cfg |= DWC3_GSBUSCFG1_PIPETRANSLIMIT(dwc->axi_pipe_limit - 1); ++ ++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, cfg); ++} ++ + /** + * dwc3_core_init - Low-level initialization of DWC3 Core + * @dwc: Pointer to our controller context structure +@@ -1308,6 +1326,8 @@ static int dwc3_core_init(struct dwc3 *d + + dwc3_set_incr_burst_type(dwc); + ++ dwc3_set_axi_pipe_limit(dwc); ++ + usb_phy_set_suspend(dwc->usb2_phy, 0); + usb_phy_set_suspend(dwc->usb3_phy, 0); + ret = phy_power_on(dwc->usb2_generic_phy); +@@ -1541,6 +1561,7 @@ static void dwc3_get_properties(struct d + u8 tx_thr_num_pkt_prd = 0; + u8 tx_max_burst_prd = 0; + u8 tx_fifo_resize_max_num; ++ u8 axi_pipe_limit; + const char *usb_psy_name; + int ret; + +@@ -1563,6 +1584,9 @@ static void dwc3_get_properties(struct d + */ + tx_fifo_resize_max_num = 6; + ++ /* Default to 0 (don't override hardware defaults) */ ++ axi_pipe_limit = 0; ++ + dwc->maximum_speed = usb_get_maximum_speed(dev); + dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev); + dwc->dr_mode = usb_get_dr_mode(dev); +@@ -1678,6 +1702,9 @@ static void dwc3_get_properties(struct d + dwc->dis_split_quirk = device_property_read_bool(dev, + "snps,dis-split-quirk"); + ++ device_property_read_u8(dev, "snps,axi-pipe-limit", ++ &axi_pipe_limit); ++ + dwc->lpm_nyet_threshold = lpm_nyet_threshold; + dwc->tx_de_emphasis = tx_de_emphasis; + +@@ -1695,6 +1722,8 @@ static void dwc3_get_properties(struct d + dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd; + dwc->tx_max_burst_prd = tx_max_burst_prd; + ++ dwc->axi_pipe_limit = axi_pipe_limit; ++ + dwc->imod_interval = 0; + + dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num; +@@ -1903,6 +1932,12 @@ static int dwc3_probe(struct platform_de + + dwc3_get_properties(dwc); + ++ if (!dwc->sysdev_is_parent) { ++ ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64)); ++ if (ret) ++ return ret; ++ } ++ + dwc->reset = devm_reset_control_array_get_optional_shared(dev); + if (IS_ERR(dwc->reset)) { + ret = PTR_ERR(dwc->reset); +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -183,6 +183,9 @@ + #define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */ + #define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff + ++/* Global SoC Bus Configuration Register 1 */ ++#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n) (((n) & 0xf) << 8) ++ + /* Global Debug LSP MUX Select */ + #define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */ + #define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff) +@@ -1056,6 +1059,7 @@ struct dwc3_scratchpad_array { + * @tx_max_burst_prd: max periodic ESS transmit burst size + * @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize + * @clear_stall_protocol: endpoint number that requires a delayed status phase ++ * @axi_max_pipe: set to override the maximum number of pipelined AXI transfers + * @hsphy_interface: "utmi" or "ulpi" + * @connected: true when we're connected to a host, false otherwise + * @softconnect: true when gadget connect is called, false when disconnect runs +@@ -1287,6 +1291,7 @@ struct dwc3 { + u8 tx_max_burst_prd; + u8 tx_fifo_resize_max_num; + u8 clear_stall_protocol; ++ u8 axi_pipe_limit; + + const char *hsphy_interface; + +--- a/drivers/usb/dwc3/host.c ++++ b/drivers/usb/dwc3/host.c +@@ -30,10 +30,10 @@ static void dwc3_host_fill_xhci_irq_res( + + static int dwc3_host_get_irq(struct dwc3 *dwc) + { +- struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); ++ struct platform_device *pdev = to_platform_device(dwc->dev); + int irq; + +- irq = platform_get_irq_byname_optional(dwc3_pdev, "host"); ++ irq = platform_get_irq_byname_optional(pdev, "host"); + if (irq > 0) { + dwc3_host_fill_xhci_irq_res(dwc, irq, "host"); + goto out; +@@ -42,7 +42,7 @@ static int dwc3_host_get_irq(struct dwc3 + if (irq == -EPROBE_DEFER) + goto out; + +- irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3"); ++ irq = platform_get_irq_byname_optional(pdev, "dwc_usb3"); + if (irq > 0) { + dwc3_host_fill_xhci_irq_res(dwc, irq, "dwc_usb3"); + goto out; +@@ -51,7 +51,7 @@ static int dwc3_host_get_irq(struct dwc3 + if (irq == -EPROBE_DEFER) + goto out; + +- irq = platform_get_irq(dwc3_pdev, 0); ++ irq = platform_get_irq(pdev, 0); + if (irq > 0) { + dwc3_host_fill_xhci_irq_res(dwc, irq, NULL); + goto out; +@@ -66,16 +66,23 @@ out: + + int dwc3_host_init(struct dwc3 *dwc) + { ++ struct platform_device *pdev = to_platform_device(dwc->dev); + struct property_entry props[4]; + struct platform_device *xhci; + int ret, irq; + int prop_idx = 0; ++ int id; + + irq = dwc3_host_get_irq(dwc); + if (irq < 0) + return irq; + +- xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); ++ id = of_alias_get_id(pdev->dev.of_node, "usb"); ++ if (id >= 0) ++ xhci = platform_device_alloc("xhci-hcd", id); ++ else ++ xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); ++ + if (!xhci) { + dev_err(dwc->dev, "couldn't allocate xHCI device\n"); + return -ENOMEM; diff --git a/target/linux/bcm27xx/patches-6.1/950-0866-drm-panel-raspberrypi-touchscreen-Insert-more-delays.patch b/target/linux/bcm27xx/patches-6.1/950-0866-drm-panel-raspberrypi-touchscreen-Insert-more-delays.patch new file mode 100644 index 0000000000..a6f0c1961c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0866-drm-panel-raspberrypi-touchscreen-Insert-more-delays.patch @@ -0,0 +1,37 @@ +From 480c8e9f48f8a96c457eb3dc0079a73598fb7477 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Wed, 1 Dec 2021 19:43:08 +0000 +Subject: [PATCH] drm/panel/raspberrypi-touchscreen: Insert more delays. + +This avoids failures in cases where the panel is enabled +or re-probed very soon after being disabled or probed. +These can occur because the Atmel device can mis-behave +over I2C for a few ms after any write to the POWERON register. +--- + drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c ++++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +@@ -299,6 +299,13 @@ static int rpi_touchscreen_prepare(struc + struct rpi_touchscreen *ts = panel_to_ts(panel); + int i, data; + ++ /* ++ * Power up the Toshiba bridge. The Atmel device can misbehave ++ * over I2C for a few ms after writes to REG_POWERON (including the ++ * write in rpi_touchscreen_disable()), so sleep before and after. ++ * Also to ensure that the bridge has been off for at least 100ms. ++ */ ++ msleep(100); + rpi_touchscreen_i2c_write(ts, REG_POWERON, 1); + usleep_range(20000, 25000); + /* Wait for nPWRDWN to go low to indicate poweron is done. */ +@@ -431,6 +438,7 @@ static int rpi_touchscreen_probe(struct + + /* Turn off at boot, so we can cleanly sequence powering on. */ + rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); ++ usleep_range(20000, 25000); + + /* Look up the DSI host. It needs to probe before we do. */ + endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); diff --git a/target/linux/bcm27xx/patches-6.1/950-0867-PCI-brcmstb-Add-BCM2712-support.patch b/target/linux/bcm27xx/patches-6.1/950-0867-PCI-brcmstb-Add-BCM2712-support.patch new file mode 100644 index 0000000000..179d03733e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0867-PCI-brcmstb-Add-BCM2712-support.patch @@ -0,0 +1,1108 @@ +From 29702857d1ab71243ea6c247dfe9b5bc43dd422f Mon Sep 17 00:00:00 2001 +From: Jim Quinlan +Date: Fri, 23 Jun 2023 10:40:57 -0400 +Subject: [PATCH] PCI: brcmstb: Add BCM2712 support + +PCI: brcmstb: differing register offsets on 2712 + +pcie-brcmstb: Add 2712 bridge reset support + +pcie: 2712 PORT_MASK and rescal support + +pcie-brcmstb: don't alter the L1SS debug register + +For reasons unknown, this disables the reference clock + +pcie-brcmstb: fix BAR2 enable and window decode + +Set UBUS ACCESS_EN to let inbound DMA work. Also BCM2712 has grown +an index in the inbound window size decode register. + +PCIe: brcmstb: Enable support for 64 MSI-Xs + +Signed-off-by: Phil Elwell + +pcie-brcmstb: Suppress read error responses + +If the link is down or the EP fails to return a read completion, the +RC's default behaviour is to return an AXI error. This causes fatal +exceptions on A76, so it's better to respond with all 1s instead. + +pcie-brcmstb: increase UBUS timeout to cater for link retrain events + +pcie-brcmstb: Handle additional inbound regions + +Signed-off-by: Phil Elwell + +pcie-brcmstb: Add support for external MSI controller + +pcie-brcmstb: add a reasonable default traffic class to priority map + +BCM2712 supports multiple traffic classes (TCs) with independent +maximally sized transfer queues for each TC. Traffic classes have no +transaction ordering requirements between them, which facilitates +out-of-order completions and arbitration between posted writes for +data streams that have no dependence on each other. + +In addition to the above benefits of splitting endpoint traffic into +individual queues, priorities can be assigned to traffic classes by +a heuristic or deterministic mechanism. The heuristic elevates AXI +QOS priority in accordance with the number of pending transfers in +each TC's queue, but for true priority signalling a forwarding +mechanism using vendor-defined messages is implemented. + +Receipt of a 3 DWORD VDM assigns a priority tag to a TC on-the-fly, +and this tag corresponds to a configurable AXI QOS value. + +As a simple baseline, assign a linear map of AXI QOS to each tag. + +pcie: brcmstb: set up the VDM forwarding interface when setting up QoS + +pcie-brcmstb: add DT bindings for MPS-size Read Completion Mode + +This controller has an optional feature that allows read completion +TLPs to be sized up to the Maximum Packet Size of a configured link. + +This can exceed the Read Completion Boundary of 128B specified in +the PCIe specification, but depending on endpoint support may increase +link read bandwidth significantly. + +pcie-brcmstb: clean up debug messages + +pcie-brcmstb: fix BCM2712A0 PHY PM errata + +The power management clock is 54MHz not 50MHz, so adjust the PM clock period +to suit. Powering off the PHY PLL in L1.2 is unsafe, so force it on. + +pcie-brcmstb: set CLKREQ functionality according to link partner support + +The RC supports either L1 with clock PM or L1 sub-state control, not both +at the same time. Examine the link partner's capabilities to determine +which is the most suitable scheme to use. + +pcie: brcmstb: don't reset block bridges in suspend or removal cases + +BCM2712 has a single rescal block for all three root complexes, and +holding PCIE1's bridge in reset will hang the chip if a different +RC wants to access any of the rescal registers. + +pcie: brcmstb: guard 2712-specific setup with a RC type check + +BCM2711 doesn't implement the UBUS control registers. + +pcie: brcmstb: On 2712 keeping the PLL powered in L1.x is not required + +A separate misconfiguration when enabling SSC (the MDIO registers no +longer do the same thing on BCM2712) had the side-effect of breaking +PLL powerdown and resume sequencing. + +Allow entry into a true L1.2 state where analogue is depowered. + +pcie: brcmstb: Fix reset warning on probe failure + +Signed-off-by: Phil Elwell + +bcm2712: pcie: adjust PHY PLL setup to use a 54MHz input refclk + +Use canned MDIO writes from Broadcom that switch the ref_clk output +pair to run from the internal fractional PLL, and set the internal PLL +to expect a 54MHz input reference clock. + +Gen3 operation is not guaranteed to be stable in this setup, so default +to gen2. + +This only works if the LCPLL is bypassed (requires latest bootloader). + +pcie: brcmstb: add missing register writes + +drivers: pcie: brcmstb: cater for BCM2712C0 bug dropping QoS on the floor + +The AXI QoS value extracted from the request fifo ends up as zero forever. +Disabling this means that "panic" signalling doesn't do anything useful, +but static priorites do work. + +Also align the selected TC:QoS map with RP1's expectations of service. + +Signed-off-by: Jonathan Bell + +drivers: pcie: brcmstb: shuffle TC priorities up to 8 + +Use the range 8-11 which puts the highest below HVS but leaves space +below for other 2712 masters. + +Signed-off-by: Jonathan Bell + +drivers: pcie: brcmstb: optionally enable QoS features by DT for BCM2712 + +It's a bad idea to universally enable "realtime" priorities for TCs +across all the RC instances on the chip. Endpoints other than RP1 may +make use of these, so you don't want e.g. NVMe descriptor fetches getting +higher priority than your remote display. + +Add two optional DT properties controlling the behaviour - FIFO-based +backpressure QoS or "message-based". Message-based signalling is +fundamentally broken due to a chip bug, so it collapses into a set of +static assignments that RP1 needs. + +The default if neither property is specified is to assign everything a +QoS of 0. + +Signed-off-by: Jonathan Bell + +drivers: pcie: brcmstb: adjust completion timeouts for bcm2712 + +Setting the RC config retry timeout makes CRS auto-polling work, but +the UBUS timeout will override the config retry. Both need to be large. + +Signed-off-by: Jonathan Bell +--- + drivers/pci/controller/pcie-brcmstb.c | 507 +++++++++++++++++++++++--- + 1 file changed, 458 insertions(+), 49 deletions(-) + +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -47,11 +48,25 @@ + #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc + #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 + ++#define PCIE_RC_TL_VDM_CTL0 0x0a20 ++#define PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK 0x10000 ++#define PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK 0x20000 ++#define PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK 0x40000 ++ ++#define PCIE_RC_TL_VDM_CTL1 0x0a0c ++#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID0_MASK 0x0000ffff ++#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID1_MASK 0xffff0000 ++ + #define PCIE_RC_DL_MDIO_ADDR 0x1100 + #define PCIE_RC_DL_MDIO_WR_DATA 0x1104 + #define PCIE_RC_DL_MDIO_RD_DATA 0x1108 + ++#define PCIE_RC_PL_PHY_CTL_15 0x184c ++#define PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK 0x400000 ++#define PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK 0xff ++ + #define PCIE_MISC_MISC_CTRL 0x4008 ++#define PCIE_MISC_MISC_CTRL_RCB_MPS_MODE_MASK 0x400 + #define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 + #define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 + #define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 +@@ -71,6 +86,7 @@ + + #define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c + #define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f ++#define PCIE_MISC_RC_BAR1_CONFIG_HI 0x4030 + + #define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034 + #define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f +@@ -78,6 +94,7 @@ + + #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c + #define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f ++#define PCIE_MISC_RC_BAR3_CONFIG_HI 0x4040 + + #define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044 + #define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 +@@ -86,12 +103,15 @@ + #define PCIE_MISC_MSI_DATA_CONFIG_VAL_32 0xffe06540 + #define PCIE_MISC_MSI_DATA_CONFIG_VAL_8 0xfff86540 + ++#define PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT 0x405c ++ + #define PCIE_MISC_PCIE_CTRL 0x4064 + #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 + #define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4 + + #define PCIE_MISC_PCIE_STATUS 0x4068 + #define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80 ++#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK_2712 0x40 + #define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20 + #define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10 + #define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40 +@@ -116,14 +136,73 @@ + #define PCIE_MEM_WIN0_LIMIT_HI(win) \ + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) + +-#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204 ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG pcie->reg_offsets[PCIE_HARD_DEBUG] + #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 + #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 + #define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000 + #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK 0x00200000 + ++#define PCIE_MISC_CTRL_1 0x40A0 ++#define PCIE_MISC_CTRL_1_OUTBOUND_TC_MASK 0xf ++#define PCIE_MISC_CTRL_1_OUTBOUND_NO_SNOOP_MASK BIT(3) ++#define PCIE_MISC_CTRL_1_OUTBOUND_RO_MASK BIT(4) ++#define PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK BIT(5) ++ ++#define PCIE_MISC_UBUS_CTRL 0x40a4 ++#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK BIT(13) ++#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK BIT(19) ++ ++#define PCIE_MISC_UBUS_TIMEOUT 0x40A8 ++ ++#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP 0x40ac ++#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK BIT(0) ++#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI 0x40b0 ++ ++#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP 0x40b4 ++#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK BIT(0) ++ ++/* Additional RC BARs */ ++#define PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK 0x1f ++#define PCIE_MISC_RC_BAR4_CONFIG_LO 0x40d4 ++#define PCIE_MISC_RC_BAR4_CONFIG_HI 0x40d8 ++/* ... */ ++#define PCIE_MISC_RC_BAR10_CONFIG_LO 0x4104 ++#define PCIE_MISC_RC_BAR10_CONFIG_HI 0x4108 ++ ++#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE 0x1 ++#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK 0xfffff000 ++#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK 0xff ++#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO 0x410c ++#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI 0x4110 ++/* ... */ ++#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_LO 0x413c ++#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_HI 0x4140 ++ ++/* AXI priority forwarding - automatic level-based */ ++#define PCIE_MISC_TC_QUEUE_TO_QOS_MAP(x) (0x4160 - (x) * 4) ++/* Defined in quarter-fullness */ ++#define QUEUE_THRESHOLD_34_TO_QOS_MAP_SHIFT 12 ++#define QUEUE_THRESHOLD_23_TO_QOS_MAP_SHIFT 8 ++#define QUEUE_THRESHOLD_12_TO_QOS_MAP_SHIFT 4 ++#define QUEUE_THRESHOLD_01_TO_QOS_MAP_SHIFT 0 ++#define QUEUE_THRESHOLD_MASK 0xf ++ ++/* VDM messages indexing TCs to AXI priorities */ ++/* Indexes 8-15 */ ++#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI 0x4164 ++/* Indexes 0-7 */ ++#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO 0x4168 ++#define VDM_PRIORITY_TO_QOS_MAP_SHIFT(x) (4 * (x)) ++#define VDM_PRIORITY_TO_QOS_MAP_MASK 0xf ++ ++#define PCIE_MISC_AXI_INTF_CTRL 0x416C ++#define AXI_REQFIFO_EN_QOS_PROPAGATION BIT(7) ++#define AXI_BRIDGE_LOW_LATENCY_MODE BIT(6) ++#define AXI_MASTER_MAX_OUTSTANDING_REQUESTS_MASK 0x3f + +-#define PCIE_INTR2_CPU_BASE 0x4300 ++#define PCIE_MISC_AXI_READ_ERROR_DATA 0x4170 ++ ++#define PCIE_INTR2_CPU_BASE (pcie->reg_offsets[INTR2_CPU]) + #define PCIE_MSI_INTR2_BASE 0x4500 + /* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */ + #define MSI_INT_STATUS 0x0 +@@ -197,6 +276,8 @@ enum { + RGR1_SW_INIT_1, + EXT_CFG_INDEX, + EXT_CFG_DATA, ++ PCIE_HARD_DEBUG, ++ INTR2_CPU, + }; + + enum { +@@ -211,6 +292,7 @@ enum pcie_type { + BCM4908, + BCM7278, + BCM2711, ++ BCM2712, + }; + + struct pcie_cfg_data { +@@ -218,6 +300,7 @@ struct pcie_cfg_data { + const enum pcie_type type; + void (*perst_set)(struct brcm_pcie *pcie, u32 val); + void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val); ++ bool (*rc_mode)(struct brcm_pcie *pcie); + }; + + struct subdev_regulators { +@@ -234,7 +317,7 @@ struct brcm_msi { + struct mutex lock; /* guards the alloc/free operations */ + u64 target_addr; + int irq; +- DECLARE_BITMAP(used, BRCM_INT_PCI_MSI_NR); ++ DECLARE_BITMAP(used, 64); + bool legacy; + /* Some chips have MSIs in bits [31..24] of a shared register. */ + int legacy_shift; +@@ -251,6 +334,7 @@ struct brcm_pcie { + struct device_node *np; + bool ssc; + bool l1ss; ++ bool rcb_mps_mode; + int gen; + u64 msi_target_addr; + struct brcm_msi *msi; +@@ -258,11 +342,14 @@ struct brcm_pcie { + enum pcie_type type; + struct reset_control *rescal; + struct reset_control *perst_reset; ++ struct reset_control *bridge_reset; + int num_memc; + u64 memc_size[PCIE_BRCM_MAX_MEMC]; + u32 hw_rev; ++ u32 qos_map; + void (*perst_set)(struct brcm_pcie *pcie, u32 val); + void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val); ++ bool (*rc_mode)(struct brcm_pcie *pcie); + struct subdev_regulators *sr; + bool ep_wakeup_capable; + }; +@@ -283,8 +370,8 @@ static int brcm_pcie_encode_ibar_size(u6 + if (log2_in >= 12 && log2_in <= 15) + /* Covers 4KB to 32KB (inclusive) */ + return (log2_in - 12) + 0x1c; +- else if (log2_in >= 16 && log2_in <= 35) +- /* Covers 64KB to 32GB, (inclusive) */ ++ else if (log2_in >= 16 && log2_in <= 36) ++ /* Covers 64KB to 64GB, (inclusive) */ + return log2_in - 15; + /* Something is awry so disable */ + return 0; +@@ -381,6 +468,35 @@ static int brcm_pcie_set_ssc(struct brcm + return ssc && pll ? 0 : -EIO; + } + ++static void brcm_pcie_munge_pll(struct brcm_pcie *pcie) ++{ ++ //print "MDIO block 0x1600 written per Dannys instruction" ++ //tmp = pcie_mdio_write(phyad, &h16&, &h50b9&) ++ //tmp = pcie_mdio_write(phyad, &h17&, &hbd1a&) ++ //tmp = pcie_mdio_write(phyad, &h1b&, &h5030&) ++ //tmp = pcie_mdio_write(phyad, &h1e&, &h0007&) ++ ++ u32 tmp; ++ int ret, i; ++ u8 regs[] = { 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1e }; ++ u16 data[] = { 0x50b9, 0xbda1, 0x0094, 0x97b4, 0x5030, 0x5030, 0x0007 }; ++ ++ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET, ++ 0x1600); ++ for (i = 0; i < ARRAY_SIZE(regs); i++) { ++ brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regs[i], &tmp); ++ dev_dbg(pcie->dev, "PCIE MDIO pre_refclk 0x%02x = 0x%04x\n", ++ regs[i], tmp); ++ } ++ for (i = 0; i < ARRAY_SIZE(regs); i++) { ++ brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, regs[i], data[i]); ++ brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regs[i], &tmp); ++ dev_dbg(pcie->dev, "PCIE MDIO post_refclk 0x%02x = 0x%04x\n", ++ regs[i], tmp); ++ } ++ usleep_range(100, 200); ++} ++ + /* Limits operation to a specific generation (1, 2, or 3) */ + static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen) + { +@@ -438,6 +554,97 @@ static void brcm_pcie_set_outbound_win(s + writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); + } + ++static void brcm_pcie_set_tc_qos(struct brcm_pcie *pcie) ++{ ++ int i; ++ u32 reg; ++ ++ if (pcie->type != BCM2712) ++ return; ++ ++ /* XXX: BCM2712C0 is broken, disable the forwarding search */ ++ reg = readl(pcie->base + PCIE_MISC_AXI_INTF_CTRL); ++ reg &= ~AXI_REQFIFO_EN_QOS_PROPAGATION; ++ writel(reg, pcie->base + PCIE_MISC_AXI_INTF_CTRL); ++ ++ /* Disable VDM reception by default - QoS map defaults to 0 */ ++ reg = readl(pcie->base + PCIE_MISC_CTRL_1); ++ reg &= ~PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK; ++ writel(reg, pcie->base + PCIE_MISC_CTRL_1); ++ ++ if (!of_property_read_u32(pcie->np, "brcm,fifo-qos-map", &pcie->qos_map)) { ++ /* ++ * Backpressure mode - bottom 4 nibbles are QoS for each ++ * quartile of FIFO level. Each TC gets the same map, because ++ * this mode is intended for nonrealtime EPs. ++ */ ++ ++ pcie->qos_map &= 0x0000ffff; ++ for (i = 0; i < 8; i++) ++ writel(pcie->qos_map, pcie->base + PCIE_MISC_TC_QUEUE_TO_QOS_MAP(i)); ++ ++ return; ++ } ++ ++ if (!of_property_read_u32(pcie->np, "brcm,vdm-qos-map", &pcie->qos_map)) { ++ ++ reg = readl(pcie->base + PCIE_MISC_CTRL_1); ++ reg |= PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK; ++ writel(reg, pcie->base + PCIE_MISC_CTRL_1); ++ ++ /* No forwarding means no point separating panic priorities from normal */ ++ writel(pcie->qos_map, pcie->base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO); ++ writel(pcie->qos_map, pcie->base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI); ++ ++ /* Match Vendor ID of 0 */ ++ writel(0, pcie->base + PCIE_RC_TL_VDM_CTL1); ++ /* Forward VDMs to priority interface - at least the rx counters work */ ++ reg = readl(pcie->base + PCIE_RC_TL_VDM_CTL0); ++ reg |= PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK | ++ PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK | ++ PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK; ++ writel(reg, pcie->base + PCIE_RC_TL_VDM_CTL0); ++ } ++} ++ ++static void brcm_pcie_config_clkreq(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); ++ int domain = pci_domain_nr(bridge->bus); ++ const struct pci_bus *bus = pci_find_bus(domain, 1); ++ struct pci_dev *pdev = (struct pci_dev *)bus->devices.next; ++ u32 tmp, link_cap = 0; ++ u16 link_ctl = 0; ++ int clkpm = 0; ++ int substates = 0; ++ ++ pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); ++ if ((link_cap & PCI_EXP_LNKCAP_CLKPM)) ++ clkpm = 1; ++ ++ pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctl); ++ if (!(link_ctl & PCI_EXP_LNKCTL_CLKREQ_EN)) ++ clkpm = 0; ++ ++ if (pcie->l1ss && pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS)) ++ substates = 1; ++ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; ++ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK; ++ ++ if (substates) ++ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK; ++ else if (clkpm) ++ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; ++ ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ ++ if (substates || clkpm) ++ dev_info(pcie->dev, "clkreq control enabled\n"); ++} ++ + static struct irq_chip brcm_msi_irq_chip = { + .name = "BRCM STB PCIe MSI", + .irq_ack = irq_chip_ack_parent, +@@ -455,7 +662,7 @@ static struct msi_domain_info brcm_msi_d + static void brcm_pcie_msi_isr(struct irq_desc *desc) + { + struct irq_chip *chip = irq_desc_get_chip(desc); +- unsigned long status; ++ unsigned long status, virq; + struct brcm_msi *msi; + struct device *dev; + u32 bit; +@@ -467,10 +674,22 @@ static void brcm_pcie_msi_isr(struct irq + status = readl(msi->intr_base + MSI_INT_STATUS); + status >>= msi->legacy_shift; + +- for_each_set_bit(bit, &status, msi->nr) { +- int ret; +- ret = generic_handle_domain_irq(msi->inner_domain, bit); +- if (ret) ++ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR/*msi->nr*/) { ++ bool found = false; ++ ++ virq = irq_find_mapping(msi->inner_domain, bit); ++ if (virq) { ++ found = true; ++ dev_dbg(dev, "MSI -> %ld\n", virq); ++ generic_handle_irq(virq); ++ } ++ virq = irq_find_mapping(msi->inner_domain, bit + 32); ++ if (virq) { ++ found = true; ++ dev_dbg(dev, "MSI -> %ld\n", virq); ++ generic_handle_irq(virq); ++ } ++ if (!found) + dev_dbg(dev, "unexpected MSI\n"); + } + +@@ -483,7 +702,7 @@ static void brcm_msi_compose_msi_msg(str + + msg->address_lo = lower_32_bits(msi->target_addr); + msg->address_hi = upper_32_bits(msi->target_addr); +- msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | data->hwirq; ++ msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | (data->hwirq & 0x1f); + } + + static int brcm_msi_set_affinity(struct irq_data *irq_data, +@@ -495,7 +714,7 @@ static int brcm_msi_set_affinity(struct + static void brcm_msi_ack_irq(struct irq_data *data) + { + struct brcm_msi *msi = irq_data_get_irq_chip_data(data); +- const int shift_amt = data->hwirq + msi->legacy_shift; ++ const int shift_amt = (data->hwirq & 0x1f) + msi->legacy_shift; + + writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR); + } +@@ -653,7 +872,7 @@ static int brcm_pcie_enable_msi(struct b + msi->legacy_shift = 24; + } else { + msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE; +- msi->nr = BRCM_INT_PCI_MSI_NR; ++ msi->nr = 64; //BRCM_INT_PCI_MSI_NR; + msi->legacy_shift = 0; + } + +@@ -670,7 +889,7 @@ static int brcm_pcie_enable_msi(struct b + } + + /* The controller is capable of serving in both RC and EP roles */ +-static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) ++static bool brcm_pcie_rc_mode_generic(struct brcm_pcie *pcie) + { + void __iomem *base = pcie->base; + u32 val = readl(base + PCIE_MISC_PCIE_STATUS); +@@ -678,6 +897,14 @@ static bool brcm_pcie_rc_mode(struct brc + return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val); + } + ++static bool brcm_pcie_rc_mode_2712(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ u32 val = readl(base + PCIE_MISC_PCIE_STATUS); ++ ++ return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK_2712, val) | 1; //XXX ++} ++ + static bool brcm_pcie_link_up(struct brcm_pcie *pcie) + { + u32 val = readl(pcie->base + PCIE_MISC_PCIE_STATUS); +@@ -749,6 +976,18 @@ static inline void brcm_pcie_bridge_sw_i + writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); + } + ++static inline void brcm_pcie_bridge_sw_init_set_2712(struct brcm_pcie *pcie, u32 val) ++{ ++ if (WARN_ONCE(!pcie->bridge_reset, ++ "missing bridge reset controller\n")) ++ return; ++ ++ if (val) ++ reset_control_assert(pcie->bridge_reset); ++ else ++ reset_control_deassert(pcie->bridge_reset); ++} ++ + static inline void brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, u32 val) + { + if (WARN_ONCE(!pcie->perst_reset, "missing PERST# reset controller\n")) +@@ -770,6 +1009,16 @@ static inline void brcm_pcie_perst_set_7 + writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL); + } + ++static inline void brcm_pcie_perst_set_2712(struct brcm_pcie *pcie, u32 val) ++{ ++ u32 tmp; ++ ++ /* Perst bit has moved and assert value is 0 */ ++ tmp = readl(pcie->base + PCIE_MISC_PCIE_CTRL); ++ u32p_replace_bits(&tmp, !val, PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK); ++ writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL); ++} ++ + static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val) + { + u32 tmp; +@@ -796,6 +1045,8 @@ static inline int brcm_pcie_get_rc_bar2_ + size += entry->res->end - entry->res->start + 1; + if (pcie_beg < lowest_pcie_addr) + lowest_pcie_addr = pcie_beg; ++ if (pcie->type == BCM2711 || pcie->type == BCM2712) ++ break; // Only consider the first entry + } + + if (lowest_pcie_addr == ~(u64)0) { +@@ -866,6 +1117,30 @@ static inline int brcm_pcie_get_rc_bar2_ + return 0; + } + ++static int brcm_pcie_get_rc_bar_n(struct brcm_pcie *pcie, ++ int idx, ++ u64 *rc_bar_cpu, ++ u64 *rc_bar_size, ++ u64 *rc_bar_pci) ++{ ++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); ++ struct resource_entry *entry; ++ int i = 0; ++ ++ resource_list_for_each_entry(entry, &bridge->dma_ranges) { ++ if (i == idx) { ++ *rc_bar_cpu = entry->res->start; ++ *rc_bar_size = entry->res->end - entry->res->start + 1; ++ *rc_bar_pci = entry->res->start - entry->offset; ++ return 0; ++ } ++ ++ i++; ++ } ++ ++ return -EINVAL; ++} ++ + static int brcm_pcie_setup(struct brcm_pcie *pcie) + { + u64 rc_bar2_offset, rc_bar2_size; +@@ -874,11 +1149,14 @@ static int brcm_pcie_setup(struct brcm_p + struct resource_entry *entry; + u32 tmp, burst, aspm_support; + int num_out_wins = 0; +- int ret, memc; ++ int ret, memc, count, i; + + /* Reset the bridge */ + pcie->bridge_sw_init_set(pcie, 1); +- pcie->perst_set(pcie, 1); ++ ++ /* Ensure that PERST# is asserted; some bootloaders may deassert it. */ ++ if (pcie->type == BCM2711) ++ pcie->perst_set(pcie, 1); + + usleep_range(100, 200); + +@@ -894,6 +1172,17 @@ static int brcm_pcie_setup(struct brcm_p + /* Wait for SerDes to be stable */ + usleep_range(100, 200); + ++ if (pcie->type == BCM2712) { ++ /* Allow a 54MHz (xosc) refclk source */ ++ brcm_pcie_munge_pll(pcie); ++ /* Fix for L1SS errata */ ++ tmp = readl(base + PCIE_RC_PL_PHY_CTL_15); ++ tmp &= ~PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK; ++ /* PM clock period is 18.52ns (round down) */ ++ tmp |= 0x12; ++ writel(tmp, base + PCIE_RC_PL_PHY_CTL_15); ++ } ++ + /* + * SCB_MAX_BURST_SIZE is a two bit field. For GENERIC chips it + * is encoded as 0=128, 1=256, 2=512, 3=Rsvd, for BCM7278 it +@@ -903,18 +1192,25 @@ static int brcm_pcie_setup(struct brcm_p + burst = 0x1; /* 256 bytes */ + else if (pcie->type == BCM2711) + burst = 0x0; /* 128 bytes */ ++ else if (pcie->type == BCM2712) ++ burst = 0x1; /* 128 bytes */ + else if (pcie->type == BCM7278) + burst = 0x3; /* 512 bytes */ + else + burst = 0x2; /* 512 bytes */ + +- /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */ ++ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN, RCB_MPS_MODE */ + tmp = readl(base + PCIE_MISC_MISC_CTRL); + u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK); + u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); + u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); ++ if (pcie->rcb_mps_mode) ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_RCB_MPS_MODE_MASK); ++ dev_info(pcie->dev, "setting SCB_ACCESS_EN, READ_UR_MODE, MAX_BURST_SIZE\n"); + writel(tmp, base + PCIE_MISC_MISC_CTRL); + ++ brcm_pcie_set_tc_qos(pcie); ++ + ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size, + &rc_bar2_offset); + if (ret) +@@ -927,7 +1223,11 @@ static int brcm_pcie_setup(struct brcm_p + writel(upper_32_bits(rc_bar2_offset), + base + PCIE_MISC_RC_BAR2_CONFIG_HI); + ++ tmp = readl(base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK); ++ writel(tmp, base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP); + tmp = readl(base + PCIE_MISC_MISC_CTRL); ++ + for (memc = 0; memc < pcie->num_memc; memc++) { + u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15; + +@@ -938,8 +1238,32 @@ static int brcm_pcie_setup(struct brcm_p + else if (memc == 2) + u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2)); + } ++ + writel(tmp, base + PCIE_MISC_MISC_CTRL); + ++ if (pcie->type == BCM2712) { ++ /* Suppress AXI error responses and return 1s for read failures */ ++ tmp = readl(base + PCIE_MISC_UBUS_CTRL); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK); ++ writel(tmp, base + PCIE_MISC_UBUS_CTRL); ++ writel(0xffffffff, base + PCIE_MISC_AXI_READ_ERROR_DATA); ++ ++ /* ++ * Adjust timeouts. The UBUS timeout also affects CRS ++ * completion retries, as the request will get terminated if ++ * either timeout expires, so both have to be a large value ++ * (in clocks of 750MHz). ++ * Set UBUS timeout to 250ms, then set RC config retry timeout ++ * to be ~240ms. ++ * ++ * Setting CRSVis=1 will stop the core from blocking on a CRS ++ * response, but does require the device to be well-behaved... ++ */ ++ writel(0xB2D0000, base + PCIE_MISC_UBUS_TIMEOUT); ++ writel(0xABA0000, base + PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT); ++ } ++ + /* + * We ideally want the MSI target address to be located in the 32bit + * addressable memory area. Some devices might depend on it. This is +@@ -952,7 +1276,7 @@ static int brcm_pcie_setup(struct brcm_p + else + pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; + +- if (!brcm_pcie_rc_mode(pcie)) { ++ if (!pcie->rc_mode(pcie)) { + dev_err(pcie->dev, "PCIe RC controller misconfigured as Endpoint\n"); + return -EINVAL; + } +@@ -976,6 +1300,38 @@ static int brcm_pcie_setup(struct brcm_p + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); + writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); + ++ /* program additional inbound windows (RC_BAR4..RC_BAR10) */ ++ count = (pcie->type == BCM2712) ? 7 : 0; ++ for (i = 0; i < count; i++) { ++ u64 bar_cpu, bar_size, bar_pci; ++ ++ ret = brcm_pcie_get_rc_bar_n(pcie, 1 + i, &bar_cpu, &bar_size, ++ &bar_pci); ++ if (ret) ++ break; ++ ++ tmp = lower_32_bits(bar_pci); ++ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(bar_size), ++ PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK); ++ writel(tmp, base + PCIE_MISC_RC_BAR4_CONFIG_LO + i * 8); ++ writel(upper_32_bits(bar_pci), ++ base + PCIE_MISC_RC_BAR4_CONFIG_HI + i * 8); ++ ++ tmp = upper_32_bits(bar_cpu) & ++ PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK; ++ writel(tmp, ++ base + PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI + i * 8); ++ tmp = lower_32_bits(bar_cpu) & ++ PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK; ++ writel(tmp | PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE, ++ base + PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO + i * 8); ++ } ++ ++ if (pcie->gen) { ++ dev_info(pcie->dev, "Forcing gen %d\n", pcie->gen); ++ brcm_pcie_set_gen(pcie, pcie->gen); ++ } ++ + /* + * For config space accesses on the RC, show the right class for + * a PCIe-PCIe bridge (the default setting is to be EP mode). +@@ -1031,7 +1387,6 @@ static int brcm_pcie_start_link(struct b + void __iomem *base = pcie->base; + u16 nlw, cls, lnksta; + bool ssc_good = false; +- u32 tmp; + int ret, i; + + /* Unassert the fundamental reset */ +@@ -1067,6 +1422,7 @@ static int brcm_pcie_start_link(struct b + dev_err(dev, "failed attempt to enter ssc mode\n"); + } + ++ + lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA); + cls = FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta); + nlw = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta); +@@ -1074,27 +1430,6 @@ static int brcm_pcie_start_link(struct b + pci_speed_string(pcie_link_speed[cls]), nlw, + ssc_good ? "(SSC)" : "(!SSC)"); + +- tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); +- if (pcie->l1ss) { +- /* +- * Enable CLKREQ# signalling include L1 Substate control of +- * the CLKREQ# signal and the external reference clock buffer. +- * meet requirement for Endpoints that require CLKREQ# +- * assertion to clock active within 400ns. +- */ +- tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; +- tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK; +- } else { +- /* +- * Refclk from RC should be gated with CLKREQ# input when +- * ASPM L0s,L1 is enabled => setting the CLKREQ_DEBUG_ENABLE +- * field to 1. +- */ +- tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK; +- tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; +- } +- writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); +- + return 0; + } + +@@ -1202,6 +1537,7 @@ static void brcm_pcie_enter_l23(struct b + + static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start) + { ++#if 0 + static const u32 shifts[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = { + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT, + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT, +@@ -1234,6 +1570,9 @@ static int brcm_phy_cntl(struct brcm_pci + dev_err(pcie->dev, "failed to %s phy\n", (start ? "start" : "stop")); + + return ret; ++#else ++ return 0; ++#endif + } + + static inline int brcm_phy_start(struct brcm_pcie *pcie) +@@ -1266,6 +1605,12 @@ static void brcm_pcie_turn_off(struct br + u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); + writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); + ++ /* ++ * Shutting down this bridge on pcie1 means accesses to rescal block ++ * will hang the chip if another RC wants to assert/deassert rescal. ++ */ ++ if (pcie->type == BCM2712) ++ return; + /* Shutdown PCIe bridge */ + pcie->bridge_sw_init_set(pcie, 1); + } +@@ -1296,9 +1641,9 @@ static int brcm_pcie_suspend_noirq(struc + if (brcm_phy_stop(pcie)) + dev_err(dev, "Could not stop phy for suspend\n"); + +- ret = reset_control_rearm(pcie->rescal); ++ ret = reset_control_assert(pcie->rescal); + if (ret) { +- dev_err(dev, "Could not rearm rescal reset\n"); ++ dev_err(dev, "Could not assert rescal reset\n"); + return ret; + } + +@@ -1393,7 +1738,7 @@ err_regulator: + if (pcie->sr) + regulator_bulk_disable(pcie->sr->num_supplies, pcie->sr->supplies); + err_reset: +- reset_control_rearm(pcie->rescal); ++ reset_control_assert(pcie->rescal); + err_disable_clk: + clk_disable_unprepare(pcie->clk); + return ret; +@@ -1405,8 +1750,8 @@ static void __brcm_pcie_remove(struct br + brcm_pcie_turn_off(pcie); + if (brcm_phy_stop(pcie)) + dev_err(pcie->dev, "Could not stop phy\n"); +- if (reset_control_rearm(pcie->rescal)) +- dev_err(pcie->dev, "Could not rearm rescal reset\n"); ++ if (reset_control_assert(pcie->rescal)) ++ dev_err(pcie->dev, "Could not assert rescal reset\n"); + clk_disable_unprepare(pcie->clk); + } + +@@ -1426,12 +1771,16 @@ static const int pcie_offsets[] = { + [RGR1_SW_INIT_1] = 0x9210, + [EXT_CFG_INDEX] = 0x9000, + [EXT_CFG_DATA] = 0x9004, ++ [PCIE_HARD_DEBUG] = 0x4204, ++ [INTR2_CPU] = 0x4300, + }; + + static const int pcie_offsets_bmips_7425[] = { + [RGR1_SW_INIT_1] = 0x8010, + [EXT_CFG_INDEX] = 0x8300, + [EXT_CFG_DATA] = 0x8304, ++ [PCIE_HARD_DEBUG] = 0x4204, ++ [INTR2_CPU] = 0x4300, + }; + + static const struct pcie_cfg_data generic_cfg = { +@@ -1439,6 +1788,7 @@ static const struct pcie_cfg_data generi + .type = GENERIC, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, ++ .rc_mode = brcm_pcie_rc_mode_generic, + }; + + static const struct pcie_cfg_data bcm7425_cfg = { +@@ -1446,6 +1796,7 @@ static const struct pcie_cfg_data bcm742 + .type = BCM7425, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, ++ .rc_mode = brcm_pcie_rc_mode_generic, + }; + + static const struct pcie_cfg_data bcm7435_cfg = { +@@ -1460,12 +1811,15 @@ static const struct pcie_cfg_data bcm490 + .type = BCM4908, + .perst_set = brcm_pcie_perst_set_4908, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, ++ .rc_mode = brcm_pcie_rc_mode_generic, + }; + + static const int pcie_offset_bcm7278[] = { + [RGR1_SW_INIT_1] = 0xc010, + [EXT_CFG_INDEX] = 0x9000, + [EXT_CFG_DATA] = 0x9004, ++ [PCIE_HARD_DEBUG] = 0x4204, ++ [INTR2_CPU] = 0x4300, + }; + + static const struct pcie_cfg_data bcm7278_cfg = { +@@ -1473,6 +1827,7 @@ static const struct pcie_cfg_data bcm727 + .type = BCM7278, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278, ++ .rc_mode = brcm_pcie_rc_mode_generic, + }; + + static const struct pcie_cfg_data bcm2711_cfg = { +@@ -1480,10 +1835,27 @@ static const struct pcie_cfg_data bcm271 + .type = BCM2711, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, ++ .rc_mode = brcm_pcie_rc_mode_generic, ++}; ++ ++static const int pcie_offsets_bcm2712[] = { ++ [EXT_CFG_INDEX] = 0x9000, ++ [EXT_CFG_DATA] = 0x9004, ++ [PCIE_HARD_DEBUG] = 0x4304, ++ [INTR2_CPU] = 0x4400, ++}; ++ ++static const struct pcie_cfg_data bcm2712_cfg = { ++ .offsets = pcie_offsets_bcm2712, ++ .type = BCM2712, ++ .perst_set = brcm_pcie_perst_set_2712, ++ .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_2712, ++ .rc_mode = brcm_pcie_rc_mode_2712, + }; + + static const struct of_device_id brcm_pcie_match[] = { + { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg }, ++ { .compatible = "brcm,bcm2712-pcie", .data = &bcm2712_cfg }, + { .compatible = "brcm,bcm4908-pcie", .data = &bcm4908_cfg }, + { .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg }, + { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg }, +@@ -1524,7 +1896,7 @@ static int brcm_pcie_probe(struct platfo + + data = of_device_get_match_data(&pdev->dev); + if (!data) { +- pr_err("failed to look up compatible string\n"); ++ dev_err(&pdev->dev, "failed to look up compatible string\n"); + return -EINVAL; + } + +@@ -1535,6 +1907,7 @@ static int brcm_pcie_probe(struct platfo + pcie->type = data->type; + pcie->perst_set = data->perst_set; + pcie->bridge_sw_init_set = data->bridge_sw_init_set; ++ pcie->rc_mode = data->rc_mode; + + pcie->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pcie->base)) +@@ -1549,6 +1922,7 @@ static int brcm_pcie_probe(struct platfo + + pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc"); + pcie->l1ss = of_property_read_bool(np, "brcm,enable-l1ss"); ++ pcie->rcb_mps_mode = of_property_read_bool(np, "brcm,enable-mps-rcb"); + + ret = clk_prepare_enable(pcie->clk); + if (ret) { +@@ -1565,14 +1939,20 @@ static int brcm_pcie_probe(struct platfo + clk_disable_unprepare(pcie->clk); + return PTR_ERR(pcie->perst_reset); + } ++ pcie->bridge_reset = ++ devm_reset_control_get_optional_exclusive(&pdev->dev, "bridge"); ++ if (IS_ERR(pcie->bridge_reset)) { ++ clk_disable_unprepare(pcie->clk); ++ return PTR_ERR(pcie->bridge_reset); ++ } + +- ret = reset_control_reset(pcie->rescal); ++ ret = reset_control_deassert(pcie->rescal); + if (ret) + dev_err(&pdev->dev, "failed to deassert 'rescal'\n"); + + ret = brcm_phy_start(pcie); + if (ret) { +- reset_control_rearm(pcie->rescal); ++ reset_control_assert(pcie->rescal); + clk_disable_unprepare(pcie->clk); + return ret; + } +@@ -1595,6 +1975,33 @@ static int brcm_pcie_probe(struct platfo + dev_err(pcie->dev, "probe of internal MSI failed"); + goto fail; + } ++ } else if (pci_msi_enabled() && msi_np != pcie->np) { ++ /* Use RC_BAR1 for MIP access */ ++ u64 msi_pci_addr; ++ u64 msi_phys_addr; ++ ++ if (of_property_read_u64(msi_np, "brcm,msi-pci-addr", &msi_pci_addr)) { ++ dev_err(pcie->dev, "Unable to find MSI PCI address\n"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ if (of_property_read_u64(msi_np, "reg", &msi_phys_addr)) { ++ dev_err(pcie->dev, "Unable to find MSI physical address\n"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ writel(lower_32_bits(msi_pci_addr) | brcm_pcie_encode_ibar_size(0x1000), ++ pcie->base + PCIE_MISC_RC_BAR1_CONFIG_LO); ++ writel(upper_32_bits(msi_pci_addr), ++ pcie->base + PCIE_MISC_RC_BAR1_CONFIG_HI); ++ ++ writel(lower_32_bits(msi_phys_addr) | ++ PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK, ++ pcie->base + PCIE_MISC_UBUS_BAR1_CONFIG_REMAP); ++ writel(upper_32_bits(msi_phys_addr), ++ pcie->base + PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI); + } + + bridge->ops = pcie->type == BCM7425 ? &brcm7425_pcie_ops : &brcm_pcie_ops; +@@ -1611,6 +2018,8 @@ static int brcm_pcie_probe(struct platfo + return ret; + } + ++ brcm_pcie_config_clkreq(pcie); ++ + return 0; + + fail: diff --git a/target/linux/bcm27xx/patches-6.1/950-0868-V4L2-Add-PiSP-opaque-formats-to-V4L2.patch b/target/linux/bcm27xx/patches-6.1/950-0868-V4L2-Add-PiSP-opaque-formats-to-V4L2.patch new file mode 100644 index 0000000000..3b50329ab1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0868-V4L2-Add-PiSP-opaque-formats-to-V4L2.patch @@ -0,0 +1,42 @@ +From 9a11300e46344917226b986a8740e7581d66adf3 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Mon, 7 Feb 2022 09:20:49 +0000 +Subject: [PATCH] V4L2: Add PiSP opaque formats to V4L2 + +Signed-off-by: Naushir Patuck +--- + drivers/media/v4l2-core/v4l2-ioctl.c | 4 +++- + include/uapi/linux/videodev2.h | 7 +++++++ + 2 files changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1452,7 +1452,9 @@ static void v4l_fill_fmtdesc(struct v4l2 + case V4L2_PIX_FMT_NV12M_10BE_8L128: descr = "10-bit NV12M (8x128 Linear, BE)"; break; + case V4L2_META_FMT_SENSOR_DATA: descr = "Sensor Ancillary Metadata"; break; + case V4L2_META_FMT_BCM2835_ISP_STATS: descr = "BCM2835 ISP Image Statistics"; break; +- case V4L2_META_FMT_RPI_BE_CFG: descr = "PiSP Config format"; break; ++ case V4L2_META_FMT_RPI_BE_CFG: descr = "PiSP BE Config format"; break; ++ case V4L2_META_FMT_RPI_FE_CFG: descr = "PiSP FE Config format"; break; ++ case V4L2_META_FMT_RPI_FE_STATS: descr = "PiSP FE Statistics format"; break; + + default: + /* Compressed formats */ +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -826,8 +826,15 @@ struct v4l2_pix_format { + #define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */ + + /* The metadata format identifier for our configuration buffers. */ ++/* The metadata format identifier for BE configuration buffers. */ + #define V4L2_META_FMT_RPI_BE_CFG v4l2_fourcc('R', 'P', 'B', 'C') + ++/* The metadata format identifier for FE configuration buffers. */ ++#define V4L2_META_FMT_RPI_FE_CFG v4l2_fourcc('R', 'P', 'F', 'C') ++ ++/* The metadata format identifier for FE configuration buffers. */ ++#define V4L2_META_FMT_RPI_FE_STATS v4l2_fourcc('R', 'P', 'F', 'S') ++ + /* priv field value to indicates that subsequent fields are valid. */ + #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe + diff --git a/target/linux/bcm27xx/patches-6.1/950-0869-V4L2-Add-PiSP-compressed-formats-to-V4L2.patch b/target/linux/bcm27xx/patches-6.1/950-0869-V4L2-Add-PiSP-compressed-formats-to-V4L2.patch new file mode 100644 index 0000000000..6836922b7c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0869-V4L2-Add-PiSP-compressed-formats-to-V4L2.patch @@ -0,0 +1,39 @@ +From 01f31f4145d49a30eb553c65ea755dde8dba1de0 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 2 Mar 2022 16:10:50 +0000 +Subject: [PATCH] V4L2: Add PiSP compressed formats to V4L2 + +Signed-off-by: Naushir Patuck +--- + drivers/media/v4l2-core/v4l2-ioctl.c | 4 ++++ + include/uapi/linux/videodev2.h | 6 +++++- + 2 files changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1507,6 +1507,10 @@ static void v4l_fill_fmtdesc(struct v4l2 + case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit Format"; break; + case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break; + case V4L2_PIX_FMT_RPI_BE: descr = "PiSP Opaque Format"; break; ++ case V4L2_PIX_FMT_PISP_COMP_RGGB: ++ case V4L2_PIX_FMT_PISP_COMP_GRBG: ++ case V4L2_PIX_FMT_PISP_COMP_GBRG: ++ case V4L2_PIX_FMT_PISP_COMP_BGGR: descr = "PiSP Bayer Compressed Format"; break; + default: + if (fmt->description[0]) + return; +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -794,7 +794,11 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_IPU3_SRGGB10 v4l2_fourcc('i', 'p', '3', 'r') /* IPU3 packed 10-bit RGGB bayer */ + + /* The pixel format for all our buffers (the precise format is found in the config buffer). */ +-#define V4L2_PIX_FMT_RPI_BE v4l2_fourcc('R', 'P', 'B', 'P') ++#define V4L2_PIX_FMT_RPI_BE v4l2_fourcc('R', 'P', 'B', 'P') ++#define V4L2_PIX_FMT_PISP_COMP_RGGB v4l2_fourcc('P', 'C', 'R', 'G') ++#define V4L2_PIX_FMT_PISP_COMP_GRBG v4l2_fourcc('P', 'C', 'G', 'R') ++#define V4L2_PIX_FMT_PISP_COMP_GBRG v4l2_fourcc('P', 'C', 'G', 'B') ++#define V4L2_PIX_FMT_PISP_COMP_BGGR v4l2_fourcc('P', 'C', 'B', 'G') + + /* SDR formats - used only for Software Defined Radio devices */ + #define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0871-dt-binding-mfd-Add-binding-for-Raspberry-Pi-RP1.patch b/target/linux/bcm27xx/patches-6.1/950-0871-dt-binding-mfd-Add-binding-for-Raspberry-Pi-RP1.patch new file mode 100644 index 0000000000..9e98dd0345 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0871-dt-binding-mfd-Add-binding-for-Raspberry-Pi-RP1.patch @@ -0,0 +1,249 @@ +From c93f469dabdbed822e5abeb5283d79fc9faa858c Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 28 Oct 2022 14:10:34 +0100 +Subject: [PATCH] dt-binding: mfd: Add binding for Raspberry Pi RP1 + +Signed-off-by: Phil Elwell +--- + include/dt-bindings/mfd/rp1.h | 235 ++++++++++++++++++++++++++++++++++ + 1 file changed, 235 insertions(+) + create mode 100644 include/dt-bindings/mfd/rp1.h + +--- /dev/null ++++ b/include/dt-bindings/mfd/rp1.h +@@ -0,0 +1,235 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This header provides constants for the PY MFD. ++ */ ++ ++#ifndef _RP1_H ++#define _RP1_H ++ ++/* Address map */ ++#define RP1_SYSINFO_BASE 0x000000 ++#define RP1_TBMAN_BASE 0x004000 ++#define RP1_SYSCFG_BASE 0x008000 ++#define RP1_OTP_BASE 0x00c000 ++#define RP1_POWER_BASE 0x010000 ++#define RP1_RESETS_BASE 0x014000 ++#define RP1_CLOCKS_BANK_DEFAULT_BASE 0x018000 ++#define RP1_CLOCKS_BANK_VIDEO_BASE 0x01c000 ++#define RP1_PLL_SYS_BASE 0x020000 ++#define RP1_PLL_AUDIO_BASE 0x024000 ++#define RP1_PLL_VIDEO_BASE 0x028000 ++#define RP1_UART0_BASE 0x030000 ++#define RP1_UART1_BASE 0x034000 ++#define RP1_UART2_BASE 0x038000 ++#define RP1_UART3_BASE 0x03c000 ++#define RP1_UART4_BASE 0x040000 ++#define RP1_UART5_BASE 0x044000 ++#define RP1_SPI8_BASE 0x04c000 ++#define RP1_SPI0_BASE 0x050000 ++#define RP1_SPI1_BASE 0x054000 ++#define RP1_SPI2_BASE 0x058000 ++#define RP1_SPI3_BASE 0x05c000 ++#define RP1_SPI4_BASE 0x060000 ++#define RP1_SPI5_BASE 0x064000 ++#define RP1_SPI6_BASE 0x068000 ++#define RP1_SPI7_BASE 0x06c000 ++#define RP1_I2C0_BASE 0x070000 ++#define RP1_I2C1_BASE 0x074000 ++#define RP1_I2C2_BASE 0x078000 ++#define RP1_I2C3_BASE 0x07c000 ++#define RP1_I2C4_BASE 0x080000 ++#define RP1_I2C5_BASE 0x084000 ++#define RP1_I2C6_BASE 0x088000 ++#define RP1_AUDIO_IN_BASE 0x090000 ++#define RP1_AUDIO_OUT_BASE 0x094000 ++#define RP1_PWM0_BASE 0x098000 ++#define RP1_PWM1_BASE 0x09c000 ++#define RP1_I2S0_BASE 0x0a0000 ++#define RP1_I2S1_BASE 0x0a4000 ++#define RP1_I2S2_BASE 0x0a8000 ++#define RP1_TIMER_BASE 0x0ac000 ++#define RP1_SDIO0_APBS_BASE 0x0b0000 ++#define RP1_SDIO1_APBS_BASE 0x0b4000 ++#define RP1_BUSFABRIC_MONITOR_BASE 0x0c0000 ++#define RP1_BUSFABRIC_AXISHIM_BASE 0x0c4000 ++#define RP1_ADC_BASE 0x0c8000 ++#define RP1_IO_BANK0_BASE 0x0d0000 ++#define RP1_IO_BANK1_BASE 0x0d4000 ++#define RP1_IO_BANK2_BASE 0x0d8000 ++#define RP1_SYS_RIO0_BASE 0x0e0000 ++#define RP1_SYS_RIO1_BASE 0x0e4000 ++#define RP1_SYS_RIO2_BASE 0x0e8000 ++#define RP1_PADS_BANK0_BASE 0x0f0000 ++#define RP1_PADS_BANK1_BASE 0x0f4000 ++#define RP1_PADS_BANK2_BASE 0x0f8000 ++#define RP1_PADS_ETH_BASE 0x0fc000 ++#define RP1_ETH_IP_BASE 0x100000 ++#define RP1_ETH_CFG_BASE 0x104000 ++#define RP1_PCIE_APBS_BASE 0x108000 ++#define RP1_MIPI0_CSIDMA_BASE 0x110000 ++#define RP1_MIPI0_CSIHOST_BASE 0x114000 ++#define RP1_MIPI0_DSIDMA_BASE 0x118000 ++#define RP1_MIPI0_DSIHOST_BASE 0x11c000 ++#define RP1_MIPI0_MIPICFG_BASE 0x120000 ++#define RP1_MIPI0_ISP_BASE 0x124000 ++#define RP1_MIPI1_CSIDMA_BASE 0x128000 ++#define RP1_MIPI1_CSIHOST_BASE 0x12c000 ++#define RP1_MIPI1_DSIDMA_BASE 0x130000 ++#define RP1_MIPI1_DSIHOST_BASE 0x134000 ++#define RP1_MIPI1_MIPICFG_BASE 0x138000 ++#define RP1_MIPI1_ISP_BASE 0x13c000 ++#define RP1_VIDEO_OUT_CFG_BASE 0x140000 ++#define RP1_VIDEO_OUT_VEC_BASE 0x144000 ++#define RP1_VIDEO_OUT_DPI_BASE 0x148000 ++#define RP1_XOSC_BASE 0x150000 ++#define RP1_WATCHDOG_BASE 0x154000 ++#define RP1_DMA_TICK_BASE 0x158000 ++#define RP1_SDIO_CLOCKS_BASE 0x15c000 ++#define RP1_USBHOST0_APBS_BASE 0x160000 ++#define RP1_USBHOST1_APBS_BASE 0x164000 ++#define RP1_ROSC0_BASE 0x168000 ++#define RP1_ROSC1_BASE 0x16c000 ++#define RP1_VBUSCTRL_BASE 0x170000 ++#define RP1_TICKS_BASE 0x174000 ++#define RP1_PIO_APBS_BASE 0x178000 ++#define RP1_SDIO0_AHBLS_BASE 0x180000 ++#define RP1_SDIO1_AHBLS_BASE 0x184000 ++#define RP1_DMA_BASE 0x188000 ++#define RP1_RAM_BASE 0x1c0000 ++#define RP1_RAM_SIZE 0x020000 ++#define RP1_USBHOST0_AXIS_BASE 0x200000 ++#define RP1_USBHOST1_AXIS_BASE 0x300000 ++#define RP1_EXAC_BASE 0x400000 ++ ++/* Interrupts */ ++ ++#define RP1_INT_IO_BANK0 0 ++#define RP1_INT_IO_BANK1 1 ++#define RP1_INT_IO_BANK2 2 ++#define RP1_INT_AUDIO_IN 3 ++#define RP1_INT_AUDIO_OUT 4 ++#define RP1_INT_PWM0 5 ++#define RP1_INT_ETH 6 ++#define RP1_INT_I2C0 7 ++#define RP1_INT_I2C1 8 ++#define RP1_INT_I2C2 9 ++#define RP1_INT_I2C3 10 ++#define RP1_INT_I2C4 11 ++#define RP1_INT_I2C5 12 ++#define RP1_INT_I2C6 13 ++#define RP1_INT_I2S0 14 ++#define RP1_INT_I2S1 15 ++#define RP1_INT_I2S2 16 ++#define RP1_INT_SDIO0 17 ++#define RP1_INT_SDIO1 18 ++#define RP1_INT_SPI0 19 ++#define RP1_INT_SPI1 20 ++#define RP1_INT_SPI2 21 ++#define RP1_INT_SPI3 22 ++#define RP1_INT_SPI4 23 ++#define RP1_INT_SPI5 24 ++#define RP1_INT_UART0 25 ++#define RP1_INT_TIMER_0 26 ++#define RP1_INT_TIMER_1 27 ++#define RP1_INT_TIMER_2 28 ++#define RP1_INT_TIMER_3 29 ++#define RP1_INT_USBHOST0 30 ++#define RP1_INT_USBHOST0_0 31 ++#define RP1_INT_USBHOST0_1 32 ++#define RP1_INT_USBHOST0_2 33 ++#define RP1_INT_USBHOST0_3 34 ++#define RP1_INT_USBHOST1 35 ++#define RP1_INT_USBHOST1_0 36 ++#define RP1_INT_USBHOST1_1 37 ++#define RP1_INT_USBHOST1_2 38 ++#define RP1_INT_USBHOST1_3 39 ++#define RP1_INT_DMA 40 ++#define RP1_INT_PWM1 41 ++#define RP1_INT_UART1 42 ++#define RP1_INT_UART2 43 ++#define RP1_INT_UART3 44 ++#define RP1_INT_UART4 45 ++#define RP1_INT_UART5 46 ++#define RP1_INT_MIPI0 47 ++#define RP1_INT_MIPI1 48 ++#define RP1_INT_VIDEO_OUT 49 ++#define RP1_INT_PIO_0 50 ++#define RP1_INT_PIO_1 51 ++#define RP1_INT_ADC_FIFO 52 ++#define RP1_INT_PCIE_OUT 53 ++#define RP1_INT_SPI6 54 ++#define RP1_INT_SPI7 55 ++#define RP1_INT_SPI8 56 ++#define RP1_INT_SYSCFG 58 ++#define RP1_INT_CLOCKS_DEFAULT 59 ++#define RP1_INT_VBUSCTRL 60 ++#define RP1_INT_PROC_MISC 57 ++#define RP1_INT_END 61 ++ ++/* DMA peripherals (for pacing) */ ++#define RP1_DMA_I2C0_RX 0x0 ++#define RP1_DMA_I2C0_TX 0x1 ++#define RP1_DMA_I2C1_RX 0x2 ++#define RP1_DMA_I2C1_TX 0x3 ++#define RP1_DMA_I2C2_RX 0x4 ++#define RP1_DMA_I2C2_TX 0x5 ++#define RP1_DMA_I2C3_RX 0x6 ++#define RP1_DMA_I2C3_TX 0x7 ++#define RP1_DMA_I2C4_RX 0x8 ++#define RP1_DMA_I2C4_TX 0x9 ++#define RP1_DMA_I2C5_RX 0xa ++#define RP1_DMA_I2C5_TX 0xb ++#define RP1_DMA_SPI0_RX 0xc ++#define RP1_DMA_SPI0_TX 0xd ++#define RP1_DMA_SPI1_RX 0xe ++#define RP1_DMA_SPI1_TX 0xf ++#define RP1_DMA_SPI2_RX 0x10 ++#define RP1_DMA_SPI2_TX 0x11 ++#define RP1_DMA_SPI3_RX 0x12 ++#define RP1_DMA_SPI3_TX 0x13 ++#define RP1_DMA_SPI4_RX 0x14 ++#define RP1_DMA_SPI4_TX 0x15 ++#define RP1_DMA_SPI5_RX 0x16 ++#define RP1_DMA_SPI5_TX 0x17 ++#define RP1_DMA_PWM0 0x18 ++#define RP1_DMA_UART0_RX 0x19 ++#define RP1_DMA_UART0_TX 0x1a ++#define RP1_DMA_AUDIO_IN_CH0 0x1b ++#define RP1_DMA_AUDIO_IN_CH1 0x1c ++#define RP1_DMA_AUDIO_OUT 0x1d ++#define RP1_DMA_PWM1 0x1e ++#define RP1_DMA_I2S0_RX 0x1f ++#define RP1_DMA_I2S0_TX 0x20 ++#define RP1_DMA_I2S1_RX 0x21 ++#define RP1_DMA_I2S1_TX 0x22 ++#define RP1_DMA_I2S2_RX 0x23 ++#define RP1_DMA_I2S2_TX 0x24 ++#define RP1_DMA_UART1_RX 0x25 ++#define RP1_DMA_UART1_TX 0x26 ++#define RP1_DMA_UART2_RX 0x27 ++#define RP1_DMA_UART2_TX 0x28 ++#define RP1_DMA_UART3_RX 0x29 ++#define RP1_DMA_UART3_TX 0x2a ++#define RP1_DMA_UART4_RX 0x2b ++#define RP1_DMA_UART4_TX 0x2c ++#define RP1_DMA_UART5_RX 0x2d ++#define RP1_DMA_UART5_TX 0x2e ++#define RP1_DMA_ADC 0x2f ++#define RP1_DMA_DMA_TICK_TICK0 0x30 ++#define RP1_DMA_DMA_TICK_TICK1 0x31 ++#define RP1_DMA_SPI6_RX 0x32 ++#define RP1_DMA_SPI6_TX 0x33 ++#define RP1_DMA_SPI7_RX 0x34 ++#define RP1_DMA_SPI7_TX 0x35 ++#define RP1_DMA_SPI8_RX 0x36 ++#define RP1_DMA_SPI8_TX 0x37 ++#define RP1_DMA_PIO_CH0_TX 0x38 ++#define RP1_DMA_PIO_CH0_RX 0x39 ++#define RP1_DMA_PIO_CH1_TX 0x3a ++#define RP1_DMA_PIO_CH1_RX 0x3b ++#define RP1_DMA_PIO_CH2_TX 0x3c ++#define RP1_DMA_PIO_CH2_RX 0x3d ++#define RP1_DMA_PIO_CH3_TX 0x3e ++#define RP1_DMA_PIO_CH3_RX 0x3f ++ ++#endif diff --git a/target/linux/bcm27xx/patches-6.1/950-0872-mfd-Add-rp1-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0872-mfd-Add-rp1-driver.patch new file mode 100644 index 0000000000..dd252cba36 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0872-mfd-Add-rp1-driver.patch @@ -0,0 +1,442 @@ +From 7196a12b94e90225686e6c34cdf65a583214f7a5 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 10 Oct 2022 14:21:50 +0100 +Subject: [PATCH] mfd: Add rp1 driver + +RP1 is a multifunction PCIe device that exposes a range of +peripherals. +Add the parent driver to manage these. + +Signed-off-by: Phil Elwell +--- + drivers/mfd/Kconfig | 11 ++ + drivers/mfd/Makefile | 1 + + drivers/mfd/rp1.c | 367 +++++++++++++++++++++++++++++++++++ + include/linux/rp1_platform.h | 20 ++ + 4 files changed, 399 insertions(+) + create mode 100644 drivers/mfd/rp1.c + create mode 100644 include/linux/rp1_platform.h + +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -2252,6 +2252,17 @@ config MFD_INTEL_M10_BMC + additional drivers must be enabled in order to use the functionality + of the device. + ++config MFD_RP1 ++ tristate "RP1 MFD driver" ++ depends on PCI ++ select MFD_CORE ++ help ++ Support for the RP1 peripheral chip. ++ ++ This driver provides support for the Raspberry Pi RP1 peripheral chip. ++ It is responsible for enabling the Device Tree node once the PCIe endpoint ++ has been configured, and handling interrupts. ++ + config MFD_RSMU_I2C + tristate "Renesas Synchronization Management Unit with I2C" + depends on I2C && OF +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -273,6 +273,7 @@ obj-$(CONFIG_MFD_RPISENSE_CORE) += rpise + obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o + obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o + obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o ++obj-$(CONFIG_MFD_RP1) += rp1.o + + obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o + obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o +--- /dev/null ++++ b/drivers/mfd/rp1.c +@@ -0,0 +1,367 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2018-22 Raspberry Pi Ltd. ++ * All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* TO DO: ++ * 1. Occasional shutdown crash - RP1 being closed before its children? ++ * 2. DT mode interrupt handling. ++ */ ++ ++#define RP1_DRIVER_NAME "rp1" ++ ++#define PCI_VENDOR_ID_RPI 0x1de4 ++#define PCI_DEVICE_ID_RP1_C0 0x0001 ++#define PCI_DEVICE_REV_RP1_C0 2 ++ ++#define RP1_ACTUAL_IRQS RP1_INT_END ++#define RP1_IRQS RP1_ACTUAL_IRQS ++ ++#define RP1_SYSCLK_RATE 200000000 ++#define RP1_SYSCLK_FPGA_RATE 60000000 ++ ++// Don't want to include the whole sysinfo reg header ++#define SYSINFO_CHIP_ID_OFFSET 0x00000000 ++#define SYSINFO_PLATFORM_OFFSET 0x00000004 ++ ++#define REG_RW 0x000 ++#define REG_SET 0x800 ++#define REG_CLR 0xc00 ++ ++// MSIX CFG registers start at 0x8 ++#define MSIX_CFG(x) (0x8 + (4 * (x))) ++ ++#define MSIX_CFG_IACK_EN BIT(3) ++#define MSIX_CFG_IACK BIT(2) ++#define MSIX_CFG_TEST BIT(1) ++#define MSIX_CFG_ENABLE BIT(0) ++ ++#define INTSTATL 0x108 ++#define INTSTATH 0x10c ++ ++struct rp1_dev { ++ struct pci_dev *pdev; ++ struct device *dev; ++ resource_size_t bar_start; ++ resource_size_t bar_end; ++ struct clk *sys_clk; ++ struct irq_domain *domain; ++ struct irq_data *pcie_irqds[64]; ++ void __iomem *msix_cfg_regs; ++}; ++ ++static bool rp1_level_triggered_irq[RP1_ACTUAL_IRQS] = { 0 }; ++ ++static struct rp1_dev *g_rp1; ++static u32 g_chip_id, g_platform; ++ ++static void dump_bar(struct pci_dev *pdev, unsigned int bar) ++{ ++ dev_info(&pdev->dev, ++ "bar%d len 0x%llx, start 0x%llx, end 0x%llx, flags, 0x%lx\n", ++ bar, ++ pci_resource_len(pdev, bar), ++ pci_resource_start(pdev, bar), ++ pci_resource_end(pdev, bar), ++ pci_resource_flags(pdev, bar)); ++} ++ ++static void msix_cfg_set(struct rp1_dev *rp1, unsigned int hwirq, u32 value) ++{ ++ writel(value, rp1->msix_cfg_regs + REG_SET + MSIX_CFG(hwirq)); ++} ++ ++static void msix_cfg_clr(struct rp1_dev *rp1, unsigned int hwirq, u32 value) ++{ ++ writel(value, rp1->msix_cfg_regs + REG_CLR + MSIX_CFG(hwirq)); ++} ++ ++static void rp1_mask_irq(struct irq_data *irqd) ++{ ++ struct rp1_dev *rp1 = irqd->domain->host_data; ++ struct irq_data *pcie_irqd = rp1->pcie_irqds[irqd->hwirq]; ++ ++ pci_msi_mask_irq(pcie_irqd); ++} ++ ++static void rp1_unmask_irq(struct irq_data *irqd) ++{ ++ struct rp1_dev *rp1 = irqd->domain->host_data; ++ struct irq_data *pcie_irqd = rp1->pcie_irqds[irqd->hwirq]; ++ ++ pci_msi_unmask_irq(pcie_irqd); ++} ++ ++static int rp1_irq_set_type(struct irq_data *irqd, unsigned int type) ++{ ++ struct rp1_dev *rp1 = irqd->domain->host_data; ++ unsigned int hwirq = (unsigned int)irqd->hwirq; ++ int ret = 0; ++ ++ switch (type) { ++ case IRQ_TYPE_LEVEL_HIGH: ++ dev_dbg(rp1->dev, "MSIX IACK EN for irq %d\n", hwirq); ++ msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK_EN); ++ rp1_level_triggered_irq[hwirq] = true; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ msix_cfg_clr(rp1, hwirq, MSIX_CFG_IACK_EN); ++ rp1_level_triggered_irq[hwirq] = false; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static struct irq_chip rp1_irq_chip = { ++ .name = "rp1_irq_chip", ++ .irq_mask = rp1_mask_irq, ++ .irq_unmask = rp1_unmask_irq, ++ .irq_set_type = rp1_irq_set_type, ++}; ++ ++static void rp1_chained_handle_irq(struct irq_desc *desc) ++{ ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ struct rp1_dev *rp1 = desc->irq_data.chip_data; ++ unsigned int hwirq = desc->irq_data.hwirq & 0x3f; ++ int new_irq; ++ ++ rp1 = g_rp1; ++ ++ chained_irq_enter(chip, desc); ++ ++ new_irq = irq_linear_revmap(rp1->domain, hwirq); ++ generic_handle_irq(new_irq); ++ if (rp1_level_triggered_irq[hwirq]) ++ msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK); ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static int rp1_irq_xlate(struct irq_domain *d, struct device_node *node, ++ const u32 *intspec, unsigned int intsize, ++ unsigned long *out_hwirq, unsigned int *out_type) ++{ ++ struct rp1_dev *rp1 = d->host_data; ++ struct irq_data *pcie_irqd; ++ unsigned long hwirq; ++ int pcie_irq; ++ int ret; ++ ++ ret = irq_domain_xlate_twocell(d, node, intspec, intsize, ++ &hwirq, out_type); ++ if (!ret) { ++ pcie_irq = pci_irq_vector(rp1->pdev, hwirq); ++ pcie_irqd = irq_get_irq_data(pcie_irq); ++ rp1->pcie_irqds[hwirq] = pcie_irqd; ++ *out_hwirq = hwirq; ++ } ++ return ret; ++} ++ ++static int rp1_irq_activate(struct irq_domain *d, struct irq_data *irqd, ++ bool reserve) ++{ ++ struct rp1_dev *rp1 = d->host_data; ++ struct irq_data *pcie_irqd; ++ ++ pcie_irqd = rp1->pcie_irqds[irqd->hwirq]; ++ msix_cfg_set(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_ENABLE); ++ return irq_domain_activate_irq(pcie_irqd, reserve); ++} ++ ++static void rp1_irq_deactivate(struct irq_domain *d, struct irq_data *irqd) ++{ ++ struct rp1_dev *rp1 = d->host_data; ++ struct irq_data *pcie_irqd; ++ ++ pcie_irqd = rp1->pcie_irqds[irqd->hwirq]; ++ msix_cfg_clr(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_ENABLE); ++ return irq_domain_deactivate_irq(pcie_irqd); ++} ++ ++static const struct irq_domain_ops rp1_domain_ops = { ++ .xlate = rp1_irq_xlate, ++ .activate = rp1_irq_activate, ++ .deactivate = rp1_irq_deactivate, ++}; ++ ++static inline dma_addr_t rp1_io_to_phys(struct rp1_dev *rp1, unsigned int offset) ++{ ++ return rp1->bar_start + offset; ++} ++ ++static u32 rp1_reg_read(struct rp1_dev *rp1, unsigned int base_addr, u32 offset) ++{ ++ dma_addr_t phys = rp1_io_to_phys(rp1, base_addr); ++ void __iomem *regblock = ioremap(phys, 0x1000); ++ u32 value = readl(regblock + offset); ++ ++ iounmap(regblock); ++ return value; ++} ++ ++void rp1_get_platform(u32 *chip_id, u32 *platform) ++{ ++ if (chip_id) ++ *chip_id = g_chip_id; ++ if (platform) ++ *platform = g_platform; ++} ++EXPORT_SYMBOL_GPL(rp1_get_platform); ++ ++static int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ struct reset_control *reset; ++ struct platform_device *pcie_pdev; ++ struct device_node *rp1_node; ++ struct rp1_dev *rp1; ++ int err = 0; ++ int i; ++ ++ reset = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ if (IS_ERR(reset)) ++ return PTR_ERR(reset); ++ reset_control_reset(reset); ++ ++ dump_bar(pdev, 0); ++ dump_bar(pdev, 1); ++ ++ if (pci_resource_len(pdev, 1) <= 0x10000) { ++ dev_err(&pdev->dev, ++ "Not initialised - is the firmware running?\n"); ++ return -EINVAL; ++ } ++ ++ /* enable pci device */ ++ err = pcim_enable_device(pdev); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Enabling PCI device has failed: %d", ++ err); ++ return err; ++ } ++ ++ pci_set_master(pdev); ++ ++ err = pci_alloc_irq_vectors(pdev, RP1_IRQS, RP1_IRQS, ++ PCI_IRQ_MSIX); ++ if (err != RP1_IRQS) { ++ dev_err(&pdev->dev, "pci_alloc_irq_vectors failed - %d\n", err); ++ return err; ++ } ++ ++ rp1 = devm_kzalloc(&pdev->dev, sizeof(*rp1), GFP_KERNEL); ++ if (!rp1) ++ return -ENOMEM; ++ ++ rp1->pdev = pdev; ++ rp1->dev = &pdev->dev; ++ ++ pci_set_drvdata(pdev, rp1); ++ ++ rp1->bar_start = pci_resource_start(pdev, 1); ++ rp1->bar_end = pci_resource_end(pdev, 1); ++ ++ // Get chip id ++ g_chip_id = rp1_reg_read(rp1, RP1_SYSINFO_BASE, SYSINFO_CHIP_ID_OFFSET); ++ g_platform = rp1_reg_read(rp1, RP1_SYSINFO_BASE, SYSINFO_PLATFORM_OFFSET); ++ dev_info(&pdev->dev, "chip_id 0x%x%s\n", g_chip_id, ++ (g_platform & RP1_PLATFORM_FPGA) ? " FPGA" : ""); ++ if (g_chip_id != RP1_C0_CHIP_ID) { ++ dev_err(&pdev->dev, "wrong chip id (%x)\n", g_chip_id); ++ return -EINVAL; ++ } ++ ++ rp1_node = of_find_node_by_name(NULL, "rp1"); ++ if (!rp1_node) { ++ dev_err(&pdev->dev, "failed to find RP1 DT node\n"); ++ return -EINVAL; ++ } ++ ++ pcie_pdev = of_find_device_by_node(rp1_node->parent); ++ rp1->domain = irq_domain_add_linear(rp1_node, RP1_IRQS, ++ &rp1_domain_ops, rp1); ++ ++ g_rp1 = rp1; ++ ++ /* TODO can this go in the rp1 device tree entry? */ ++ rp1->msix_cfg_regs = ioremap(rp1_io_to_phys(rp1, RP1_PCIE_APBS_BASE), 0x1000); ++ ++ for (i = 0; i < RP1_IRQS; i++) { ++ int irq = irq_create_mapping(rp1->domain, i); ++ ++ if (irq < 0) { ++ dev_err(&pdev->dev, "failed to create irq mapping\n"); ++ return irq; ++ } ++ ++ irq_set_chip_data(irq, rp1); ++ irq_set_chip_and_handler(irq, &rp1_irq_chip, handle_level_irq); ++ irq_set_probe(irq); ++ irq_set_chained_handler(pci_irq_vector(pdev, i), ++ rp1_chained_handle_irq); ++ } ++ ++ if (rp1_node) ++ of_platform_populate(rp1_node, NULL, NULL, &pcie_pdev->dev); ++ ++ of_node_put(rp1_node); ++ ++ return 0; ++} ++ ++static void rp1_remove(struct pci_dev *pdev) ++{ ++ struct rp1_dev *rp1 = pci_get_drvdata(pdev); ++ ++ mfd_remove_devices(&pdev->dev); ++ ++ clk_unregister(rp1->sys_clk); ++} ++ ++static const struct pci_device_id dev_id_table[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RP1_C0), }, ++ { 0, } ++}; ++ ++static struct pci_driver rp1_driver = { ++ .name = RP1_DRIVER_NAME, ++ .id_table = dev_id_table, ++ .probe = rp1_probe, ++ .remove = rp1_remove, ++}; ++ ++module_pci_driver(rp1_driver); ++ ++MODULE_AUTHOR("Phil Elwell "); ++MODULE_DESCRIPTION("RP1 wrapper"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/include/linux/rp1_platform.h +@@ -0,0 +1,20 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2021-2022 Raspberry Pi Ltd. ++ * All rights reserved. ++ */ ++ ++#ifndef _RP1_PLATFORM_H ++#define _RP1_PLATFORM_H ++ ++#include ++ ++#define RP1_B0_CHIP_ID 0x10001927 ++#define RP1_C0_CHIP_ID 0x20001927 ++ ++#define RP1_PLATFORM_ASIC BIT(1) ++#define RP1_PLATFORM_FPGA BIT(0) ++ ++void rp1_get_platform(u32 *chip_id, u32 *platform); ++ ++#endif diff --git a/target/linux/bcm27xx/patches-6.1/950-0873-dt-bindings-clock-Add-bindings-for-Raspberry-Pi-RP1.patch b/target/linux/bcm27xx/patches-6.1/950-0873-dt-bindings-clock-Add-bindings-for-Raspberry-Pi-RP1.patch new file mode 100644 index 0000000000..f94782438b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0873-dt-bindings-clock-Add-bindings-for-Raspberry-Pi-RP1.patch @@ -0,0 +1,65 @@ +From 00ff2819eb852b54fe22e7181646e40d560576dc Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 28 Oct 2022 14:12:18 +0100 +Subject: [PATCH] dt-bindings: clock: Add bindings for Raspberry Pi RP1 + +Signed-off-by: Phil Elwell +--- + include/dt-bindings/clock/rp1.h | 51 +++++++++++++++++++++++++++++++++ + 1 file changed, 51 insertions(+) + create mode 100644 include/dt-bindings/clock/rp1.h + +--- /dev/null ++++ b/include/dt-bindings/clock/rp1.h +@@ -0,0 +1,51 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 Raspberry Pi Ltd. ++ */ ++ ++#define RP1_PLL_SYS_CORE 0 ++#define RP1_PLL_AUDIO_CORE 1 ++#define RP1_PLL_VIDEO_CORE 2 ++ ++#define RP1_PLL_SYS 3 ++#define RP1_PLL_AUDIO 4 ++#define RP1_PLL_VIDEO 5 ++ ++#define RP1_PLL_SYS_PRI_PH 6 ++#define RP1_PLL_SYS_SEC_PH 7 ++ ++#define RP1_PLL_SYS_SEC 8 ++#define RP1_PLL_AUDIO_SEC 9 ++#define RP1_PLL_VIDEO_SEC 10 ++ ++#define RP1_CLK_SYS 11 ++#define RP1_CLK_SLOW_SYS 12 ++#define RP1_CLK_DMA 13 ++#define RP1_CLK_UART 14 ++#define RP1_CLK_ETH 15 ++#define RP1_CLK_PWM0 16 ++#define RP1_CLK_PWM1 17 ++#define RP1_CLK_AUDIO_IN 18 ++#define RP1_CLK_AUDIO_OUT 19 ++#define RP1_CLK_I2S 20 ++#define RP1_CLK_MIPI0_CFG 21 ++#define RP1_CLK_MIPI1_CFG 22 ++#define RP1_CLK_PCIE_AUX 23 ++#define RP1_CLK_USBH0_MICROFRAME 24 ++#define RP1_CLK_USBH1_MICROFRAME 25 ++#define RP1_CLK_USBH0_SUSPEND 26 ++#define RP1_CLK_USBH1_SUSPEND 27 ++#define RP1_CLK_ETH_TSU 28 ++#define RP1_CLK_ADC 29 ++#define RP1_CLK_SDIO_TIMER 30 ++#define RP1_CLK_SDIO_ALT_SRC 31 ++#define RP1_CLK_GP0 32 ++#define RP1_CLK_GP1 33 ++#define RP1_CLK_GP2 34 ++#define RP1_CLK_GP3 35 ++#define RP1_CLK_GP4 36 ++#define RP1_CLK_GP5 37 ++#define RP1_CLK_VEC 38 ++#define RP1_CLK_DPI 39 ++#define RP1_CLK_MIPI0_DPI 40 ++#define RP1_CLK_MIPI1_DPI 41 diff --git a/target/linux/bcm27xx/patches-6.1/950-0874-clk-Add-rp1-clock-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0874-clk-Add-rp1-clock-driver.patch new file mode 100644 index 0000000000..2a861d18c7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0874-clk-Add-rp1-clock-driver.patch @@ -0,0 +1,2208 @@ +From 66517cdfea750b89d86f78af55ef773cbd3e005f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 10 Oct 2022 14:25:38 +0100 +Subject: [PATCH] clk: Add rp1 clock driver + +RP1 contains various PLLs and clocks for driving the hardware +blocks, so add a driver to configure these. + +Signed-off-by: Phil Elwell +--- + drivers/clk/Kconfig | 7 + + drivers/clk/Makefile | 1 + + drivers/clk/clk-rp1.c | 2085 +++++++++++++++++++++++++++++++ + include/dt-bindings/clock/rp1.h | 69 +- + 4 files changed, 2128 insertions(+), 34 deletions(-) + create mode 100644 drivers/clk/clk-rp1.c + +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -89,6 +89,13 @@ config COMMON_CLK_RK808 + These multi-function devices have two fixed-rate oscillators, clocked at 32KHz each. + Clkout1 is always on, Clkout2 can off by control register. + ++config COMMON_CLK_RP1 ++ tristate "Raspberry Pi RP1-based clock support" ++ depends on PCI || COMPILE_TEST ++ depends on COMMON_CLK ++ help ++ Enable common clock framework support for Raspberry Pi RP1 ++ + config COMMON_CLK_HI655X + tristate "Clock driver for Hi655x" if EXPERT + depends on (MFD_HI655X_PMIC || COMPILE_TEST) +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -58,6 +58,7 @@ obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk- + obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o + obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o + obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o ++obj-$(CONFIG_COMMON_CLK_RP1) += clk-rp1.o + obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o + obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o + obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o +--- /dev/null ++++ b/drivers/clk/clk-rp1.c +@@ -0,0 +1,2085 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2023 Raspberry Pi Ltd. ++ * ++ * Clock driver for RP1 PCIe multifunction chip. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#define PLL_SYS_CS 0x08000 ++#define PLL_SYS_PWR 0x08004 ++#define PLL_SYS_FBDIV_INT 0x08008 ++#define PLL_SYS_FBDIV_FRAC 0x0800c ++#define PLL_SYS_PRIM 0x08010 ++#define PLL_SYS_SEC 0x08014 ++ ++#define PLL_AUDIO_CS 0x0c000 ++#define PLL_AUDIO_PWR 0x0c004 ++#define PLL_AUDIO_FBDIV_INT 0x0c008 ++#define PLL_AUDIO_FBDIV_FRAC 0x0c00c ++#define PLL_AUDIO_PRIM 0x0c010 ++#define PLL_AUDIO_SEC 0x0c014 ++ ++#define PLL_VIDEO_CS 0x10000 ++#define PLL_VIDEO_PWR 0x10004 ++#define PLL_VIDEO_FBDIV_INT 0x10008 ++#define PLL_VIDEO_FBDIV_FRAC 0x1000c ++#define PLL_VIDEO_PRIM 0x10010 ++#define PLL_VIDEO_SEC 0x10014 ++ ++#define CLK_SYS_CTRL 0x00014 ++#define CLK_SYS_DIV_INT 0x00018 ++#define CLK_SYS_SEL 0x00020 ++ ++#define CLK_SLOW_SYS_CTRL 0x00024 ++#define CLK_SLOW_SYS_DIV_INT 0x00028 ++#define CLK_SLOW_SYS_SEL 0x00030 ++ ++#define CLK_DMA_CTRL 0x00044 ++#define CLK_DMA_DIV_INT 0x00048 ++#define CLK_DMA_SEL 0x00050 ++ ++#define CLK_UART_CTRL 0x00054 ++#define CLK_UART_DIV_INT 0x00058 ++#define CLK_UART_SEL 0x00060 ++ ++#define CLK_ETH_CTRL 0x00064 ++#define CLK_ETH_DIV_INT 0x00068 ++#define CLK_ETH_SEL 0x00070 ++ ++#define CLK_PWM0_CTRL 0x00074 ++#define CLK_PWM0_DIV_INT 0x00078 ++#define CLK_PWM0_DIV_FRAC 0x0007c ++#define CLK_PWM0_SEL 0x00080 ++ ++#define CLK_PWM1_CTRL 0x00084 ++#define CLK_PWM1_DIV_INT 0x00088 ++#define CLK_PWM1_DIV_FRAC 0x0008c ++#define CLK_PWM1_SEL 0x00090 ++ ++#define CLK_AUDIO_IN_CTRL 0x00094 ++#define CLK_AUDIO_IN_DIV_INT 0x00098 ++#define CLK_AUDIO_IN_SEL 0x000a0 ++ ++#define CLK_AUDIO_OUT_CTRL 0x000a4 ++#define CLK_AUDIO_OUT_DIV_INT 0x000a8 ++#define CLK_AUDIO_OUT_SEL 0x000b0 ++ ++#define CLK_I2S_CTRL 0x000b4 ++#define CLK_I2S_DIV_INT 0x000b8 ++#define CLK_I2S_SEL 0x000c0 ++ ++#define CLK_MIPI0_CFG_CTRL 0x000c4 ++#define CLK_MIPI0_CFG_DIV_INT 0x000c8 ++#define CLK_MIPI0_CFG_SEL 0x000d0 ++ ++#define CLK_MIPI1_CFG_CTRL 0x000d4 ++#define CLK_MIPI1_CFG_DIV_INT 0x000d8 ++#define CLK_MIPI1_CFG_SEL 0x000e0 ++ ++#define CLK_PCIE_AUX_CTRL 0x000e4 ++#define CLK_PCIE_AUX_DIV_INT 0x000e8 ++#define CLK_PCIE_AUX_SEL 0x000f0 ++ ++#define CLK_USBH0_MICROFRAME_CTRL 0x000f4 ++#define CLK_USBH0_MICROFRAME_DIV_INT 0x000f8 ++#define CLK_USBH0_MICROFRAME_SEL 0x00100 ++ ++#define CLK_USBH1_MICROFRAME_CTRL 0x00104 ++#define CLK_USBH1_MICROFRAME_DIV_INT 0x00108 ++#define CLK_USBH1_MICROFRAME_SEL 0x00110 ++ ++#define CLK_USBH0_SUSPEND_CTRL 0x00114 ++#define CLK_USBH0_SUSPEND_DIV_INT 0x00118 ++#define CLK_USBH0_SUSPEND_SEL 0x00120 ++ ++#define CLK_USBH1_SUSPEND_CTRL 0x00124 ++#define CLK_USBH1_SUSPEND_DIV_INT 0x00128 ++#define CLK_USBH1_SUSPEND_SEL 0x00130 ++ ++#define CLK_ETH_TSU_CTRL 0x00134 ++#define CLK_ETH_TSU_DIV_INT 0x00138 ++#define CLK_ETH_TSU_SEL 0x00140 ++ ++#define CLK_ADC_CTRL 0x00144 ++#define CLK_ADC_DIV_INT 0x00148 ++#define CLK_ADC_SEL 0x00150 ++ ++#define CLK_SDIO_TIMER_CTRL 0x00154 ++#define CLK_SDIO_TIMER_DIV_INT 0x00158 ++#define CLK_SDIO_TIMER_SEL 0x00160 ++ ++#define CLK_SDIO_ALT_SRC_CTRL 0x00164 ++#define CLK_SDIO_ALT_SRC_DIV_INT 0x00168 ++#define CLK_SDIO_ALT_SRC_SEL 0x00170 ++ ++#define CLK_GP0_CTRL 0x00174 ++#define CLK_GP0_DIV_INT 0x00178 ++#define CLK_GP0_DIV_FRAC 0x0017c ++#define CLK_GP0_SEL 0x00180 ++ ++#define CLK_GP1_CTRL 0x00184 ++#define CLK_GP1_DIV_INT 0x00188 ++#define CLK_GP1_DIV_FRAC 0x0018c ++#define CLK_GP1_SEL 0x00190 ++ ++#define CLK_GP2_CTRL 0x00194 ++#define CLK_GP2_DIV_INT 0x00198 ++#define CLK_GP2_DIV_FRAC 0x0019c ++#define CLK_GP2_SEL 0x001a0 ++ ++#define CLK_GP3_CTRL 0x001a4 ++#define CLK_GP3_DIV_INT 0x001a8 ++#define CLK_GP3_DIV_FRAC 0x001ac ++#define CLK_GP3_SEL 0x001b0 ++ ++#define CLK_GP4_CTRL 0x001b4 ++#define CLK_GP4_DIV_INT 0x001b8 ++#define CLK_GP4_DIV_FRAC 0x001bc ++#define CLK_GP4_SEL 0x001c0 ++ ++#define CLK_GP5_CTRL 0x001c4 ++#define CLK_GP5_DIV_INT 0x001c8 ++#define CLK_GP5_DIV_FRAC 0x001cc ++#define CLK_GP5_SEL 0x001d0 ++ ++#define CLK_SYS_RESUS_CTRL 0x0020c ++ ++#define CLK_SLOW_SYS_RESUS_CTRL 0x00214 ++ ++#define FC0_REF_KHZ 0x0021c ++#define FC0_MIN_KHZ 0x00220 ++#define FC0_MAX_KHZ 0x00224 ++#define FC0_DELAY 0x00228 ++#define FC0_INTERVAL 0x0022c ++#define FC0_SRC 0x00230 ++#define FC0_STATUS 0x00234 ++#define FC0_RESULT 0x00238 ++#define FC_SIZE 0x20 ++#define FC_COUNT 8 ++#define FC_NUM(idx, off) ((idx) * 32 + (off)) ++ ++#define AUX_SEL 1 ++ ++#define VIDEO_CLOCKS_OFFSET 0x4000 ++#define VIDEO_CLK_VEC_CTRL (VIDEO_CLOCKS_OFFSET + 0x0000) ++#define VIDEO_CLK_VEC_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0004) ++#define VIDEO_CLK_VEC_SEL (VIDEO_CLOCKS_OFFSET + 0x000c) ++#define VIDEO_CLK_DPI_CTRL (VIDEO_CLOCKS_OFFSET + 0x0010) ++#define VIDEO_CLK_DPI_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0014) ++#define VIDEO_CLK_DPI_SEL (VIDEO_CLOCKS_OFFSET + 0x001c) ++#define VIDEO_CLK_MIPI0_DPI_CTRL (VIDEO_CLOCKS_OFFSET + 0x0020) ++#define VIDEO_CLK_MIPI0_DPI_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0024) ++#define VIDEO_CLK_MIPI0_DPI_DIV_FRAC (VIDEO_CLOCKS_OFFSET + 0x0028) ++#define VIDEO_CLK_MIPI0_DPI_SEL (VIDEO_CLOCKS_OFFSET + 0x002c) ++#define VIDEO_CLK_MIPI1_DPI_CTRL (VIDEO_CLOCKS_OFFSET + 0x0030) ++#define VIDEO_CLK_MIPI1_DPI_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0034) ++#define VIDEO_CLK_MIPI1_DPI_DIV_FRAC (VIDEO_CLOCKS_OFFSET + 0x0038) ++#define VIDEO_CLK_MIPI1_DPI_SEL (VIDEO_CLOCKS_OFFSET + 0x003c) ++ ++#define DIV_INT_8BIT_MAX 0x000000ffu /* max divide for most clocks */ ++#define DIV_INT_16BIT_MAX 0x0000ffffu /* max divide for GPx, PWM */ ++#define DIV_INT_24BIT_MAX 0x00ffffffu /* max divide for CLK_SYS */ ++ ++#define FC0_STATUS_DONE BIT(4) ++#define FC0_STATUS_RUNNING BIT(8) ++#define FC0_RESULT_FRAC_SHIFT 5 ++ ++#define PLL_PRIM_DIV1_SHIFT 16 ++#define PLL_PRIM_DIV1_MASK 0x00070000 ++#define PLL_PRIM_DIV2_SHIFT 12 ++#define PLL_PRIM_DIV2_MASK 0x00007000 ++ ++#define PLL_SEC_DIV_SHIFT 8 ++#define PLL_SEC_DIV_WIDTH 5 ++#define PLL_SEC_DIV_MASK 0x00001f00 ++ ++#define PLL_CS_LOCK BIT(31) ++#define PLL_CS_REFDIV_SHIFT 0 ++ ++#define PLL_PWR_PD BIT(0) ++#define PLL_PWR_DACPD BIT(1) ++#define PLL_PWR_DSMPD BIT(2) ++#define PLL_PWR_POSTDIVPD BIT(3) ++#define PLL_PWR_4PHASEPD BIT(4) ++#define PLL_PWR_VCOPD BIT(5) ++#define PLL_PWR_MASK 0x0000003f ++ ++#define PLL_SEC_RST BIT(16) ++#define PLL_SEC_IMPL BIT(31) ++ ++/* PLL phase output for both PRI and SEC */ ++#define PLL_PH_EN BIT(4) ++#define PLL_PH_PHASE_SHIFT 0 ++ ++#define RP1_PLL_PHASE_0 0 ++#define RP1_PLL_PHASE_90 1 ++#define RP1_PLL_PHASE_180 2 ++#define RP1_PLL_PHASE_270 3 ++ ++/* Clock fields for all clocks */ ++#define CLK_CTRL_ENABLE BIT(11) ++#define CLK_CTRL_AUXSRC_MASK 0x000003e0 ++#define CLK_CTRL_AUXSRC_SHIFT 5 ++#define CLK_CTRL_SRC_SHIFT 0 ++#define CLK_DIV_FRAC_BITS 16 ++ ++#define KHz 1000 ++#define MHz (KHz * KHz) ++#define LOCK_TIMEOUT_NS 100000000 ++#define FC_TIMEOUT_NS 100000000 ++ ++#define MAX_CLK_PARENTS 8 ++ ++#define MEASURE_CLOCK_RATE ++const char * const fc0_ref_clk_name = "clk_slow_sys"; ++ ++#define ABS_DIFF(a, b) ((a) > (b) ? (a) - (b) : (b) - (a)) ++#define DIV_U64_NEAREST(a, b) div_u64(((a) + ((b) >> 1)), (b)) ++ ++/* ++ * Names of the reference clock for the pll cores. This name must match ++ * the DT reference clock-output-name. ++ */ ++static const char *const ref_clock = "xosc"; ++ ++/* ++ * Secondary PLL channel output divider table. ++ * Divider values range from 8 to 19. ++ * Invalid values default to 19 ++ */ ++static const struct clk_div_table pll_sec_div_table[] = { ++ { 0x00, 19 }, ++ { 0x01, 19 }, ++ { 0x02, 19 }, ++ { 0x03, 19 }, ++ { 0x04, 19 }, ++ { 0x05, 19 }, ++ { 0x06, 19 }, ++ { 0x07, 19 }, ++ { 0x08, 8 }, ++ { 0x09, 9 }, ++ { 0x0a, 10 }, ++ { 0x0b, 11 }, ++ { 0x0c, 12 }, ++ { 0x0d, 13 }, ++ { 0x0e, 14 }, ++ { 0x0f, 15 }, ++ { 0x10, 16 }, ++ { 0x11, 17 }, ++ { 0x12, 18 }, ++ { 0x13, 19 }, ++ { 0x14, 19 }, ++ { 0x15, 19 }, ++ { 0x16, 19 }, ++ { 0x17, 19 }, ++ { 0x18, 19 }, ++ { 0x19, 19 }, ++ { 0x1a, 19 }, ++ { 0x1b, 19 }, ++ { 0x1c, 19 }, ++ { 0x1d, 19 }, ++ { 0x1e, 19 }, ++ { 0x1f, 19 }, ++ { 0 } ++}; ++ ++struct rp1_clockman { ++ struct device *dev; ++ void __iomem *regs; ++ spinlock_t regs_lock; /* spinlock for all clocks */ ++ ++ /* Must be last */ ++ struct clk_hw_onecell_data onecell; ++}; ++ ++struct rp1_pll_core_data { ++ const char *name; ++ u32 cs_reg; ++ u32 pwr_reg; ++ u32 fbdiv_int_reg; ++ u32 fbdiv_frac_reg; ++ unsigned long flags; ++ u32 fc0_src; ++}; ++ ++struct rp1_pll_data { ++ const char *name; ++ const char *source_pll; ++ u32 ctrl_reg; ++ unsigned long flags; ++ u32 fc0_src; ++}; ++ ++struct rp1_pll_ph_data { ++ const char *name; ++ const char *source_pll; ++ unsigned int phase; ++ unsigned int fixed_divider; ++ u32 ph_reg; ++ unsigned long flags; ++ u32 fc0_src; ++}; ++ ++struct rp1_pll_divider_data { ++ const char *name; ++ const char *source_pll; ++ u32 sec_reg; ++ unsigned long flags; ++ u32 fc0_src; ++}; ++ ++struct rp1_clock_data { ++ const char *name; ++ const char *const parents[MAX_CLK_PARENTS]; ++ int num_std_parents; ++ int num_aux_parents; ++ unsigned long flags; ++ u32 clk_src_mask; ++ u32 ctrl_reg; ++ u32 div_int_reg; ++ u32 div_frac_reg; ++ u32 sel_reg; ++ u32 div_int_max; ++ u32 fc0_src; ++}; ++ ++struct rp1_pll_core { ++ struct clk_hw hw; ++ struct rp1_clockman *clockman; ++ const struct rp1_pll_core_data *data; ++ unsigned long cached_rate; ++}; ++ ++struct rp1_pll { ++ struct clk_hw hw; ++ struct clk_divider div; ++ struct rp1_clockman *clockman; ++ const struct rp1_pll_data *data; ++ unsigned long cached_rate; ++}; ++ ++struct rp1_pll_ph { ++ struct clk_hw hw; ++ struct rp1_clockman *clockman; ++ const struct rp1_pll_ph_data *data; ++}; ++ ++struct rp1_clock { ++ struct clk_hw hw; ++ struct rp1_clockman *clockman; ++ const struct rp1_clock_data *data; ++ unsigned long cached_rate; ++}; ++ ++static void rp1_debugfs_regset(struct rp1_clockman *clockman, u32 base, ++ const struct debugfs_reg32 *regs, ++ size_t nregs, struct dentry *dentry) ++{ ++ struct debugfs_regset32 *regset; ++ ++ regset = devm_kzalloc(clockman->dev, sizeof(*regset), GFP_KERNEL); ++ if (!regset) ++ return; ++ ++ regset->regs = regs; ++ regset->nregs = nregs; ++ regset->base = clockman->regs + base; ++ ++ debugfs_create_regset32("regdump", 0444, dentry, regset); ++} ++ ++static inline u32 set_register_field(u32 reg, u32 val, u32 mask, u32 shift) ++{ ++ reg &= ~mask; ++ reg |= (val << shift) & mask; ++ return reg; ++} ++ ++static inline ++void clockman_write(struct rp1_clockman *clockman, u32 reg, u32 val) ++{ ++ writel(val, clockman->regs + reg); ++} ++ ++static inline u32 clockman_read(struct rp1_clockman *clockman, u32 reg) ++{ ++ return readl(clockman->regs + reg); ++} ++ ++#ifdef MEASURE_CLOCK_RATE ++static unsigned long clockman_measure_clock(struct rp1_clockman *clockman, ++ const char *clk_name, ++ unsigned int fc0_src) ++{ ++ struct clk *ref_clk = __clk_lookup(fc0_ref_clk_name); ++ unsigned long result; ++ ktime_t timeout; ++ unsigned int fc_idx, fc_offset, fc_src; ++ ++ fc_idx = fc0_src / 32; ++ fc_src = fc0_src % 32; ++ ++ /* fc_src == 0 is invalid. */ ++ if (!fc_src || fc_idx >= FC_COUNT) ++ return 0; ++ ++ fc_offset = fc_idx * FC_SIZE; ++ ++ /* Ensure the frequency counter is idle. */ ++ timeout = ktime_add_ns(ktime_get(), FC_TIMEOUT_NS); ++ while (clockman_read(clockman, fc_offset + FC0_STATUS) & FC0_STATUS_RUNNING) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(clockman->dev, "%s: FC0 busy timeout\n", ++ clk_name); ++ return 0; ++ } ++ cpu_relax(); ++ } ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, fc_offset + FC0_REF_KHZ, ++ clk_get_rate(ref_clk) / KHz); ++ clockman_write(clockman, fc_offset + FC0_MIN_KHZ, 0); ++ clockman_write(clockman, fc_offset + FC0_MAX_KHZ, 0x1ffffff); ++ clockman_write(clockman, fc_offset + FC0_INTERVAL, 8); ++ clockman_write(clockman, fc_offset + FC0_DELAY, 7); ++ clockman_write(clockman, fc_offset + FC0_SRC, fc_src); ++ spin_unlock(&clockman->regs_lock); ++ ++ /* Ensure the frequency counter is idle. */ ++ timeout = ktime_add_ns(ktime_get(), FC_TIMEOUT_NS); ++ while (!(clockman_read(clockman, fc_offset + FC0_STATUS) & FC0_STATUS_DONE)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(clockman->dev, "%s: FC0 wait timeout\n", ++ clk_name); ++ return 0; ++ } ++ cpu_relax(); ++ } ++ ++ result = clockman_read(clockman, fc_offset + FC0_RESULT); ++ ++ /* Disable FC0 */ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, fc_offset + FC0_SRC, 0); ++ spin_unlock(&clockman->regs_lock); ++ ++ return result; ++} ++#endif ++ ++static int rp1_pll_core_is_on(struct clk_hw *hw) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ u32 pwr = clockman_read(clockman, data->pwr_reg); ++ ++ return (pwr & PLL_PWR_PD) || (pwr & PLL_PWR_POSTDIVPD); ++} ++ ++static int rp1_pll_core_on(struct clk_hw *hw) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ u32 fbdiv_frac; ++ ktime_t timeout; ++ ++ spin_lock(&clockman->regs_lock); ++ ++ if (!(clockman_read(clockman, data->cs_reg) & PLL_CS_LOCK)) { ++ /* Reset to a known state. */ ++ clockman_write(clockman, data->pwr_reg, PLL_PWR_MASK); ++ clockman_write(clockman, data->fbdiv_int_reg, 20); ++ clockman_write(clockman, data->fbdiv_frac_reg, 0); ++ clockman_write(clockman, data->cs_reg, 1 << PLL_CS_REFDIV_SHIFT); ++ } ++ ++ /* Come out of reset. */ ++ fbdiv_frac = clockman_read(clockman, data->fbdiv_frac_reg); ++ clockman_write(clockman, data->pwr_reg, fbdiv_frac ? 0 : PLL_PWR_DSMPD); ++ spin_unlock(&clockman->regs_lock); ++ ++ /* Wait for the PLL to lock. */ ++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ while (!(clockman_read(clockman, data->cs_reg) & PLL_CS_LOCK)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(clockman->dev, "%s: can't lock PLL\n", ++ clk_hw_get_name(hw)); ++ return -ETIMEDOUT; ++ } ++ cpu_relax(); ++ } ++ ++ return 0; ++} ++ ++static void rp1_pll_core_off(struct clk_hw *hw) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->pwr_reg, 0); ++ spin_unlock(&clockman->regs_lock); ++} ++ ++static inline unsigned long get_pll_core_divider(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate, ++ u32 *div_int, u32 *div_frac) ++{ ++ unsigned long calc_rate; ++ u32 fbdiv_int, fbdiv_frac; ++ u64 div_fp64; /* 32.32 fixed point fraction. */ ++ ++ /* Factor of reference clock to VCO frequency. */ ++ div_fp64 = (u64)(rate) << 32; ++ div_fp64 = DIV_U64_NEAREST(div_fp64, parent_rate); ++ ++ /* Round the fractional component at 24 bits. */ ++ div_fp64 += 1 << (32 - 24 - 1); ++ ++ fbdiv_int = div_fp64 >> 32; ++ fbdiv_frac = (div_fp64 >> (32 - 24)) & 0xffffff; ++ ++ calc_rate = ++ ((u64)parent_rate * (((u64)fbdiv_int << 24) + fbdiv_frac) + (1 << 23)) >> 24; ++ ++ *div_int = fbdiv_int; ++ *div_frac = fbdiv_frac; ++ ++ return calc_rate; ++} ++ ++static int rp1_pll_core_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ unsigned long calc_rate; ++ u32 fbdiv_int, fbdiv_frac; ++ ++ // todo: is this needed?? ++ //rp1_pll_off(hw); ++ ++ /* Disable dividers to start with. */ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->fbdiv_int_reg, 0); ++ clockman_write(clockman, data->fbdiv_frac_reg, 0); ++ spin_unlock(&clockman->regs_lock); ++ ++ calc_rate = get_pll_core_divider(hw, rate, parent_rate, ++ &fbdiv_int, &fbdiv_frac); ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->pwr_reg, fbdiv_frac ? 0 : PLL_PWR_DSMPD); ++ clockman_write(clockman, data->fbdiv_int_reg, fbdiv_int); ++ clockman_write(clockman, data->fbdiv_frac_reg, fbdiv_frac); ++ spin_unlock(&clockman->regs_lock); ++ ++ /* Check that reference frequency is no greater than VCO / 16. */ ++ BUG_ON(parent_rate > (rate / 16)); ++ ++ pll_core->cached_rate = calc_rate; ++ ++ spin_lock(&clockman->regs_lock); ++ /* Don't need to divide ref unless parent_rate > (output freq / 16) */ ++ clockman_write(clockman, data->cs_reg, ++ clockman_read(clockman, data->cs_reg) | ++ (1 << PLL_CS_REFDIV_SHIFT)); ++ spin_unlock(&clockman->regs_lock); ++ ++ return 0; ++} ++ ++static unsigned long rp1_pll_core_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ u32 fbdiv_int, fbdiv_frac; ++ unsigned long calc_rate; ++ ++ fbdiv_int = clockman_read(clockman, data->fbdiv_int_reg); ++ fbdiv_frac = clockman_read(clockman, data->fbdiv_frac_reg); ++ calc_rate = ++ ((u64)parent_rate * (((u64)fbdiv_int << 24) + fbdiv_frac) + (1 << 23)) >> 24; ++ ++ return calc_rate; ++} ++ ++static long rp1_pll_core_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ u32 fbdiv_int, fbdiv_frac; ++ long calc_rate; ++ ++ calc_rate = get_pll_core_divider(hw, rate, *parent_rate, ++ &fbdiv_int, &fbdiv_frac); ++ return calc_rate; ++} ++ ++static void rp1_pll_core_debug_init(struct clk_hw *hw, struct dentry *dentry) ++{ ++ struct rp1_pll_core *pll_core = container_of(hw, struct rp1_pll_core, hw); ++ struct rp1_clockman *clockman = pll_core->clockman; ++ const struct rp1_pll_core_data *data = pll_core->data; ++ struct debugfs_reg32 *regs; ++ ++ regs = devm_kcalloc(clockman->dev, 4, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ regs[0].name = "cs"; ++ regs[0].offset = data->cs_reg; ++ regs[1].name = "pwr"; ++ regs[1].offset = data->pwr_reg; ++ regs[2].name = "fbdiv_int"; ++ regs[2].offset = data->fbdiv_int_reg; ++ regs[3].name = "fbdiv_frac"; ++ regs[3].offset = data->fbdiv_frac_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, 4, dentry); ++} ++ ++static void get_pll_prim_dividers(unsigned long rate, unsigned long parent_rate, ++ u32 *divider1, u32 *divider2) ++{ ++ unsigned int div1, div2; ++ unsigned int best_div1 = 7, best_div2 = 7; ++ unsigned long best_rate_diff = ++ ABS_DIFF(DIV_ROUND_CLOSEST(parent_rate, best_div1 * best_div2), rate); ++ long rate_diff, calc_rate; ++ ++ for (div1 = 1; div1 <= 7; div1++) { ++ for (div2 = 1; div2 <= div1; div2++) { ++ calc_rate = DIV_ROUND_CLOSEST(parent_rate, div1 * div2); ++ rate_diff = ABS_DIFF(calc_rate, rate); ++ ++ if (calc_rate == rate) { ++ best_div1 = div1; ++ best_div2 = div2; ++ goto done; ++ } else if (rate_diff < best_rate_diff) { ++ best_div1 = div1; ++ best_div2 = div2; ++ best_rate_diff = rate_diff; ++ } ++ } ++ } ++ ++done: ++ *divider1 = best_div1; ++ *divider2 = best_div2; ++} ++ ++static int rp1_pll_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct rp1_pll *pll = container_of(hw, struct rp1_pll, hw); ++ struct rp1_clockman *clockman = pll->clockman; ++ const struct rp1_pll_data *data = pll->data; ++ u32 prim, prim_div1, prim_div2; ++ ++ get_pll_prim_dividers(rate, parent_rate, &prim_div1, &prim_div2); ++ ++ spin_lock(&clockman->regs_lock); ++ prim = clockman_read(clockman, data->ctrl_reg); ++ prim = set_register_field(prim, prim_div1, PLL_PRIM_DIV1_MASK, ++ PLL_PRIM_DIV1_SHIFT); ++ prim = set_register_field(prim, prim_div2, PLL_PRIM_DIV2_MASK, ++ PLL_PRIM_DIV2_SHIFT); ++ clockman_write(clockman, data->ctrl_reg, prim); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static unsigned long rp1_pll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_pll *pll = container_of(hw, struct rp1_pll, hw); ++ struct rp1_clockman *clockman = pll->clockman; ++ const struct rp1_pll_data *data = pll->data; ++ u32 prim, prim_div1, prim_div2; ++ ++ prim = clockman_read(clockman, data->ctrl_reg); ++ prim_div1 = (prim & PLL_PRIM_DIV1_MASK) >> PLL_PRIM_DIV1_SHIFT; ++ prim_div2 = (prim & PLL_PRIM_DIV2_MASK) >> PLL_PRIM_DIV2_SHIFT; ++ ++ if (!prim_div1 || !prim_div2) { ++ dev_err(clockman->dev, "%s: (%s) zero divider value\n", ++ __func__, data->name); ++ return 0; ++ } ++ ++ return DIV_ROUND_CLOSEST(parent_rate, prim_div1 * prim_div2); ++} ++ ++static long rp1_pll_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ u32 div1, div2; ++ ++ get_pll_prim_dividers(rate, *parent_rate, &div1, &div2); ++ ++ return DIV_ROUND_CLOSEST(*parent_rate, div1 * div2); ++} ++ ++static void rp1_pll_debug_init(struct clk_hw *hw, ++ struct dentry *dentry) ++{ ++ struct rp1_pll *pll = container_of(hw, struct rp1_pll, hw); ++ struct rp1_clockman *clockman = pll->clockman; ++ const struct rp1_pll_data *data = pll->data; ++ struct debugfs_reg32 *regs; ++ ++ regs = devm_kcalloc(clockman->dev, 1, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ regs[0].name = "prim"; ++ regs[0].offset = data->ctrl_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, 1, dentry); ++} ++ ++static int rp1_pll_ph_is_on(struct clk_hw *hw) ++{ ++ struct rp1_pll_ph *pll = container_of(hw, struct rp1_pll_ph, hw); ++ struct rp1_clockman *clockman = pll->clockman; ++ const struct rp1_pll_ph_data *data = pll->data; ++ ++ return !!(clockman_read(clockman, data->ph_reg) & PLL_PH_EN); ++} ++ ++static int rp1_pll_ph_on(struct clk_hw *hw) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ struct rp1_clockman *clockman = pll_ph->clockman; ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ u32 ph_reg; ++ ++ /* todo: ensure pri/sec is enabled! */ ++ spin_lock(&clockman->regs_lock); ++ ph_reg = clockman_read(clockman, data->ph_reg); ++ ph_reg |= data->phase << PLL_PH_PHASE_SHIFT; ++ ph_reg |= PLL_PH_EN; ++ clockman_write(clockman, data->ph_reg, ph_reg); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static void rp1_pll_ph_off(struct clk_hw *hw) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ struct rp1_clockman *clockman = pll_ph->clockman; ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->ph_reg, ++ clockman_read(clockman, data->ph_reg) & ~PLL_PH_EN); ++ spin_unlock(&clockman->regs_lock); ++} ++ ++static int rp1_pll_ph_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ struct rp1_clockman *clockman = pll_ph->clockman; ++ ++ /* Nothing really to do here! */ ++ WARN_ON(data->fixed_divider != 1 && data->fixed_divider != 2); ++ WARN_ON(rate != parent_rate / data->fixed_divider); ++ ++#ifdef MEASURE_CLOCK_RATE ++ if (rp1_pll_ph_is_on(hw)) ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static unsigned long rp1_pll_ph_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ ++ return parent_rate / data->fixed_divider; ++} ++ ++static long rp1_pll_ph_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ ++ return *parent_rate / data->fixed_divider; ++} ++ ++static void rp1_pll_ph_debug_init(struct clk_hw *hw, ++ struct dentry *dentry) ++{ ++ struct rp1_pll_ph *pll_ph = container_of(hw, struct rp1_pll_ph, hw); ++ const struct rp1_pll_ph_data *data = pll_ph->data; ++ struct rp1_clockman *clockman = pll_ph->clockman; ++ struct debugfs_reg32 *regs; ++ ++ regs = devm_kcalloc(clockman->dev, 1, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ regs[0].name = "ph_reg"; ++ regs[0].offset = data->ph_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, 1, dentry); ++} ++ ++static int rp1_pll_divider_is_on(struct clk_hw *hw) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ ++ return !(clockman_read(clockman, data->ctrl_reg) & PLL_SEC_RST); ++} ++ ++static int rp1_pll_divider_on(struct clk_hw *hw) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ ++ spin_lock(&clockman->regs_lock); ++ /* Check the implementation bit is set! */ ++ WARN_ON(!(clockman_read(clockman, data->ctrl_reg) & PLL_SEC_IMPL)); ++ clockman_write(clockman, data->ctrl_reg, ++ clockman_read(clockman, data->ctrl_reg) & ~PLL_SEC_RST); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static void rp1_pll_divider_off(struct clk_hw *hw) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->ctrl_reg, PLL_SEC_RST); ++ spin_unlock(&clockman->regs_lock); ++} ++ ++static int rp1_pll_divider_set_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ u32 div, sec; ++ ++ div = DIV_ROUND_UP_ULL(parent_rate, rate); ++ div = clamp(div, 8u, 19u); ++ ++ spin_lock(&clockman->regs_lock); ++ sec = clockman_read(clockman, data->ctrl_reg); ++ sec = set_register_field(sec, div, PLL_SEC_DIV_MASK, PLL_SEC_DIV_SHIFT); ++ ++ /* Must keep the divider in reset to change the value. */ ++ sec |= PLL_SEC_RST; ++ clockman_write(clockman, data->ctrl_reg, sec); ++ ++ // todo: must sleep 10 pll vco cycles ++ sec &= ~PLL_SEC_RST; ++ clockman_write(clockman, data->ctrl_reg, sec); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ if (rp1_pll_divider_is_on(hw)) ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static unsigned long rp1_pll_divider_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return clk_divider_ops.recalc_rate(hw, parent_rate); ++} ++ ++static long rp1_pll_divider_round_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ return clk_divider_ops.round_rate(hw, rate, parent_rate); ++} ++ ++static void rp1_pll_divider_debug_init(struct clk_hw *hw, struct dentry *dentry) ++{ ++ struct rp1_pll *divider = container_of(hw, struct rp1_pll, div.hw); ++ struct rp1_clockman *clockman = divider->clockman; ++ const struct rp1_pll_data *data = divider->data; ++ struct debugfs_reg32 *regs; ++ ++ regs = devm_kcalloc(clockman->dev, 1, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ regs[0].name = "sec"; ++ regs[0].offset = data->ctrl_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, 1, dentry); ++} ++ ++static int rp1_clock_is_on(struct clk_hw *hw) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ ++ return !!(clockman_read(clockman, data->ctrl_reg) & CLK_CTRL_ENABLE); ++} ++ ++static unsigned long rp1_clock_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ u64 calc_rate; ++ u64 div; ++ ++ u32 frac; ++ ++ div = clockman_read(clockman, data->div_int_reg); ++ frac = (data->div_frac_reg != 0) ? ++ clockman_read(clockman, data->div_frac_reg) : 0; ++ ++ /* If the integer portion of the divider is 0, treat it as 2^16 */ ++ if (!div) ++ div = 1 << 16; ++ ++ div = (div << CLK_DIV_FRAC_BITS) | (frac >> (32 - CLK_DIV_FRAC_BITS)); ++ ++ calc_rate = (u64)parent_rate << CLK_DIV_FRAC_BITS; ++ calc_rate = div64_u64(calc_rate, div); ++ ++ return calc_rate; ++} ++ ++static int rp1_clock_on(struct clk_hw *hw) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->ctrl_reg, ++ clockman_read(clockman, data->ctrl_reg) | CLK_CTRL_ENABLE); ++ spin_unlock(&clockman->regs_lock); ++ ++#ifdef MEASURE_CLOCK_RATE ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static void rp1_clock_off(struct clk_hw *hw) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ ++ spin_lock(&clockman->regs_lock); ++ clockman_write(clockman, data->ctrl_reg, ++ clockman_read(clockman, data->ctrl_reg) & ~CLK_CTRL_ENABLE); ++ spin_unlock(&clockman->regs_lock); ++} ++ ++static u32 rp1_clock_choose_div(unsigned long rate, unsigned long parent_rate, ++ const struct rp1_clock_data *data) ++{ ++ u64 div; ++ ++ /* ++ * Due to earlier rounding, calculated parent_rate may differ from ++ * expected value. Don't fail on a small discrepancy near unity divide. ++ */ ++ if (!rate || rate > parent_rate + (parent_rate >> CLK_DIV_FRAC_BITS)) ++ return 0; ++ ++ /* ++ * Always express div in fixed-point format for fractional division; ++ * If no fractional divider is present, the fraction part will be zero. ++ */ ++ if (data->div_frac_reg) { ++ div = (u64)parent_rate << CLK_DIV_FRAC_BITS; ++ div = DIV_U64_NEAREST(div, rate); ++ } else { ++ div = DIV_U64_NEAREST(parent_rate, rate); ++ div <<= CLK_DIV_FRAC_BITS; ++ } ++ ++ div = clamp(div, ++ 1ull << CLK_DIV_FRAC_BITS, ++ (u64)data->div_int_max << CLK_DIV_FRAC_BITS); ++ ++ return div; ++} ++ ++static u8 rp1_clock_get_parent(struct clk_hw *hw) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ u32 sel, ctrl; ++ u8 parent; ++ ++ /* Sel is one-hot, so find the first bit set */ ++ sel = clockman_read(clockman, data->sel_reg); ++ parent = ffs(sel) - 1; ++ ++ /* sel == 0 implies the parent clock is not enabled yet. */ ++ if (!sel) { ++ /* Read the clock src from the CTRL register instead */ ++ ctrl = clockman_read(clockman, data->ctrl_reg); ++ parent = (ctrl & data->clk_src_mask) >> CLK_CTRL_SRC_SHIFT; ++ } ++ ++ if (parent >= data->num_std_parents) ++ parent = AUX_SEL; ++ ++ if (parent == AUX_SEL) { ++ /* ++ * Clock parent is an auxiliary source, so get the parent from ++ * the AUXSRC register field. ++ */ ++ ctrl = clockman_read(clockman, data->ctrl_reg); ++ parent = (ctrl & CLK_CTRL_AUXSRC_MASK) >> CLK_CTRL_AUXSRC_SHIFT; ++ parent += data->num_std_parents; ++ } ++ ++ return parent; ++} ++ ++static int rp1_clock_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ u32 ctrl, sel; ++ ++ spin_lock(&clockman->regs_lock); ++ ctrl = clockman_read(clockman, data->ctrl_reg); ++ ++ if (index >= data->num_std_parents) { ++ /* This is an aux source request */ ++ if (index >= data->num_std_parents + data->num_aux_parents) ++ return -EINVAL; ++ ++ /* Select parent from aux list */ ++ ctrl = set_register_field(ctrl, index - data->num_std_parents, ++ CLK_CTRL_AUXSRC_MASK, ++ CLK_CTRL_AUXSRC_SHIFT); ++ /* Set src to aux list */ ++ ctrl = set_register_field(ctrl, AUX_SEL, data->clk_src_mask, ++ CLK_CTRL_SRC_SHIFT); ++ } else { ++ ctrl = set_register_field(ctrl, index, data->clk_src_mask, ++ CLK_CTRL_SRC_SHIFT); ++ } ++ ++ clockman_write(clockman, data->ctrl_reg, ctrl); ++ spin_unlock(&clockman->regs_lock); ++ ++ sel = rp1_clock_get_parent(hw); ++ WARN(sel != index, "(%s): Parent index req %u returned back %u\n", ++ data->name, index, sel); ++ ++ return 0; ++} ++ ++static int rp1_clock_set_rate_and_parent(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate, ++ u8 parent) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ u32 div = rp1_clock_choose_div(rate, parent_rate, data); ++ ++ WARN(rate > 4000000000ll, "rate is -ve (%d)\n", (int)rate); ++ ++ if (WARN(!div, ++ "clk divider calculated as 0! (%s, rate %ld, parent rate %ld)\n", ++ data->name, rate, parent_rate)) ++ div = 1 << CLK_DIV_FRAC_BITS; ++ ++ spin_lock(&clockman->regs_lock); ++ ++ clockman_write(clockman, data->div_int_reg, div >> CLK_DIV_FRAC_BITS); ++ if (data->div_frac_reg) ++ clockman_write(clockman, data->div_frac_reg, div << (32 - CLK_DIV_FRAC_BITS)); ++ ++ spin_unlock(&clockman->regs_lock); ++ ++ if (parent != 0xff) ++ rp1_clock_set_parent(hw, parent); ++ ++#ifdef MEASURE_CLOCK_RATE ++ if (rp1_clock_is_on(hw)) ++ clockman_measure_clock(clockman, data->name, data->fc0_src); ++#endif ++ return 0; ++} ++ ++static int rp1_clock_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ return rp1_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff); ++} ++ ++static void rp1_clock_choose_div_and_prate(struct clk_hw *hw, ++ int parent_idx, ++ unsigned long rate, ++ unsigned long *prate, ++ unsigned long *calc_rate) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ const struct rp1_clock_data *data = clock->data; ++ struct clk_hw *parent; ++ u32 div; ++ u64 tmp; ++ ++ parent = clk_hw_get_parent_by_index(hw, parent_idx); ++ *prate = clk_hw_get_rate(parent); ++ div = rp1_clock_choose_div(rate, *prate, data); ++ ++ if (!div) { ++ *calc_rate = 0; ++ return; ++ } ++ ++ /* Recalculate to account for rounding errors */ ++ tmp = (u64)*prate << CLK_DIV_FRAC_BITS; ++ tmp = div_u64(tmp, div); ++ *calc_rate = tmp; ++} ++ ++static int rp1_clock_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ struct clk_hw *parent, *best_parent = NULL; ++ unsigned long best_rate = 0; ++ unsigned long best_prate = 0; ++ unsigned long best_rate_diff = ULONG_MAX; ++ unsigned long prate, calc_rate; ++ size_t i; ++ ++ /* ++ * If the NO_REPARENT flag is set, try to use existing parent. ++ */ ++ if ((clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT)) { ++ i = rp1_clock_get_parent(hw); ++ parent = clk_hw_get_parent_by_index(hw, i); ++ if (parent) { ++ rp1_clock_choose_div_and_prate(hw, i, req->rate, &prate, ++ &calc_rate); ++ if (calc_rate > 0) { ++ req->best_parent_hw = parent; ++ req->best_parent_rate = prate; ++ req->rate = calc_rate; ++ return 0; ++ } ++ } ++ } ++ ++ /* ++ * Select parent clock that results in the closest rate (lower or ++ * higher) ++ */ ++ for (i = 0; i < clk_hw_get_num_parents(hw); i++) { ++ parent = clk_hw_get_parent_by_index(hw, i); ++ if (!parent) ++ continue; ++ ++ rp1_clock_choose_div_and_prate(hw, i, req->rate, &prate, ++ &calc_rate); ++ ++ if (ABS_DIFF(calc_rate, req->rate) < best_rate_diff) { ++ best_parent = parent; ++ best_prate = prate; ++ best_rate = calc_rate; ++ best_rate_diff = ABS_DIFF(calc_rate, req->rate); ++ ++ if (best_rate_diff == 0) ++ break; ++ } ++ } ++ ++ if (best_rate == 0) ++ return -EINVAL; ++ ++ req->best_parent_hw = best_parent; ++ req->best_parent_rate = best_prate; ++ req->rate = best_rate; ++ ++ return 0; ++} ++ ++static void rp1_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) ++{ ++ struct rp1_clock *clock = container_of(hw, struct rp1_clock, hw); ++ struct rp1_clockman *clockman = clock->clockman; ++ const struct rp1_clock_data *data = clock->data; ++ struct debugfs_reg32 *regs; ++ int i; ++ ++ regs = devm_kcalloc(clockman->dev, 4, sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return; ++ ++ i = 0; ++ regs[i].name = "ctrl"; ++ regs[i++].offset = data->ctrl_reg; ++ regs[i].name = "div_int"; ++ regs[i++].offset = data->div_int_reg; ++ regs[i].name = "div_frac"; ++ regs[i++].offset = data->div_frac_reg; ++ regs[i].name = "sel"; ++ regs[i++].offset = data->sel_reg; ++ ++ rp1_debugfs_regset(clockman, 0, regs, i, dentry); ++} ++ ++static const struct clk_ops rp1_pll_core_ops = { ++ .is_prepared = rp1_pll_core_is_on, ++ .prepare = rp1_pll_core_on, ++ .unprepare = rp1_pll_core_off, ++ .set_rate = rp1_pll_core_set_rate, ++ .recalc_rate = rp1_pll_core_recalc_rate, ++ .round_rate = rp1_pll_core_round_rate, ++ .debug_init = rp1_pll_core_debug_init, ++}; ++ ++static const struct clk_ops rp1_pll_ops = { ++ .set_rate = rp1_pll_set_rate, ++ .recalc_rate = rp1_pll_recalc_rate, ++ .round_rate = rp1_pll_round_rate, ++ .debug_init = rp1_pll_debug_init, ++}; ++ ++static const struct clk_ops rp1_pll_ph_ops = { ++ .is_prepared = rp1_pll_ph_is_on, ++ .prepare = rp1_pll_ph_on, ++ .unprepare = rp1_pll_ph_off, ++ .set_rate = rp1_pll_ph_set_rate, ++ .recalc_rate = rp1_pll_ph_recalc_rate, ++ .round_rate = rp1_pll_ph_round_rate, ++ .debug_init = rp1_pll_ph_debug_init, ++}; ++ ++static const struct clk_ops rp1_pll_divider_ops = { ++ .is_prepared = rp1_pll_divider_is_on, ++ .prepare = rp1_pll_divider_on, ++ .unprepare = rp1_pll_divider_off, ++ .set_rate = rp1_pll_divider_set_rate, ++ .recalc_rate = rp1_pll_divider_recalc_rate, ++ .round_rate = rp1_pll_divider_round_rate, ++ .debug_init = rp1_pll_divider_debug_init, ++}; ++ ++static const struct clk_ops rp1_clk_ops = { ++ .is_prepared = rp1_clock_is_on, ++ .prepare = rp1_clock_on, ++ .unprepare = rp1_clock_off, ++ .recalc_rate = rp1_clock_recalc_rate, ++ .get_parent = rp1_clock_get_parent, ++ .set_parent = rp1_clock_set_parent, ++ .set_rate_and_parent = rp1_clock_set_rate_and_parent, ++ .set_rate = rp1_clock_set_rate, ++ .determine_rate = rp1_clock_determine_rate, ++ .debug_init = rp1_clk_debug_init, ++}; ++ ++static bool rp1_clk_is_claimed(const char *name); ++ ++static struct clk_hw *rp1_register_pll_core(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_pll_core_data *pll_core_data = data; ++ struct rp1_pll_core *pll_core; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ /* All of the PLL cores derive from the external oscillator. */ ++ init.parent_names = &ref_clock; ++ init.num_parents = 1; ++ init.name = pll_core_data->name; ++ init.ops = &rp1_pll_core_ops; ++ init.flags = pll_core_data->flags | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL; ++ ++ pll_core = kzalloc(sizeof(*pll_core), GFP_KERNEL); ++ if (!pll_core) ++ return NULL; ++ ++ pll_core->clockman = clockman; ++ pll_core->data = pll_core_data; ++ pll_core->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &pll_core->hw); ++ if (ret) { ++ kfree(pll_core); ++ return NULL; ++ } ++ ++ return &pll_core->hw; ++} ++ ++static struct clk_hw *rp1_register_pll(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_pll_data *pll_data = data; ++ struct rp1_pll *pll; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ init.parent_names = &pll_data->source_pll; ++ init.num_parents = 1; ++ init.name = pll_data->name; ++ init.ops = &rp1_pll_ops; ++ init.flags = pll_data->flags | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL; ++ ++ pll = kzalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) ++ return NULL; ++ ++ pll->clockman = clockman; ++ pll->data = pll_data; ++ pll->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &pll->hw); ++ if (ret) { ++ kfree(pll); ++ return NULL; ++ } ++ ++ return &pll->hw; ++} ++ ++static struct clk_hw *rp1_register_pll_ph(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_pll_ph_data *ph_data = data; ++ struct rp1_pll_ph *ph; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ /* All of the PLLs derive from the external oscillator. */ ++ init.parent_names = &ph_data->source_pll; ++ init.num_parents = 1; ++ init.name = ph_data->name; ++ init.ops = &rp1_pll_ph_ops; ++ init.flags = ph_data->flags | CLK_IGNORE_UNUSED; ++ ++ ph = kzalloc(sizeof(*ph), GFP_KERNEL); ++ if (!ph) ++ return NULL; ++ ++ ph->clockman = clockman; ++ ph->data = ph_data; ++ ph->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &ph->hw); ++ if (ret) { ++ kfree(ph); ++ return NULL; ++ } ++ ++ return &ph->hw; ++} ++ ++static struct clk_hw *rp1_register_pll_divider(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_pll_data *divider_data = data; ++ struct rp1_pll *divider; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ ++ init.parent_names = ÷r_data->source_pll; ++ init.num_parents = 1; ++ init.name = divider_data->name; ++ init.ops = &rp1_pll_divider_ops; ++ init.flags = divider_data->flags | CLK_IGNORE_UNUSED; ++ ++ divider = devm_kzalloc(clockman->dev, sizeof(*divider), GFP_KERNEL); ++ if (!divider) ++ return NULL; ++ ++ divider->div.reg = clockman->regs + divider_data->ctrl_reg; ++ divider->div.shift = PLL_SEC_DIV_SHIFT; ++ divider->div.width = PLL_SEC_DIV_WIDTH; ++ divider->div.flags = CLK_DIVIDER_ROUND_CLOSEST; ++ divider->div.lock = &clockman->regs_lock; ++ divider->div.hw.init = &init; ++ divider->div.table = pll_sec_div_table; ++ ++ if (!rp1_clk_is_claimed(divider_data->source_pll)) ++ init.flags |= CLK_IS_CRITICAL; ++ if (!rp1_clk_is_claimed(divider_data->name)) ++ divider->div.flags |= CLK_IS_CRITICAL; ++ ++ divider->clockman = clockman; ++ divider->data = divider_data; ++ ++ ret = devm_clk_hw_register(clockman->dev, ÷r->div.hw); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return ÷r->div.hw; ++} ++ ++static struct clk_hw *rp1_register_clock(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const struct rp1_clock_data *clock_data = data; ++ struct rp1_clock *clock; ++ struct clk_init_data init; ++ int ret; ++ ++ BUG_ON(MAX_CLK_PARENTS < ++ clock_data->num_std_parents + clock_data->num_aux_parents); ++ /* There must be a gap for the AUX selector */ ++ BUG_ON((clock_data->num_std_parents > AUX_SEL) && ++ strcmp("-", clock_data->parents[AUX_SEL])); ++ ++ memset(&init, 0, sizeof(init)); ++ init.parent_names = clock_data->parents; ++ init.num_parents = ++ clock_data->num_std_parents + clock_data->num_aux_parents; ++ init.name = clock_data->name; ++ init.flags = clock_data->flags | CLK_IGNORE_UNUSED; ++ init.ops = &rp1_clk_ops; ++ ++ clock = devm_kzalloc(clockman->dev, sizeof(*clock), GFP_KERNEL); ++ if (!clock) ++ return NULL; ++ ++ clock->clockman = clockman; ++ clock->data = clock_data; ++ clock->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &clock->hw); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return &clock->hw; ++} ++ ++struct rp1_clk_desc { ++ struct clk_hw *(*clk_register)(struct rp1_clockman *clockman, ++ const void *data); ++ const void *data; ++}; ++ ++/* Assignment helper macros for different clock types. */ ++#define _REGISTER(f, ...) { .clk_register = f, .data = __VA_ARGS__ } ++ ++#define REGISTER_PLL_CORE(...) _REGISTER(&rp1_register_pll_core, \ ++ &(struct rp1_pll_core_data) \ ++ {__VA_ARGS__}) ++ ++#define REGISTER_PLL(...) _REGISTER(&rp1_register_pll, \ ++ &(struct rp1_pll_data) \ ++ {__VA_ARGS__}) ++ ++#define REGISTER_PLL_PH(...) _REGISTER(&rp1_register_pll_ph, \ ++ &(struct rp1_pll_ph_data) \ ++ {__VA_ARGS__}) ++ ++#define REGISTER_PLL_DIV(...) _REGISTER(&rp1_register_pll_divider, \ ++ &(struct rp1_pll_data) \ ++ {__VA_ARGS__}) ++ ++#define REGISTER_CLK(...) _REGISTER(&rp1_register_clock, \ ++ &(struct rp1_clock_data) \ ++ {__VA_ARGS__}) ++ ++static const struct rp1_clk_desc clk_desc_array[] = { ++ [RP1_PLL_SYS_CORE] = REGISTER_PLL_CORE( ++ .name = "pll_sys_core", ++ .cs_reg = PLL_SYS_CS, ++ .pwr_reg = PLL_SYS_PWR, ++ .fbdiv_int_reg = PLL_SYS_FBDIV_INT, ++ .fbdiv_frac_reg = PLL_SYS_FBDIV_FRAC, ++ ), ++ ++ [RP1_PLL_AUDIO_CORE] = REGISTER_PLL_CORE( ++ .name = "pll_audio_core", ++ .cs_reg = PLL_AUDIO_CS, ++ .pwr_reg = PLL_AUDIO_PWR, ++ .fbdiv_int_reg = PLL_AUDIO_FBDIV_INT, ++ .fbdiv_frac_reg = PLL_AUDIO_FBDIV_FRAC, ++ ), ++ ++ [RP1_PLL_VIDEO_CORE] = REGISTER_PLL_CORE( ++ .name = "pll_video_core", ++ .cs_reg = PLL_VIDEO_CS, ++ .pwr_reg = PLL_VIDEO_PWR, ++ .fbdiv_int_reg = PLL_VIDEO_FBDIV_INT, ++ .fbdiv_frac_reg = PLL_VIDEO_FBDIV_FRAC, ++ ), ++ ++ [RP1_PLL_SYS] = REGISTER_PLL( ++ .name = "pll_sys", ++ .source_pll = "pll_sys_core", ++ .ctrl_reg = PLL_SYS_PRIM, ++ .fc0_src = FC_NUM(0, 2), ++ ), ++ ++ [RP1_PLL_AUDIO] = REGISTER_PLL( ++ .name = "pll_audio", ++ .source_pll = "pll_audio_core", ++ .ctrl_reg = PLL_AUDIO_PRIM, ++ .fc0_src = FC_NUM(4, 2), ++ ), ++ ++ [RP1_PLL_VIDEO] = REGISTER_PLL( ++ .name = "pll_video", ++ .source_pll = "pll_video_core", ++ .ctrl_reg = PLL_VIDEO_PRIM, ++ .fc0_src = FC_NUM(3, 2), ++ ), ++ ++ [RP1_PLL_SYS_PRI_PH] = REGISTER_PLL_PH( ++ .name = "pll_sys_pri_ph", ++ .source_pll = "pll_sys", ++ .ph_reg = PLL_SYS_PRIM, ++ .fixed_divider = 2, ++ .phase = RP1_PLL_PHASE_0, ++ .fc0_src = FC_NUM(1, 2), ++ ), ++ ++ [RP1_PLL_AUDIO_PRI_PH] = REGISTER_PLL_PH( ++ .name = "pll_audio_pri_ph", ++ .source_pll = "pll_audio", ++ .ph_reg = PLL_AUDIO_PRIM, ++ .fixed_divider = 2, ++ .phase = RP1_PLL_PHASE_0, ++ .fc0_src = FC_NUM(5, 1), ++ ), ++ ++ [RP1_PLL_SYS_SEC] = REGISTER_PLL_DIV( ++ .name = "pll_sys_sec", ++ .source_pll = "pll_sys_core", ++ .ctrl_reg = PLL_SYS_SEC, ++ .fc0_src = FC_NUM(2, 2), ++ ), ++ ++ [RP1_PLL_AUDIO_SEC] = REGISTER_PLL_DIV( ++ .name = "pll_audio_sec", ++ .source_pll = "pll_audio_core", ++ .ctrl_reg = PLL_AUDIO_SEC, ++ .fc0_src = FC_NUM(6, 2), ++ ), ++ ++ [RP1_PLL_VIDEO_SEC] = REGISTER_PLL_DIV( ++ .name = "pll_video_sec", ++ .source_pll = "pll_video_core", ++ .ctrl_reg = PLL_VIDEO_SEC, ++ .fc0_src = FC_NUM(5, 3), ++ ), ++ ++ [RP1_CLK_SYS] = REGISTER_CLK( ++ .name = "clk_sys", ++ .parents = {"xosc", "-", "pll_sys"}, ++ .num_std_parents = 3, ++ .num_aux_parents = 0, ++ .ctrl_reg = CLK_SYS_CTRL, ++ .div_int_reg = CLK_SYS_DIV_INT, ++ .sel_reg = CLK_SYS_SEL, ++ .div_int_max = DIV_INT_24BIT_MAX, ++ .fc0_src = FC_NUM(0, 4), ++ .clk_src_mask = 0x3, ++ ), ++ ++ [RP1_CLK_SLOW_SYS] = REGISTER_CLK( ++ .name = "clk_slow_sys", ++ .parents = {"xosc"}, ++ .num_std_parents = 1, ++ .num_aux_parents = 0, ++ .ctrl_reg = CLK_SLOW_SYS_CTRL, ++ .div_int_reg = CLK_SLOW_SYS_DIV_INT, ++ .sel_reg = CLK_SLOW_SYS_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(1, 4), ++ .clk_src_mask = 0x1, ++ ), ++ ++ [RP1_CLK_UART] = REGISTER_CLK( ++ .name = "clk_uart", ++ .parents = {"pll_sys_pri_ph", ++ "pll_video", ++ "xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 3, ++ .ctrl_reg = CLK_UART_CTRL, ++ .div_int_reg = CLK_UART_DIV_INT, ++ .sel_reg = CLK_UART_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(6, 7), ++ ), ++ ++ [RP1_CLK_ETH] = REGISTER_CLK( ++ .name = "clk_eth", ++ .parents = {"-"}, ++ .num_std_parents = 1, ++ .num_aux_parents = 0, ++ .ctrl_reg = CLK_ETH_CTRL, ++ .div_int_reg = CLK_ETH_DIV_INT, ++ .sel_reg = CLK_ETH_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(4, 6), ++ ), ++ ++ [RP1_CLK_PWM0] = REGISTER_CLK( ++ .name = "clk_pwm0", ++ .parents = {"pll_audio_pri_ph", ++ "pll_video_sec", ++ "xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 3, ++ .ctrl_reg = CLK_PWM0_CTRL, ++ .div_int_reg = CLK_PWM0_DIV_INT, ++ .div_frac_reg = CLK_PWM0_DIV_FRAC, ++ .sel_reg = CLK_PWM0_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .fc0_src = FC_NUM(0, 5), ++ ), ++ ++ [RP1_CLK_PWM1] = REGISTER_CLK( ++ .name = "clk_pwm1", ++ .parents = {"pll_audio_pri_ph", ++ "pll_video_sec", ++ "xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 3, ++ .ctrl_reg = CLK_PWM1_CTRL, ++ .div_int_reg = CLK_PWM1_DIV_INT, ++ .div_frac_reg = CLK_PWM1_DIV_FRAC, ++ .sel_reg = CLK_PWM1_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .fc0_src = FC_NUM(1, 5), ++ ), ++ ++ [RP1_CLK_AUDIO_IN] = REGISTER_CLK( ++ .name = "clk_audio_in", ++ .parents = {"-"}, ++ .num_std_parents = 1, ++ .num_aux_parents = 0, ++ .ctrl_reg = CLK_AUDIO_IN_CTRL, ++ .div_int_reg = CLK_AUDIO_IN_DIV_INT, ++ .sel_reg = CLK_AUDIO_IN_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(2, 5), ++ ), ++ ++ [RP1_CLK_AUDIO_OUT] = REGISTER_CLK( ++ .name = "clk_audio_out", ++ .parents = {"-"}, ++ .num_std_parents = 1, ++ .num_aux_parents = 0, ++ .ctrl_reg = CLK_AUDIO_OUT_CTRL, ++ .div_int_reg = CLK_AUDIO_OUT_DIV_INT, ++ .sel_reg = CLK_AUDIO_OUT_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(3, 5), ++ ), ++ ++ [RP1_CLK_I2S] = REGISTER_CLK( ++ .name = "clk_i2s", ++ .parents = {"xosc", ++ "pll_audio", ++ "pll_audio_sec"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 3, ++ .ctrl_reg = CLK_I2S_CTRL, ++ .div_int_reg = CLK_I2S_DIV_INT, ++ .sel_reg = CLK_I2S_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(4, 4), ++ ), ++ ++ [RP1_CLK_MIPI0_CFG] = REGISTER_CLK( ++ .name = "clk_mipi0_cfg", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_MIPI0_CFG_CTRL, ++ .div_int_reg = CLK_MIPI0_CFG_DIV_INT, ++ .sel_reg = CLK_MIPI0_CFG_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(4, 5), ++ ), ++ ++ [RP1_CLK_MIPI1_CFG] = REGISTER_CLK( ++ .name = "clk_mipi1_cfg", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_MIPI1_CFG_CTRL, ++ .div_int_reg = CLK_MIPI1_CFG_DIV_INT, ++ .sel_reg = CLK_MIPI1_CFG_SEL, ++ .clk_src_mask = 1, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(5, 6), ++ ), ++ ++ [RP1_CLK_ETH_TSU] = REGISTER_CLK( ++ .name = "clk_eth_tsu", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_ETH_TSU_CTRL, ++ .div_int_reg = CLK_ETH_TSU_DIV_INT, ++ .sel_reg = CLK_ETH_TSU_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(5, 7), ++ ), ++ ++ [RP1_CLK_ADC] = REGISTER_CLK( ++ .name = "clk_adc", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_ADC_CTRL, ++ .div_int_reg = CLK_ADC_DIV_INT, ++ .sel_reg = CLK_ADC_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(5, 5), ++ ), ++ ++ [RP1_CLK_SDIO_TIMER] = REGISTER_CLK( ++ .name = "clk_sdio_timer", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_SDIO_TIMER_CTRL, ++ .div_int_reg = CLK_SDIO_TIMER_DIV_INT, ++ .sel_reg = CLK_SDIO_TIMER_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(3, 4), ++ ), ++ ++ [RP1_CLK_SDIO_ALT_SRC] = REGISTER_CLK( ++ .name = "clk_sdio_alt_src", ++ .parents = {"pll_sys"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_SDIO_ALT_SRC_CTRL, ++ .div_int_reg = CLK_SDIO_ALT_SRC_DIV_INT, ++ .sel_reg = CLK_SDIO_ALT_SRC_SEL, ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(5, 4), ++ ), ++ ++ [RP1_CLK_GP0] = REGISTER_CLK( ++ .name = "clk_gp0", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_GP0_CTRL, ++ .div_int_reg = CLK_GP0_DIV_INT, ++ .div_frac_reg = CLK_GP0_DIV_FRAC, ++ .sel_reg = CLK_GP0_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .fc0_src = FC_NUM(0, 1), ++ ), ++ ++ [RP1_CLK_GP1] = REGISTER_CLK( ++ .name = "clk_gp1", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_GP1_CTRL, ++ .div_int_reg = CLK_GP1_DIV_INT, ++ .div_frac_reg = CLK_GP1_DIV_FRAC, ++ .sel_reg = CLK_GP1_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .fc0_src = FC_NUM(1, 1), ++ ), ++ ++ [RP1_CLK_GP2] = REGISTER_CLK( ++ .name = "clk_gp2", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_GP2_CTRL, ++ .div_int_reg = CLK_GP2_DIV_INT, ++ .div_frac_reg = CLK_GP2_DIV_FRAC, ++ .sel_reg = CLK_GP2_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .fc0_src = FC_NUM(2, 1), ++ ), ++ ++ [RP1_CLK_GP3] = REGISTER_CLK( ++ .name = "clk_gp3", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_GP3_CTRL, ++ .div_int_reg = CLK_GP3_DIV_INT, ++ .div_frac_reg = CLK_GP3_DIV_FRAC, ++ .sel_reg = CLK_GP3_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .fc0_src = FC_NUM(3, 1), ++ ), ++ ++ [RP1_CLK_GP4] = REGISTER_CLK( ++ .name = "clk_gp4", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_GP4_CTRL, ++ .div_int_reg = CLK_GP4_DIV_INT, ++ .div_frac_reg = CLK_GP4_DIV_FRAC, ++ .sel_reg = CLK_GP4_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .fc0_src = FC_NUM(4, 1), ++ ), ++ ++ [RP1_CLK_GP5] = REGISTER_CLK( ++ .name = "clk_gp5", ++ .parents = {"xosc"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 1, ++ .ctrl_reg = CLK_GP5_CTRL, ++ .div_int_reg = CLK_GP5_DIV_INT, ++ .div_frac_reg = CLK_GP5_DIV_FRAC, ++ .sel_reg = CLK_GP5_SEL, ++ .div_int_max = DIV_INT_16BIT_MAX, ++ .fc0_src = FC_NUM(5, 1), ++ ), ++ ++ [RP1_CLK_VEC] = REGISTER_CLK( ++ .name = "clk_vec", ++ .parents = {"pll_sys_pri_ph", ++ "pll_video_sec", ++ "pll_video", ++ "clk_gp0", ++ "clk_gp1", ++ "clk_gp2", ++ "clk_gp3", ++ "clk_gp4"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, /* XXX in fact there are more than 8 */ ++ .ctrl_reg = VIDEO_CLK_VEC_CTRL, ++ .div_int_reg = VIDEO_CLK_VEC_DIV_INT, ++ .sel_reg = VIDEO_CLK_VEC_SEL, ++ .flags = CLK_SET_RATE_NO_REPARENT, /* Let VEC driver set parent */ ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(0, 6), ++ ), ++ ++ [RP1_CLK_DPI] = REGISTER_CLK( ++ .name = "clk_dpi", ++ .parents = {"pll_sys", ++ "pll_video_sec", ++ "pll_video", ++ "clk_gp0", ++ "clk_gp1", ++ "clk_gp2", ++ "clk_gp3", ++ "clk_gp4"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, /* XXX in fact there are more than 8 */ ++ .ctrl_reg = VIDEO_CLK_DPI_CTRL, ++ .div_int_reg = VIDEO_CLK_DPI_DIV_INT, ++ .sel_reg = VIDEO_CLK_DPI_SEL, ++ .flags = CLK_SET_RATE_NO_REPARENT, /* Let DPI driver set parent */ ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(1, 6), ++ ), ++ ++ [RP1_CLK_MIPI0_DPI] = REGISTER_CLK( ++ .name = "clk_mipi0_dpi", ++ .parents = {"pll_sys", ++ "pll_video_sec", ++ "pll_video", ++ "clksrc_mipi0_dsi_byteclk", ++ "clk_gp0", ++ "clk_gp1", ++ "clk_gp2", ++ "clk_gp3"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, /* XXX in fact there are more than 8 */ ++ .ctrl_reg = VIDEO_CLK_MIPI0_DPI_CTRL, ++ .div_int_reg = VIDEO_CLK_MIPI0_DPI_DIV_INT, ++ .div_frac_reg = VIDEO_CLK_MIPI0_DPI_DIV_FRAC, ++ .sel_reg = VIDEO_CLK_MIPI0_DPI_SEL, ++ .flags = CLK_SET_RATE_NO_REPARENT, /* Let DSI driver set parent */ ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(2, 6), ++ ), ++ ++ [RP1_CLK_MIPI1_DPI] = REGISTER_CLK( ++ .name = "clk_mipi1_dpi", ++ .parents = {"pll_sys", ++ "pll_video_sec", ++ "pll_video", ++ "clksrc_mipi1_dsi_byteclk", ++ "clk_gp0", ++ "clk_gp1", ++ "clk_gp2", ++ "clk_gp3"}, ++ .num_std_parents = 0, ++ .num_aux_parents = 8, /* XXX in fact there are more than 8 */ ++ .ctrl_reg = VIDEO_CLK_MIPI1_DPI_CTRL, ++ .div_int_reg = VIDEO_CLK_MIPI1_DPI_DIV_INT, ++ .div_frac_reg = VIDEO_CLK_MIPI1_DPI_DIV_FRAC, ++ .sel_reg = VIDEO_CLK_MIPI1_DPI_SEL, ++ .flags = CLK_SET_RATE_NO_REPARENT, /* Let DSI driver set parent */ ++ .div_int_max = DIV_INT_8BIT_MAX, ++ .fc0_src = FC_NUM(3, 6), ++ ), ++}; ++ ++static bool rp1_clk_claimed[ARRAY_SIZE(clk_desc_array)]; ++ ++static bool rp1_clk_is_claimed(const char *name) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) { ++ if (clk_desc_array[i].data) { ++ const char *clk_name = *(const char **)(clk_desc_array[i].data); ++ ++ if (!strcmp(name, clk_name)) ++ return rp1_clk_claimed[i]; ++ } ++ } ++ ++ return false; ++} ++ ++static int rp1_clk_probe(struct platform_device *pdev) ++{ ++ const struct rp1_clk_desc *desc; ++ struct device *dev = &pdev->dev; ++ struct rp1_clockman *clockman; ++ struct resource *res; ++ struct clk_hw **hws; ++ const size_t asize = ARRAY_SIZE(clk_desc_array); ++ u32 chip_id, platform; ++ unsigned int i; ++ u32 clk_id; ++ int ret; ++ ++ clockman = devm_kzalloc(dev, struct_size(clockman, onecell.hws, asize), ++ GFP_KERNEL); ++ if (!clockman) ++ return -ENOMEM; ++ ++ rp1_get_platform(&chip_id, &platform); ++ ++ spin_lock_init(&clockman->regs_lock); ++ clockman->dev = dev; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ clockman->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(clockman->regs)) ++ return PTR_ERR(clockman->regs); ++ ++ memset(rp1_clk_claimed, 0, sizeof(rp1_clk_claimed)); ++ for (i = 0; ++ !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", ++ i, &clk_id); ++ i++) ++ rp1_clk_claimed[clk_id] = true; ++ ++ platform_set_drvdata(pdev, clockman); ++ ++ clockman->onecell.num = asize; ++ hws = clockman->onecell.hws; ++ ++ for (i = 0; i < asize; i++) { ++ desc = &clk_desc_array[i]; ++ if (desc->clk_register && desc->data) ++ hws[i] = desc->clk_register(clockman, desc->data); ++ } ++ ++ ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, ++ &clockman->onecell); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static const struct of_device_id rp1_clk_of_match[] = { ++ { .compatible = "raspberrypi,rp1-clocks" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, rp1_clk_of_match); ++ ++static struct platform_driver rp1_clk_driver = { ++ .driver = { ++ .name = "rp1-clk", ++ .of_match_table = rp1_clk_of_match, ++ }, ++ .probe = rp1_clk_probe, ++}; ++ ++static int __init __rp1_clk_driver_init(void) ++{ ++ return platform_driver_register(&rp1_clk_driver); ++} ++postcore_initcall(__rp1_clk_driver_init); ++ ++MODULE_AUTHOR("Naushir Patuck "); ++MODULE_DESCRIPTION("RP1 clock driver"); ++MODULE_LICENSE("GPL"); +--- a/include/dt-bindings/clock/rp1.h ++++ b/include/dt-bindings/clock/rp1.h +@@ -13,39 +13,40 @@ + + #define RP1_PLL_SYS_PRI_PH 6 + #define RP1_PLL_SYS_SEC_PH 7 ++#define RP1_PLL_AUDIO_PRI_PH 8 + +-#define RP1_PLL_SYS_SEC 8 +-#define RP1_PLL_AUDIO_SEC 9 +-#define RP1_PLL_VIDEO_SEC 10 ++#define RP1_PLL_SYS_SEC 9 ++#define RP1_PLL_AUDIO_SEC 10 ++#define RP1_PLL_VIDEO_SEC 11 + +-#define RP1_CLK_SYS 11 +-#define RP1_CLK_SLOW_SYS 12 +-#define RP1_CLK_DMA 13 +-#define RP1_CLK_UART 14 +-#define RP1_CLK_ETH 15 +-#define RP1_CLK_PWM0 16 +-#define RP1_CLK_PWM1 17 +-#define RP1_CLK_AUDIO_IN 18 +-#define RP1_CLK_AUDIO_OUT 19 +-#define RP1_CLK_I2S 20 +-#define RP1_CLK_MIPI0_CFG 21 +-#define RP1_CLK_MIPI1_CFG 22 +-#define RP1_CLK_PCIE_AUX 23 +-#define RP1_CLK_USBH0_MICROFRAME 24 +-#define RP1_CLK_USBH1_MICROFRAME 25 +-#define RP1_CLK_USBH0_SUSPEND 26 +-#define RP1_CLK_USBH1_SUSPEND 27 +-#define RP1_CLK_ETH_TSU 28 +-#define RP1_CLK_ADC 29 +-#define RP1_CLK_SDIO_TIMER 30 +-#define RP1_CLK_SDIO_ALT_SRC 31 +-#define RP1_CLK_GP0 32 +-#define RP1_CLK_GP1 33 +-#define RP1_CLK_GP2 34 +-#define RP1_CLK_GP3 35 +-#define RP1_CLK_GP4 36 +-#define RP1_CLK_GP5 37 +-#define RP1_CLK_VEC 38 +-#define RP1_CLK_DPI 39 +-#define RP1_CLK_MIPI0_DPI 40 +-#define RP1_CLK_MIPI1_DPI 41 ++#define RP1_CLK_SYS 12 ++#define RP1_CLK_SLOW_SYS 13 ++#define RP1_CLK_DMA 14 ++#define RP1_CLK_UART 15 ++#define RP1_CLK_ETH 16 ++#define RP1_CLK_PWM0 17 ++#define RP1_CLK_PWM1 18 ++#define RP1_CLK_AUDIO_IN 19 ++#define RP1_CLK_AUDIO_OUT 20 ++#define RP1_CLK_I2S 21 ++#define RP1_CLK_MIPI0_CFG 22 ++#define RP1_CLK_MIPI1_CFG 23 ++#define RP1_CLK_PCIE_AUX 24 ++#define RP1_CLK_USBH0_MICROFRAME 25 ++#define RP1_CLK_USBH1_MICROFRAME 26 ++#define RP1_CLK_USBH0_SUSPEND 27 ++#define RP1_CLK_USBH1_SUSPEND 28 ++#define RP1_CLK_ETH_TSU 29 ++#define RP1_CLK_ADC 30 ++#define RP1_CLK_SDIO_TIMER 31 ++#define RP1_CLK_SDIO_ALT_SRC 32 ++#define RP1_CLK_GP0 33 ++#define RP1_CLK_GP1 34 ++#define RP1_CLK_GP2 35 ++#define RP1_CLK_GP3 36 ++#define RP1_CLK_GP4 37 ++#define RP1_CLK_GP5 38 ++#define RP1_CLK_VEC 39 ++#define RP1_CLK_DPI 40 ++#define RP1_CLK_MIPI0_DPI 41 ++#define RP1_CLK_MIPI1_DPI 42 diff --git a/target/linux/bcm27xx/patches-6.1/950-0875-dt-bindings-pinctrl-Add-bindings-for-Raspberry-Pi-RP.patch b/target/linux/bcm27xx/patches-6.1/950-0875-dt-bindings-pinctrl-Add-bindings-for-Raspberry-Pi-RP.patch new file mode 100644 index 0000000000..d0180a65ba --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0875-dt-bindings-pinctrl-Add-bindings-for-Raspberry-Pi-RP.patch @@ -0,0 +1,60 @@ +From 19b934ce3763c9465c5c80302f7c142d30b75869 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 28 Oct 2022 14:13:30 +0100 +Subject: [PATCH] dt-bindings: pinctrl: Add bindings for Raspberry Pi RP1 + +Signed-off-by: Phil Elwell +--- + include/dt-bindings/pinctrl/rp1.h | 46 +++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + create mode 100644 include/dt-bindings/pinctrl/rp1.h + +--- /dev/null ++++ b/include/dt-bindings/pinctrl/rp1.h +@@ -0,0 +1,46 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Header providing constants for RP1 pinctrl bindings. ++ * ++ * Copyright (C) 2019-2022 Raspberry Pi Ltd. ++ */ ++ ++#ifndef __DT_BINDINGS_PINCTRL_RP1_H__ ++#define __DT_BINDINGS_PINCTRL_RP1_H__ ++ ++/* brcm,function property */ ++#define RP1_FSEL_GPIO_IN 0 ++#define RP1_FSEL_GPIO_OUT 1 ++#define RP1_FSEL_ALT0_LEGACY 4 ++#define RP1_FSEL_ALT1_LEGACY 5 ++#define RP1_FSEL_ALT2_LEGACY 6 ++#define RP1_FSEL_ALT3_LEGACY 7 ++#define RP1_FSEL_ALT4_LEGACY 3 ++#define RP1_FSEL_ALT5_LEGACY 2 ++#define RP1_FSEL_ALT0 0x08 ++#define RP1_FSEL_ALT0INV 0x09 ++#define RP1_FSEL_ALT1 0x0a ++#define RP1_FSEL_ALT1INV 0x0b ++#define RP1_FSEL_ALT2 0x0c ++#define RP1_FSEL_ALT2INV 0x0d ++#define RP1_FSEL_ALT3 0x0e ++#define RP1_FSEL_ALT3INV 0x0f ++#define RP1_FSEL_ALT4 0x10 ++#define RP1_FSEL_ALT4INV 0x11 ++#define RP1_FSEL_ALT5 0x12 ++#define RP1_FSEL_ALT5INV 0x13 ++#define RP1_FSEL_ALT6 0x14 ++#define RP1_FSEL_ALT6INV 0x15 ++#define RP1_FSEL_ALT7 0x16 ++#define RP1_FSEL_ALT7INV 0x17 ++#define RP1_FSEL_ALT8 0x18 ++#define RP1_FSEL_ALT8INV 0x19 ++#define RP1_FSEL_NONE 0x1a ++ ++/* brcm,pull property */ ++#define RP1_PUD_OFF 0 ++#define RP1_PUD_DOWN 1 ++#define RP1_PUD_UP 2 ++#define RP1_PUD_KEEP 3 ++ ++#endif /* __DT_BINDINGS_PINCTRL_RP1_H__ */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0876-pinctrl-Add-rp1-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0876-pinctrl-Add-rp1-driver.patch new file mode 100644 index 0000000000..c824cddb51 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0876-pinctrl-Add-rp1-driver.patch @@ -0,0 +1,1666 @@ +From 4d4cc5be473a7767052122a87393a83d10f9ed41 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 10 Oct 2022 14:21:11 +0100 +Subject: [PATCH] pinctrl: Add rp1 driver + +RP1 exposes GPIOs. Add a pinctrl driver to allow control of those. + +Signed-off-by: Phil Elwell +--- + drivers/pinctrl/Kconfig | 7 + + drivers/pinctrl/Makefile | 1 + + drivers/pinctrl/pinctrl-rp1.c | 1571 +++++++++++++++++++++++++++++ + include/dt-bindings/pinctrl/rp1.h | 46 - + 4 files changed, 1579 insertions(+), 46 deletions(-) + create mode 100644 drivers/pinctrl/pinctrl-rp1.c + delete mode 100644 include/dt-bindings/pinctrl/rp1.h + +--- a/drivers/pinctrl/Kconfig ++++ b/drivers/pinctrl/Kconfig +@@ -512,6 +512,13 @@ config PINCTRL_ZYNQMP + This driver can also be built as a module. If so, the module + will be called pinctrl-zynqmp. + ++config PINCTRL_RP1 ++ bool "Pinctrl driver for RP1" ++ select PINMUX ++ select PINCONF ++ select GENERIC_PINCONF ++ select GPIOLIB_IRQCHIP ++ + source "drivers/pinctrl/actions/Kconfig" + source "drivers/pinctrl/aspeed/Kconfig" + source "drivers/pinctrl/bcm/Kconfig" +--- a/drivers/pinctrl/Makefile ++++ b/drivers/pinctrl/Makefile +@@ -42,6 +42,7 @@ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-p + obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o + obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o + obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o ++obj-$(CONFIG_PINCTRL_RP1) += pinctrl-rp1.o + obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o + obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o + obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o +--- /dev/null ++++ b/drivers/pinctrl/pinctrl-rp1.c +@@ -0,0 +1,1571 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Driver for Raspberry Pi RP1 GPIO unit (pinctrl + GPIO) ++ * ++ * Copyright (C) 2023 Raspberry Pi Ltd. ++ * ++ * This driver is inspired by: ++ * pinctrl-bcm2835.c, please see original file for copyright information ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "core.h" ++#include "pinconf.h" ++#include "pinctrl-utils.h" ++ ++#define MODULE_NAME "pinctrl-rp1" ++#define RP1_NUM_GPIOS 54 ++#define RP1_NUM_BANKS 3 ++ ++#define RP1_RW_OFFSET 0x0000 ++#define RP1_XOR_OFFSET 0x1000 ++#define RP1_SET_OFFSET 0x2000 ++#define RP1_CLR_OFFSET 0x3000 ++ ++#define RP1_GPIO_STATUS 0x0000 ++#define RP1_GPIO_CTRL 0x0004 ++ ++#define RP1_GPIO_PCIE_INTE 0x011c ++#define RP1_GPIO_PCIE_INTS 0x0124 ++ ++#define RP1_GPIO_EVENTS_SHIFT_RAW 20 ++#define RP1_GPIO_STATUS_FALLING BIT(20) ++#define RP1_GPIO_STATUS_RISING BIT(21) ++#define RP1_GPIO_STATUS_LOW BIT(22) ++#define RP1_GPIO_STATUS_HIGH BIT(23) ++ ++#define RP1_GPIO_EVENTS_SHIFT_FILTERED 24 ++#define RP1_GPIO_STATUS_F_FALLING BIT(24) ++#define RP1_GPIO_STATUS_F_RISING BIT(25) ++#define RP1_GPIO_STATUS_F_LOW BIT(26) ++#define RP1_GPIO_STATUS_F_HIGH BIT(27) ++ ++#define RP1_GPIO_CTRL_FUNCSEL_LSB 0 ++#define RP1_GPIO_CTRL_FUNCSEL_MASK 0x0000001f ++#define RP1_GPIO_CTRL_OUTOVER_LSB 12 ++#define RP1_GPIO_CTRL_OUTOVER_MASK 0x00003000 ++#define RP1_GPIO_CTRL_OEOVER_LSB 14 ++#define RP1_GPIO_CTRL_OEOVER_MASK 0x0000c000 ++#define RP1_GPIO_CTRL_INOVER_LSB 16 ++#define RP1_GPIO_CTRL_INOVER_MASK 0x00030000 ++#define RP1_GPIO_CTRL_IRQEN_FALLING BIT(20) ++#define RP1_GPIO_CTRL_IRQEN_RISING BIT(21) ++#define RP1_GPIO_CTRL_IRQEN_LOW BIT(22) ++#define RP1_GPIO_CTRL_IRQEN_HIGH BIT(23) ++#define RP1_GPIO_CTRL_IRQEN_F_FALLING BIT(24) ++#define RP1_GPIO_CTRL_IRQEN_F_RISING BIT(25) ++#define RP1_GPIO_CTRL_IRQEN_F_LOW BIT(26) ++#define RP1_GPIO_CTRL_IRQEN_F_HIGH BIT(27) ++#define RP1_GPIO_CTRL_IRQRESET BIT(28) ++#define RP1_GPIO_CTRL_IRQOVER_LSB 30 ++#define RP1_GPIO_CTRL_IRQOVER_MASK 0xc0000000 ++ ++#define RP1_INT_EDGE_FALLING BIT(0) ++#define RP1_INT_EDGE_RISING BIT(1) ++#define RP1_INT_LEVEL_LOW BIT(2) ++#define RP1_INT_LEVEL_HIGH BIT(3) ++#define RP1_INT_MASK 0xf ++ ++#define RP1_INT_EDGE_BOTH (RP1_INT_EDGE_FALLING | \ ++ RP1_INT_EDGE_RISING) ++#define RP1_PUD_OFF 0 ++#define RP1_PUD_DOWN 1 ++#define RP1_PUD_UP 2 ++ ++#define RP1_FSEL_COUNT 9 ++ ++#define RP1_FSEL_ALT0 0x00 ++#define RP1_FSEL_GPIO 0x05 ++#define RP1_FSEL_NONE 0x09 ++#define RP1_FSEL_NONE_HW 0x1f ++ ++#define RP1_DIR_OUTPUT 0 ++#define RP1_DIR_INPUT 1 ++ ++#define RP1_OUTOVER_PERI 0 ++#define RP1_OUTOVER_INVPERI 1 ++#define RP1_OUTOVER_LOW 2 ++#define RP1_OUTOVER_HIGH 3 ++ ++#define RP1_OEOVER_PERI 0 ++#define RP1_OEOVER_INVPERI 1 ++#define RP1_OEOVER_DISABLE 2 ++#define RP1_OEOVER_ENABLE 3 ++ ++#define RP1_INOVER_PERI 0 ++#define RP1_INOVER_INVPERI 1 ++#define RP1_INOVER_LOW 2 ++#define RP1_INOVER_HIGH 3 ++ ++#define RP1_RIO_OUT 0x00 ++#define RP1_RIO_OE 0x04 ++#define RP1_RIO_IN 0x08 ++ ++#define RP1_PAD_SLEWFAST_MASK 0x00000001 ++#define RP1_PAD_SLEWFAST_LSB 0 ++#define RP1_PAD_SCHMITT_MASK 0x00000002 ++#define RP1_PAD_SCHMITT_LSB 1 ++#define RP1_PAD_PULL_MASK 0x0000000c ++#define RP1_PAD_PULL_LSB 2 ++#define RP1_PAD_DRIVE_MASK 0x00000030 ++#define RP1_PAD_DRIVE_LSB 4 ++#define RP1_PAD_IN_ENABLE_MASK 0x00000040 ++#define RP1_PAD_IN_ENABLE_LSB 6 ++#define RP1_PAD_OUT_DISABLE_MASK 0x00000080 ++#define RP1_PAD_OUT_DISABLE_LSB 7 ++ ++#define RP1_PAD_DRIVE_2MA 0x00000000 ++#define RP1_PAD_DRIVE_4MA 0x00000010 ++#define RP1_PAD_DRIVE_8MA 0x00000020 ++#define RP1_PAD_DRIVE_12MA 0x00000030 ++ ++#define FLD_GET(r, f) (((r) & (f ## _MASK)) >> (f ## _LSB)) ++#define FLD_SET(r, f, v) r = (((r) & ~(f ## _MASK)) | ((v) << (f ## _LSB))) ++ ++#define FUNC(f) \ ++ [func_##f] = #f ++#define RP1_MAX_FSEL 8 ++#define PIN(i, f0, f1, f2, f3, f4, f5, f6, f7, f8) \ ++ [i] = { \ ++ .funcs = { \ ++ func_##f0, \ ++ func_##f1, \ ++ func_##f2, \ ++ func_##f3, \ ++ func_##f4, \ ++ func_##f5, \ ++ func_##f6, \ ++ func_##f7, \ ++ func_##f8, \ ++ }, \ ++ } ++ ++#define LEGACY_MAP(n, f0, f1, f2, f3, f4, f5) \ ++ [n] = { \ ++ func_gpio, \ ++ func_gpio, \ ++ func_##f5, \ ++ func_##f4, \ ++ func_##f0, \ ++ func_##f1, \ ++ func_##f2, \ ++ func_##f3, \ ++ } ++ ++struct rp1_iobank_desc { ++ int min_gpio; ++ int num_gpios; ++ int gpio_offset; ++ int inte_offset; ++ int ints_offset; ++ int rio_offset; ++ int pads_offset; ++}; ++ ++struct rp1_pin_info { ++ u8 num; ++ u8 bank; ++ u8 offset; ++ u8 fsel; ++ u8 irq_type; ++ ++ void __iomem *gpio; ++ void __iomem *rio; ++ void __iomem *inte; ++ void __iomem *ints; ++ void __iomem *pad; ++}; ++ ++enum funcs { ++ func_alt0, ++ func_alt1, ++ func_alt2, ++ func_alt3, ++ func_alt4, ++ func_gpio, ++ func_alt6, ++ func_alt7, ++ func_alt8, ++ func_none, ++ func_aaud, ++ func_dcd0, ++ func_dpi, ++ func_dsi0_te_ext, ++ func_dsi1_te_ext, ++ func_dsr0, ++ func_dtr0, ++ func_gpclk0, ++ func_gpclk1, ++ func_gpclk2, ++ func_gpclk3, ++ func_gpclk4, ++ func_gpclk5, ++ func_i2c0, ++ func_i2c1, ++ func_i2c2, ++ func_i2c3, ++ func_i2c4, ++ func_i2c5, ++ func_i2c6, ++ func_i2s0, ++ func_i2s1, ++ func_i2s2, ++ func_ir, ++ func_mic, ++ func_pcie_clkreq_n, ++ func_pio, ++ func_proc_rio, ++ func_pwm0, ++ func_pwm1, ++ func_ri0, ++ func_sd0, ++ func_sd1, ++ func_spi0, ++ func_spi1, ++ func_spi2, ++ func_spi3, ++ func_spi4, ++ func_spi5, ++ func_spi6, ++ func_spi7, ++ func_spi8, ++ func_uart0, ++ func_uart1, ++ func_uart2, ++ func_uart3, ++ func_uart4, ++ func_uart5, ++ func_vbus0, ++ func_vbus1, ++ func_vbus2, ++ func_vbus3, ++ func__, ++ func_count = func__, ++ func_invalid = func__, ++}; ++ ++struct rp1_pin_funcs { ++ u8 funcs[RP1_FSEL_COUNT]; ++}; ++ ++struct rp1_pinctrl { ++ struct device *dev; ++ void __iomem *gpio_base; ++ void __iomem *rio_base; ++ void __iomem *pads_base; ++ int irq[RP1_NUM_BANKS]; ++ struct rp1_pin_info pins[RP1_NUM_GPIOS]; ++ ++ struct pinctrl_dev *pctl_dev; ++ struct gpio_chip gpio_chip; ++ struct pinctrl_gpio_range gpio_range; ++ ++ raw_spinlock_t irq_lock[RP1_NUM_BANKS]; ++}; ++ ++const struct rp1_iobank_desc rp1_iobanks[RP1_NUM_BANKS] = { ++ /* gpio inte ints rio pads */ ++ { 0, 28, 0x0000, 0x011c, 0x0124, 0x0000, 0x0004 }, ++ { 28, 6, 0x4000, 0x411c, 0x4124, 0x4000, 0x4004 }, ++ { 34, 20, 0x8000, 0x811c, 0x8124, 0x8000, 0x8004 }, ++}; ++ ++/* pins are just named GPIO0..GPIO53 */ ++#define RP1_GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a) ++static struct pinctrl_pin_desc rp1_gpio_pins[] = { ++ RP1_GPIO_PIN(0), ++ RP1_GPIO_PIN(1), ++ RP1_GPIO_PIN(2), ++ RP1_GPIO_PIN(3), ++ RP1_GPIO_PIN(4), ++ RP1_GPIO_PIN(5), ++ RP1_GPIO_PIN(6), ++ RP1_GPIO_PIN(7), ++ RP1_GPIO_PIN(8), ++ RP1_GPIO_PIN(9), ++ RP1_GPIO_PIN(10), ++ RP1_GPIO_PIN(11), ++ RP1_GPIO_PIN(12), ++ RP1_GPIO_PIN(13), ++ RP1_GPIO_PIN(14), ++ RP1_GPIO_PIN(15), ++ RP1_GPIO_PIN(16), ++ RP1_GPIO_PIN(17), ++ RP1_GPIO_PIN(18), ++ RP1_GPIO_PIN(19), ++ RP1_GPIO_PIN(20), ++ RP1_GPIO_PIN(21), ++ RP1_GPIO_PIN(22), ++ RP1_GPIO_PIN(23), ++ RP1_GPIO_PIN(24), ++ RP1_GPIO_PIN(25), ++ RP1_GPIO_PIN(26), ++ RP1_GPIO_PIN(27), ++ RP1_GPIO_PIN(28), ++ RP1_GPIO_PIN(29), ++ RP1_GPIO_PIN(30), ++ RP1_GPIO_PIN(31), ++ RP1_GPIO_PIN(32), ++ RP1_GPIO_PIN(33), ++ RP1_GPIO_PIN(34), ++ RP1_GPIO_PIN(35), ++ RP1_GPIO_PIN(36), ++ RP1_GPIO_PIN(37), ++ RP1_GPIO_PIN(38), ++ RP1_GPIO_PIN(39), ++ RP1_GPIO_PIN(40), ++ RP1_GPIO_PIN(41), ++ RP1_GPIO_PIN(42), ++ RP1_GPIO_PIN(43), ++ RP1_GPIO_PIN(44), ++ RP1_GPIO_PIN(45), ++ RP1_GPIO_PIN(46), ++ RP1_GPIO_PIN(47), ++ RP1_GPIO_PIN(48), ++ RP1_GPIO_PIN(49), ++ RP1_GPIO_PIN(50), ++ RP1_GPIO_PIN(51), ++ RP1_GPIO_PIN(52), ++ RP1_GPIO_PIN(53), ++}; ++ ++/* one pin per group */ ++static const char * const rp1_gpio_groups[] = { ++ "gpio0", ++ "gpio1", ++ "gpio2", ++ "gpio3", ++ "gpio4", ++ "gpio5", ++ "gpio6", ++ "gpio7", ++ "gpio8", ++ "gpio9", ++ "gpio10", ++ "gpio11", ++ "gpio12", ++ "gpio13", ++ "gpio14", ++ "gpio15", ++ "gpio16", ++ "gpio17", ++ "gpio18", ++ "gpio19", ++ "gpio20", ++ "gpio21", ++ "gpio22", ++ "gpio23", ++ "gpio24", ++ "gpio25", ++ "gpio26", ++ "gpio27", ++ "gpio28", ++ "gpio29", ++ "gpio30", ++ "gpio31", ++ "gpio32", ++ "gpio33", ++ "gpio34", ++ "gpio35", ++ "gpio36", ++ "gpio37", ++ "gpio38", ++ "gpio39", ++ "gpio40", ++ "gpio41", ++ "gpio42", ++ "gpio43", ++ "gpio44", ++ "gpio45", ++ "gpio46", ++ "gpio47", ++ "gpio48", ++ "gpio49", ++ "gpio50", ++ "gpio51", ++ "gpio52", ++ "gpio53", ++}; ++ ++static const char * const rp1_func_names[] = { ++ FUNC(alt0), ++ FUNC(alt1), ++ FUNC(alt2), ++ FUNC(alt3), ++ FUNC(alt4), ++ FUNC(gpio), ++ FUNC(alt6), ++ FUNC(alt7), ++ FUNC(alt8), ++ FUNC(none), ++ FUNC(aaud), ++ FUNC(dcd0), ++ FUNC(dpi), ++ FUNC(dsi0_te_ext), ++ FUNC(dsi1_te_ext), ++ FUNC(dsr0), ++ FUNC(dtr0), ++ FUNC(gpclk0), ++ FUNC(gpclk1), ++ FUNC(gpclk2), ++ FUNC(gpclk3), ++ FUNC(gpclk4), ++ FUNC(gpclk5), ++ FUNC(i2c0), ++ FUNC(i2c1), ++ FUNC(i2c2), ++ FUNC(i2c3), ++ FUNC(i2c4), ++ FUNC(i2c5), ++ FUNC(i2c6), ++ FUNC(i2s0), ++ FUNC(i2s1), ++ FUNC(i2s2), ++ FUNC(ir), ++ FUNC(mic), ++ FUNC(pcie_clkreq_n), ++ FUNC(pio), ++ FUNC(proc_rio), ++ FUNC(pwm0), ++ FUNC(pwm1), ++ FUNC(ri0), ++ FUNC(sd0), ++ FUNC(sd1), ++ FUNC(spi0), ++ FUNC(spi1), ++ FUNC(spi2), ++ FUNC(spi3), ++ FUNC(spi4), ++ FUNC(spi5), ++ FUNC(spi6), ++ FUNC(spi7), ++ FUNC(spi8), ++ FUNC(uart0), ++ FUNC(uart1), ++ FUNC(uart2), ++ FUNC(uart3), ++ FUNC(uart4), ++ FUNC(uart5), ++ FUNC(vbus0), ++ FUNC(vbus1), ++ FUNC(vbus2), ++ FUNC(vbus3), ++ [func_invalid] = "?" ++}; ++ ++static const struct rp1_pin_funcs rp1_gpio_pin_funcs[] = { ++ PIN(0, spi0, dpi, uart1, i2c0, _, gpio, proc_rio, pio, spi2), ++ PIN(1, spi0, dpi, uart1, i2c0, _, gpio, proc_rio, pio, spi2), ++ PIN(2, spi0, dpi, uart1, i2c1, ir, gpio, proc_rio, pio, spi2), ++ PIN(3, spi0, dpi, uart1, i2c1, ir, gpio, proc_rio, pio, spi2), ++ PIN(4, gpclk0, dpi, uart2, i2c2, ri0, gpio, proc_rio, pio, spi3), ++ PIN(5, gpclk1, dpi, uart2, i2c2, dtr0, gpio, proc_rio, pio, spi3), ++ PIN(6, gpclk2, dpi, uart2, i2c3, dcd0, gpio, proc_rio, pio, spi3), ++ PIN(7, spi0, dpi, uart2, i2c3, dsr0, gpio, proc_rio, pio, spi3), ++ PIN(8, spi0, dpi, uart3, i2c0, _, gpio, proc_rio, pio, spi4), ++ PIN(9, spi0, dpi, uart3, i2c0, _, gpio, proc_rio, pio, spi4), ++ PIN(10, spi0, dpi, uart3, i2c1, _, gpio, proc_rio, pio, spi4), ++ PIN(11, spi0, dpi, uart3, i2c1, _, gpio, proc_rio, pio, spi4), ++ PIN(12, pwm0, dpi, uart4, i2c2, aaud, gpio, proc_rio, pio, spi5), ++ PIN(13, pwm0, dpi, uart4, i2c2, aaud, gpio, proc_rio, pio, spi5), ++ PIN(14, pwm0, dpi, uart4, i2c3, uart0, gpio, proc_rio, pio, spi5), ++ PIN(15, pwm0, dpi, uart4, i2c3, uart0, gpio, proc_rio, pio, spi5), ++ PIN(16, spi1, dpi, dsi0_te_ext, _, uart0, gpio, proc_rio, pio, _), ++ PIN(17, spi1, dpi, dsi1_te_ext, _, uart0, gpio, proc_rio, pio, _), ++ PIN(18, spi1, dpi, i2s0, pwm0, i2s1, gpio, proc_rio, pio, gpclk1), ++ PIN(19, spi1, dpi, i2s0, pwm0, i2s1, gpio, proc_rio, pio, _), ++ PIN(20, spi1, dpi, i2s0, gpclk0, i2s1, gpio, proc_rio, pio, _), ++ PIN(21, spi1, dpi, i2s0, gpclk1, i2s1, gpio, proc_rio, pio, _), ++ PIN(22, sd0, dpi, i2s0, i2c3, i2s1, gpio, proc_rio, pio, _), ++ PIN(23, sd0, dpi, i2s0, i2c3, i2s1, gpio, proc_rio, pio, _), ++ PIN(24, sd0, dpi, i2s0, _, i2s1, gpio, proc_rio, pio, spi2), ++ PIN(25, sd0, dpi, i2s0, mic, i2s1, gpio, proc_rio, pio, spi3), ++ PIN(26, sd0, dpi, i2s0, mic, i2s1, gpio, proc_rio, pio, spi5), ++ PIN(27, sd0, dpi, i2s0, mic, i2s1, gpio, proc_rio, pio, spi1), ++ PIN(28, sd1, i2c4, i2s2, spi6, vbus0, gpio, proc_rio, _, _), ++ PIN(29, sd1, i2c4, i2s2, spi6, vbus0, gpio, proc_rio, _, _), ++ PIN(30, sd1, i2c5, i2s2, spi6, uart5, gpio, proc_rio, _, _), ++ PIN(31, sd1, i2c5, i2s2, spi6, uart5, gpio, proc_rio, _, _), ++ PIN(32, sd1, gpclk3, i2s2, spi6, uart5, gpio, proc_rio, _, _), ++ PIN(33, sd1, gpclk4, i2s2, spi6, uart5, gpio, proc_rio, _, _), ++ PIN(34, pwm1, gpclk3, vbus0, i2c4, mic, gpio, proc_rio, _, _), ++ PIN(35, spi8, pwm1, vbus0, i2c4, mic, gpio, proc_rio, _, _), ++ PIN(36, spi8, uart5, pcie_clkreq_n, i2c5, mic, gpio, proc_rio, _, _), ++ PIN(37, spi8, uart5, mic, i2c5, pcie_clkreq_n, gpio, proc_rio, _, _), ++ PIN(38, spi8, uart5, mic, i2c6, aaud, gpio, proc_rio, dsi0_te_ext, _), ++ PIN(39, spi8, uart5, mic, i2c6, aaud, gpio, proc_rio, dsi1_te_ext, _), ++ PIN(40, pwm1, uart5, i2c4, spi6, aaud, gpio, proc_rio, _, _), ++ PIN(41, pwm1, uart5, i2c4, spi6, aaud, gpio, proc_rio, _, _), ++ PIN(42, gpclk5, uart5, vbus1, spi6, i2s2, gpio, proc_rio, _, _), ++ PIN(43, gpclk4, uart5, vbus1, spi6, i2s2, gpio, proc_rio, _, _), ++ PIN(44, gpclk5, i2c5, pwm1, spi6, i2s2, gpio, proc_rio, _, _), ++ PIN(45, pwm1, i2c5, spi7, spi6, i2s2, gpio, proc_rio, _, _), ++ PIN(46, gpclk3, i2c4, spi7, mic, i2s2, gpio, proc_rio, dsi0_te_ext, _), ++ PIN(47, gpclk5, i2c4, spi7, mic, i2s2, gpio, proc_rio, dsi1_te_ext, _), ++ PIN(48, pwm1, pcie_clkreq_n, spi7, mic, uart5, gpio, proc_rio, _, _), ++ PIN(49, spi8, spi7, i2c5, aaud, uart5, gpio, proc_rio, _, _), ++ PIN(50, spi8, spi7, i2c5, aaud, vbus2, gpio, proc_rio, _, _), ++ PIN(51, spi8, spi7, i2c6, aaud, vbus2, gpio, proc_rio, _, _), ++ PIN(52, spi8, _, i2c6, aaud, vbus3, gpio, proc_rio, _, _), ++ PIN(53, spi8, spi7, _, pcie_clkreq_n, vbus3, gpio, proc_rio, _, _), ++}; ++ ++static const u8 legacy_fsel_map[][8] = { ++ LEGACY_MAP(0, i2c0, _, dpi, spi2, uart1, _), ++ LEGACY_MAP(1, i2c0, _, dpi, spi2, uart1, _), ++ LEGACY_MAP(2, i2c1, _, dpi, spi2, uart1, _), ++ LEGACY_MAP(3, i2c1, _, dpi, spi2, uart1, _), ++ LEGACY_MAP(4, gpclk0, _, dpi, spi3, uart2, i2c2), ++ LEGACY_MAP(5, gpclk1, _, dpi, spi3, uart2, i2c2), ++ LEGACY_MAP(6, gpclk2, _, dpi, spi3, uart2, i2c3), ++ LEGACY_MAP(7, spi0, _, dpi, spi3, uart2, i2c3), ++ LEGACY_MAP(8, spi0, _, dpi, _, uart3, i2c0), ++ LEGACY_MAP(9, spi0, _, dpi, _, uart3, i2c0), ++ LEGACY_MAP(10, spi0, _, dpi, _, uart3, i2c1), ++ LEGACY_MAP(11, spi0, _, dpi, _, uart3, i2c1), ++ LEGACY_MAP(12, pwm0, _, dpi, spi5, uart4, i2c2), ++ LEGACY_MAP(13, pwm0, _, dpi, spi5, uart4, i2c2), ++ LEGACY_MAP(14, uart0, _, dpi, spi5, uart4, _), ++ LEGACY_MAP(15, uart0, _, dpi, spi5, uart4, _), ++ LEGACY_MAP(16, _, _, dpi, uart0, spi1, _), ++ LEGACY_MAP(17, _, _, dpi, uart0, spi1, _), ++ LEGACY_MAP(18, i2s0, _, dpi, _, spi1, pwm0), ++ LEGACY_MAP(19, i2s0, _, dpi, _, spi1, pwm0), ++ LEGACY_MAP(20, i2s0, _, dpi, _, spi1, gpclk0), ++ LEGACY_MAP(21, i2s0, _, dpi, _, spi1, gpclk1), ++ LEGACY_MAP(22, sd0, _, dpi, _, _, i2c3), ++ LEGACY_MAP(23, sd0, _, dpi, _, _, i2c3), ++ LEGACY_MAP(24, sd0, _, dpi, _, _, spi2), ++ LEGACY_MAP(25, sd0, _, dpi, _, _, spi3), ++ LEGACY_MAP(26, sd0, _, dpi, _, _, spi5), ++ LEGACY_MAP(27, sd0, _, dpi, _, _, _), ++}; ++ ++static const char * const irq_type_names[] = { ++ [IRQ_TYPE_NONE] = "none", ++ [IRQ_TYPE_EDGE_RISING] = "edge-rising", ++ [IRQ_TYPE_EDGE_FALLING] = "edge-falling", ++ [IRQ_TYPE_EDGE_BOTH] = "edge-both", ++ [IRQ_TYPE_LEVEL_HIGH] = "level-high", ++ [IRQ_TYPE_LEVEL_LOW] = "level-low", ++}; ++ ++static int rp1_pinconf_set(struct pinctrl_dev *pctldev, ++ unsigned int offset, unsigned long *configs, ++ unsigned int num_configs); ++ ++static struct rp1_pin_info *rp1_get_pin(struct gpio_chip *chip, ++ unsigned int offset) ++{ ++ struct rp1_pinctrl *pc = gpiochip_get_data(chip); ++ ++ if (pc && offset < RP1_NUM_GPIOS) ++ return &pc->pins[offset]; ++ return NULL; ++} ++ ++static struct rp1_pin_info *rp1_get_pin_pctl(struct pinctrl_dev *pctldev, ++ unsigned int offset) ++{ ++ struct rp1_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ ++ if (pc && offset < RP1_NUM_GPIOS) ++ return &pc->pins[offset]; ++ return NULL; ++} ++ ++static void rp1_pad_update(struct rp1_pin_info *pin, u32 clr, u32 set) ++{ ++ u32 padctrl = readl(pin->pad); ++ ++ padctrl &= ~clr; ++ padctrl |= set; ++ ++ writel(padctrl, pin->pad); ++} ++ ++static void rp1_input_enable(struct rp1_pin_info *pin, int value) ++{ ++ rp1_pad_update(pin, RP1_PAD_IN_ENABLE_MASK, ++ value ? RP1_PAD_IN_ENABLE_MASK : 0); ++} ++ ++static void rp1_output_enable(struct rp1_pin_info *pin, int value) ++{ ++ rp1_pad_update(pin, RP1_PAD_OUT_DISABLE_MASK, ++ value ? 0 : RP1_PAD_OUT_DISABLE_MASK); ++} ++ ++static u32 rp1_get_fsel(struct rp1_pin_info *pin) ++{ ++ u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL); ++ u32 oeover = FLD_GET(ctrl, RP1_GPIO_CTRL_OEOVER); ++ u32 fsel = FLD_GET(ctrl, RP1_GPIO_CTRL_FUNCSEL); ++ ++ if (oeover != RP1_OEOVER_PERI || fsel >= RP1_FSEL_COUNT) ++ fsel = RP1_FSEL_NONE; ++ ++ return fsel; ++} ++ ++static void rp1_set_fsel(struct rp1_pin_info *pin, u32 fsel) ++{ ++ u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL); ++ ++ if (fsel >= RP1_FSEL_COUNT) ++ fsel = RP1_FSEL_NONE_HW; ++ ++ rp1_input_enable(pin, 1); ++ rp1_output_enable(pin, 1); ++ ++ if (fsel == RP1_FSEL_NONE) { ++ FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_DISABLE); ++ } else { ++ FLD_SET(ctrl, RP1_GPIO_CTRL_OUTOVER, RP1_OUTOVER_PERI); ++ FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_PERI); ++ } ++ FLD_SET(ctrl, RP1_GPIO_CTRL_FUNCSEL, fsel); ++ writel(ctrl, pin->gpio + RP1_GPIO_CTRL); ++} ++ ++static int rp1_get_dir(struct rp1_pin_info *pin) ++{ ++ return !(readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ? ++ RP1_DIR_INPUT : RP1_DIR_OUTPUT; ++} ++ ++static void rp1_set_dir(struct rp1_pin_info *pin, bool is_input) ++{ ++ int offset = is_input ? RP1_CLR_OFFSET : RP1_SET_OFFSET; ++ ++ writel(1 << pin->offset, pin->rio + RP1_RIO_OE + offset); ++} ++ ++static int rp1_get_value(struct rp1_pin_info *pin) ++{ ++ return !!(readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset)); ++} ++ ++static void rp1_set_value(struct rp1_pin_info *pin, int value) ++{ ++ /* Assume the pin is already an output */ ++ writel(1 << pin->offset, ++ pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET)); ++} ++ ++static int rp1_gpio_get(struct gpio_chip *chip, unsigned offset) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ int ret; ++ ++ if (!pin) ++ return -EINVAL; ++ ret = rp1_get_value(pin); ++ return ret; ++} ++ ++static void rp1_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ ++ if (pin) ++ rp1_set_value(pin, value); ++} ++ ++static int rp1_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ u32 fsel; ++ ++ if (!pin) ++ return -EINVAL; ++ fsel = rp1_get_fsel(pin); ++ if (fsel != RP1_FSEL_GPIO) ++ return -EINVAL; ++ return (rp1_get_dir(pin) == RP1_DIR_OUTPUT) ? ++ GPIO_LINE_DIRECTION_OUT : ++ GPIO_LINE_DIRECTION_IN; ++} ++ ++static int rp1_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ ++ if (!pin) ++ return -EINVAL; ++ rp1_set_dir(pin, RP1_DIR_INPUT); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ return 0; ++} ++ ++static int rp1_gpio_direction_output(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin(chip, offset); ++ ++ if (!pin) ++ return -EINVAL; ++ rp1_set_value(pin, value); ++ rp1_set_dir(pin, RP1_DIR_OUTPUT); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ return 0; ++} ++ ++static int rp1_gpio_set_config(struct gpio_chip *gc, unsigned offset, ++ unsigned long config) ++{ ++ struct rp1_pinctrl *pc = gpiochip_get_data(gc); ++ unsigned long configs[] = { config }; ++ ++ return rp1_pinconf_set(pc->pctl_dev, offset, configs, ++ ARRAY_SIZE(configs)); ++} ++ ++static const struct gpio_chip rp1_gpio_chip = { ++ .label = MODULE_NAME, ++ .owner = THIS_MODULE, ++ .request = gpiochip_generic_request, ++ .free = gpiochip_generic_free, ++ .direction_input = rp1_gpio_direction_input, ++ .direction_output = rp1_gpio_direction_output, ++ .get_direction = rp1_gpio_get_direction, ++ .get = rp1_gpio_get, ++ .set = rp1_gpio_set, ++ .base = -1, ++ .set_config = rp1_gpio_set_config, ++ .ngpio = RP1_NUM_GPIOS, ++ .can_sleep = false, ++}; ++ ++static void rp1_gpio_irq_handler(struct irq_desc *desc) ++{ ++ struct gpio_chip *chip = irq_desc_get_handler_data(desc); ++ struct rp1_pinctrl *pc = gpiochip_get_data(chip); ++ struct irq_chip *host_chip = irq_desc_get_chip(desc); ++ const struct rp1_iobank_desc *bank; ++ int irq = irq_desc_get_irq(desc); ++ unsigned long ints; ++ int b; ++ ++ if (pc->irq[0] == irq) ++ bank = &rp1_iobanks[0]; ++ else if (pc->irq[1] == irq) ++ bank = &rp1_iobanks[1]; ++ else ++ bank = &rp1_iobanks[2]; ++ ++ chained_irq_enter(host_chip, desc); ++ ++ ints = readl(pc->gpio_base + bank->ints_offset); ++ for_each_set_bit(b, &ints, 32) { ++ struct rp1_pin_info *pin = rp1_get_pin(chip, b); ++ ++ writel(RP1_GPIO_CTRL_IRQRESET, ++ pin->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL); ++ generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain, ++ bank->gpio_offset + b)); ++ } ++ ++ chained_irq_exit(host_chip, desc); ++} ++ ++static void rp1_gpio_irq_config(struct rp1_pin_info *pin, bool enable) ++{ ++ writel(1 << pin->offset, ++ pin->inte + (enable ? RP1_SET_OFFSET : RP1_CLR_OFFSET)); ++ if (!enable) ++ /* Clear any latched events */ ++ writel(RP1_GPIO_CTRL_IRQRESET, ++ pin->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL); ++} ++ ++static void rp1_gpio_irq_enable(struct irq_data *data) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ++ unsigned gpio = irqd_to_hwirq(data); ++ struct rp1_pin_info *pin = rp1_get_pin(chip, gpio); ++ ++ rp1_gpio_irq_config(pin, true); ++} ++ ++static void rp1_gpio_irq_disable(struct irq_data *data) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ++ unsigned gpio = irqd_to_hwirq(data); ++ struct rp1_pin_info *pin = rp1_get_pin(chip, gpio); ++ ++ rp1_gpio_irq_config(pin, false); ++} ++ ++static int rp1_irq_set_type(struct rp1_pin_info *pin, unsigned int type) ++{ ++ u32 irq_flags; ++ ++ switch (type) { ++ case IRQ_TYPE_NONE: ++ irq_flags = 0; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ irq_flags = RP1_INT_EDGE_RISING; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ irq_flags = RP1_INT_EDGE_FALLING; ++ break; ++ case IRQ_TYPE_EDGE_BOTH: ++ irq_flags = RP1_INT_EDGE_RISING | RP1_INT_EDGE_FALLING; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ irq_flags = RP1_INT_LEVEL_HIGH; ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ irq_flags = RP1_INT_LEVEL_LOW; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ /* Clear them all */ ++ writel(RP1_INT_MASK << RP1_GPIO_EVENTS_SHIFT_RAW, ++ pin->gpio + RP1_CLR_OFFSET + RP1_GPIO_CTRL); ++ /* Set those that are needed */ ++ writel(irq_flags << RP1_GPIO_EVENTS_SHIFT_RAW, ++ pin->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL); ++ pin->irq_type = type; ++ ++ return 0; ++} ++ ++static int rp1_gpio_irq_set_type(struct irq_data *data, unsigned int type) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ++ struct rp1_pinctrl *pc = gpiochip_get_data(chip); ++ unsigned gpio = irqd_to_hwirq(data); ++ struct rp1_pin_info *pin = rp1_get_pin(chip, gpio); ++ int bank = pin->bank; ++ unsigned long flags; ++ int ret; ++ ++ raw_spin_lock_irqsave(&pc->irq_lock[bank], flags); ++ ++ ret = rp1_irq_set_type(pin, type); ++ if (!ret) { ++ if (type & IRQ_TYPE_EDGE_BOTH) ++ irq_set_handler_locked(data, handle_edge_irq); ++ else ++ irq_set_handler_locked(data, handle_level_irq); ++ } ++ ++ raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags); ++ ++ return ret; ++} ++ ++static void rp1_gpio_irq_ack(struct irq_data *data) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ++ unsigned gpio = irqd_to_hwirq(data); ++ struct rp1_pin_info *pin = rp1_get_pin(chip, gpio); ++ ++ /* Clear any latched events */ ++ writel(RP1_GPIO_CTRL_IRQRESET, pin->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL); ++} ++ ++static struct irq_chip rp1_gpio_irq_chip = { ++ .name = MODULE_NAME, ++ .irq_enable = rp1_gpio_irq_enable, ++ .irq_disable = rp1_gpio_irq_disable, ++ .irq_set_type = rp1_gpio_irq_set_type, ++ .irq_ack = rp1_gpio_irq_ack, ++ .irq_mask = rp1_gpio_irq_disable, ++ .irq_unmask = rp1_gpio_irq_enable, ++ .flags = IRQCHIP_IMMUTABLE, ++}; ++ ++static int rp1_pctl_get_groups_count(struct pinctrl_dev *pctldev) ++{ ++ return ARRAY_SIZE(rp1_gpio_groups); ++} ++ ++static const char *rp1_pctl_get_group_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ return rp1_gpio_groups[selector]; ++} ++ ++static enum funcs rp1_get_fsel_func(unsigned pin, unsigned fsel) ++{ ++ if (pin < RP1_NUM_GPIOS) { ++ if (fsel < RP1_FSEL_COUNT) ++ return rp1_gpio_pin_funcs[pin].funcs[fsel]; ++ else if (fsel == RP1_FSEL_NONE) ++ return func_none; ++ } ++ return func_invalid; ++} ++ ++static int rp1_pctl_get_group_pins(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const unsigned **pins, ++ unsigned *num_pins) ++{ ++ *pins = &rp1_gpio_pins[selector].number; ++ *num_pins = 1; ++ ++ return 0; ++} ++ ++static void rp1_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, ++ struct seq_file *s, ++ unsigned offset) ++{ ++ struct rp1_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ struct gpio_chip *chip = &pc->gpio_chip; ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ u32 fsel = rp1_get_fsel(pin); ++ enum funcs func = rp1_get_fsel_func(offset, fsel); ++ int value = rp1_get_value(pin); ++ int irq = irq_find_mapping(chip->irq.domain, offset); ++ ++ seq_printf(s, "function %s (%s) in %s; irq %d (%s)", ++ rp1_func_names[fsel], rp1_func_names[func], ++ value ? "hi" : "lo", ++ irq, irq_type_names[pin->irq_type]); ++} ++ ++static void rp1_pctl_dt_free_map(struct pinctrl_dev *pctldev, ++ struct pinctrl_map *maps, unsigned num_maps) ++{ ++ int i; ++ ++ for (i = 0; i < num_maps; i++) ++ if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN) ++ kfree(maps[i].data.configs.configs); ++ ++ kfree(maps); ++} ++ ++static int rp1_pctl_legacy_map_func(struct rp1_pinctrl *pc, ++ struct device_node *np, u32 pin, u32 fnum, ++ struct pinctrl_map *maps, ++ unsigned int *num_maps) ++{ ++ struct pinctrl_map *map = &maps[*num_maps]; ++ enum funcs func; ++ ++ if (fnum >= ARRAY_SIZE(legacy_fsel_map[0])) { ++ dev_err(pc->dev, "%pOF: invalid brcm,function %d\n", np, fnum); ++ return -EINVAL; ++ } ++ ++ func = legacy_fsel_map[pin][fnum]; ++ if (func == func_invalid) { ++ dev_err(pc->dev, "%pOF: brcm,function %d not supported on pin %d\n", ++ np, fnum, pin); ++ } ++ ++ map->type = PIN_MAP_TYPE_MUX_GROUP; ++ map->data.mux.group = rp1_gpio_groups[pin]; ++ map->data.mux.function = rp1_func_names[func]; ++ (*num_maps)++; ++ ++ return 0; ++} ++ ++static int rp1_pctl_legacy_map_pull(struct rp1_pinctrl *pc, ++ struct device_node *np, u32 pin, u32 pull, ++ struct pinctrl_map *maps, ++ unsigned int *num_maps) ++{ ++ struct pinctrl_map *map = &maps[*num_maps]; ++ enum pin_config_param param; ++ unsigned long *configs; ++ ++ switch (pull) { ++ case RP1_PUD_OFF: ++ param = PIN_CONFIG_BIAS_DISABLE; ++ break; ++ case RP1_PUD_DOWN: ++ param = PIN_CONFIG_BIAS_PULL_DOWN; ++ break; ++ case RP1_PUD_UP: ++ param = PIN_CONFIG_BIAS_PULL_UP; ++ break; ++ default: ++ dev_err(pc->dev, "%pOF: invalid brcm,pull %d\n", np, pull); ++ return -EINVAL; ++ } ++ ++ configs = kzalloc(sizeof(*configs), GFP_KERNEL); ++ if (!configs) ++ return -ENOMEM; ++ ++ configs[0] = pinconf_to_config_packed(param, 0); ++ map->type = PIN_MAP_TYPE_CONFIGS_PIN; ++ map->data.configs.group_or_pin = rp1_gpio_pins[pin].name; ++ map->data.configs.configs = configs; ++ map->data.configs.num_configs = 1; ++ (*num_maps)++; ++ ++ return 0; ++} ++ ++static int rp1_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, ++ struct device_node *np, ++ struct pinctrl_map **map, ++ unsigned int *num_maps) ++{ ++ struct rp1_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); ++ struct property *pins, *funcs, *pulls; ++ int num_pins, num_funcs, num_pulls, maps_per_pin; ++ struct pinctrl_map *maps; ++ unsigned long *configs = NULL; ++ const char *function = NULL; ++ unsigned int reserved_maps; ++ int num_configs = 0; ++ int i, err; ++ u32 pin, func, pull; ++ ++ /* Check for legacy pin declaration */ ++ pins = of_find_property(np, "brcm,pins", NULL); ++ ++ if (!pins) /* Assume generic bindings in this node */ ++ return pinconf_generic_dt_node_to_map_all(pctldev, np, map, num_maps); ++ ++ funcs = of_find_property(np, "brcm,function", NULL); ++ if (!funcs) ++ of_property_read_string(np, "function", &function); ++ ++ pulls = of_find_property(np, "brcm,pull", NULL); ++ if (!pulls) ++ pinconf_generic_parse_dt_config(np, pctldev, &configs, &num_configs); ++ ++ if (!function && !funcs && !num_configs && !pulls) { ++ dev_err(pc->dev, ++ "%pOF: no function, brcm,function, brcm,pull, etc.\n", ++ np); ++ return -EINVAL; ++ } ++ ++ num_pins = pins->length / 4; ++ num_funcs = funcs ? (funcs->length / 4) : 0; ++ num_pulls = pulls ? (pulls->length / 4) : 0; ++ ++ if (num_funcs > 1 && num_funcs != num_pins) { ++ dev_err(pc->dev, ++ "%pOF: brcm,function must have 1 or %d entries\n", ++ np, num_pins); ++ return -EINVAL; ++ } ++ ++ if (num_pulls > 1 && num_pulls != num_pins) { ++ dev_err(pc->dev, ++ "%pOF: brcm,pull must have 1 or %d entries\n", ++ np, num_pins); ++ return -EINVAL; ++ } ++ ++ maps_per_pin = 0; ++ if (function || num_funcs) ++ maps_per_pin++; ++ if (num_configs || num_pulls) ++ maps_per_pin++; ++ reserved_maps = num_pins * maps_per_pin; ++ maps = kcalloc(reserved_maps, sizeof(*maps), GFP_KERNEL); ++ if (!maps) ++ return -ENOMEM; ++ ++ *num_maps = 0; ++ ++ for (i = 0; i < num_pins; i++) { ++ err = of_property_read_u32_index(np, "brcm,pins", i, &pin); ++ if (err) ++ goto out; ++ if (pin >= ARRAY_SIZE(legacy_fsel_map)) { ++ dev_err(pc->dev, "%pOF: invalid brcm,pins value %d\n", ++ np, pin); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (num_funcs) { ++ err = of_property_read_u32_index(np, "brcm,function", ++ (num_funcs > 1) ? i : 0, ++ &func); ++ if (err) ++ goto out; ++ err = rp1_pctl_legacy_map_func(pc, np, pin, func, ++ maps, num_maps); ++ } else if (function) { ++ err = pinctrl_utils_add_map_mux(pctldev, &maps, ++ &reserved_maps, num_maps, ++ rp1_gpio_groups[pin], ++ function); ++ } ++ ++ if (err) ++ goto out; ++ ++ if (num_pulls) { ++ err = of_property_read_u32_index(np, "brcm,pull", ++ (num_pulls > 1) ? i : 0, ++ &pull); ++ if (err) ++ goto out; ++ err = rp1_pctl_legacy_map_pull(pc, np, pin, pull, ++ maps, num_maps); ++ } else if (num_configs) { ++ err = pinctrl_utils_add_map_configs(pctldev, &maps, ++ &reserved_maps, num_maps, ++ rp1_gpio_groups[pin], ++ configs, num_configs, ++ PIN_MAP_TYPE_CONFIGS_PIN); ++ } ++ ++ if (err) ++ goto out; ++ } ++ ++ *map = maps; ++ ++ return 0; ++ ++out: ++ rp1_pctl_dt_free_map(pctldev, maps, reserved_maps); ++ return err; ++} ++ ++static const struct pinctrl_ops rp1_pctl_ops = { ++ .get_groups_count = rp1_pctl_get_groups_count, ++ .get_group_name = rp1_pctl_get_group_name, ++ .get_group_pins = rp1_pctl_get_group_pins, ++ .pin_dbg_show = rp1_pctl_pin_dbg_show, ++ .dt_node_to_map = rp1_pctl_dt_node_to_map, ++ .dt_free_map = rp1_pctl_dt_free_map, ++}; ++ ++static int rp1_pmx_free(struct pinctrl_dev *pctldev, unsigned offset) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ u32 fsel = rp1_get_fsel(pin); ++ ++ /* Return non-GPIOs to GPIO_IN */ ++ if (fsel != RP1_FSEL_GPIO) { ++ rp1_set_dir(pin, RP1_DIR_INPUT); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ } ++ ++ return 0; ++} ++ ++static int rp1_pmx_get_functions_count(struct pinctrl_dev *pctldev) ++{ ++ return func_count; ++} ++ ++static const char *rp1_pmx_get_function_name(struct pinctrl_dev *pctldev, ++ unsigned selector) ++{ ++ return (selector < func_count) ? rp1_func_names[selector] : NULL; ++} ++ ++static int rp1_pmx_get_function_groups(struct pinctrl_dev *pctldev, ++ unsigned selector, ++ const char * const **groups, ++ unsigned * const num_groups) ++{ ++ /* every pin can do every function */ ++ *groups = rp1_gpio_groups; ++ *num_groups = ARRAY_SIZE(rp1_gpio_groups); ++ ++ return 0; ++} ++ ++static int rp1_pmx_set(struct pinctrl_dev *pctldev, unsigned func_selector, ++ unsigned group_selector) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, group_selector); ++ const u8 *pin_funcs; ++ int fsel; ++ ++ /* func_selector is an enum funcs, so needs translation */ ++ ++ if (func_selector >= RP1_FSEL_COUNT) { ++ /* Convert to an fsel number */ ++ pin_funcs = rp1_gpio_pin_funcs[pin->num].funcs; ++ for (fsel = 0; fsel < RP1_FSEL_COUNT; fsel++) { ++ if (pin_funcs[fsel] == func_selector) ++ break; ++ } ++ } else { ++ fsel = (int)func_selector; ++ } ++ ++ if (fsel >= RP1_FSEL_COUNT && fsel != RP1_FSEL_NONE) ++ return -EINVAL; ++ ++ rp1_set_fsel(pin, fsel); ++ ++ return 0; ++} ++ ++static void rp1_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned offset) ++{ ++ (void)rp1_pmx_free(pctldev, offset); ++} ++ ++static int rp1_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned offset, ++ bool input) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ ++ rp1_set_dir(pin, input); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ ++ return 0; ++} ++ ++static const struct pinmux_ops rp1_pmx_ops = { ++ .free = rp1_pmx_free, ++ .get_functions_count = rp1_pmx_get_functions_count, ++ .get_function_name = rp1_pmx_get_function_name, ++ .get_function_groups = rp1_pmx_get_function_groups, ++ .set_mux = rp1_pmx_set, ++ .gpio_disable_free = rp1_pmx_gpio_disable_free, ++ .gpio_set_direction = rp1_pmx_gpio_set_direction, ++}; ++ ++static void rp1_pull_config_set(struct rp1_pin_info *pin, unsigned int arg) ++{ ++ u32 padctrl = readl(pin->pad); ++ ++ FLD_SET(padctrl, RP1_PAD_PULL, arg & 0x3); ++ ++ writel(padctrl, pin->pad); ++} ++ ++/* Generic pinconf methods */ ++ ++static int rp1_pinconf_set(struct pinctrl_dev *pctldev, unsigned int offset, ++ unsigned long *configs, unsigned int num_configs) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ u32 param, arg; ++ int i; ++ ++ if (!pin) ++ return -EINVAL; ++ ++ for (i = 0; i < num_configs; i++) { ++ param = pinconf_to_config_param(configs[i]); ++ arg = pinconf_to_config_argument(configs[i]); ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ rp1_pull_config_set(pin, RP1_PUD_OFF); ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ rp1_pull_config_set(pin, RP1_PUD_DOWN); ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_UP: ++ rp1_pull_config_set(pin, RP1_PUD_UP); ++ break; ++ ++ case PIN_CONFIG_INPUT_ENABLE: ++ rp1_input_enable(pin, arg); ++ break; ++ ++ case PIN_CONFIG_OUTPUT_ENABLE: ++ rp1_output_enable(pin, arg); ++ break; ++ ++ case PIN_CONFIG_OUTPUT: ++ rp1_set_value(pin, arg); ++ rp1_set_dir(pin, RP1_DIR_OUTPUT); ++ rp1_set_fsel(pin, RP1_FSEL_GPIO); ++ break; ++ ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ rp1_pad_update(pin, RP1_PAD_SCHMITT_MASK, ++ arg ? RP1_PAD_SCHMITT_MASK : 0); ++ break; ++ ++ case PIN_CONFIG_SLEW_RATE: ++ rp1_pad_update(pin, RP1_PAD_SLEWFAST_MASK, ++ arg ? RP1_PAD_SLEWFAST_MASK : 0); ++ break; ++ ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ switch (arg) { ++ case 2: ++ arg = RP1_PAD_DRIVE_2MA; ++ break; ++ case 4: ++ arg = RP1_PAD_DRIVE_4MA; ++ break; ++ case 8: ++ arg = RP1_PAD_DRIVE_8MA; ++ break; ++ case 12: ++ arg = RP1_PAD_DRIVE_12MA; ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ rp1_pad_update(pin, RP1_PAD_DRIVE_MASK, arg); ++ break; ++ ++ default: ++ return -ENOTSUPP; ++ ++ } /* switch param type */ ++ } /* for each config */ ++ ++ return 0; ++} ++ ++static int rp1_pinconf_get(struct pinctrl_dev *pctldev, unsigned offset, ++ unsigned long *config) ++{ ++ struct rp1_pin_info *pin = rp1_get_pin_pctl(pctldev, offset); ++ enum pin_config_param param = pinconf_to_config_param(*config); ++ u32 padctrl; ++ u32 arg; ++ ++ if (!pin) ++ return -EINVAL; ++ ++ padctrl = readl(pin->pad); ++ ++ switch (param) { ++ case PIN_CONFIG_INPUT_ENABLE: ++ arg = !!(padctrl & RP1_PAD_IN_ENABLE_MASK); ++ break; ++ case PIN_CONFIG_OUTPUT_ENABLE: ++ arg = !(padctrl & RP1_PAD_OUT_DISABLE_MASK); ++ break; ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ arg = !!(padctrl & RP1_PAD_SCHMITT_MASK); ++ break; ++ case PIN_CONFIG_SLEW_RATE: ++ arg = !!(padctrl & RP1_PAD_SLEWFAST_MASK); ++ break; ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ switch (padctrl & RP1_PAD_DRIVE_MASK) { ++ case RP1_PAD_DRIVE_2MA: ++ arg = 2; ++ break; ++ case RP1_PAD_DRIVE_4MA: ++ arg = 4; ++ break; ++ case RP1_PAD_DRIVE_8MA: ++ arg = 8; ++ break; ++ case RP1_PAD_DRIVE_12MA: ++ arg = 12; ++ break; ++ } ++ break; ++ case PIN_CONFIG_BIAS_DISABLE: ++ arg = ((padctrl & RP1_PAD_PULL_MASK) == (RP1_PUD_OFF << RP1_PAD_PULL_LSB)); ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ arg = ((padctrl & RP1_PAD_PULL_MASK) == (RP1_PUD_DOWN << RP1_PAD_PULL_LSB)); ++ break; ++ ++ case PIN_CONFIG_BIAS_PULL_UP: ++ arg = ((padctrl & RP1_PAD_PULL_MASK) == (RP1_PUD_UP << RP1_PAD_PULL_LSB)); ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ ++ *config = pinconf_to_config_packed(param, arg); ++ ++ return 0; ++} ++ ++static const struct pinconf_ops rp1_pinconf_ops = { ++ .is_generic = true, ++ .pin_config_get = rp1_pinconf_get, ++ .pin_config_set = rp1_pinconf_set, ++}; ++ ++static struct pinctrl_desc rp1_pinctrl_desc = { ++ .name = MODULE_NAME, ++ .pins = rp1_gpio_pins, ++ .npins = ARRAY_SIZE(rp1_gpio_pins), ++ .pctlops = &rp1_pctl_ops, ++ .pmxops = &rp1_pmx_ops, ++ .confops = &rp1_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++static struct pinctrl_gpio_range rp1_pinctrl_gpio_range = { ++ .name = MODULE_NAME, ++ .npins = RP1_NUM_GPIOS, ++}; ++ ++static const struct of_device_id rp1_pinctrl_match[] = { ++ { ++ .compatible = "raspberrypi,rp1-gpio", ++ .data = &rp1_pinconf_ops, ++ }, ++ {} ++}; ++ ++static inline void __iomem *devm_auto_iomap(struct platform_device *pdev, ++ unsigned int index) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ ++ if (np) ++ return devm_of_iomap(dev, np, (int)index, NULL); ++ else ++ return devm_platform_ioremap_resource(pdev, index); ++} ++ ++static int rp1_pinctrl_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct rp1_pinctrl *pc; ++ struct gpio_irq_chip *girq; ++ int err, i; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(rp1_gpio_pins) != RP1_NUM_GPIOS); ++ BUILD_BUG_ON(ARRAY_SIZE(rp1_gpio_groups) != RP1_NUM_GPIOS); ++ ++ pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); ++ if (!pc) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, pc); ++ pc->dev = dev; ++ ++ pc->gpio_base = devm_auto_iomap(pdev, 0); ++ if (IS_ERR(pc->gpio_base)) { ++ dev_err(dev, "could not get GPIO IO memory\n"); ++ return PTR_ERR(pc->gpio_base); ++ } ++ ++ pc->rio_base = devm_auto_iomap(pdev, 1); ++ if (IS_ERR(pc->rio_base)) { ++ dev_err(dev, "could not get RIO IO memory\n"); ++ return PTR_ERR(pc->rio_base); ++ } ++ ++ pc->pads_base = devm_auto_iomap(pdev, 2); ++ if (IS_ERR(pc->pads_base)) { ++ dev_err(dev, "could not get PADS IO memory\n"); ++ return PTR_ERR(pc->pads_base); ++ } ++ ++ pc->gpio_chip = rp1_gpio_chip; ++ pc->gpio_chip.parent = dev; ++ ++ for (i = 0; i < RP1_NUM_BANKS; i++) { ++ const struct rp1_iobank_desc *bank = &rp1_iobanks[i]; ++ int j; ++ ++ for (j = 0; j < bank->num_gpios; j++) { ++ struct rp1_pin_info *pin = ++ &pc->pins[bank->min_gpio + j]; ++ ++ pin->num = bank->min_gpio + j; ++ pin->bank = i; ++ pin->offset = j; ++ ++ pin->gpio = pc->gpio_base + bank->gpio_offset + ++ j * sizeof(u32) * 2; ++ pin->inte = pc->gpio_base + bank->inte_offset; ++ pin->ints = pc->gpio_base + bank->ints_offset; ++ pin->rio = pc->rio_base + bank->rio_offset; ++ pin->pad = pc->pads_base + bank->pads_offset + ++ j * sizeof(u32); ++ } ++ ++ raw_spin_lock_init(&pc->irq_lock[i]); ++ } ++ ++ pc->pctl_dev = devm_pinctrl_register(dev, &rp1_pinctrl_desc, pc); ++ if (IS_ERR(pc->pctl_dev)) ++ return PTR_ERR(pc->pctl_dev); ++ ++ girq = &pc->gpio_chip.irq; ++ girq->chip = &rp1_gpio_irq_chip; ++ girq->parent_handler = rp1_gpio_irq_handler; ++ girq->num_parents = RP1_NUM_BANKS; ++ girq->parents = pc->irq; ++ ++ /* ++ * Use the same handler for all groups: this is necessary ++ * since we use one gpiochip to cover all lines - the ++ * irq handler then needs to figure out which group and ++ * bank that was firing the IRQ and look up the per-group ++ * and bank data. ++ */ ++ for (i = 0; i < RP1_NUM_BANKS; i++) { ++ pc->irq[i] = irq_of_parse_and_map(np, i); ++ if (!pc->irq[i]) { ++ girq->num_parents = i; ++ break; ++ } ++ } ++ ++ girq->default_type = IRQ_TYPE_NONE; ++ girq->handler = handle_level_irq; ++ ++ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc); ++ if (err) { ++ dev_err(dev, "could not add GPIO chip\n"); ++ return err; ++ } ++ ++ pc->gpio_range = rp1_pinctrl_gpio_range; ++ pc->gpio_range.base = pc->gpio_chip.base; ++ pc->gpio_range.gc = &pc->gpio_chip; ++ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); ++ ++ return 0; ++} ++ ++static struct platform_driver rp1_pinctrl_driver = { ++ .probe = rp1_pinctrl_probe, ++ .driver = { ++ .name = MODULE_NAME, ++ .of_match_table = rp1_pinctrl_match, ++ .suppress_bind_attrs = true, ++ }, ++}; ++builtin_platform_driver(rp1_pinctrl_driver); +--- a/include/dt-bindings/pinctrl/rp1.h ++++ /dev/null +@@ -1,46 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Header providing constants for RP1 pinctrl bindings. +- * +- * Copyright (C) 2019-2022 Raspberry Pi Ltd. +- */ +- +-#ifndef __DT_BINDINGS_PINCTRL_RP1_H__ +-#define __DT_BINDINGS_PINCTRL_RP1_H__ +- +-/* brcm,function property */ +-#define RP1_FSEL_GPIO_IN 0 +-#define RP1_FSEL_GPIO_OUT 1 +-#define RP1_FSEL_ALT0_LEGACY 4 +-#define RP1_FSEL_ALT1_LEGACY 5 +-#define RP1_FSEL_ALT2_LEGACY 6 +-#define RP1_FSEL_ALT3_LEGACY 7 +-#define RP1_FSEL_ALT4_LEGACY 3 +-#define RP1_FSEL_ALT5_LEGACY 2 +-#define RP1_FSEL_ALT0 0x08 +-#define RP1_FSEL_ALT0INV 0x09 +-#define RP1_FSEL_ALT1 0x0a +-#define RP1_FSEL_ALT1INV 0x0b +-#define RP1_FSEL_ALT2 0x0c +-#define RP1_FSEL_ALT2INV 0x0d +-#define RP1_FSEL_ALT3 0x0e +-#define RP1_FSEL_ALT3INV 0x0f +-#define RP1_FSEL_ALT4 0x10 +-#define RP1_FSEL_ALT4INV 0x11 +-#define RP1_FSEL_ALT5 0x12 +-#define RP1_FSEL_ALT5INV 0x13 +-#define RP1_FSEL_ALT6 0x14 +-#define RP1_FSEL_ALT6INV 0x15 +-#define RP1_FSEL_ALT7 0x16 +-#define RP1_FSEL_ALT7INV 0x17 +-#define RP1_FSEL_ALT8 0x18 +-#define RP1_FSEL_ALT8INV 0x19 +-#define RP1_FSEL_NONE 0x1a +- +-/* brcm,pull property */ +-#define RP1_PUD_OFF 0 +-#define RP1_PUD_DOWN 1 +-#define RP1_PUD_UP 2 +-#define RP1_PUD_KEEP 3 +- +-#endif /* __DT_BINDINGS_PINCTRL_RP1_H__ */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0877-serial-pl011-rp1-uart-support.patch b/target/linux/bcm27xx/patches-6.1/950-0877-serial-pl011-rp1-uart-support.patch new file mode 100644 index 0000000000..b0b9897e89 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0877-serial-pl011-rp1-uart-support.patch @@ -0,0 +1,129 @@ +From f88da9e21d8eff58eeb9280ae96bf9593121d8eb Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 12 Oct 2022 13:24:51 +0100 +Subject: [PATCH] serial: pl011: rp1 uart support + +Signed-off-by: Phil Elwell +--- + drivers/tty/serial/amba-pl011.c | 96 +++++++++++++++++++++++++++++++++ + 1 file changed, 96 insertions(+) + +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -152,6 +152,20 @@ static const struct vendor_data vendor_s + .fixed_options = true, + }; + ++static struct vendor_data vendor_arm_axi = { ++ .reg_offset = pl011_std_offsets, ++ .ifls = UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8, ++ .fr_busy = UART01x_FR_BUSY, ++ .fr_dsr = UART01x_FR_DSR, ++ .fr_cts = UART01x_FR_CTS, ++ .fr_ri = UART011_FR_RI, ++ .oversampling = false, ++ .dma_threshold = false, ++ .cts_event_workaround = false, ++ .always_enabled = false, ++ .fixed_options = false, ++}; ++ + #ifdef CONFIG_ACPI_SPCR_TABLE + static const struct vendor_data vendor_qdt_qdf2400_e44 = { + .reg_offset = pl011_std_offsets, +@@ -2972,6 +2986,86 @@ static struct platform_driver arm_sbsa_u + }, + }; + ++static int pl011_axi_probe(struct platform_device *pdev) ++{ ++ struct uart_amba_port *uap; ++ struct vendor_data *vendor = &vendor_arm_axi; ++ struct resource *r; ++ unsigned int periphid; ++ int portnr, ret, irq; ++ ++ portnr = pl011_find_free_port(); ++ if (portnr < 0) ++ return portnr; ++ ++ uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port), ++ GFP_KERNEL); ++ if (!uap) ++ return -ENOMEM; ++ ++ uap->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(uap->clk)) ++ return PTR_ERR(uap->clk); ++ ++ if (of_property_read_bool(pdev->dev.of_node, "cts-event-workaround")) { ++ vendor->cts_event_workaround = true; ++ dev_info(&pdev->dev, "cts_event_workaround enabled\n"); ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ periphid = 0x00241011; /* A safe default */ ++ of_property_read_u32(pdev->dev.of_node, "arm,primecell-periphid", ++ &periphid); ++ ++ uap->reg_offset = vendor->reg_offset; ++ uap->vendor = vendor; ++ uap->fifosize = (AMBA_REV_BITS(periphid) < 3) ? 16 : 32; ++ uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM; ++ uap->port.irq = irq; ++ uap->port.ops = &amba_pl011_pops; ++ ++ snprintf(uap->type, sizeof(uap->type), "PL011 AXI"); ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ ret = pl011_setup_port(&pdev->dev, uap, r, portnr); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, uap); ++ ++ return pl011_register_port(uap); ++} ++ ++static int pl011_axi_remove(struct platform_device *pdev) ++{ ++ struct uart_amba_port *uap = platform_get_drvdata(pdev); ++ ++ uart_remove_one_port(&amba_reg, &uap->port); ++ pl011_unregister_port(uap); ++ return 0; ++} ++ ++static const struct of_device_id pl011_axi_of_match[] = { ++ { .compatible = "arm,pl011-axi" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, pl011_axi_of_match); ++ ++static struct platform_driver pl011_axi_platform_driver = { ++ .probe = pl011_axi_probe, ++ .remove = pl011_axi_remove, ++ .driver = { ++ .name = "pl011-axi", ++ .pm = &pl011_dev_pm_ops, ++ .of_match_table = of_match_ptr(pl011_axi_of_match), ++ .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011), ++ }, ++}; ++ + static const struct amba_id pl011_ids[] = { + { + .id = 0x00041011, +@@ -3005,6 +3099,8 @@ static int __init pl011_init(void) + + if (platform_driver_register(&arm_sbsa_uart_platform_driver)) + pr_warn("could not register SBSA UART platform driver\n"); ++ if (platform_driver_register(&pl011_axi_platform_driver)) ++ pr_warn("could not register PL011 AXI platform driver\n"); + return amba_driver_register(&pl011_driver); + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-0878-mmc-sdhci-of-dwcmshc-define-sdio-timeout-clocks.patch b/target/linux/bcm27xx/patches-6.1/950-0878-mmc-sdhci-of-dwcmshc-define-sdio-timeout-clocks.patch new file mode 100644 index 0000000000..6bc21a6a57 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0878-mmc-sdhci-of-dwcmshc-define-sdio-timeout-clocks.patch @@ -0,0 +1,83 @@ +From 4a5ac516ca0a820e7c006ae408872009e37e114b Mon Sep 17 00:00:00 2001 +From: Liam Fraser +Date: Thu, 14 Mar 2019 16:01:26 +0000 +Subject: [PATCH] mmc: sdhci-of-dwcmshc: define sdio timeout clocks + +Signed-off-by: Liam Fraser +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 12 ++++++++++++ + drivers/mmc/host/sdhci-pltfm.c | 8 ++++++++ + drivers/mmc/host/sdhci-pltfm.h | 3 +++ + 3 files changed, 23 insertions(+) + +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -330,6 +330,7 @@ static const struct sdhci_ops sdhci_dwcm + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, + .get_max_clock = dwcmshc_get_max_clock, ++ .get_timeout_clock = sdhci_pltfm_clk_get_timeout_clock, + .reset = sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + }; +@@ -500,6 +501,16 @@ static int dwcmshc_probe(struct platform + clk_prepare_enable(priv->bus_clk); + } + ++ pltfm_host->timeout_clk = devm_clk_get(&pdev->dev, "timeout"); ++ if (IS_ERR(pltfm_host->timeout_clk)) { ++ err = PTR_ERR(pltfm_host->timeout_clk); ++ dev_err(&pdev->dev, "failed to get timeout clk: %d\n", err); ++ goto free_pltfm; ++ } ++ err = clk_prepare_enable(pltfm_host->timeout_clk); ++ if (err) ++ goto free_pltfm; ++ + err = mmc_of_parse(host->mmc); + if (err) + goto err_clk; +@@ -550,6 +561,7 @@ err_setup_host: + sdhci_cleanup_host(host); + err_clk: + clk_disable_unprepare(pltfm_host->clk); ++ clk_disable_unprepare(pltfm_host->timeout_clk); + clk_disable_unprepare(priv->bus_clk); + if (rk_priv) + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, +--- a/drivers/mmc/host/sdhci-pltfm.c ++++ b/drivers/mmc/host/sdhci-pltfm.c +@@ -33,6 +33,14 @@ unsigned int sdhci_pltfm_clk_get_max_clo + } + EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock); + ++unsigned int sdhci_pltfm_clk_get_timeout_clock(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ ++ return clk_get_rate(pltfm_host->timeout_clk); ++} ++EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_timeout_clock); ++ + static const struct sdhci_ops sdhci_pltfm_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, +--- a/drivers/mmc/host/sdhci-pltfm.h ++++ b/drivers/mmc/host/sdhci-pltfm.h +@@ -20,6 +20,7 @@ struct sdhci_pltfm_data { + + struct sdhci_pltfm_host { + struct clk *clk; ++ struct clk *timeout_clk; + + /* migrate from sdhci_of_host */ + unsigned int clock; +@@ -106,6 +107,8 @@ extern int sdhci_pltfm_unregister(struct + + extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host); + ++extern unsigned int sdhci_pltfm_clk_get_timeout_clock(struct sdhci_host *host); ++ + static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host) + { + return host->private; diff --git a/target/linux/bcm27xx/patches-6.1/950-0879-mmc-sdhci-of-dwcmshc-rp1-sdio-changes.patch b/target/linux/bcm27xx/patches-6.1/950-0879-mmc-sdhci-of-dwcmshc-rp1-sdio-changes.patch new file mode 100644 index 0000000000..12d614fd94 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0879-mmc-sdhci-of-dwcmshc-rp1-sdio-changes.patch @@ -0,0 +1,83 @@ +From 14a43b3fd43bf9b230f93d1eba276d40aac969ba Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 12 Oct 2022 14:07:32 +0100 +Subject: [PATCH] mmc: sdhci-of-dwcmshc: rp1 sdio changes + +Signed-off-by: Phil Elwell +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 29 ++++++++++++++++++++++++++--- + 1 file changed, 26 insertions(+), 3 deletions(-) + +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -87,6 +87,7 @@ struct rk35xx_priv { + + struct dwcmshc_priv { + struct clk *bus_clk; ++ struct clk *sdio_clk; + int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ + void *priv; /* pointer to SoC private stuff */ + }; +@@ -114,6 +115,17 @@ static void dwcmshc_adma_write_desc(stru + sdhci_adma_write_desc(host, desc, addr, len, cmd); + } + ++static void dwcmshc_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ ++ if (priv->sdio_clk) ++ clk_set_rate(priv->sdio_clk, clock); ++ ++ sdhci_set_clock(host, clock); ++} ++ + static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host) + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +@@ -326,7 +338,7 @@ static void rk35xx_sdhci_reset(struct sd + } + + static const struct sdhci_ops sdhci_dwcmshc_ops = { +- .set_clock = sdhci_set_clock, ++ .set_clock = dwcmshc_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, + .get_max_clock = dwcmshc_get_max_clock, +@@ -346,8 +358,10 @@ static const struct sdhci_ops sdhci_dwcm + + static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { + .ops = &sdhci_dwcmshc_ops, +- .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +- .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | ++ SDHCI_QUIRK_BROKEN_CARD_DETECTION, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_BROKEN_HS200, + }; + + #ifdef CONFIG_ACPI +@@ -499,6 +513,14 @@ static int dwcmshc_probe(struct platform + priv->bus_clk = devm_clk_get(dev, "bus"); + if (!IS_ERR(priv->bus_clk)) + clk_prepare_enable(priv->bus_clk); ++ ++ pltfm_host->timeout_clk = devm_clk_get(dev, "timeout"); ++ if (!IS_ERR(pltfm_host->timeout_clk)) ++ err = clk_prepare_enable(pltfm_host->timeout_clk); ++ if (err) ++ goto free_pltfm; ++ ++ priv->sdio_clk = devm_clk_get_optional(&pdev->dev, "sdio"); + } + + pltfm_host->timeout_clk = devm_clk_get(&pdev->dev, "timeout"); +@@ -516,6 +538,7 @@ static int dwcmshc_probe(struct platform + goto err_clk; + + sdhci_get_of_property(pdev); ++ sdhci_enable_v4_mode(host); + + priv->vendor_specific_area1 = + sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK; diff --git a/target/linux/bcm27xx/patches-6.1/950-0880-clk-rp1-Add-sdio-clk-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0880-clk-rp1-Add-sdio-clk-driver.patch new file mode 100644 index 0000000000..7db5202ae4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0880-clk-rp1-Add-sdio-clk-driver.patch @@ -0,0 +1,641 @@ +From b427cc1a83404f48b12dec2efbef076b38df6218 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 12 Oct 2022 14:20:07 +0100 +Subject: [PATCH] clk: rp1: Add sdio-clk driver + +Signed-off-by: Phil Elwell +--- + drivers/clk/Kconfig | 6 + + drivers/clk/Makefile | 1 + + drivers/clk/clk-rp1-sdio.c | 600 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 607 insertions(+) + create mode 100644 drivers/clk/clk-rp1-sdio.c + +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -96,6 +96,12 @@ config COMMON_CLK_RP1 + help + Enable common clock framework support for Raspberry Pi RP1 + ++config COMMON_CLK_RP1_SDIO ++ tristate "Clock driver for the RP1 SDIO interfaces" ++ depends on MFD_RP1 ++ help ++ SDIO clock driver for the RP1 support chip ++ + config COMMON_CLK_HI655X + tristate "Clock driver for Hi655x" if EXPERT + depends on (MFD_HI655X_PMIC || COMPILE_TEST) +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -59,6 +59,7 @@ obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm + obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o + obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o + obj-$(CONFIG_COMMON_CLK_RP1) += clk-rp1.o ++obj-$(CONFIG_COMMON_CLK_RP1_SDIO) += clk-rp1-sdio.o + obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o + obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o + obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o +--- /dev/null ++++ b/drivers/clk/clk-rp1-sdio.c +@@ -0,0 +1,600 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * SDIO clock driver for RP1 ++ * ++ * Copyright (C) 2023 Raspberry Pi Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++// Register : MODE ++#define MODE 0x00000000 ++#define MODE_BITS 0x70030000 ++#define MODE_RESET 0x00000000 ++// Field : MODE_STEPS_PER_CYCLE ++#define MODE_STEPS_PER_CYCLE_RESET 0x0 ++#define MODE_STEPS_PER_CYCLE_BITS 0x70000000 ++#define MODE_STEPS_PER_CYCLE_MSB 30 ++#define MODE_STEPS_PER_CYCLE_LSB 28 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_20 0x0 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_10 0x1 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_16 0x2 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_8 0x3 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_12 0x4 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_6 0x5 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_5 0x6 ++#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_4 0x7 ++// Field : MODE_SRC_SEL ++#define MODE_SRC_SEL_RESET 0x0 ++#define MODE_SRC_SEL_BITS 0x00030000 ++#define MODE_SRC_SEL_MSB 17 ++#define MODE_SRC_SEL_LSB 16 ++#define MODE_SRC_SEL_VALUE_STOP 0x0 ++#define MODE_SRC_SEL_VALUE_CLK_ALT_SRC 0x1 ++#define MODE_SRC_SEL_VALUE_PLL_SYS_VCO 0x2 ++#define MODE_SRC_SEL_VALUE_PLL_SYS_VCO_AGAIN 0x3 ++// Register : FROMIP ++#define FROMIP 0x00000004 ++#define FROMIP_BITS 0x0f9713ff ++#define FROMIP_RESET 0x00000000 ++// Field : FROMIP_TUNING_CCLK_SEL ++#define FROMIP_TUNING_CCLK_SEL_RESET 0x0 ++#define FROMIP_TUNING_CCLK_SEL_BITS 0x0f000000 ++#define FROMIP_TUNING_CCLK_SEL_MSB 27 ++#define FROMIP_TUNING_CCLK_SEL_LSB 24 ++// Field : FROMIP_TUNING_CCLK_UPDATE ++#define FROMIP_TUNING_CCLK_UPDATE_RESET 0x0 ++#define FROMIP_TUNING_CCLK_UPDATE_BITS 0x00800000 ++#define FROMIP_TUNING_CCLK_UPDATE_MSB 23 ++#define FROMIP_TUNING_CCLK_UPDATE_LSB 23 ++// Field : FROMIP_SAMPLE_CCLK_SEL ++#define FROMIP_SAMPLE_CCLK_SEL_RESET 0x0 ++#define FROMIP_SAMPLE_CCLK_SEL_BITS 0x00100000 ++#define FROMIP_SAMPLE_CCLK_SEL_MSB 20 ++#define FROMIP_SAMPLE_CCLK_SEL_LSB 20 ++// Field : FROMIP_CLK2CARD_ON ++#define FROMIP_CLK2CARD_ON_RESET 0x0 ++#define FROMIP_CLK2CARD_ON_BITS 0x00040000 ++#define FROMIP_CLK2CARD_ON_MSB 18 ++#define FROMIP_CLK2CARD_ON_LSB 18 ++// Field : FROMIP_CARD_CLK_STABLE ++#define FROMIP_CARD_CLK_STABLE_RESET 0x0 ++#define FROMIP_CARD_CLK_STABLE_BITS 0x00020000 ++#define FROMIP_CARD_CLK_STABLE_MSB 17 ++#define FROMIP_CARD_CLK_STABLE_LSB 17 ++// Field : FROMIP_CARD_CLK_EN ++#define FROMIP_CARD_CLK_EN_RESET 0x0 ++#define FROMIP_CARD_CLK_EN_BITS 0x00010000 ++#define FROMIP_CARD_CLK_EN_MSB 16 ++#define FROMIP_CARD_CLK_EN_LSB 16 ++// Field : FROMIP_CLK_GEN_SEL ++#define FROMIP_CLK_GEN_SEL_RESET 0x0 ++#define FROMIP_CLK_GEN_SEL_BITS 0x00001000 ++#define FROMIP_CLK_GEN_SEL_MSB 12 ++#define FROMIP_CLK_GEN_SEL_LSB 12 ++// Field : FROMIP_FREQ_SEL ++#define FROMIP_FREQ_SEL_RESET 0x000 ++#define FROMIP_FREQ_SEL_BITS 0x000003ff ++#define FROMIP_FREQ_SEL_MSB 9 ++#define FROMIP_FREQ_SEL_LSB 0 ++// Register : LOCAL ++#define LOCAL 0x00000008 ++#define LOCAL_BITS 0x1f9713ff ++#define LOCAL_RESET 0x00000000 ++// Field : LOCAL_TUNING_CCLK_SEL ++#define LOCAL_TUNING_CCLK_SEL_RESET 0x00 ++#define LOCAL_TUNING_CCLK_SEL_BITS 0x1f000000 ++#define LOCAL_TUNING_CCLK_SEL_MSB 28 ++#define LOCAL_TUNING_CCLK_SEL_LSB 24 ++// Field : LOCAL_TUNING_CCLK_UPDATE ++#define LOCAL_TUNING_CCLK_UPDATE_RESET 0x0 ++#define LOCAL_TUNING_CCLK_UPDATE_BITS 0x00800000 ++#define LOCAL_TUNING_CCLK_UPDATE_MSB 23 ++#define LOCAL_TUNING_CCLK_UPDATE_LSB 23 ++// Field : LOCAL_SAMPLE_CCLK_SEL ++#define LOCAL_SAMPLE_CCLK_SEL_RESET 0x0 ++#define LOCAL_SAMPLE_CCLK_SEL_BITS 0x00100000 ++#define LOCAL_SAMPLE_CCLK_SEL_MSB 20 ++#define LOCAL_SAMPLE_CCLK_SEL_LSB 20 ++// Field : LOCAL_CLK2CARD_ON ++#define LOCAL_CLK2CARD_ON_RESET 0x0 ++#define LOCAL_CLK2CARD_ON_BITS 0x00040000 ++#define LOCAL_CLK2CARD_ON_MSB 18 ++#define LOCAL_CLK2CARD_ON_LSB 18 ++// Field : LOCAL_CARD_CLK_STABLE ++#define LOCAL_CARD_CLK_STABLE_RESET 0x0 ++#define LOCAL_CARD_CLK_STABLE_BITS 0x00020000 ++#define LOCAL_CARD_CLK_STABLE_MSB 17 ++#define LOCAL_CARD_CLK_STABLE_LSB 17 ++// Field : LOCAL_CARD_CLK_EN ++#define LOCAL_CARD_CLK_EN_RESET 0x0 ++#define LOCAL_CARD_CLK_EN_BITS 0x00010000 ++#define LOCAL_CARD_CLK_EN_MSB 16 ++#define LOCAL_CARD_CLK_EN_LSB 16 ++// Field : LOCAL_CLK_GEN_SEL ++#define LOCAL_CLK_GEN_SEL_RESET 0x0 ++#define LOCAL_CLK_GEN_SEL_BITS 0x00001000 ++#define LOCAL_CLK_GEN_SEL_MSB 12 ++#define LOCAL_CLK_GEN_SEL_LSB 12 ++#define LOCAL_CLK_GEN_SEL_VALUE_PROGCLOCKMODE 0x0 ++#define LOCAL_CLK_GEN_SEL_VALUE_DIVCLOCKMODE 0x1 ++// Field : LOCAL_FREQ_SEL ++#define LOCAL_FREQ_SEL_RESET 0x000 ++#define LOCAL_FREQ_SEL_BITS 0x000003ff ++#define LOCAL_FREQ_SEL_MSB 9 ++#define LOCAL_FREQ_SEL_LSB 0 ++// Register : USE_LOCAL ++#define USE_LOCAL 0x0000000c ++#define USE_LOCAL_BITS 0x01951001 ++#define USE_LOCAL_RESET 0x00000000 ++// Field : USE_LOCAL_TUNING_CCLK_SEL ++#define USE_LOCAL_TUNING_CCLK_SEL_RESET 0x0 ++#define USE_LOCAL_TUNING_CCLK_SEL_BITS 0x01000000 ++#define USE_LOCAL_TUNING_CCLK_SEL_MSB 24 ++#define USE_LOCAL_TUNING_CCLK_SEL_LSB 24 ++// Field : USE_LOCAL_TUNING_CCLK_UPDATE ++#define USE_LOCAL_TUNING_CCLK_UPDATE_RESET 0x0 ++#define USE_LOCAL_TUNING_CCLK_UPDATE_BITS 0x00800000 ++#define USE_LOCAL_TUNING_CCLK_UPDATE_MSB 23 ++#define USE_LOCAL_TUNING_CCLK_UPDATE_LSB 23 ++// Field : USE_LOCAL_SAMPLE_CCLK_SEL ++#define USE_LOCAL_SAMPLE_CCLK_SEL_RESET 0x0 ++#define USE_LOCAL_SAMPLE_CCLK_SEL_BITS 0x00100000 ++#define USE_LOCAL_SAMPLE_CCLK_SEL_MSB 20 ++#define USE_LOCAL_SAMPLE_CCLK_SEL_LSB 20 ++// Field : USE_LOCAL_CLK2CARD_ON ++#define USE_LOCAL_CLK2CARD_ON_RESET 0x0 ++#define USE_LOCAL_CLK2CARD_ON_BITS 0x00040000 ++#define USE_LOCAL_CLK2CARD_ON_MSB 18 ++#define USE_LOCAL_CLK2CARD_ON_LSB 18 ++// Field : USE_LOCAL_CARD_CLK_EN ++#define USE_LOCAL_CARD_CLK_EN_RESET 0x0 ++#define USE_LOCAL_CARD_CLK_EN_BITS 0x00010000 ++#define USE_LOCAL_CARD_CLK_EN_MSB 16 ++#define USE_LOCAL_CARD_CLK_EN_LSB 16 ++// Field : USE_LOCAL_CLK_GEN_SEL ++#define USE_LOCAL_CLK_GEN_SEL_RESET 0x0 ++#define USE_LOCAL_CLK_GEN_SEL_BITS 0x00001000 ++#define USE_LOCAL_CLK_GEN_SEL_MSB 12 ++#define USE_LOCAL_CLK_GEN_SEL_LSB 12 ++// Field : USE_LOCAL_FREQ_SEL ++#define USE_LOCAL_FREQ_SEL_RESET 0x0 ++#define USE_LOCAL_FREQ_SEL_BITS 0x00000001 ++#define USE_LOCAL_FREQ_SEL_MSB 0 ++#define USE_LOCAL_FREQ_SEL_LSB 0 ++// Register : SD_DELAY ++#define SD_DELAY 0x00000010 ++#define SD_DELAY_BITS 0x0000001f ++#define SD_DELAY_RESET 0x00000000 ++// Field : SD_DELAY_STEPS ++#define SD_DELAY_STEPS_RESET 0x00 ++#define SD_DELAY_STEPS_BITS 0x0000001f ++#define SD_DELAY_STEPS_MSB 4 ++#define SD_DELAY_STEPS_LSB 0 ++// Register : RX_DELAY ++#define RX_DELAY 0x00000014 ++#define RX_DELAY_BITS 0x19f3331f ++#define RX_DELAY_RESET 0x00000000 ++// Field : RX_DELAY_BYPASS ++#define RX_DELAY_BYPASS_RESET 0x0 ++#define RX_DELAY_BYPASS_BITS 0x10000000 ++#define RX_DELAY_BYPASS_MSB 28 ++#define RX_DELAY_BYPASS_LSB 28 ++// Field : RX_DELAY_FAIL_ACTUAL ++#define RX_DELAY_FAIL_ACTUAL_RESET 0x0 ++#define RX_DELAY_FAIL_ACTUAL_BITS 0x08000000 ++#define RX_DELAY_FAIL_ACTUAL_MSB 27 ++#define RX_DELAY_FAIL_ACTUAL_LSB 27 ++// Field : RX_DELAY_ACTUAL ++#define RX_DELAY_ACTUAL_RESET 0x00 ++#define RX_DELAY_ACTUAL_BITS 0x01f00000 ++#define RX_DELAY_ACTUAL_MSB 24 ++#define RX_DELAY_ACTUAL_LSB 20 ++// Field : RX_DELAY_OFFSET ++#define RX_DELAY_OFFSET_RESET 0x0 ++#define RX_DELAY_OFFSET_BITS 0x00030000 ++#define RX_DELAY_OFFSET_MSB 17 ++#define RX_DELAY_OFFSET_LSB 16 ++// Field : RX_DELAY_OVERFLOW ++#define RX_DELAY_OVERFLOW_RESET 0x0 ++#define RX_DELAY_OVERFLOW_BITS 0x00003000 ++#define RX_DELAY_OVERFLOW_MSB 13 ++#define RX_DELAY_OVERFLOW_LSB 12 ++#define RX_DELAY_OVERFLOW_VALUE_ALLOW 0x0 ++#define RX_DELAY_OVERFLOW_VALUE_CLAMP 0x1 ++#define RX_DELAY_OVERFLOW_VALUE_FAIL 0x2 ++// Field : RX_DELAY_MAP ++#define RX_DELAY_MAP_RESET 0x0 ++#define RX_DELAY_MAP_BITS 0x00000300 ++#define RX_DELAY_MAP_MSB 9 ++#define RX_DELAY_MAP_LSB 8 ++#define RX_DELAY_MAP_VALUE_DIRECT 0x0 ++#define RX_DELAY_MAP_VALUE 0x1 ++#define RX_DELAY_MAP_VALUE_STRETCH 0x2 ++// Field : RX_DELAY_FIXED ++#define RX_DELAY_FIXED_RESET 0x00 ++#define RX_DELAY_FIXED_BITS 0x0000001f ++#define RX_DELAY_FIXED_MSB 4 ++#define RX_DELAY_FIXED_LSB 0 ++// Register : NDIV ++#define NDIV 0x00000018 ++#define NDIV_BITS 0x1fff0000 ++#define NDIV_RESET 0x00110000 ++// Field : NDIV_DIVB ++#define NDIV_DIVB_RESET 0x001 ++#define NDIV_DIVB_BITS 0x1ff00000 ++#define NDIV_DIVB_MSB 28 ++#define NDIV_DIVB_LSB 20 ++// Field : NDIV_DIVA ++#define NDIV_DIVA_RESET 0x1 ++#define NDIV_DIVA_BITS 0x000f0000 ++#define NDIV_DIVA_MSB 19 ++#define NDIV_DIVA_LSB 16 ++// Register : CS ++#define CS 0x0000001c ++#define CS_BITS 0x00111101 ++#define CS_RESET 0x00000001 ++// Field : CS_RX_DEL_UPDATED ++#define CS_RX_DEL_UPDATED_RESET 0x0 ++#define CS_RX_DEL_UPDATED_BITS 0x00100000 ++#define CS_RX_DEL_UPDATED_MSB 20 ++#define CS_RX_DEL_UPDATED_LSB 20 ++// Field : CS_RX_CLK_RUNNING ++#define CS_RX_CLK_RUNNING_RESET 0x0 ++#define CS_RX_CLK_RUNNING_BITS 0x00010000 ++#define CS_RX_CLK_RUNNING_MSB 16 ++#define CS_RX_CLK_RUNNING_LSB 16 ++// Field : CS_SD_CLK_RUNNING ++#define CS_SD_CLK_RUNNING_RESET 0x0 ++#define CS_SD_CLK_RUNNING_BITS 0x00001000 ++#define CS_SD_CLK_RUNNING_MSB 12 ++#define CS_SD_CLK_RUNNING_LSB 12 ++// Field : CS_TX_CLK_RUNNING ++#define CS_TX_CLK_RUNNING_RESET 0x0 ++#define CS_TX_CLK_RUNNING_BITS 0x00000100 ++#define CS_TX_CLK_RUNNING_MSB 8 ++#define CS_TX_CLK_RUNNING_LSB 8 ++// Field : CS_RESET ++#define CS_RESET_RESET 0x1 ++#define CS_RESET_BITS 0x00000001 ++#define CS_RESET_MSB 0 ++#define CS_RESET_LSB 0 ++ ++#define FPGA_SRC_RATE 400000000 ++ ++/* Base number of steps to delay in relation to tx clk. ++ * The relationship of the 3 clocks are as follows: ++ * tx_clk: This clock is provided to the controller. Data is sent out ++ * to the pads using this clock. ++ * sd_clk: This clock is sent out to the card. ++ * rx_clk: This clock is used to sample the data coming back from the card. ++ * This may need to be several steps ahead of the tx_clk. The default rx delay ++ * is used as a base delay, and can be further adjusted by the sd host ++ * controller during the tuning process if using a DDR50 or faster SD card ++ */ ++/* ++ * PRJY-1813 - the default SD clock delay needs to be set to ~60% of the total ++ * number of steps to meet tISU (>6ns) and tIH (>2ns) in high-speed mode. ++ * On FPGA this means delay SDCLK by 5, and sample RX with a delay of 6. ++ */ ++#define DEFAULT_RX_DELAY 6 ++#define DEFAULT_SD_DELAY 5 ++ ++struct rp1_sdio_clkgen { ++ struct device *dev; ++ ++ /* Source clock. Either PLL VCO or fixed freq on FPGA */ ++ struct clk *src_clk; ++ /* Desired base frequency. Max freq card can go */ ++ struct clk *base_clk; ++ ++ struct clk_hw hw; ++ void __iomem *regs; ++ ++ /* Starting value of local register before changing freq */ ++ u32 local_base; ++}; ++ ++static inline void clkgen_write(struct rp1_sdio_clkgen *clkgen, u32 reg, u32 val) ++{ ++ dev_dbg(clkgen->dev, "%s: write reg 0x%x: 0x%x\n", __func__, reg, val); ++ writel(val, clkgen->regs + reg); ++} ++ ++static inline u32 clkgen_read(struct rp1_sdio_clkgen *clkgen, u32 reg) ++{ ++ u32 val = readl(clkgen->regs + reg); ++ ++ dev_dbg(clkgen->dev, "%s: read reg 0x%x: 0x%x\n", __func__, reg, val); ++ return val; ++} ++ ++static int get_steps(unsigned int steps) ++{ ++ int ret = -1; ++ ++ if (steps == 4) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_4; ++ else if (steps == 5) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_5; ++ else if (steps == 6) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_6; ++ else if (steps == 8) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_8; ++ else if (steps == 10) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_10; ++ else if (steps == 12) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_12; ++ else if (steps == 16) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_16; ++ else if (steps == 20) ++ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_20; ++ return ret; ++} ++ ++static int rp1_sdio_clk_init(struct rp1_sdio_clkgen *clkgen) ++{ ++ unsigned long src_rate = clk_get_rate(clkgen->src_clk); ++ unsigned long base_rate = clk_get_rate(clkgen->base_clk); ++ unsigned int steps = src_rate / base_rate; ++ u32 reg = 0; ++ int steps_value = 0; ++ ++ dev_dbg(clkgen->dev, "init: src_rate %lu, base_rate %lu, steps %d\n", ++ src_rate, base_rate, steps); ++ ++ /* Assert reset while we set up clkgen */ ++ clkgen_write(clkgen, CS, CS_RESET_BITS); ++ ++ /* Pick clock source */ ++ if (src_rate == FPGA_SRC_RATE) { ++ /* Using ALT SRC */ ++ reg |= MODE_SRC_SEL_VALUE_CLK_ALT_SRC << MODE_SRC_SEL_LSB; ++ } else { ++ /* Assume we are using PLL SYS VCO */ ++ reg |= MODE_SRC_SEL_VALUE_PLL_SYS_VCO << MODE_SRC_SEL_LSB; ++ } ++ ++ /* How many delay steps are available in one cycle for this source */ ++ steps_value = get_steps(steps); ++ if (steps_value < 0) { ++ dev_err(clkgen->dev, "Invalid step value: %d\n", steps); ++ return -EINVAL; ++ } ++ reg |= steps_value << MODE_STEPS_PER_CYCLE_LSB; ++ ++ /* Mode register is done now*/ ++ clkgen_write(clkgen, MODE, reg); ++ ++ /* Now set delay mode */ ++ /* Clamp value if out of range rx delay is used */ ++ reg = RX_DELAY_OVERFLOW_VALUE_CLAMP << RX_DELAY_OVERFLOW_LSB; ++ /* SD tuning bus goes from 0x0 to 0xf but we don't necessarily have that ++ * many steps available depending on the source so map 0x0 -> 0xf to one ++ * cycle of rx delay ++ */ ++ reg |= RX_DELAY_MAP_VALUE_STRETCH << RX_DELAY_MAP_LSB; ++ ++ /* Default RX delay */ ++ dev_dbg(clkgen->dev, "default rx delay %d\n", DEFAULT_RX_DELAY); ++ reg |= (DEFAULT_RX_DELAY & RX_DELAY_FIXED_BITS) << RX_DELAY_FIXED_LSB; ++ clkgen_write(clkgen, RX_DELAY, reg); ++ ++ /* Default SD delay */ ++ dev_dbg(clkgen->dev, "default sd delay %d\n", DEFAULT_SD_DELAY); ++ reg = (DEFAULT_SD_DELAY & SD_DELAY_STEPS_BITS) << SD_DELAY_STEPS_LSB; ++ clkgen_write(clkgen, SD_DELAY, reg); ++ ++ /* We select freq, we turn on tx clock, we turn on sd clk, ++ * we pick clock generator mode ++ */ ++ reg = USE_LOCAL_FREQ_SEL_BITS | USE_LOCAL_CARD_CLK_EN_BITS | ++ USE_LOCAL_CLK2CARD_ON_BITS | USE_LOCAL_CLK_GEN_SEL_BITS; ++ clkgen_write(clkgen, USE_LOCAL, reg); ++ ++ /* Deassert reset. Reset bit is only writable bit of CS ++ * reg so fine to write a 0. ++ */ ++ clkgen_write(clkgen, CS, 0); ++ ++ return 0; ++} ++ ++#define RUNNING \ ++ (CS_TX_CLK_RUNNING_BITS | CS_RX_CLK_RUNNING_BITS | \ ++ CS_SD_CLK_RUNNING_BITS) ++static int rp1_sdio_clk_is_prepared(struct clk_hw *hw) ++{ ++ struct rp1_sdio_clkgen *clkgen = ++ container_of(hw, struct rp1_sdio_clkgen, hw); ++ u32 status; ++ ++ dev_dbg(clkgen->dev, "is_prepared\n"); ++ status = clkgen_read(clkgen, CS); ++ return ((status & RUNNING) == RUNNING); ++} ++ ++/* Can define an additional divider if an sd card isn't working at full speed */ ++/* #define SLOWDOWN 3 */ ++ ++static unsigned long rp1_sdio_clk_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ /* Get the current rate */ ++ struct rp1_sdio_clkgen *clkgen = ++ container_of(hw, struct rp1_sdio_clkgen, hw); ++ unsigned long actual_rate = 0; ++ u32 ndiv_diva; ++ u32 ndiv_divb; ++ u32 tmp; ++ u32 div; ++ ++ tmp = clkgen_read(clkgen, LOCAL); ++ if ((tmp & LOCAL_CLK2CARD_ON_BITS) == 0) { ++ dev_dbg(clkgen->dev, "get_rate 0\n"); ++ return 0; ++ } ++ ++ tmp = clkgen_read(clkgen, NDIV); ++ ndiv_diva = (tmp & NDIV_DIVA_BITS) >> NDIV_DIVA_LSB; ++ ndiv_divb = (tmp & NDIV_DIVB_BITS) >> NDIV_DIVB_LSB; ++ div = ndiv_diva * ndiv_divb; ++ actual_rate = (clk_get_rate(clkgen->base_clk) / div); ++ ++#ifdef SLOWDOWN ++ actual_rate *= SLOWDOWN; ++#endif ++ ++ dev_dbg(clkgen->dev, "get_rate. ndiv_diva %d, ndiv_divb %d = %lu\n", ++ ndiv_diva, ndiv_divb, actual_rate); ++ ++ return actual_rate; ++} ++ ++static int rp1_sdio_clk_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct rp1_sdio_clkgen *clkgen = ++ container_of(hw, struct rp1_sdio_clkgen, hw); ++ u32 div; ++ u32 reg; ++ ++ dev_dbg(clkgen->dev, "set_rate %lu\n", rate); ++ ++ if (rate == 0) { ++ /* Keep tx clock running */ ++ clkgen_write(clkgen, LOCAL, LOCAL_CARD_CLK_EN_BITS); ++ return 0; ++ } ++ ++#ifdef SLOWDOWN ++ rate /= SLOWDOWN; ++#endif ++ ++ div = (clk_get_rate(clkgen->base_clk) / rate) - 1; ++ reg = LOCAL_CLK_GEN_SEL_BITS | LOCAL_CARD_CLK_EN_BITS | ++ LOCAL_CLK2CARD_ON_BITS | (div << LOCAL_FREQ_SEL_LSB); ++ clkgen_write(clkgen, LOCAL, reg); ++ ++ return 0; ++} ++ ++#define MAX_NDIV (256 * 8) ++static int rp1_sdio_clk_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ unsigned long rate; ++ struct rp1_sdio_clkgen *clkgen = ++ container_of(hw, struct rp1_sdio_clkgen, hw); ++ unsigned long base_rate = clk_get_rate(clkgen->base_clk); ++ u32 div; ++ ++ /* What is the actual rate I can get if I request xyz */ ++ if (req->rate) { ++ div = min((u32)(base_rate / req->rate), (u32)MAX_NDIV); ++ rate = base_rate / div; ++ req->rate = rate; ++ dev_dbg(clkgen->dev, "determine_rate %lu: %lu / %d = %lu\n", ++ req->rate, base_rate, div, rate); ++ } else { ++ rate = 0; ++ dev_dbg(clkgen->dev, "determine_rate %lu: %lu\n", req->rate, ++ rate); ++ } ++ ++ return 0; ++} ++ ++static const struct clk_ops rp1_sdio_clk_ops = { ++ .is_prepared = rp1_sdio_clk_is_prepared, ++ .recalc_rate = rp1_sdio_clk_get_rate, ++ .set_rate = rp1_sdio_clk_set_rate, ++ .determine_rate = rp1_sdio_clk_determine_rate, ++}; ++ ++static int rp1_sdio_clk_probe(struct platform_device *pdev) ++{ ++ struct device_node *node = pdev->dev.of_node; ++ struct rp1_sdio_clkgen *clkgen; ++ void __iomem *regs; ++ struct clk_init_data init = {}; ++ int ret; ++ ++ clkgen = devm_kzalloc(&pdev->dev, sizeof(*clkgen), GFP_KERNEL); ++ if (!clkgen) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, clkgen); ++ ++ clkgen->dev = &pdev->dev; ++ ++ /* Source freq */ ++ clkgen->src_clk = devm_clk_get(&pdev->dev, "src"); ++ if (IS_ERR(clkgen->src_clk)) { ++ int err = PTR_ERR(clkgen->src_clk); ++ ++ dev_err(&pdev->dev, "failed to get src clk: %d\n", err); ++ return err; ++ } ++ ++ /* Desired maximum output freq (i.e. base freq) */ ++ clkgen->base_clk = devm_clk_get(&pdev->dev, "base"); ++ if (IS_ERR(clkgen->base_clk)) { ++ int err = PTR_ERR(clkgen->base_clk); ++ ++ dev_err(&pdev->dev, "failed to get base clk: %d\n", err); ++ return err; ++ } ++ ++ regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ init.name = node->name; ++ init.ops = &rp1_sdio_clk_ops; ++ init.flags = CLK_GET_RATE_NOCACHE; ++ ++ clkgen->hw.init = &init; ++ clkgen->regs = regs; ++ ++ dev_info(&pdev->dev, "loaded %s\n", init.name); ++ ++ ret = devm_clk_hw_register(&pdev->dev, &clkgen->hw); ++ if (ret) ++ return ret; ++ ++ ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &clkgen->hw); ++ if (ret) ++ return ret; ++ ++ ret = rp1_sdio_clk_init(clkgen); ++ return ret; ++} ++ ++static int rp1_sdio_clk_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id rp1_sdio_clk_dt_ids[] = { ++ { .compatible = "raspberrypi,rp1-sdio-clk", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, rp1_sdio_clk_dt_ids); ++ ++static struct platform_driver rp1_sdio_clk_driver = { ++ .probe = rp1_sdio_clk_probe, ++ .remove = rp1_sdio_clk_remove, ++ .driver = { ++ .name = "rp1-sdio-clk", ++ .of_match_table = rp1_sdio_clk_dt_ids, ++ }, ++}; ++module_platform_driver(rp1_sdio_clk_driver); ++ ++MODULE_AUTHOR("Liam Fraser "); ++MODULE_DESCRIPTION("RP1 SDIO clock driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/bcm27xx/patches-6.1/950-0881-i2c-designware-Add-SMBUS-quick-command-support.patch b/target/linux/bcm27xx/patches-6.1/950-0881-i2c-designware-Add-SMBUS-quick-command-support.patch new file mode 100644 index 0000000000..ea3b315501 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0881-i2c-designware-Add-SMBUS-quick-command-support.patch @@ -0,0 +1,76 @@ +From 50adadfaf324ed5cbb59ce2b85eda59de4e3801a Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 4 Dec 2020 15:20:36 +0000 +Subject: [PATCH] i2c: designware: Add SMBUS quick command support + +The SMBUS emulation code turns an SMBUS quick command into a zero- +length read. This controller can't do zero length accesses, but it +can do quick commands, so reverse the emulation. The alternative +would be to properly implement the SMBUS support but that is a lot +more work, and unnecessary just to get i2cdetect working. + +Signed-off-by: Phil Elwell +--- + drivers/i2c/busses/i2c-designware-core.h | 2 ++ + drivers/i2c/busses/i2c-designware-master.c | 17 +++++++++++++++-- + 2 files changed, 17 insertions(+), 2 deletions(-) + +--- a/drivers/i2c/busses/i2c-designware-core.h ++++ b/drivers/i2c/busses/i2c-designware-core.h +@@ -117,7 +117,9 @@ + + #define DW_IC_ERR_TX_ABRT 0x1 + ++#define DW_IC_TAR_SPECIAL BIT(11) + #define DW_IC_TAR_10BITADDR_MASTER BIT(12) ++#define DW_IC_TAR_SMBUS_QUICK_CMD BIT(16) + + #define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3)) + #define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2) +--- a/drivers/i2c/busses/i2c-designware-master.c ++++ b/drivers/i2c/busses/i2c-designware-master.c +@@ -228,6 +228,10 @@ static void i2c_dw_xfer_init(struct dw_i + ic_tar = DW_IC_TAR_10BITADDR_MASTER; + } + ++ /* Convert a zero-length read into an SMBUS quick command */ ++ if (!msgs[dev->msg_write_idx].len) ++ ic_tar = DW_IC_TAR_SPECIAL | DW_IC_TAR_SMBUS_QUICK_CMD; ++ + regmap_update_bits(dev->map, DW_IC_CON, DW_IC_CON_10BITADDR_MASTER, + ic_con); + +@@ -409,6 +413,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) + regmap_read(dev->map, DW_IC_RXFLR, &flr); + rx_limit = dev->rx_fifo_depth - flr; + ++ /* Handle SMBUS quick commands */ ++ if (!buf_len) { ++ if (msgs[dev->msg_write_idx].flags & I2C_M_RD) ++ regmap_write(dev->map, DW_IC_DATA_CMD, 0x300); ++ else ++ regmap_write(dev->map, DW_IC_DATA_CMD, 0x200); ++ } ++ + while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { + u32 cmd = 0; + +@@ -673,7 +685,7 @@ static const struct i2c_algorithm i2c_dw + }; + + static const struct i2c_adapter_quirks i2c_dw_quirks = { +- .flags = I2C_AQ_NO_ZERO_LEN, ++ .flags = 0, + }; + + static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) +@@ -813,7 +825,8 @@ void i2c_dw_configure_master(struct dw_i + { + struct i2c_timings *t = &dev->timings; + +- dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY; ++ dev->functionality = I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_QUICK | ++ DW_IC_DEFAULT_FUNCTIONALITY; + + dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | + DW_IC_CON_RESTART_EN; diff --git a/target/linux/bcm27xx/patches-6.1/950-0882-dmaengine-dw-axi-dmac-Fixes-for-RP1.patch b/target/linux/bcm27xx/patches-6.1/950-0882-dmaengine-dw-axi-dmac-Fixes-for-RP1.patch new file mode 100644 index 0000000000..fff6cfdeb4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0882-dmaengine-dw-axi-dmac-Fixes-for-RP1.patch @@ -0,0 +1,355 @@ +From 0a1cd70189daec3baf4b4a233dd8e25ffbb9d512 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 28 Apr 2021 17:46:01 +0100 +Subject: [PATCH] dmaengine: dw-axi-dmac: Fixes for RP1 + +Don't assume that DMA addresses of devices are the same as their +physical addresses - convert correctly. + +The CFG2 register layout is used when there are more than 8 channels, +but also when configured for more than 16 target peripheral devices +because the index of the handshake signal has to be made wider. + +Reset the DMAC on probe + +The driver goes to the trouble of tracking when transfers have been +paused, but then doesn't report that state when queried. + +Not having APB registers is not an error - for most use cases it's +not even of interest, it's expected. Demote the message to debug level, +which is disabled by default. + +Each channel has a descriptor pool, which is shared between transfers. +It is unsafe to treat the total number of descriptors allocated from a +pool as the number allocated to a specific transfer; doing so leads +to releasing buffers that shouldn't be released and walking off the +ends of descriptor lists. Instead, give each transfer descriptor its +own count. + +Support partial transfers: +Some use cases involve streaming from a device where the transfer only +proceeds when the device's FIFO occupancy exceeds a certain threshold. +In such cases (e.g. when pulling data from a UART) it is important to +know how much data has been transferred so far, in order that remaining +bytes can be read from the FIFO directly by software. + +Add the necessary code to provide this "residue" value with a finer, +sub-transfer granularity. + +In order to prevent the occasional byte getting stuck in the DMA +controller's internal buffers, restrict the destination memory width +to the source register width. + +Signed-off-by: Phil Elwell +--- + .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 136 +++++++++++++++--- + drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 3 + + 2 files changed, 118 insertions(+), 21 deletions(-) + +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -79,6 +80,17 @@ axi_chan_iowrite64(struct axi_dma_chan * + iowrite32(upper_32_bits(val), chan->chan_regs + reg + 4); + } + ++static inline u64 ++axi_chan_ioread64(struct axi_dma_chan *chan, u32 reg) ++{ ++ /* ++ * We split one 64 bit read into two 32 bit reads as some HW doesn't ++ * support 64 bit access. ++ */ ++ return ((u64)ioread32(chan->chan_regs + reg + 4) << 32) + ++ ioread32(chan->chan_regs + reg); ++} ++ + static inline void axi_chan_config_write(struct axi_dma_chan *chan, + struct axi_dma_chan_config *config) + { +@@ -86,7 +98,7 @@ static inline void axi_chan_config_write + + cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS | + config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS); +- if (chan->chip->dw->hdata->reg_map_8_channels) { ++ if (!chan->chip->dw->hdata->reg_map_cfg2) { + cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS | + config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS | + config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS | +@@ -214,7 +226,18 @@ static void axi_dma_hw_init(struct axi_d + { + int ret; + u32 i; ++ int retries = 1000; + ++ axi_dma_iowrite32(chip, DMAC_RESET, 1); ++ while (axi_dma_ioread32(chip, DMAC_RESET)) { ++ retries--; ++ if (!retries) { ++ dev_err(chip->dev, "%s: DMAC failed to reset\n", ++ __func__); ++ return; ++ } ++ cpu_relax(); ++ } + for (i = 0; i < chip->dw->hdata->nr_channels; i++) { + axi_chan_irq_disable(&chip->dw->chan[i], DWAXIDMAC_IRQ_ALL); + axi_chan_disable(&chip->dw->chan[i]); +@@ -276,7 +299,7 @@ static struct axi_dma_lli *axi_desc_get( + static void axi_desc_put(struct axi_dma_desc *desc) + { + struct axi_dma_chan *chan = desc->chan; +- int count = atomic_read(&chan->descs_allocated); ++ u32 count = desc->hw_desc_count; + struct axi_dma_hw_desc *hw_desc; + int descs_put; + +@@ -298,6 +321,48 @@ static void vchan_desc_put(struct virt_d + axi_desc_put(vd_to_axi_desc(vdesc)); + } + ++static u32 axi_dma_desc_src_pos(struct axi_dma_desc *desc, dma_addr_t addr) ++{ ++ unsigned int idx = 0; ++ u32 pos = 0; ++ ++ while (pos < desc->length) { ++ struct axi_dma_hw_desc *hw_desc = &desc->hw_desc[idx++]; ++ u32 len = hw_desc->len; ++ dma_addr_t start = le64_to_cpu(hw_desc->lli->sar); ++ ++ if (addr >= start && addr <= (start + len)) { ++ pos += addr - start; ++ break; ++ } ++ ++ pos += len; ++ } ++ ++ return pos; ++} ++ ++static u32 axi_dma_desc_dst_pos(struct axi_dma_desc *desc, dma_addr_t addr) ++{ ++ unsigned int idx = 0; ++ u32 pos = 0; ++ ++ while (pos < desc->length) { ++ struct axi_dma_hw_desc *hw_desc = &desc->hw_desc[idx++]; ++ u32 len = hw_desc->len; ++ dma_addr_t start = le64_to_cpu(hw_desc->lli->dar); ++ ++ if (addr >= start && addr <= (start + len)) { ++ pos += addr - start; ++ break; ++ } ++ ++ pos += len; ++ } ++ ++ return pos; ++} ++ + static enum dma_status + dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, + struct dma_tx_state *txstate) +@@ -307,10 +372,7 @@ dma_chan_tx_status(struct dma_chan *dcha + enum dma_status status; + u32 completed_length; + unsigned long flags; +- u32 completed_blocks; + size_t bytes = 0; +- u32 length; +- u32 len; + + status = dma_cookie_status(dchan, cookie, txstate); + if (status == DMA_COMPLETE || !txstate) +@@ -319,16 +381,31 @@ dma_chan_tx_status(struct dma_chan *dcha + spin_lock_irqsave(&chan->vc.lock, flags); + + vdesc = vchan_find_desc(&chan->vc, cookie); +- if (vdesc) { +- length = vd_to_axi_desc(vdesc)->length; +- completed_blocks = vd_to_axi_desc(vdesc)->completed_blocks; +- len = vd_to_axi_desc(vdesc)->hw_desc[0].len; +- completed_length = completed_blocks * len; +- bytes = length - completed_length; ++ if (vdesc && vdesc == vchan_next_desc(&chan->vc)) { ++ /* This descriptor is in-progress */ ++ struct axi_dma_desc *desc = vd_to_axi_desc(vdesc); ++ dma_addr_t addr; ++ ++ if (chan->direction == DMA_MEM_TO_DEV) { ++ addr = axi_chan_ioread64(chan, CH_SAR); ++ completed_length = axi_dma_desc_src_pos(desc, addr); ++ } else if (chan->direction == DMA_DEV_TO_MEM) { ++ addr = axi_chan_ioread64(chan, CH_DAR); ++ completed_length = axi_dma_desc_dst_pos(desc, addr); ++ } else { ++ completed_length = 0; ++ } ++ bytes = desc->length - completed_length; ++ } else if (vdesc) { ++ /* Still in the queue so not started */ ++ bytes = vd_to_axi_desc(vdesc)->length; + } + +- spin_unlock_irqrestore(&chan->vc.lock, flags); ++ if (chan->is_paused && status == DMA_IN_PROGRESS) ++ status = DMA_PAUSED; ++ + dma_set_residue(txstate, bytes); ++ spin_unlock_irqrestore(&chan->vc.lock, flags); + + return status; + } +@@ -516,7 +593,7 @@ static void dw_axi_dma_set_hw_channel(st + unsigned long reg_value, val; + + if (!chip->apb_regs) { +- dev_err(chip->dev, "apb_regs not initialized\n"); ++ dev_dbg(chip->dev, "apb_regs not initialized\n"); + return; + } + +@@ -620,18 +697,25 @@ static int dw_axi_dma_set_hw_desc(struct + switch (chan->direction) { + case DMA_MEM_TO_DEV: + reg_width = __ffs(chan->config.dst_addr_width); +- device_addr = chan->config.dst_addr; ++ device_addr = phys_to_dma(chan->chip->dev, chan->config.dst_addr); + ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS | + mem_width << CH_CTL_L_SRC_WIDTH_POS | ++ DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_DST_MSIZE_POS | ++ DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS | + DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS; + block_ts = len >> mem_width; + break; + case DMA_DEV_TO_MEM: + reg_width = __ffs(chan->config.src_addr_width); +- device_addr = chan->config.src_addr; ++ /* Prevent partial access units getting lost */ ++ if (mem_width > reg_width) ++ mem_width = reg_width; ++ device_addr = phys_to_dma(chan->chip->dev, chan->config.src_addr); + ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS | + mem_width << CH_CTL_L_DST_WIDTH_POS | ++ DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS | ++ DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_SRC_MSIZE_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS | + DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS; + block_ts = len >> reg_width; +@@ -667,9 +751,6 @@ static int dw_axi_dma_set_hw_desc(struct + } + + hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1); +- +- ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS | +- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS; + hw_desc->lli->ctl_lo = cpu_to_le32(ctllo); + + set_desc_src_master(hw_desc); +@@ -764,6 +845,8 @@ dw_axi_dma_chan_prep_cyclic(struct dma_c + src_addr += segment_len; + } + ++ desc->hw_desc_count = total_segments; ++ + llp = desc->hw_desc[0].llp; + + /* Managed transfer list */ +@@ -843,6 +926,8 @@ dw_axi_dma_chan_prep_slave_sg(struct dma + } while (len >= segment_len); + } + ++ desc->hw_desc_count = loop; ++ + /* Set end-of-link to the last link descriptor of list */ + set_desc_last(&desc->hw_desc[num_sgs - 1]); + +@@ -950,6 +1035,8 @@ dma_chan_prep_dma_memcpy(struct dma_chan + num++; + } + ++ desc->hw_desc_count = num; ++ + /* Set end-of-link to the last link descriptor of list */ + set_desc_last(&desc->hw_desc[num - 1]); + /* Managed transfer list */ +@@ -998,7 +1085,7 @@ static void axi_chan_dump_lli(struct axi + static void axi_chan_list_dump_lli(struct axi_dma_chan *chan, + struct axi_dma_desc *desc_head) + { +- int count = atomic_read(&chan->descs_allocated); ++ u32 count = desc_head->hw_desc_count; + int i; + + for (i = 0; i < count; i++) +@@ -1041,11 +1128,11 @@ out: + + static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan) + { +- int count = atomic_read(&chan->descs_allocated); + struct axi_dma_hw_desc *hw_desc; + struct axi_dma_desc *desc; + struct virt_dma_desc *vd; + unsigned long flags; ++ u32 count; + u64 llp; + int i; + +@@ -1067,6 +1154,7 @@ static void axi_chan_block_xfer_complete + if (chan->cyclic) { + desc = vd_to_axi_desc(vd); + if (desc) { ++ count = desc->hw_desc_count; + llp = lo_hi_readq(chan->chan_regs + CH_LLP); + for (i = 0; i < count; i++) { + hw_desc = &desc->hw_desc[i]; +@@ -1310,6 +1398,8 @@ static int parse_device_properties(struc + chip->dw->hdata->nr_channels = tmp; + if (tmp <= DMA_REG_MAP_CH_REF) + chip->dw->hdata->reg_map_8_channels = true; ++ else ++ chip->dw->hdata->reg_map_cfg2 = true; + + ret = device_property_read_u32(dev, "snps,dma-masters", &tmp); + if (ret) +@@ -1319,6 +1409,10 @@ static int parse_device_properties(struc + + chip->dw->hdata->nr_masters = tmp; + ++ ret = device_property_read_u32(dev, "snps,dma-targets", &tmp); ++ if (!ret && tmp > 16) ++ chip->dw->hdata->reg_map_cfg2 = true; ++ + ret = device_property_read_u32(dev, "snps,data-width", &tmp); + if (ret) + return ret; +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +@@ -32,6 +32,8 @@ struct dw_axi_dma_hcfg { + u32 axi_rw_burst_len; + /* Register map for DMAX_NUM_CHANNELS <= 8 */ + bool reg_map_8_channels; ++ /* Register map for DMAX_NUM_CHANNELS > 8 || DMAX_NUM_HS_IF > 16*/ ++ bool reg_map_cfg2; + bool restrict_axi_burst_len; + }; + +@@ -100,6 +102,7 @@ struct axi_dma_desc { + + struct virt_dma_desc vd; + struct axi_dma_chan *chan; ++ u32 hw_desc_count; + u32 completed_blocks; + u32 length; + u32 period_len; diff --git a/target/linux/bcm27xx/patches-6.1/950-0883-spi-dw-Handle-combined-tx-and-rx-messages.patch b/target/linux/bcm27xx/patches-6.1/950-0883-spi-dw-Handle-combined-tx-and-rx-messages.patch new file mode 100644 index 0000000000..68eca7961f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0883-spi-dw-Handle-combined-tx-and-rx-messages.patch @@ -0,0 +1,64 @@ +From 8a9c0607ce0daa91c48faefd70ea73bda54ed0ae Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 29 Nov 2022 10:09:54 +0000 +Subject: [PATCH] spi: dw: Handle combined tx and rx messages + +Signed-off-by: Phil Elwell +--- + drivers/spi/spi-dw-core.c | 12 +++++++++--- + drivers/spi/spi-dw-mmio.c | 8 ++++++-- + 2 files changed, 15 insertions(+), 5 deletions(-) + +--- a/drivers/spi/spi-dw-core.c ++++ b/drivers/spi/spi-dw-core.c +@@ -244,8 +244,11 @@ static irqreturn_t dw_spi_transfer_handl + */ + if (irq_status & DW_SPI_INT_TXEI) { + dw_writer(dws); +- if (!dws->tx_len) ++ if (!dws->tx_len) { + dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); ++ if (!dws->rx_len) ++ spi_finalize_current_transfer(dws->master); ++ } + } + + return IRQ_HANDLED; +@@ -372,8 +375,11 @@ static void dw_spi_irq_setup(struct dw_s + + dws->transfer_handler = dw_spi_transfer_handler; + +- imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI | +- DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI; ++ imask = 0; ++ if (dws->tx_len) ++ imask |= DW_SPI_INT_TXEI | DW_SPI_INT_TXOI; ++ if (dws->rx_len) ++ imask |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI; + dw_spi_umask_intr(dws, imask); + } + +--- a/drivers/spi/spi-dw-mmio.c ++++ b/drivers/spi/spi-dw-mmio.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "spi-dw.h" + +@@ -280,8 +281,11 @@ static int dw_spi_mmio_probe(struct plat + dws->paddr = mem->start; + + dws->irq = platform_get_irq(pdev, 0); +- if (dws->irq < 0) +- return dws->irq; /* -ENXIO */ ++ if (dws->irq < 0) { ++ if (dws->irq != -ENXIO) ++ return dws->irq; /* -ENXIO */ ++ dws->irq = IRQ_NOTCONNECTED; ++ } + + dwsmmio->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dwsmmio->clk)) diff --git a/target/linux/bcm27xx/patches-6.1/950-0884-pwm-Add-support-for-RP1-PWM.patch b/target/linux/bcm27xx/patches-6.1/950-0884-pwm-Add-support-for-RP1-PWM.patch new file mode 100644 index 0000000000..241d6c49db --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0884-pwm-Add-support-for-RP1-PWM.patch @@ -0,0 +1,292 @@ +From 824f18efc8ad59e2783570ae2df83e2cd16b9f04 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 14 Feb 2023 14:03:54 +0000 +Subject: [PATCH] pwm: Add support for RP1 PWM + +Add a driver for the RP1 PWM block. + +Signed-off-by: Phil Elwell +--- + .../devicetree/bindings/pwm/pwm-rp1.yaml | 38 ++++ + drivers/pwm/Kconfig | 9 + + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm-rp1.c | 203 ++++++++++++++++++ + 4 files changed, 251 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pwm/pwm-rp1.yaml + create mode 100644 drivers/pwm/pwm-rp1.c + +--- /dev/null ++++ b/Documentation/devicetree/bindings/pwm/pwm-rp1.yaml +@@ -0,0 +1,38 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/pwm/pwm-rp1.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Raspberry Pi RP1 PWM controller ++ ++maintainers: ++ - Naushir Patuck ++ ++properties: ++ compatible: ++ enum: ++ - raspberrypi,rp1-pwm ++ ++ reg: ++ maxItems: 1 ++ ++ "#pwm-cells": ++ const: 3 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - "#pwm-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ pwm0: pwm@98000 { ++ compatible = "raspberrypi,rp1-pwm"; ++ reg = <0x0 0x98000 0x0 0x100>; ++ clocks = <&rp1_sys>; ++ #pwm-cells = <3>; ++ }; +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -451,6 +451,15 @@ config PWM_RASPBERRYPI_POE + Enable Raspberry Pi firmware controller PWM bus used to control the + official RPI PoE hat + ++config PWM_RP1 ++ tristate "RP1 PWM support" ++ depends on ARCH_BCM2835 || COMPILE_TEST ++ help ++ PWM framework driver for Raspberry Pi RP1 controller ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-rp1. ++ + config PWM_RCAR + tristate "Renesas R-Car PWM support" + depends on ARCH_RENESAS || COMPILE_TEST +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-om + obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o + obj-$(CONFIG_PWM_PXA) += pwm-pxa.o + obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o ++obj-$(CONFIG_PWM_RP1) += pwm-rp1.o + obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o + obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o + obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o +--- /dev/null ++++ b/drivers/pwm/pwm-rp1.c +@@ -0,0 +1,203 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * pwm-rp1.c ++ * ++ * Raspberry Pi RP1 PWM. ++ * ++ * Copyright © 2023 Raspberry Pi Ltd. ++ * ++ * Author: Naushir Patuck (naush@raspberrypi.com) ++ * ++ * Based on the pwm-bcm2835 driver by: ++ * Bart Tanghe ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PWM_GLOBAL_CTRL 0x000 ++#define PWM_CHANNEL_CTRL(x) (0x014 + ((x) * 16)) ++#define PWM_RANGE(x) (0x018 + ((x) * 16)) ++#define PWM_DUTY(x) (0x020 + ((x) * 16)) ++ ++/* 8:FIFO_POP_MASK + 0:Trailing edge M/S modulation */ ++#define PWM_CHANNEL_DEFAULT (BIT(8) + BIT(0)) ++#define PWM_CHANNEL_ENABLE(x) BIT(x) ++#define PWM_POLARITY BIT(3) ++#define SET_UPDATE BIT(31) ++#define PWM_MODE_MASK GENMASK(1, 0) ++ ++struct rp1_pwm { ++ struct pwm_chip chip; ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++}; ++ ++static inline struct rp1_pwm *to_rp1_pwm(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct rp1_pwm, chip); ++} ++ ++static void rp1_pwm_apply_config(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct rp1_pwm *pc = to_rp1_pwm(chip); ++ u32 value; ++ ++ value = readl(pc->base + PWM_GLOBAL_CTRL); ++ value |= SET_UPDATE; ++ writel(value, pc->base + PWM_GLOBAL_CTRL); ++} ++ ++static int rp1_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct rp1_pwm *pc = to_rp1_pwm(chip); ++ ++ writel(PWM_CHANNEL_DEFAULT, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ return 0; ++} ++ ++static void rp1_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct rp1_pwm *pc = to_rp1_pwm(chip); ++ u32 value; ++ ++ value = readl(pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ value &= ~PWM_MODE_MASK; ++ writel(value, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ rp1_pwm_apply_config(chip, pwm); ++} ++ ++static int rp1_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ struct rp1_pwm *pc = to_rp1_pwm(chip); ++ unsigned long clk_rate = clk_get_rate(pc->clk); ++ unsigned long clk_period; ++ u32 value; ++ ++ if (!clk_rate) { ++ dev_err(pc->dev, "failed to get clock rate\n"); ++ return -EINVAL; ++ } ++ ++ /* set period */ ++ clk_period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, clk_rate); ++ ++ writel(DIV_ROUND_CLOSEST(state->duty_cycle, clk_period), ++ pc->base + PWM_DUTY(pwm->hwpwm)); ++ ++ /* set duty cycle */ ++ writel(DIV_ROUND_CLOSEST(state->period, clk_period), ++ pc->base + PWM_RANGE(pwm->hwpwm)); ++ ++ /* set polarity */ ++ value = readl(pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ if (state->polarity == PWM_POLARITY_NORMAL) ++ value &= ~PWM_POLARITY; ++ else ++ value |= PWM_POLARITY; ++ writel(value, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm)); ++ ++ /* enable/disable */ ++ value = readl(pc->base + PWM_GLOBAL_CTRL); ++ if (state->enabled) ++ value |= PWM_CHANNEL_ENABLE(pwm->hwpwm); ++ else ++ value &= ~PWM_CHANNEL_ENABLE(pwm->hwpwm); ++ writel(value, pc->base + PWM_GLOBAL_CTRL); ++ ++ rp1_pwm_apply_config(chip, pwm); ++ ++ return 0; ++} ++ ++static const struct pwm_ops rp1_pwm_ops = { ++ .request = rp1_pwm_request, ++ .free = rp1_pwm_free, ++ .apply = rp1_pwm_apply, ++ .owner = THIS_MODULE, ++}; ++ ++static int rp1_pwm_probe(struct platform_device *pdev) ++{ ++ struct rp1_pwm *pc; ++ struct resource *res; ++ int ret; ++ ++ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); ++ if (!pc) ++ return -ENOMEM; ++ ++ pc->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pc->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(pc->base)) ++ return PTR_ERR(pc->base); ++ ++ pc->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(pc->clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), ++ "clock not found\n"); ++ ++ ret = clk_prepare_enable(pc->clk); ++ if (ret) ++ return ret; ++ ++ pc->chip.dev = &pdev->dev; ++ pc->chip.ops = &rp1_pwm_ops; ++ pc->chip.base = -1; ++ pc->chip.npwm = 4; ++ pc->chip.of_xlate = of_pwm_xlate_with_flags; ++ pc->chip.of_pwm_n_cells = 3; ++ ++ platform_set_drvdata(pdev, pc); ++ ++ ret = pwmchip_add(&pc->chip); ++ if (ret < 0) ++ goto add_fail; ++ ++ return 0; ++ ++add_fail: ++ clk_disable_unprepare(pc->clk); ++ return ret; ++} ++ ++static int rp1_pwm_remove(struct platform_device *pdev) ++{ ++ struct rp1_pwm *pc = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(pc->clk); ++ ++ pwmchip_remove(&pc->chip); ++ ++ return 0; ++} ++ ++static const struct of_device_id rp1_pwm_of_match[] = { ++ { .compatible = "raspberrypi,rp1-pwm" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, rp1_pwm_of_match); ++ ++static struct platform_driver rp1_pwm_driver = { ++ .driver = { ++ .name = "rpi-pwm", ++ .of_match_table = rp1_pwm_of_match, ++ }, ++ .probe = rp1_pwm_probe, ++ .remove = rp1_pwm_remove, ++}; ++module_platform_driver(rp1_pwm_driver); ++ ++MODULE_AUTHOR("Naushir Patuck +Date: Tue, 14 Feb 2023 14:58:33 +0000 +Subject: [PATCH] drm: Add RP1 DSI driver + +Add support for the RP1 DSI hardware. + +Signed-off-by: Nick Hollinghurst +--- + drivers/gpu/drm/Kconfig | 2 + + drivers/gpu/drm/Makefile | 1 + + drivers/gpu/drm/rp1/Kconfig | 5 + + drivers/gpu/drm/rp1/Makefile | 4 + + drivers/gpu/drm/rp1/rp1-dsi/Kconfig | 15 + + drivers/gpu/drm/rp1/rp1-dsi/Makefile | 5 + + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c | 537 ++++++++ + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h | 94 ++ + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c | 443 ++++++ + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 1504 +++++++++++++++++++++ + 10 files changed, 2610 insertions(+) + create mode 100644 drivers/gpu/drm/rp1/Kconfig + create mode 100644 drivers/gpu/drm/rp1/Makefile + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/Kconfig + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/Makefile + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c + create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c + +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -384,6 +384,8 @@ source "drivers/gpu/drm/v3d/Kconfig" + + source "drivers/gpu/drm/vc4/Kconfig" + ++source "drivers/gpu/drm/rp1/Kconfig" ++ + source "drivers/gpu/drm/etnaviv/Kconfig" + + source "drivers/gpu/drm/hisilicon/Kconfig" +--- a/drivers/gpu/drm/Makefile ++++ b/drivers/gpu/drm/Makefile +@@ -148,3 +148,4 @@ obj-y += gud/ + obj-$(CONFIG_DRM_HYPERV) += hyperv/ + obj-y += solomon/ + obj-$(CONFIG_DRM_SPRD) += sprd/ ++obj-y += rp1/ +--- /dev/null ++++ b/drivers/gpu/drm/rp1/Kconfig +@@ -0,0 +1,5 @@ ++source "drivers/gpu/drm/rp1/rp1-dsi/Kconfig" ++ ++source "drivers/gpu/drm/rp1/rp1-dpi/Kconfig" ++ ++source "drivers/gpu/drm/rp1/rp1-vec/Kconfig" +--- /dev/null ++++ b/drivers/gpu/drm/rp1/Makefile +@@ -0,0 +1,4 @@ ++obj-$(CONFIG_DRM_RP1_DSI) += rp1-dsi/ ++obj-$(CONFIG_DRM_RP1_DPI) += rp1-dpi/ ++obj-$(CONFIG_DRM_RP1_VEC) += rp1-vec/ ++ +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/Kconfig +@@ -0,0 +1,15 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config DRM_RP1_DSI ++ tristate "DRM Support for RP1 DSI" ++ depends on DRM ++ select MFD_RP1 ++ select DRM_GEM_DMA_HELPER ++ select DRM_KMS_HELPER ++ select DRM_MIPI_DSI ++ select DRM_VRAM_HELPER ++ select DRM_TTM ++ select DRM_TTM_HELPER ++ select GENERIC_PHY ++ select GENERIC_PHY_MIPI_DPHY ++ help ++ Choose this option to enable DSI display on RP1 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++drm-rp1-dsi-y := rp1_dsi.o rp1_dsi_dma.o rp1_dsi_dsi.o ++ ++obj-$(CONFIG_DRM_RP1_DSI) += drm-rp1-dsi.o +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c +@@ -0,0 +1,537 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rp1_dsi.h" ++ ++static inline struct rp1_dsi * ++bridge_to_rp1_dsi(struct drm_bridge *bridge) ++{ ++ return container_of(bridge, struct rp1_dsi, bridge); ++} ++ ++static void rp1_dsi_bridge_pre_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++ struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); ++ ++ rp1dsi_dsi_setup(dsi, &dsi->pipe.crtc.state->adjusted_mode); ++} ++ ++static void rp1_dsi_bridge_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++} ++ ++static void rp1_dsi_bridge_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *state) ++{ ++} ++ ++static void rp1_dsi_bridge_post_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *state) ++{ ++ struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); ++ ++ if (dsi->dsi_running) { ++ rp1dsi_dsi_stop(dsi); ++ dsi->dsi_running = false; ++ } ++} ++ ++static int rp1_dsi_bridge_attach(struct drm_bridge *bridge, ++ enum drm_bridge_attach_flags flags) ++{ ++ struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); ++ ++ /* Attach the panel or bridge to the dsi bridge */ ++ return drm_bridge_attach(bridge->encoder, dsi->out_bridge, ++ &dsi->bridge, flags); ++ return 0; ++} ++ ++static const struct drm_bridge_funcs rp1_dsi_bridge_funcs = { ++ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, ++ .atomic_reset = drm_atomic_helper_bridge_reset, ++ .atomic_pre_enable = rp1_dsi_bridge_pre_enable, ++ .atomic_enable = rp1_dsi_bridge_enable, ++ .atomic_disable = rp1_dsi_bridge_disable, ++ .atomic_post_disable = rp1_dsi_bridge_post_disable, ++ .attach = rp1_dsi_bridge_attach, ++}; ++ ++static void rp1dsi_pipe_update(struct drm_simple_display_pipe *pipe, ++ struct drm_plane_state *old_state) ++{ ++ struct drm_pending_vblank_event *event; ++ unsigned long flags; ++ struct drm_framebuffer *fb = pipe->plane.state->fb; ++ struct rp1_dsi *dsi = pipe->crtc.dev->dev_private; ++ struct drm_gem_object *gem = fb ? drm_gem_fb_get_obj(fb, 0) : NULL; ++ struct drm_gem_dma_object *dma_obj = gem ? to_drm_gem_dma_obj(gem) : NULL; ++ bool can_update = fb && dma_obj && dsi && dsi->pipe_enabled; ++ ++ /* (Re-)start DSI,DMA where required; and update FB address */ ++ if (can_update) { ++ if (!dsi->dma_running || fb->format->format != dsi->cur_fmt) { ++ if (dsi->dma_running && fb->format->format != dsi->cur_fmt) { ++ rp1dsi_dma_stop(dsi); ++ dsi->dma_running = false; ++ } ++ if (!dsi->dma_running) { ++ rp1dsi_dma_setup(dsi, ++ fb->format->format, dsi->display_format, ++ &pipe->crtc.state->adjusted_mode); ++ dsi->dma_running = true; ++ } ++ dsi->cur_fmt = fb->format->format; ++ drm_crtc_vblank_on(&pipe->crtc); ++ } ++ rp1dsi_dma_update(dsi, dma_obj->dma_addr, fb->offsets[0], fb->pitches[0]); ++ } ++ ++ /* Arm VBLANK event (or call it immediately in some error cases) */ ++ spin_lock_irqsave(&pipe->crtc.dev->event_lock, flags); ++ event = pipe->crtc.state->event; ++ if (event) { ++ pipe->crtc.state->event = NULL; ++ if (can_update && drm_crtc_vblank_get(&pipe->crtc) == 0) ++ drm_crtc_arm_vblank_event(&pipe->crtc, event); ++ else ++ drm_crtc_send_vblank_event(&pipe->crtc, event); ++ } ++ spin_unlock_irqrestore(&pipe->crtc.dev->event_lock, flags); ++} ++ ++static inline struct rp1_dsi * ++encoder_to_rp1_dsi(struct drm_encoder *encoder) ++{ ++ struct drm_simple_display_pipe *pipe = ++ container_of(encoder, struct drm_simple_display_pipe, encoder); ++ return container_of(pipe, struct rp1_dsi, pipe); ++} ++ ++static void rp1dsi_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct rp1_dsi *dsi = encoder_to_rp1_dsi(encoder); ++ ++ /* Put DSI into video mode before starting video */ ++ rp1dsi_dsi_set_cmdmode(dsi, 0); ++ ++ /* Start DMA -> DPI */ ++ dsi->pipe_enabled = true; ++ dsi->cur_fmt = 0xdeadbeef; ++ rp1dsi_pipe_update(&dsi->pipe, 0); ++} ++ ++static void rp1dsi_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct rp1_dsi *dsi = encoder_to_rp1_dsi(encoder); ++ ++ drm_crtc_vblank_off(&dsi->pipe.crtc); ++ if (dsi->dma_running) { ++ rp1dsi_dma_stop(dsi); ++ dsi->dma_running = false; ++ } ++ dsi->pipe_enabled = false; ++ ++ /* Return to command mode after stopping video */ ++ rp1dsi_dsi_set_cmdmode(dsi, 1); ++} ++ ++static const struct drm_encoder_helper_funcs rp1_dsi_encoder_funcs = { ++ .enable = rp1dsi_encoder_enable, ++ .disable = rp1dsi_encoder_disable, ++}; ++ ++static void rp1dsi_pipe_enable(struct drm_simple_display_pipe *pipe, ++ struct drm_crtc_state *crtc_state, ++ struct drm_plane_state *plane_state) ++{ ++} ++ ++static void rp1dsi_pipe_disable(struct drm_simple_display_pipe *pipe) ++{ ++} ++ ++static int rp1dsi_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dsi *dsi = pipe->crtc.dev->dev_private; ++ ++ if (dsi) ++ rp1dsi_dma_vblank_ctrl(dsi, 1); ++ ++ return 0; ++} ++ ++static void rp1dsi_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dsi *dsi = pipe->crtc.dev->dev_private; ++ ++ if (dsi) ++ rp1dsi_dma_vblank_ctrl(dsi, 0); ++} ++ ++static const struct drm_simple_display_pipe_funcs rp1dsi_pipe_funcs = { ++ .enable = rp1dsi_pipe_enable, ++ .update = rp1dsi_pipe_update, ++ .disable = rp1dsi_pipe_disable, ++ .prepare_fb = drm_gem_simple_display_pipe_prepare_fb, ++ .enable_vblank = rp1dsi_pipe_enable_vblank, ++ .disable_vblank = rp1dsi_pipe_disable_vblank, ++}; ++ ++static const struct drm_mode_config_funcs rp1dsi_mode_funcs = { ++ .fb_create = drm_gem_fb_create, ++ .atomic_check = drm_atomic_helper_check, ++ .atomic_commit = drm_atomic_helper_commit, ++}; ++ ++static const u32 rp1dsi_formats[] = { ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_RGB888, ++ DRM_FORMAT_BGR888, ++ DRM_FORMAT_RGB565 ++}; ++ ++static void rp1dsi_stopall(struct drm_device *drm) ++{ ++ if (drm->dev_private) { ++ struct rp1_dsi *dsi = drm->dev_private; ++ ++ if (dsi->dma_running || rp1dsi_dma_busy(dsi)) { ++ rp1dsi_dma_stop(dsi); ++ dsi->dma_running = false; ++ } ++ if (dsi->dsi_running) { ++ rp1dsi_dsi_stop(dsi); ++ dsi->dsi_running = false; ++ } ++ if (dsi->clocks[RP1DSI_CLOCK_CFG]) ++ clk_disable_unprepare(dsi->clocks[RP1DSI_CLOCK_CFG]); ++ } ++} ++ ++DEFINE_DRM_GEM_DMA_FOPS(rp1dsi_fops); ++ ++static struct drm_driver rp1dsi_driver = { ++ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, ++ .fops = &rp1dsi_fops, ++ .name = "drm-rp1-dsi", ++ .desc = "drm-rp1-dsi", ++ .date = "0", ++ .major = 1, ++ .minor = 0, ++ DRM_GEM_DMA_DRIVER_OPS, ++ .release = rp1dsi_stopall, ++}; ++ ++static int rp1dsi_bind(struct rp1_dsi *dsi) ++{ ++ struct platform_device *pdev = dsi->pdev; ++ struct drm_device *drm = dsi->drm; ++ int ret; ++ ++ dsi->out_bridge = drmm_of_get_bridge(drm, pdev->dev.of_node, 0, 0); ++ if (IS_ERR(dsi->out_bridge)) ++ return PTR_ERR(dsi->out_bridge); ++ ++ ret = drmm_mode_config_init(drm); ++ if (ret) ++ goto rtn; ++ ++ drm->mode_config.max_width = 4096; ++ drm->mode_config.max_height = 4096; ++ drm->mode_config.fb_base = 0; ++ drm->mode_config.preferred_depth = 32; ++ drm->mode_config.prefer_shadow = 0; ++ drm->mode_config.prefer_shadow_fbdev = 1; ++ drm->mode_config.quirk_addfb_prefer_host_byte_order = true; ++ drm->mode_config.funcs = &rp1dsi_mode_funcs; ++ drm_vblank_init(drm, 1); ++ ++ ret = drm_simple_display_pipe_init(drm, ++ &dsi->pipe, ++ &rp1dsi_pipe_funcs, ++ rp1dsi_formats, ++ ARRAY_SIZE(rp1dsi_formats), ++ NULL, NULL); ++ if (ret) ++ goto rtn; ++ ++ /* We need slightly more complex encoder handling (enabling/disabling ++ * video mode), so add encoder helper functions. ++ */ ++ drm_encoder_helper_add(&dsi->pipe.encoder, &rp1_dsi_encoder_funcs); ++ ++ ret = drm_simple_display_pipe_attach_bridge(&dsi->pipe, &dsi->bridge); ++ if (ret) ++ goto rtn; ++ ++ drm_bridge_add(&dsi->bridge); ++ ++ drm_mode_config_reset(drm); ++ ++ if (dsi->clocks[RP1DSI_CLOCK_CFG]) ++ clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_CFG]); ++ ++ ret = drm_dev_register(drm, 0); ++ ++ if (ret == 0) ++ drm_fbdev_generic_setup(drm, 32); ++ ++rtn: ++ if (ret) ++ dev_err(&pdev->dev, "%s returned %d\n", __func__, ret); ++ else ++ dev_info(&pdev->dev, "%s succeeded", __func__); ++ ++ return ret; ++} ++ ++static void rp1dsi_unbind(struct rp1_dsi *dsi) ++{ ++ struct drm_device *drm = dsi->drm; ++ ++ rp1dsi_stopall(drm); ++ drm_dev_unregister(drm); ++ drm_atomic_helper_shutdown(drm); ++} ++ ++int rp1dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi_dev) ++{ ++ struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host); ++ ++ dev_info(&dsi->pdev->dev, "%s: Attach DSI device name=%s channel=%d lanes=%d format=%d flags=0x%lx hs_rate=%lu lp_rate=%lu", ++ __func__, dsi_dev->name, dsi_dev->channel, dsi_dev->lanes, ++ dsi_dev->format, dsi_dev->mode_flags, dsi_dev->hs_rate, ++ dsi_dev->lp_rate); ++ dsi->vc = dsi_dev->channel & 3; ++ dsi->lanes = dsi_dev->lanes; ++ ++ switch (dsi_dev->format) { ++ case MIPI_DSI_FMT_RGB666: ++ case MIPI_DSI_FMT_RGB666_PACKED: ++ case MIPI_DSI_FMT_RGB565: ++ case MIPI_DSI_FMT_RGB888: ++ break; ++ default: ++ return -EINVAL; ++ } ++ dsi->display_format = dsi_dev->format; ++ dsi->display_flags = dsi_dev->mode_flags; ++ dsi->display_hs_rate = dsi_dev->hs_rate; ++ dsi->display_lp_rate = dsi_dev->lp_rate; ++ ++ /* ++ * Previously, we added a separate component to handle panel/bridge ++ * discovery and DRM registration, but now it's just a function call. ++ * The downstream/attaching device should deal with -EPROBE_DEFER ++ */ ++ return rp1dsi_bind(dsi); ++} ++ ++int rp1dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi_dev) ++{ ++ struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host); ++ ++ /* ++ * Unregister the DRM driver. ++ * TODO: Check we are cleaning up correctly and not doing things multiple times! ++ */ ++ rp1dsi_unbind(dsi); ++ return 0; ++} ++ ++ssize_t rp1dsi_host_transfer(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg) ++{ ++ struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host); ++ struct mipi_dsi_packet packet; ++ int ret = 0; ++ ++ /* Write */ ++ ret = mipi_dsi_create_packet(&packet, msg); ++ if (ret) { ++ dev_err(dsi->drm->dev, "RP1DSI: failed to create packet: %d\n", ret); ++ return ret; ++ } ++ ++ rp1dsi_dsi_send(dsi, *(u32 *)(&packet.header), packet.payload_length, packet.payload); ++ ++ /* Optional read back */ ++ if (msg->rx_len && msg->rx_buf) ++ ret = rp1dsi_dsi_recv(dsi, msg->rx_len, msg->rx_buf); ++ ++ return (ssize_t)ret; ++} ++ ++static const struct mipi_dsi_host_ops rp1dsi_mipi_dsi_host_ops = { ++ .attach = rp1dsi_host_attach, ++ .detach = rp1dsi_host_detach, ++ .transfer = rp1dsi_host_transfer ++}; ++ ++static int rp1dsi_platform_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct drm_device *drm; ++ struct rp1_dsi *dsi; ++ int i, ret; ++ ++ drm = drm_dev_alloc(&rp1dsi_driver, dev); ++ if (IS_ERR(drm)) { ++ ret = PTR_ERR(drm); ++ return ret; ++ } ++ dsi = drmm_kzalloc(drm, sizeof(*dsi), GFP_KERNEL); ++ if (!dsi) { ++ ret = -ENOMEM; ++ goto err_free_drm; ++ } ++ init_completion(&dsi->finished); ++ dsi->drm = drm; ++ dsi->pdev = pdev; ++ drm->dev_private = dsi; ++ platform_set_drvdata(pdev, drm); ++ ++ dsi->bridge.funcs = &rp1_dsi_bridge_funcs; ++ dsi->bridge.of_node = dev->of_node; ++ dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; ++ ++ /* Safe default values for DSI mode */ ++ dsi->lanes = 1; ++ dsi->display_format = MIPI_DSI_FMT_RGB888; ++ dsi->display_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM; ++ ++ /* Hardware resources */ ++ for (i = 0; i < RP1DSI_NUM_CLOCKS; i++) { ++ static const char * const myclocknames[RP1DSI_NUM_CLOCKS] = { ++ "cfgclk", "dpiclk", "byteclk", "refclk" ++ }; ++ dsi->clocks[i] = devm_clk_get(dev, myclocknames[i]); ++ if (IS_ERR(dsi->clocks[i])) { ++ ret = PTR_ERR(dsi->clocks[i]); ++ dev_err(dev, "Error getting clocks[%d]\n", i); ++ goto err_free_drm; ++ } ++ } ++ ++ for (i = 0; i < RP1DSI_NUM_HW_BLOCKS; i++) { ++ dsi->hw_base[i] = ++ devm_ioremap_resource(dev, ++ platform_get_resource(dsi->pdev, ++ IORESOURCE_MEM, ++ i)); ++ if (IS_ERR(dsi->hw_base[i])) { ++ ret = PTR_ERR(dsi->hw_base[i]); ++ dev_err(dev, "Error memory mapping regs[%d]\n", i); ++ goto err_free_drm; ++ } ++ } ++ ret = platform_get_irq(dsi->pdev, 0); ++ if (ret > 0) ++ ret = devm_request_irq(dev, ret, rp1dsi_dma_isr, ++ IRQF_SHARED, "rp1-dsi", dsi); ++ if (ret) { ++ dev_err(dev, "Unable to request interrupt\n"); ++ ret = -EINVAL; ++ goto err_free_drm; ++ } ++ rp1dsi_mipicfg_setup(dsi); ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ ++ /* Create the MIPI DSI Host and wait for the panel/bridge to attach to it */ ++ dsi->dsi_host.ops = &rp1dsi_mipi_dsi_host_ops; ++ dsi->dsi_host.dev = dev; ++ ret = mipi_dsi_host_register(&dsi->dsi_host); ++ if (ret) ++ goto err_free_drm; ++ ++ return ret; ++ ++err_free_drm: ++ dev_err(dev, "%s fail %d\n", __func__, ret); ++ drm_dev_put(drm); ++ return ret; ++} ++ ++static int rp1dsi_platform_remove(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ struct rp1_dsi *dsi = drm->dev_private; ++ ++ mipi_dsi_host_unregister(&dsi->dsi_host); ++ return 0; ++} ++ ++static void rp1dsi_platform_shutdown(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1dsi_stopall(drm); ++} ++ ++static const struct of_device_id rp1dsi_of_match[] = { ++ { ++ .compatible = "raspberrypi,rp1dsi", ++ }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rp1dsi_of_match); ++ ++static struct platform_driver rp1dsi_platform_driver = { ++ .probe = rp1dsi_platform_probe, ++ .remove = rp1dsi_platform_remove, ++ .shutdown = rp1dsi_platform_shutdown, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rp1dsi_of_match, ++ }, ++}; ++ ++module_platform_driver(rp1dsi_platform_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MIPI DSI driver for Raspberry Pi RP1"); ++MODULE_AUTHOR("Nick Hollinghurst"); +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h +@@ -0,0 +1,94 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++#ifndef _RP1_DSI_H_ ++#define _RP1_DSI_H_ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define MODULE_NAME "drm-rp1-dsi" ++#define DRIVER_NAME "drm-rp1-dsi" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define RP1DSI_HW_BLOCK_DMA 0 ++#define RP1DSI_HW_BLOCK_DSI 1 ++#define RP1DSI_HW_BLOCK_CFG 2 ++#define RP1DSI_NUM_HW_BLOCKS 3 ++ ++#define RP1DSI_CLOCK_CFG 0 ++#define RP1DSI_CLOCK_DPI 1 ++#define RP1DSI_CLOCK_BYTE 2 ++#define RP1DSI_CLOCK_REF 3 ++#define RP1DSI_NUM_CLOCKS 4 ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct rp1_dsi { ++ /* DRM and platform device pointers */ ++ struct drm_device *drm; ++ struct platform_device *pdev; ++ ++ /* Framework and helper objects */ ++ struct drm_simple_display_pipe pipe; ++ struct drm_bridge bridge; ++ struct drm_bridge *out_bridge; ++ struct mipi_dsi_host dsi_host; ++ ++ /* Clocks. We need DPI clock; the others are frequency references */ ++ struct clk *clocks[RP1DSI_NUM_CLOCKS]; ++ ++ /* Block (DSI DMA, DSI Host) base addresses, and current state */ ++ void __iomem *hw_base[RP1DSI_NUM_HW_BLOCKS]; ++ u32 cur_fmt; ++ bool dsi_running, dma_running, pipe_enabled; ++ struct completion finished; ++ ++ /* Attached display parameters (from mipi_dsi_device) */ ++ unsigned long display_flags, display_hs_rate, display_lp_rate; ++ enum mipi_dsi_pixel_format display_format; ++ u8 vc; ++ u8 lanes; ++ ++ /* DPHY */ ++ u8 hsfreq_index; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the DSI/DPI/DMA block */ ++ ++void rp1dsi_dma_setup(struct rp1_dsi *dsi, ++ u32 in_format, enum mipi_dsi_pixel_format out_format, ++ struct drm_display_mode const *mode); ++void rp1dsi_dma_update(struct rp1_dsi *dsi, dma_addr_t addr, u32 offset, u32 stride); ++void rp1dsi_dma_stop(struct rp1_dsi *dsi); ++int rp1dsi_dma_busy(struct rp1_dsi *dsi); ++irqreturn_t rp1dsi_dma_isr(int irq, void *dev); ++void rp1dsi_dma_vblank_ctrl(struct rp1_dsi *dsi, int enable); ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the MIPICFG block and check RP1 platform */ ++ ++void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi); ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the SNPS D-PHY and DSI block setup */ ++ ++void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode); ++void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 header, int len, const u8 *buf); ++int rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf); ++void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int cmd_mode); ++void rp1dsi_dsi_stop(struct rp1_dsi *dsi); ++ ++#endif ++ +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c +@@ -0,0 +1,443 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "rp1_dsi.h" ++ ++// --- DPI DMA REGISTERS (derived from Argon firmware, via RP1 drivers/mipi, with corrections) --- ++ ++// Control ++#define DPI_DMA_CONTROL 0x0 ++#define DPI_DMA_CONTROL_ARM_SHIFT 0 ++#define DPI_DMA_CONTROL_ARM_MASK BIT(DPI_DMA_CONTROL_ARM_SHIFT) ++#define DPI_DMA_CONTROL_ALIGN16_SHIFT 2 ++#define DPI_DMA_CONTROL_ALIGN16_MASK BIT(DPI_DMA_CONTROL_ALIGN16_SHIFT) ++#define DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT 1 ++#define DPI_DMA_CONTROL_AUTO_REPEAT_MASK BIT(DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT) ++#define DPI_DMA_CONTROL_HIGH_WATER_SHIFT 3 ++#define DPI_DMA_CONTROL_HIGH_WATER_MASK (0x1FF << DPI_DMA_CONTROL_HIGH_WATER_SHIFT) ++#define DPI_DMA_CONTROL_DEN_POL_SHIFT 12 ++#define DPI_DMA_CONTROL_DEN_POL_MASK BIT(DPI_DMA_CONTROL_DEN_POL_SHIFT) ++#define DPI_DMA_CONTROL_HSYNC_POL_SHIFT 13 ++#define DPI_DMA_CONTROL_HSYNC_POL_MASK BIT(DPI_DMA_CONTROL_HSYNC_POL_SHIFT) ++#define DPI_DMA_CONTROL_VSYNC_POL_SHIFT 14 ++#define DPI_DMA_CONTROL_VSYNC_POL_MASK BIT(DPI_DMA_CONTROL_VSYNC_POL_SHIFT) ++#define DPI_DMA_CONTROL_COLORM_SHIFT 15 ++#define DPI_DMA_CONTROL_COLORM_MASK BIT(DPI_DMA_CONTROL_COLORM_SHIFT) ++#define DPI_DMA_CONTROL_SHUTDN_SHIFT 16 ++#define DPI_DMA_CONTROL_SHUTDN_MASK BIT(DPI_DMA_CONTROL_SHUTDN_SHIFT) ++#define DPI_DMA_CONTROL_HBP_EN_SHIFT 17 ++#define DPI_DMA_CONTROL_HBP_EN_MASK BIT(DPI_DMA_CONTROL_HBP_EN_SHIFT) ++#define DPI_DMA_CONTROL_HFP_EN_SHIFT 18 ++#define DPI_DMA_CONTROL_HFP_EN_MASK BIT(DPI_DMA_CONTROL_HFP_EN_SHIFT) ++#define DPI_DMA_CONTROL_VBP_EN_SHIFT 19 ++#define DPI_DMA_CONTROL_VBP_EN_MASK BIT(DPI_DMA_CONTROL_VBP_EN_SHIFT) ++#define DPI_DMA_CONTROL_VFP_EN_SHIFT 20 ++#define DPI_DMA_CONTROL_VFP_EN_MASK BIT(DPI_DMA_CONTROL_VFP_EN_SHIFT) ++#define DPI_DMA_CONTROL_HSYNC_EN_SHIFT 21 ++#define DPI_DMA_CONTROL_HSYNC_EN_MASK BIT(DPI_DMA_CONTROL_HSYNC_EN_SHIFT) ++#define DPI_DMA_CONTROL_VSYNC_EN_SHIFT 22 ++#define DPI_DMA_CONTROL_VSYNC_EN_MASK BIT(DPI_DMA_CONTROL_VSYNC_EN_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_IMMED_SHIFT 23 ++#define DPI_DMA_CONTROL_FORCE_IMMED_MASK BIT(DPI_DMA_CONTROL_FORCE_IMMED_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT 24 ++#define DPI_DMA_CONTROL_FORCE_DRAIN_MASK BIT(DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT 25 ++#define DPI_DMA_CONTROL_FORCE_EMPTY_MASK BIT(DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT) ++ ++// IRQ_ENABLES ++#define DPI_DMA_IRQ_EN 0x04 ++#define DPI_DMA_IRQ_EN_DMA_READY_SHIFT 0 ++#define DPI_DMA_IRQ_EN_DMA_READY_MASK BIT(DPI_DMA_IRQ_EN_DMA_READY_SHIFT) ++#define DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT 1 ++#define DPI_DMA_IRQ_EN_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT) ++#define DPI_DMA_IRQ_EN_FRAME_START_SHIFT 2 ++#define DPI_DMA_IRQ_EN_FRAME_START_MASK BIT(DPI_DMA_IRQ_EN_FRAME_START_SHIFT) ++#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT 3 ++#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT) ++#define DPI_DMA_IRQ_EN_TE_SHIFT 4 ++#define DPI_DMA_IRQ_EN_TE_MASK BIT(DPI_DMA_IRQ_EN_TE_SHIFT) ++#define DPI_DMA_IRQ_EN_ERROR_SHIFT 5 ++#define DPI_DMA_IRQ_EN_ERROR_MASK BIT(DPI_DMA_IRQ_EN_ERROR_SHIFT) ++#define DPI_DMA_IRQ_EN_MATCH_SHIFT 6 ++#define DPI_DMA_IRQ_EN_MATCH_MASK BIT(DPI_DMA_IRQ_EN_MATCH_SHIFT) ++#define DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT 16 ++#define DPI_DMA_IRQ_EN_MATCH_LINE_MASK (0xFFF << DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT) ++ ++// IRQ_FLAGS ++#define DPI_DMA_IRQ_FLAGS 0x08 ++#define DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT 0 ++#define DPI_DMA_IRQ_FLAGS_DMA_READY_MASK BIT(DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT 1 ++#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT 2 ++#define DPI_DMA_IRQ_FLAGS_FRAME_START_MASK BIT(DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT 3 ++#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_TE_SHIFT 4 ++#define DPI_DMA_IRQ_FLAGS_TE_MASK BIT(DPI_DMA_IRQ_FLAGS_TE_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_ERROR_SHIFT 5 ++#define DPI_DMA_IRQ_FLAGS_ERROR_MASK BIT(DPI_DMA_IRQ_FLAGS_ERROR_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_MATCH_SHIFT 6 ++#define DPI_DMA_IRQ_FLAGS_MATCH_MASK BIT(DPI_DMA_IRQ_FLAGS_MATCH_SHIFT) ++ ++// QOS ++#define DPI_DMA_QOS 0xC ++#define DPI_DMA_QOS_DQOS_SHIFT 0 ++#define DPI_DMA_QOS_DQOS_MASK (0xF << DPI_DMA_QOS_DQOS_SHIFT) ++#define DPI_DMA_QOS_ULEV_SHIFT 4 ++#define DPI_DMA_QOS_ULEV_MASK (0xF << DPI_DMA_QOS_ULEV_SHIFT) ++#define DPI_DMA_QOS_UQOS_SHIFT 8 ++#define DPI_DMA_QOS_UQOS_MASK (0xF << DPI_DMA_QOS_UQOS_SHIFT) ++#define DPI_DMA_QOS_LLEV_SHIFT 12 ++#define DPI_DMA_QOS_LLEV_MASK (0xF << DPI_DMA_QOS_LLEV_SHIFT) ++#define DPI_DMA_QOS_LQOS_SHIFT 16 ++#define DPI_DMA_QOS_LQOS_MASK (0xF << DPI_DMA_QOS_LQOS_SHIFT) ++ ++// Panics ++#define DPI_DMA_PANICS 0x38 ++#define DPI_DMA_PANICS_UPPER_COUNT_SHIFT 0 ++#define DPI_DMA_PANICS_UPPER_COUNT_MASK \ ++ (0x0000FFFF << DPI_DMA_PANICS_UPPER_COUNT_SHIFT) ++#define DPI_DMA_PANICS_LOWER_COUNT_SHIFT 16 ++#define DPI_DMA_PANICS_LOWER_COUNT_MASK \ ++ (0x0000FFFF << DPI_DMA_PANICS_LOWER_COUNT_SHIFT) ++ ++// DMA Address Lower: ++#define DPI_DMA_DMA_ADDR_L 0x10 ++ ++// DMA Address Upper: ++#define DPI_DMA_DMA_ADDR_H 0x40 ++ ++// DMA stride ++#define DPI_DMA_DMA_STRIDE 0x14 ++ ++// Visible Area ++#define DPI_DMA_VISIBLE_AREA 0x18 ++#define DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT 0 ++#define DPI_DMA_VISIBLE_AREA_ROWSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT) ++#define DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT 16 ++#define DPI_DMA_VISIBLE_AREA_COLSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT) ++ ++// Sync width ++#define DPI_DMA_SYNC_WIDTH 0x1C ++#define DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT 0 ++#define DPI_DMA_SYNC_WIDTH_ROWSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT) ++#define DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT 16 ++#define DPI_DMA_SYNC_WIDTH_COLSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT) ++ ++// Back porch ++#define DPI_DMA_BACK_PORCH 0x20 ++#define DPI_DMA_BACK_PORCH_ROWSM1_SHIFT 0 ++#define DPI_DMA_BACK_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_ROWSM1_SHIFT) ++#define DPI_DMA_BACK_PORCH_COLSM1_SHIFT 16 ++#define DPI_DMA_BACK_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_COLSM1_SHIFT) ++ ++// Front porch ++#define DPI_DMA_FRONT_PORCH 0x24 ++#define DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT 0 ++#define DPI_DMA_FRONT_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT) ++#define DPI_DMA_FRONT_PORCH_COLSM1_SHIFT 16 ++#define DPI_DMA_FRONT_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_COLSM1_SHIFT) ++ ++// Input masks ++#define DPI_DMA_IMASK 0x2C ++#define DPI_DMA_IMASK_R_SHIFT 0 ++#define DPI_DMA_IMASK_R_MASK (0x3FF << DPI_DMA_IMASK_R_SHIFT) ++#define DPI_DMA_IMASK_G_SHIFT 10 ++#define DPI_DMA_IMASK_G_MASK (0x3FF << DPI_DMA_IMASK_G_SHIFT) ++#define DPI_DMA_IMASK_B_SHIFT 20 ++#define DPI_DMA_IMASK_B_MASK (0x3FF << DPI_DMA_IMASK_B_SHIFT) ++ ++// Output Masks ++#define DPI_DMA_OMASK 0x30 ++#define DPI_DMA_OMASK_R_SHIFT 0 ++#define DPI_DMA_OMASK_R_MASK (0x3FF << DPI_DMA_OMASK_R_SHIFT) ++#define DPI_DMA_OMASK_G_SHIFT 10 ++#define DPI_DMA_OMASK_G_MASK (0x3FF << DPI_DMA_OMASK_G_SHIFT) ++#define DPI_DMA_OMASK_B_SHIFT 20 ++#define DPI_DMA_OMASK_B_MASK (0x3FF << DPI_DMA_OMASK_B_SHIFT) ++ ++// Shifts ++#define DPI_DMA_SHIFT 0x28 ++#define DPI_DMA_SHIFT_IR_SHIFT 0 ++#define DPI_DMA_SHIFT_IR_MASK (0x1F << DPI_DMA_SHIFT_IR_SHIFT) ++#define DPI_DMA_SHIFT_IG_SHIFT 5 ++#define DPI_DMA_SHIFT_IG_MASK (0x1F << DPI_DMA_SHIFT_IG_SHIFT) ++#define DPI_DMA_SHIFT_IB_SHIFT 10 ++#define DPI_DMA_SHIFT_IB_MASK (0x1F << DPI_DMA_SHIFT_IB_SHIFT) ++#define DPI_DMA_SHIFT_OR_SHIFT 15 ++#define DPI_DMA_SHIFT_OR_MASK (0x1F << DPI_DMA_SHIFT_OR_SHIFT) ++#define DPI_DMA_SHIFT_OG_SHIFT 20 ++#define DPI_DMA_SHIFT_OG_MASK (0x1F << DPI_DMA_SHIFT_OG_SHIFT) ++#define DPI_DMA_SHIFT_OB_SHIFT 25 ++#define DPI_DMA_SHIFT_OB_MASK (0x1F << DPI_DMA_SHIFT_OB_SHIFT) ++ ++// Scaling ++#define DPI_DMA_RGBSZ 0x34 ++#define DPI_DMA_RGBSZ_BPP_SHIFT 16 ++#define DPI_DMA_RGBSZ_BPP_MASK (0x3 << DPI_DMA_RGBSZ_BPP_SHIFT) ++#define DPI_DMA_RGBSZ_R_SHIFT 0 ++#define DPI_DMA_RGBSZ_R_MASK (0xF << DPI_DMA_RGBSZ_R_SHIFT) ++#define DPI_DMA_RGBSZ_G_SHIFT 4 ++#define DPI_DMA_RGBSZ_G_MASK (0xF << DPI_DMA_RGBSZ_G_SHIFT) ++#define DPI_DMA_RGBSZ_B_SHIFT 8 ++#define DPI_DMA_RGBSZ_B_MASK (0xF << DPI_DMA_RGBSZ_B_SHIFT) ++ ++// Status ++#define DPI_DMA_STATUS 0x3c ++ ++#define BITS(field, val) (((val) << (field ## _SHIFT)) & (field ## _MASK)) ++ ++static unsigned int rp1dsi_dma_read(struct rp1_dsi *dsi, unsigned int reg) ++{ ++ void __iomem *addr = dsi->hw_base[RP1DSI_HW_BLOCK_DMA] + reg; ++ ++ return readl(addr); ++} ++ ++static void rp1dsi_dma_write(struct rp1_dsi *dsi, unsigned int reg, unsigned int val) ++{ ++ void __iomem *addr = dsi->hw_base[RP1DSI_HW_BLOCK_DMA] + reg; ++ ++ writel(val, addr); ++} ++ ++int rp1dsi_dma_busy(struct rp1_dsi *dsi) ++{ ++ return (rp1dsi_dma_read(dsi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0; ++} ++ ++/* Table of supported input (in-memory/DMA) pixel formats. */ ++struct rp1dsi_ipixfmt { ++ u32 format; /* DRM format code */ ++ u32 mask; /* RGB masks (10 bits each, left justified) */ ++ u32 shift; /* RGB MSB positions in the memory word */ ++ u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */ ++}; ++ ++#define IMASK_RGB(r, g, b) (BITS(DPI_DMA_IMASK_R, r) | \ ++ BITS(DPI_DMA_IMASK_G, g) | \ ++ BITS(DPI_DMA_IMASK_B, b)) ++#define ISHIFT_RGB(r, g, b) (BITS(DPI_DMA_SHIFT_IR, r) | \ ++ BITS(DPI_DMA_SHIFT_IG, g) | \ ++ BITS(DPI_DMA_SHIFT_IB, b)) ++ ++static const struct rp1dsi_ipixfmt my_formats[] = { ++ { ++ .format = DRM_FORMAT_XRGB8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_XBGR8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_RGB888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), ++ }, ++ { ++ .format = DRM_FORMAT_BGR888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), ++ }, ++ { ++ .format = DRM_FORMAT_RGB565, ++ .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0), ++ .shift = ISHIFT_RGB(15, 10, 4), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_R, 5) | BITS(DPI_DMA_RGBSZ_G, 6) | ++ BITS(DPI_DMA_RGBSZ_B, 5) | BITS(DPI_DMA_RGBSZ_BPP, 1), ++ } ++}; ++ ++/* Choose the internal on-the-bus DPI format as expected by DSI Host. */ ++static u32 get_omask_oshift(enum mipi_dsi_pixel_format fmt, u32 *oshift) ++{ ++ switch (fmt) { ++ case MIPI_DSI_FMT_RGB565: ++ *oshift = BITS(DPI_DMA_SHIFT_OR, 15) | ++ BITS(DPI_DMA_SHIFT_OG, 10) | ++ BITS(DPI_DMA_SHIFT_OB, 4); ++ return BITS(DPI_DMA_OMASK_R, 0x3e0) | ++ BITS(DPI_DMA_OMASK_G, 0x3f0) | ++ BITS(DPI_DMA_OMASK_B, 0x3e0); ++ case MIPI_DSI_FMT_RGB666_PACKED: ++ *oshift = BITS(DPI_DMA_SHIFT_OR, 17) | ++ BITS(DPI_DMA_SHIFT_OG, 11) | ++ BITS(DPI_DMA_SHIFT_OB, 5); ++ return BITS(DPI_DMA_OMASK_R, 0x3f0) | ++ BITS(DPI_DMA_OMASK_G, 0x3f0) | ++ BITS(DPI_DMA_OMASK_B, 0x3f0); ++ case MIPI_DSI_FMT_RGB666: ++ *oshift = BITS(DPI_DMA_SHIFT_OR, 21) | ++ BITS(DPI_DMA_SHIFT_OG, 13) | ++ BITS(DPI_DMA_SHIFT_OB, 5); ++ return BITS(DPI_DMA_OMASK_R, 0x3f0) | ++ BITS(DPI_DMA_OMASK_G, 0x3f0) | ++ BITS(DPI_DMA_OMASK_B, 0x3f0); ++ default: ++ *oshift = BITS(DPI_DMA_SHIFT_OR, 23) | ++ BITS(DPI_DMA_SHIFT_OG, 15) | ++ BITS(DPI_DMA_SHIFT_OB, 7); ++ return BITS(DPI_DMA_OMASK_R, 0x3fc) | ++ BITS(DPI_DMA_OMASK_G, 0x3fc) | ++ BITS(DPI_DMA_OMASK_B, 0x3fc); ++ } ++} ++ ++void rp1dsi_dma_setup(struct rp1_dsi *dsi, ++ u32 in_format, enum mipi_dsi_pixel_format out_format, ++ struct drm_display_mode const *mode) ++{ ++ u32 oshift; ++ int i; ++ ++ /* ++ * Configure all DSI/DPI/DMA block registers, except base address. ++ * DMA will not actually start until a FB base address is specified ++ * using rp1dsi_dma_update(). ++ */ ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_VISIBLE_AREA, ++ BITS(DPI_DMA_VISIBLE_AREA_ROWSM1, mode->vdisplay - 1) | ++ BITS(DPI_DMA_VISIBLE_AREA_COLSM1, mode->hdisplay - 1)); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_SYNC_WIDTH, ++ BITS(DPI_DMA_SYNC_WIDTH_ROWSM1, mode->vsync_end - mode->vsync_start - 1) | ++ BITS(DPI_DMA_SYNC_WIDTH_COLSM1, mode->hsync_end - mode->hsync_start - 1)); ++ ++ /* In the DPIDMA registers, "back porch" time includes sync width */ ++ rp1dsi_dma_write(dsi, DPI_DMA_BACK_PORCH, ++ BITS(DPI_DMA_BACK_PORCH_ROWSM1, mode->vtotal - mode->vsync_start - 1) | ++ BITS(DPI_DMA_BACK_PORCH_COLSM1, mode->htotal - mode->hsync_start - 1)); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_FRONT_PORCH, ++ BITS(DPI_DMA_FRONT_PORCH_ROWSM1, mode->vsync_start - mode->vdisplay - 1) | ++ BITS(DPI_DMA_FRONT_PORCH_COLSM1, mode->hsync_start - mode->hdisplay - 1)); ++ ++ /* Input to output pixel format conversion */ ++ for (i = 0; i < ARRAY_SIZE(my_formats); ++i) { ++ if (my_formats[i].format == in_format) ++ break; ++ } ++ if (i >= ARRAY_SIZE(my_formats)) { ++ drm_err(dsi->drm, "%s: bad input format\n", __func__); ++ i = 0; ++ } ++ rp1dsi_dma_write(dsi, DPI_DMA_IMASK, my_formats[i].mask); ++ rp1dsi_dma_write(dsi, DPI_DMA_OMASK, get_omask_oshift(out_format, &oshift)); ++ rp1dsi_dma_write(dsi, DPI_DMA_SHIFT, my_formats[i].shift | oshift); ++ if (out_format == MIPI_DSI_FMT_RGB888) ++ rp1dsi_dma_write(dsi, DPI_DMA_RGBSZ, my_formats[i].rgbsz); ++ else ++ rp1dsi_dma_write(dsi, DPI_DMA_RGBSZ, my_formats[i].rgbsz & DPI_DMA_RGBSZ_BPP_MASK); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_QOS, ++ BITS(DPI_DMA_QOS_DQOS, 0x0) | ++ BITS(DPI_DMA_QOS_ULEV, 0xb) | ++ BITS(DPI_DMA_QOS_UQOS, 0x2) | ++ BITS(DPI_DMA_QOS_LLEV, 0x8) | ++ BITS(DPI_DMA_QOS_LQOS, 0x7)); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_IRQ_FLAGS, -1); ++ rp1dsi_dma_vblank_ctrl(dsi, 1); ++ ++ i = rp1dsi_dma_busy(dsi); ++ if (i) ++ drm_err(dsi->drm, "RP1DSI: Unexpectedly busy at start!"); ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_CONTROL, ++ BITS(DPI_DMA_CONTROL_ARM, (i == 0)) | ++ BITS(DPI_DMA_CONTROL_AUTO_REPEAT, 1) | ++ BITS(DPI_DMA_CONTROL_HIGH_WATER, 448) | ++ BITS(DPI_DMA_CONTROL_DEN_POL, 0) | ++ BITS(DPI_DMA_CONTROL_HSYNC_POL, 0) | ++ BITS(DPI_DMA_CONTROL_VSYNC_POL, 0) | ++ BITS(DPI_DMA_CONTROL_COLORM, 0) | ++ BITS(DPI_DMA_CONTROL_SHUTDN, 0) | ++ BITS(DPI_DMA_CONTROL_HBP_EN, 1) | ++ BITS(DPI_DMA_CONTROL_HFP_EN, 1) | ++ BITS(DPI_DMA_CONTROL_VBP_EN, 1) | ++ BITS(DPI_DMA_CONTROL_VFP_EN, 1) | ++ BITS(DPI_DMA_CONTROL_HSYNC_EN, 1) | ++ BITS(DPI_DMA_CONTROL_VSYNC_EN, 1)); ++} ++ ++void rp1dsi_dma_update(struct rp1_dsi *dsi, dma_addr_t addr, u32 offset, u32 stride) ++{ ++ /* ++ * Update STRIDE, DMAH and DMAL only. When called after rp1dsi_dma_setup(), ++ * DMA starts immediately; if already running, the buffer will flip at ++ * the next vertical sync event. ++ */ ++ u64 a = addr + offset; ++ ++ rp1dsi_dma_write(dsi, DPI_DMA_DMA_STRIDE, stride); ++ rp1dsi_dma_write(dsi, DPI_DMA_DMA_ADDR_H, a >> 32); ++ rp1dsi_dma_write(dsi, DPI_DMA_DMA_ADDR_L, a & 0xFFFFFFFFu); ++} ++ ++void rp1dsi_dma_stop(struct rp1_dsi *dsi) ++{ ++ /* ++ * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for ++ * the current and any queued frame to end. "Force drain" flags are not used, ++ * as they seem to prevent DMA from re-starting properly; it's safer to wait. ++ */ ++ u32 ctrl; ++ ++ reinit_completion(&dsi->finished); ++ ctrl = rp1dsi_dma_read(dsi, DPI_DMA_CONTROL); ++ ctrl &= ~(DPI_DMA_CONTROL_ARM_MASK | DPI_DMA_CONTROL_AUTO_REPEAT_MASK); ++ rp1dsi_dma_write(dsi, DPI_DMA_CONTROL, ctrl); ++ if (!wait_for_completion_timeout(&dsi->finished, HZ / 10)) ++ drm_err(dsi->drm, "%s: timed out waiting for idle\n", __func__); ++ rp1dsi_dma_write(dsi, DPI_DMA_IRQ_EN, 0); ++} ++ ++void rp1dsi_dma_vblank_ctrl(struct rp1_dsi *dsi, int enable) ++{ ++ rp1dsi_dma_write(dsi, DPI_DMA_IRQ_EN, ++ BITS(DPI_DMA_IRQ_EN_AFIFO_EMPTY, 1) | ++ BITS(DPI_DMA_IRQ_EN_UNDERFLOW, 1) | ++ BITS(DPI_DMA_IRQ_EN_DMA_READY, !!enable) | ++ BITS(DPI_DMA_IRQ_EN_MATCH_LINE, 4095)); ++} ++ ++irqreturn_t rp1dsi_dma_isr(int irq, void *dev) ++{ ++ struct rp1_dsi *dsi = dev; ++ u32 u = rp1dsi_dma_read(dsi, DPI_DMA_IRQ_FLAGS); ++ ++ if (u) { ++ rp1dsi_dma_write(dsi, DPI_DMA_IRQ_FLAGS, u); ++ if (dsi) { ++ if (u & DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK) ++ drm_err_ratelimited(dsi->drm, ++ "Underflow! (panics=0x%08x)\n", ++ rp1dsi_dma_read(dsi, DPI_DMA_PANICS)); ++ if (u & DPI_DMA_IRQ_FLAGS_DMA_READY_MASK) ++ drm_crtc_handle_vblank(&dsi->pipe.crtc); ++ if (u & DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK) ++ complete(&dsi->finished); ++ } ++ } ++ return u ? IRQ_HANDLED : IRQ_NONE; ++} +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c +@@ -0,0 +1,1504 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "drm/drm_print.h" ++ ++#include "rp1_dsi.h" ++ ++/* ------------------------------- Synopsis DSI ------------------------ */ ++#define DSI_VERSION_CFG 0x000 ++#define DSI_PWR_UP 0x004 ++#define DSI_CLKMGR_CFG 0x008 ++#define DSI_DPI_VCID 0x00C ++#define DSI_DPI_COLOR_CODING 0x010 ++#define DSI_DPI_CFG_POL 0x014 ++#define DSI_DPI_LP_CMD_TIM 0x018 ++#define DSI_DBI_VCID 0x01C ++#define DSI_DBI_CFG 0x020 ++#define DSI_DBI_PARTITIONING_EN 0x024 ++#define DSI_DBI_CMDSIZE 0x028 ++#define DSI_PCKHDL_CFG 0x02C ++#define DSI_GEN_VCID 0x030 ++#define DSI_MODE_CFG 0x034 ++#define DSI_VID_MODE_CFG 0x038 ++#define DSI_VID_PKT_SIZE 0x03C ++#define DSI_VID_NUM_CHUNKS 0x040 ++#define DSI_VID_NULL_SIZE 0x044 ++#define DSI_VID_HSA_TIME 0x048 ++#define DSI_VID_HBP_TIME 0x04C ++#define DSI_VID_HLINE_TIME 0x050 ++#define DSI_VID_VSA_LINES 0x054 ++#define DSI_VID_VBP_LINES 0x058 ++#define DSI_VID_VFP_LINES 0x05C ++#define DSI_VID_VACTIVE_LINES 0x060 ++#define DSI_EDPI_CMD_SIZE 0x064 ++#define DSI_CMD_MODE_CFG 0x068 ++#define DSI_GEN_HDR 0x06C ++#define DSI_GEN_PLD_DATA 0x070 ++#define DSI_CMD_PKT_STATUS 0x074 ++#define DSI_TO_CNT_CFG 0x078 ++#define DSI_HS_RD_TO_CNT 0x07C ++#define DSI_LP_RD_TO_CNT 0x080 ++#define DSI_HS_WR_TO_CNT 0x084 ++#define DSI_LP_WR_TO_CNT 0x088 ++#define DSI_BTA_TO_CNT 0x08C ++#define DSI_SDF_3D 0x090 ++#define DSI_LPCLK_CTRL 0x094 ++#define DSI_PHY_TMR_LPCLK_CFG 0x098 ++#define DSI_PHY_TMR_HS2LP_LSB 16 ++#define DSI_PHY_TMR_LP2HS_LSB 0 ++#define DSI_PHY_TMR_CFG 0x09C ++#define DSI_PHY_TMR_RD_CFG 0x0F4 ++#define DSI_PHYRSTZ 0x0A0 ++#define DSI_PHY_IF_CFG 0x0A4 ++#define DSI_PHY_ULPS_CTRL 0x0A8 ++#define DSI_PHY_TX_TRIGGERS 0x0AC ++#define DSI_PHY_STATUS 0x0B0 ++ ++#define DSI_PHY_TST_CTRL0 0x0B4 ++#define DSI_PHY_TST_CTRL1 0x0B8 ++#define DSI_INT_ST0 0x0BC ++#define DSI_INT_ST1 0x0C0 ++#define DSI_INT_MASK0_CFG 0x0C4 ++#define DSI_INT_MASK1_CFG 0x0C8 ++#define DSI_PHY_CAL 0x0CC ++#define DSI_HEXP_NPKT_CLR 0x104 ++#define DSI_HEXP_NPKT_SIZE 0x108 ++#define DSI_VID_SHADOW_CTRL 0x100 ++ ++#define DSI_DPI_VCID_ACT 0x10C ++#define DSI_DPI_COLOR_CODING_ACT 0x110 ++#define DSI_DPI_LP_CMD_TIM_ACT 0x118 ++#define DSI_VID_MODE_CFG_ACT 0x138 ++#define DSI_VID_PKT_SIZE_ACT 0x13C ++#define DSI_VID_NUM_CHUNKS_ACT 0x140 ++#define DSI_VID_NULL_SIZE_ACT 0x144 ++#define DSI_VID_HSA_TIME_ACT 0x148 ++#define DSI_VID_HBP_TIME_ACT 0x14C ++#define DSI_VID_HLINE_TIME_ACT 0x150 ++#define DSI_VID_VSA_LINES_ACT 0x154 ++#define DSI_VID_VBP_LINES_ACT 0x158 ++#define DSI_VID_VFP_LINES_ACT 0x15C ++#define DSI_VID_VACTIVE_LINES_ACT 0x160 ++#define DSI_SDF_3D_CFG_ACT 0x190 ++ ++#define DSI_INT_FORCE0 0x0D8 ++#define DSI_INT_FORCE1 0x0DC ++ ++#define DSI_AUTO_ULPS_MODE 0x0E0 ++#define DSI_AUTO_ULPS_ENTRY_DELAY 0x0E4 ++#define DSI_AUTO_ULPS_WAKEUP_TIME 0x0E8 ++#define DSI_EDPI_ADV_FEATURES 0x0EC ++ ++#define DSI_DSC_PARAMETER 0x0F0 ++ ++/* And some bitfield definitions */ ++ ++#define DPHY_PWR_UP_SHUTDOWNZ_LSB 0 ++#define DPHY_PWR_UP_SHUTDOWNZ_BITS BIT(DPHY_PWR_UP_SHUTDOWNZ_LSB) ++ ++#define DPHY_CTRL0_PHY_TESTCLK_LSB 1 ++#define DPHY_CTRL0_PHY_TESTCLK_BITS BIT(DPHY_CTRL0_PHY_TESTCLK_LSB) ++#define DPHY_CTRL0_PHY_TESTCLR_LSB 0 ++#define DPHY_CTRL0_PHY_TESTCLR_BITS BIT(DPHY_CTRL0_PHY_TESTCLR_LSB) ++ ++#define DPHY_CTRL1_PHY_TESTDIN_LSB 0 ++#define DPHY_CTRL1_PHY_TESTDIN_BITS (0xff << DPHY_CTRL1_PHY_TESTDIN_LSB) ++#define DPHY_CTRL1_PHY_TESTDOUT_LSB 8 ++#define DPHY_CTRL1_PHY_TESTDOUT_BITS (0xff << DPHY_CTRL1_PHY_TESTDOUT_LSB) ++#define DPHY_CTRL1_PHY_TESTEN_LSB 16 ++#define DPHY_CTRL1_PHY_TESTEN_BITS BIT(DPHY_CTRL1_PHY_TESTEN_LSB) ++ ++#define DSI_PHYRSTZ_SHUTDOWNZ_LSB 0 ++#define DSI_PHYRSTZ_SHUTDOWNZ_BITS BIT(DSI_PHYRSTZ_SHUTDOWNZ_LSB) ++#define DSI_PHYRSTZ_RSTZ_LSB 1 ++#define DSI_PHYRSTZ_RSTZ_BITS BIT(DSI_PHYRSTZ_RSTZ_LSB) ++#define DSI_PHYRSTZ_ENABLECLK_LSB 2 ++#define DSI_PHYRSTZ_ENABLECLK_BITS BIT(DSI_PHYRSTZ_ENABLECLK_LSB) ++#define DSI_PHYRSTZ_FORCEPLL_LSB 3 ++#define DSI_PHYRSTZ_FORCEPLL_BITS BIT(DSI_PHYRSTZ_FORCEPLL_LSB) ++ ++#define DPHY_HS_RX_CTRL_LANE0_OFFSET 0x44 ++#define DPHY_PLL_INPUT_DIV_OFFSET 0x17 ++#define DPHY_PLL_LOOP_DIV_OFFSET 0x18 ++#define DPHY_PLL_DIV_CTRL_OFFSET 0x19 ++ ++#define DPHY_PLL_BIAS_OFFSET 0x10 ++#define DPHY_PLL_BIAS_VCO_RANGE_LSB 3 ++#define DPHY_PLL_BIAS_USE_PROGRAMMED_VCO_RANGE BIT(7) ++ ++#define DPHY_PLL_CHARGE_PUMP_OFFSET 0x11 ++#define DPHY_PLL_LPF_OFFSET 0x12 ++ ++#define DSI_WRITE(reg, val) writel((val), dsi->hw_base[RP1DSI_HW_BLOCK_DSI] + (reg)) ++#define DSI_READ(reg) readl(dsi->hw_base[RP1DSI_HW_BLOCK_DSI] + (reg)) ++ ++// ================================================================================ ++// Register block : RPI_MIPICFG ++// Version : 1 ++// Bus type : apb ++// Description : Register block to control mipi DPHY ++// ================================================================================ ++#define RPI_MIPICFG_REGS_RWTYPE_MSB 13 ++#define RPI_MIPICFG_REGS_RWTYPE_LSB 12 ++// ================================================================================ ++// Register : RPI_MIPICFG_CLK2FC ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_CLK2FC_OFFSET 0x00000000 ++#define RPI_MIPICFG_CLK2FC_BITS 0x00000007 ++#define RPI_MIPICFG_CLK2FC_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_CLK2FC_SEL ++// Description : select a clock to be sent to the frequency counter ++// 7 = none ++// 6 = none ++// 5 = none ++// 4 = rxbyteclkhs (187.5MHz) ++// 3 = rxclkesc0 (20MHz) ++// 2 = txbyteclkhs (187.5MHz) ++// 1 = txclkesc (125MHz) ++// 0 = none ++#define RPI_MIPICFG_CLK2FC_SEL_RESET 0x0 ++#define RPI_MIPICFG_CLK2FC_SEL_BITS 0x00000007 ++#define RPI_MIPICFG_CLK2FC_SEL_MSB 2 ++#define RPI_MIPICFG_CLK2FC_SEL_LSB 0 ++#define RPI_MIPICFG_CLK2FC_SEL_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_CFG ++// JTAG access : asynchronous ++// Description : Top level configuration ++#define RPI_MIPICFG_CFG_OFFSET 0x00000004 ++#define RPI_MIPICFG_CFG_BITS 0x00000111 ++#define RPI_MIPICFG_CFG_RESET 0x00000001 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_CFG_DPIUPDATE ++// Description : Indicate the DSI block that the next frame will have a new video configuration ++#define RPI_MIPICFG_CFG_DPIUPDATE_RESET 0x0 ++#define RPI_MIPICFG_CFG_DPIUPDATE_BITS 0x00000100 ++#define RPI_MIPICFG_CFG_DPIUPDATE_MSB 8 ++#define RPI_MIPICFG_CFG_DPIUPDATE_LSB 8 ++#define RPI_MIPICFG_CFG_DPIUPDATE_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_CFG_SEL_TE_EXT ++// Description : Select the TE source: 1 - ext, 0 - int ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_RESET 0x0 ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_BITS 0x00000010 ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_MSB 4 ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_LSB 4 ++#define RPI_MIPICFG_CFG_SEL_TE_EXT_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_CFG_SEL_CSI_DSI_N ++// Description : Select PHY direction: input to CSI, output from DSI. CSI 1 DSI 0 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_RESET 0x1 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_BITS 0x00000001 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_MSB 0 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_LSB 0 ++#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_TE ++// JTAG access : synchronous ++// Description : Tearing effect processing ++#define RPI_MIPICFG_TE_OFFSET 0x00000008 ++#define RPI_MIPICFG_TE_BITS 0x10ffffff ++#define RPI_MIPICFG_TE_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_TE_ARM ++// Description : Tearing effect arm ++#define RPI_MIPICFG_TE_ARM_RESET 0x0 ++#define RPI_MIPICFG_TE_ARM_BITS 0x10000000 ++#define RPI_MIPICFG_TE_ARM_MSB 28 ++#define RPI_MIPICFG_TE_ARM_LSB 28 ++#define RPI_MIPICFG_TE_ARM_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_TE_HALT_CYC ++// Description : When arm pulse has been seen, wait for te; then halt the dpi block ++// for this many clk_dpi cycles ++#define RPI_MIPICFG_TE_HALT_CYC_RESET 0x000000 ++#define RPI_MIPICFG_TE_HALT_CYC_BITS 0x00ffffff ++#define RPI_MIPICFG_TE_HALT_CYC_MSB 23 ++#define RPI_MIPICFG_TE_HALT_CYC_LSB 0 ++#define RPI_MIPICFG_TE_HALT_CYC_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_MONITOR ++// JTAG access : asynchronous ++// Description : DPHY status monitors for analog DFT ++#define RPI_MIPICFG_DPHY_MONITOR_OFFSET 0x00000010 ++#define RPI_MIPICFG_DPHY_MONITOR_BITS 0x00111fff ++#define RPI_MIPICFG_DPHY_MONITOR_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_LOCK ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_BITS 0x00100000 ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_MSB 20 ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_LSB 20 ++#define RPI_MIPICFG_DPHY_MONITOR_LOCK_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_BISTOK ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_BITS 0x00010000 ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_MSB 16 ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_LSB 16 ++#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_BITS 0x00001000 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_MSB 12 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_LSB 12 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_RESET 0x0 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_BITS 0x00000f00 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_MSB 11 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_LSB 8 ++#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_MONITOR_TESTDOUT ++// Description : None ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_RESET 0x00 ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_BITS 0x000000ff ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_MSB 7 ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_LSB 0 ++#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_0 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_0_OFFSET 0x00000014 ++#define RPI_MIPICFG_DPHY_CTRL_0_BITS 0x0000003f ++#define RPI_MIPICFG_DPHY_CTRL_0_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE ++// Description : When set in lpmode, TXCLKESC is driven from clk_vec(driven from clocks block) ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_BITS 0x00000020 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_MSB 5 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_LSB 5 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA ++// Description : When set, drive the DPHY from the test registers ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_BITS 0x00000010 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_MSB 4 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_LSB 4 ++#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS ++// Description : When test_ena is set, disable cfg_clk ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_BITS 0x00000008 ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_MSB 3 ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_LSB 3 ++#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS ++// Description : When test_ena is set, disable refclk ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_BITS 0x00000004 ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_MSB 2 ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_LSB 2 ++#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS ++// Description : When test_ena is set, disable txclkesc ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_BITS 0x00000002 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_MSB 1 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_LSB 1 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS ++// Description : When test_ena is set, disable txbyteclkhs ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_BITS 0x00000001 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_MSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_1 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_1_OFFSET 0x00000018 ++#define RPI_MIPICFG_DPHY_CTRL_1_BITS 0x7fffffff ++#define RPI_MIPICFG_DPHY_CTRL_1_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_BITS 0x40000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_MSB 30 ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_LSB 30 ++#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_BITS 0x20000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_MSB 29 ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_LSB 29 ++#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_RSTZ ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_BITS 0x10000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_MSB 28 ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_LSB 28 ++#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_BITS 0x08000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_MSB 27 ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_LSB 27 ++#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BISTON ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_BITS 0x04000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_MSB 26 ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_LSB 26 ++#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_BITS 0x02000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_MSB 25 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_LSB 25 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_BITS 0x01000000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_MSB 24 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_LSB 24 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_BITS 0x00800000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_MSB 23 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_LSB 23 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_BITS 0x00400000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_MSB 22 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_LSB 22 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_BITS 0x00200000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_MSB 21 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_LSB 21 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_BITS 0x00100000 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_MSB 20 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_LSB 20 ++#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_BITS 0x00080000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_MSB 19 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_LSB 19 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_BITS 0x00040000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_MSB 18 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_LSB 18 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_BITS 0x00020000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_MSB 17 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_LSB 17 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_BITS 0x00010000 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_MSB 16 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_LSB 16 ++#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_BITS 0x00008000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_MSB 15 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_LSB 15 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_BITS 0x00004000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_MSB 14 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_LSB 14 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_BITS 0x00002000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_MSB 13 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_LSB 13 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_BITS 0x00001000 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_MSB 12 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_LSB 12 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_BITS 0x00000800 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_MSB 11 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_LSB 11 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_BITS 0x00000400 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_MSB 10 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_LSB 10 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_BITS 0x00000200 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_MSB 9 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_LSB 9 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_BITS 0x00000100 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_MSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_LSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_BITS 0x00000080 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_MSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_LSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_BITS 0x00000040 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_MSB 6 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_LSB 6 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_BITS 0x00000020 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_MSB 5 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_LSB 5 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_BITS 0x00000010 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_MSB 4 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_LSB 4 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_BITS 0x00000008 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_MSB 3 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_LSB 3 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_BITS 0x00000004 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_MSB 2 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_LSB 2 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_BITS 0x00000002 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_MSB 1 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_LSB 1 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_BITS 0x00000001 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_MSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_2 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_2_OFFSET 0x0000001c ++#define RPI_MIPICFG_DPHY_CTRL_2_BITS 0x000007ff ++#define RPI_MIPICFG_DPHY_CTRL_2_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTCLK ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_BITS 0x00000400 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_MSB 10 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_LSB 10 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTEN ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_BITS 0x00000200 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_MSB 9 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_LSB 9 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTCLR ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_RESET 0x0 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_BITS 0x00000100 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_MSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_LSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTDIN ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_BITS 0x000000ff ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_MSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_3 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_3_OFFSET 0x00000020 ++#define RPI_MIPICFG_DPHY_CTRL_3_BITS 0xffffffff ++#define RPI_MIPICFG_DPHY_CTRL_3_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_BITS 0xff000000 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_MSB 31 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_LSB 24 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_BITS 0x00ff0000 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_MSB 23 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_LSB 16 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_BITS 0x0000ff00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_MSB 15 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_LSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_BITS 0x000000ff ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_MSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_DPHY_CTRL_4 ++// JTAG access : asynchronous ++// Description : DPHY control for analog DFT ++#define RPI_MIPICFG_DPHY_CTRL_4_OFFSET 0x00000024 ++#define RPI_MIPICFG_DPHY_CTRL_4_BITS 0xffffffff ++#define RPI_MIPICFG_DPHY_CTRL_4_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_BITS 0xff000000 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_MSB 31 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_LSB 24 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_BITS 0x00ff0000 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_MSB 23 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_LSB 16 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_BITS 0x0000ff00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_MSB 15 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_LSB 8 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0 ++// Description : None ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_RESET 0x00 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_BITS 0x000000ff ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_MSB 7 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_LSB 0 ++#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_INTR ++// JTAG access : synchronous ++// Description : Raw Interrupts ++#define RPI_MIPICFG_INTR_OFFSET 0x00000028 ++#define RPI_MIPICFG_INTR_BITS 0x0000000f ++#define RPI_MIPICFG_INTR_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTR_DSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTR_DSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTR_DSI_HOST_BITS 0x00000008 ++#define RPI_MIPICFG_INTR_DSI_HOST_MSB 3 ++#define RPI_MIPICFG_INTR_DSI_HOST_LSB 3 ++#define RPI_MIPICFG_INTR_DSI_HOST_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTR_CSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTR_CSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTR_CSI_HOST_BITS 0x00000004 ++#define RPI_MIPICFG_INTR_CSI_HOST_MSB 2 ++#define RPI_MIPICFG_INTR_CSI_HOST_LSB 2 ++#define RPI_MIPICFG_INTR_CSI_HOST_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTR_DSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTR_DSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTR_DSI_DMA_BITS 0x00000002 ++#define RPI_MIPICFG_INTR_DSI_DMA_MSB 1 ++#define RPI_MIPICFG_INTR_DSI_DMA_LSB 1 ++#define RPI_MIPICFG_INTR_DSI_DMA_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTR_CSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTR_CSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTR_CSI_DMA_BITS 0x00000001 ++#define RPI_MIPICFG_INTR_CSI_DMA_MSB 0 ++#define RPI_MIPICFG_INTR_CSI_DMA_LSB 0 ++#define RPI_MIPICFG_INTR_CSI_DMA_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_INTE ++// JTAG access : synchronous ++// Description : Interrupt Enable ++#define RPI_MIPICFG_INTE_OFFSET 0x0000002c ++#define RPI_MIPICFG_INTE_BITS 0x0000000f ++#define RPI_MIPICFG_INTE_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTE_DSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTE_DSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTE_DSI_HOST_BITS 0x00000008 ++#define RPI_MIPICFG_INTE_DSI_HOST_MSB 3 ++#define RPI_MIPICFG_INTE_DSI_HOST_LSB 3 ++#define RPI_MIPICFG_INTE_DSI_HOST_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTE_CSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTE_CSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTE_CSI_HOST_BITS 0x00000004 ++#define RPI_MIPICFG_INTE_CSI_HOST_MSB 2 ++#define RPI_MIPICFG_INTE_CSI_HOST_LSB 2 ++#define RPI_MIPICFG_INTE_CSI_HOST_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTE_DSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTE_DSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTE_DSI_DMA_BITS 0x00000002 ++#define RPI_MIPICFG_INTE_DSI_DMA_MSB 1 ++#define RPI_MIPICFG_INTE_DSI_DMA_LSB 1 ++#define RPI_MIPICFG_INTE_DSI_DMA_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTE_CSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTE_CSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTE_CSI_DMA_BITS 0x00000001 ++#define RPI_MIPICFG_INTE_CSI_DMA_MSB 0 ++#define RPI_MIPICFG_INTE_CSI_DMA_LSB 0 ++#define RPI_MIPICFG_INTE_CSI_DMA_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_INTF ++// JTAG access : synchronous ++// Description : Interrupt Force ++#define RPI_MIPICFG_INTF_OFFSET 0x00000030 ++#define RPI_MIPICFG_INTF_BITS 0x0000000f ++#define RPI_MIPICFG_INTF_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTF_DSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTF_DSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTF_DSI_HOST_BITS 0x00000008 ++#define RPI_MIPICFG_INTF_DSI_HOST_MSB 3 ++#define RPI_MIPICFG_INTF_DSI_HOST_LSB 3 ++#define RPI_MIPICFG_INTF_DSI_HOST_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTF_CSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTF_CSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTF_CSI_HOST_BITS 0x00000004 ++#define RPI_MIPICFG_INTF_CSI_HOST_MSB 2 ++#define RPI_MIPICFG_INTF_CSI_HOST_LSB 2 ++#define RPI_MIPICFG_INTF_CSI_HOST_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTF_DSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTF_DSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTF_DSI_DMA_BITS 0x00000002 ++#define RPI_MIPICFG_INTF_DSI_DMA_MSB 1 ++#define RPI_MIPICFG_INTF_DSI_DMA_LSB 1 ++#define RPI_MIPICFG_INTF_DSI_DMA_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTF_CSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTF_CSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTF_CSI_DMA_BITS 0x00000001 ++#define RPI_MIPICFG_INTF_CSI_DMA_MSB 0 ++#define RPI_MIPICFG_INTF_CSI_DMA_LSB 0 ++#define RPI_MIPICFG_INTF_CSI_DMA_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_INTS ++// JTAG access : synchronous ++// Description : Interrupt status after masking & forcing ++#define RPI_MIPICFG_INTS_OFFSET 0x00000034 ++#define RPI_MIPICFG_INTS_BITS 0x0000000f ++#define RPI_MIPICFG_INTS_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTS_DSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTS_DSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTS_DSI_HOST_BITS 0x00000008 ++#define RPI_MIPICFG_INTS_DSI_HOST_MSB 3 ++#define RPI_MIPICFG_INTS_DSI_HOST_LSB 3 ++#define RPI_MIPICFG_INTS_DSI_HOST_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTS_CSI_HOST ++// Description : None ++#define RPI_MIPICFG_INTS_CSI_HOST_RESET 0x0 ++#define RPI_MIPICFG_INTS_CSI_HOST_BITS 0x00000004 ++#define RPI_MIPICFG_INTS_CSI_HOST_MSB 2 ++#define RPI_MIPICFG_INTS_CSI_HOST_LSB 2 ++#define RPI_MIPICFG_INTS_CSI_HOST_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTS_DSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTS_DSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTS_DSI_DMA_BITS 0x00000002 ++#define RPI_MIPICFG_INTS_DSI_DMA_MSB 1 ++#define RPI_MIPICFG_INTS_DSI_DMA_LSB 1 ++#define RPI_MIPICFG_INTS_DSI_DMA_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_INTS_CSI_DMA ++// Description : None ++#define RPI_MIPICFG_INTS_CSI_DMA_RESET 0x0 ++#define RPI_MIPICFG_INTS_CSI_DMA_BITS 0x00000001 ++#define RPI_MIPICFG_INTS_CSI_DMA_MSB 0 ++#define RPI_MIPICFG_INTS_CSI_DMA_LSB 0 ++#define RPI_MIPICFG_INTS_CSI_DMA_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_BLOCK_ID ++// JTAG access : asynchronous ++// Description : Block Identifier ++#define RPI_MIPICFG_BLOCK_ID_OFFSET 0x00000038 ++#define RPI_MIPICFG_BLOCK_ID_BITS 0xffffffff ++#define RPI_MIPICFG_BLOCK_ID_RESET 0x4d495049 ++#define RPI_MIPICFG_BLOCK_ID_MSB 31 ++#define RPI_MIPICFG_BLOCK_ID_LSB 0 ++#define RPI_MIPICFG_BLOCK_ID_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_INSTANCE_ID ++// JTAG access : asynchronous ++// Description : Block Instance Identifier ++#define RPI_MIPICFG_INSTANCE_ID_OFFSET 0x0000003c ++#define RPI_MIPICFG_INSTANCE_ID_BITS 0x0000000f ++#define RPI_MIPICFG_INSTANCE_ID_RESET 0x00000000 ++#define RPI_MIPICFG_INSTANCE_ID_MSB 3 ++#define RPI_MIPICFG_INSTANCE_ID_LSB 0 ++#define RPI_MIPICFG_INSTANCE_ID_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_AUTO ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_AUTO_OFFSET 0x00000040 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_AUTO_RESET 0x00000007 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_AUTO_CSI ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_AUTO_DPI ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_PARALLEL ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_OFFSET 0x00000044 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_RESET 0x00000006 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_PARALLEL_CSI ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_PARALLEL_DPI ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_RESET 0x1 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_CTRL ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_CTRL_OFFSET 0x00000048 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_CTRL_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_CTRL_CSI ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_CTRL_DPI ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_ACCESS "RW" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_TRIG ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_TRIG_OFFSET 0x0000004c ++#define RPI_MIPICFG_RSTSEQ_TRIG_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_TRIG_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_TRIG_CSI ++// Description : Pulses the reset output ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_ACCESS "SC" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_TRIG_DPI ++// Description : Pulses the reset output ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_ACCESS "SC" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER ++// Description : Pulses the reset output ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_ACCESS "SC" ++// ================================================================================ ++// Register : RPI_MIPICFG_RSTSEQ_DONE ++// JTAG access : synchronous ++// Description : None ++#define RPI_MIPICFG_RSTSEQ_DONE_OFFSET 0x00000050 ++#define RPI_MIPICFG_RSTSEQ_DONE_BITS 0x00000007 ++#define RPI_MIPICFG_RSTSEQ_DONE_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_DONE_CSI ++// Description : Indicates the current state of the reset ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_BITS 0x00000004 ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_MSB 2 ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_LSB 2 ++#define RPI_MIPICFG_RSTSEQ_DONE_CSI_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_DONE_DPI ++// Description : Indicates the current state of the reset ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_BITS 0x00000002 ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_MSB 1 ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_LSB 1 ++#define RPI_MIPICFG_RSTSEQ_DONE_DPI_ACCESS "RO" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER ++// Description : Indicates the current state of the reset ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_RESET 0x0 ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_BITS 0x00000001 ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_MSB 0 ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_LSB 0 ++#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_ACCESS "RO" ++// ================================================================================ ++// Register : RPI_MIPICFG_DFTSS ++// JTAG access : asynchronous ++// Description : None ++#define RPI_MIPICFG_DFTSS_OFFSET 0x00000054 ++#define RPI_MIPICFG_DFTSS_BITS 0x0000001f ++#define RPI_MIPICFG_DFTSS_RESET 0x00000000 ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_JTAG_COPY ++// Description : None ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_BITS 0x00000010 ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_MSB 4 ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_LSB 4 ++#define RPI_MIPICFG_DFTSS_JTAG_COPY_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY ++// Description : None ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_BITS 0x00000008 ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_MSB 3 ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_LSB 3 ++#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS ++// Description : None ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_BITS 0x00000004 ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_MSB 2 ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_LSB 2 ++#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_BYPASS_INSYNCS ++// Description : None ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_BITS 0x00000002 ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_MSB 1 ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_LSB 1 ++#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_ACCESS "RW" ++// -------------------------------------------------------------------------------- ++// Field : RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS ++// Description : None ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_RESET 0x0 ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_BITS 0x00000001 ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_MSB 0 ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_LSB 0 ++#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_ACCESS "RW" ++ ++#define CFG_WRITE(reg, val) writel((val), dsi->hw_base[RP1DSI_HW_BLOCK_CFG] + (reg ## _OFFSET)) ++#define CFG_READ(reg) readl(dsi->hw_base[RP1DSI_HW_BLOCK_CFG] + (reg ## _OFFSET)) ++ ++/* ------------------------------- DPHY setup stuff ------------------------ */ ++ ++static void dphy_transaction(struct rp1_dsi *dsi, uint8_t test_code, uint8_t test_data) ++{ ++ /* ++ * See pg 101 of mipi dphy bidir databook ++ * Assume we start with testclk high. ++ * Each APB write takes at least 10ns and we ignore TESTDOUT ++ * so there is no need for extra delays between the transitions. ++ */ ++ u32 tmp; ++ ++ DSI_WRITE(DSI_PHY_TST_CTRL1, test_code | DPHY_CTRL1_PHY_TESTEN_BITS); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, 0); ++ tmp = (DSI_READ(DSI_PHY_TST_CTRL1) >> DPHY_CTRL1_PHY_TESTDOUT_LSB) & 0xFF; ++ DSI_WRITE(DSI_PHY_TST_CTRL1, test_data); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); ++} ++ ++static uint8_t dphy_get_div(u32 refclk_khz, u32 vco_freq_khz, u32 *ptr_m, u32 *ptr_n) ++{ ++ /* ++ * See pg 77-78 of dphy databook ++ * fvco = m/n * refclk ++ * with the limit ++ * 40MHz >= fREFCLK / N >= 5MHz ++ * M (multiplier) must be an even number between 2 and 300 ++ * N (input divider) must be an integer between 1 and 100 ++ * ++ * In practice, given a 50MHz reference clock, it can produce any ++ * multiple of 10MHz, 11.1111MHz, 12.5MHz, 14.286MHz or 16.667MHz ++ * with < 1% error for all frequencies above 495MHz. ++ */ ++ ++ static const u32 REF_DIVN_MAX = 40000u; ++ static const u32 REF_DIVN_MIN = 5000u; ++ u32 best_n, best_m, best_err = 0x7fffffff; ++ unsigned int n; ++ ++ for (n = 1 + refclk_khz / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk_khz && n < 100; ++n) { ++ u32 half_m = (n * vco_freq_khz + refclk_khz) / (2 * refclk_khz); ++ ++ if (half_m < 150) { ++ u32 f = (2 * half_m * refclk_khz) / n; ++ u32 err = (f > vco_freq_khz) ? f - vco_freq_khz : vco_freq_khz - f; ++ ++ if (err < best_err) { ++ best_n = n; ++ best_m = 2 * half_m; ++ best_err = err; ++ if (err == 0) ++ break; ++ } ++ } ++ } ++ ++ if (64 * best_err < vco_freq_khz) { /* tolerate small error */ ++ *ptr_n = best_n; ++ *ptr_m = best_m; ++ return 1; ++ } ++ return 0; ++} ++ ++struct hsfreq_range { ++ u16 mhz_max; ++ u8 hsfreqrange; ++ u8 clk_lp2hs; ++ u8 clk_hs2lp; ++ u8 data_lp2hs; /* excluding clk lane entry */ ++ u8 data_hs2lp; ++}; ++ ++/* See Table A-3 on page 258 of dphy databook */ ++static const struct hsfreq_range hsfreq_table[] = { ++ { 89, 0b000000, 32, 20, 26, 13 }, ++ { 99, 0b010000, 35, 23, 28, 14 }, ++ { 109, 0b100000, 32, 22, 26, 13 }, ++ { 129, 0b000001, 31, 20, 27, 13 }, ++ { 139, 0b010001, 33, 22, 26, 14 }, ++ { 149, 0b100001, 33, 21, 26, 14 }, ++ { 169, 0b000010, 32, 20, 27, 13 }, ++ { 179, 0b010010, 36, 23, 30, 15 }, ++ { 199, 0b100010, 40, 22, 33, 15 }, ++ { 219, 0b000011, 40, 22, 33, 15 }, ++ { 239, 0b010011, 44, 24, 36, 16 }, ++ { 249, 0b100011, 48, 24, 38, 17 }, ++ { 269, 0b000100, 48, 24, 38, 17 }, ++ { 299, 0b010100, 50, 27, 41, 18 }, ++ { 329, 0b000101, 56, 28, 45, 18 }, ++ { 359, 0b010101, 59, 28, 48, 19 }, ++ { 399, 0b100101, 61, 30, 50, 20 }, ++ { 449, 0b000110, 67, 31, 55, 21 }, ++ { 499, 0b010110, 73, 31, 59, 22 }, ++ { 549, 0b000111, 79, 36, 63, 24 }, ++ { 599, 0b010111, 83, 37, 68, 25 }, ++ { 649, 0b001000, 90, 38, 73, 27 }, ++ { 699, 0b011000, 95, 40, 77, 28 }, ++ { 749, 0b001001, 102, 40, 84, 28 }, ++ { 799, 0b011001, 106, 42, 87, 30 }, ++ { 849, 0b101001, 113, 44, 93, 31 }, ++ { 899, 0b111001, 118, 47, 98, 32 }, ++ { 949, 0b001010, 124, 47, 102, 34 }, ++ { 999, 0b011010, 130, 49, 107, 35 }, ++ { 1049, 0b101010, 135, 51, 111, 37 }, ++ { 1099, 0b111010, 139, 51, 114, 38 }, ++ { 1149, 0b001011, 146, 54, 120, 40 }, ++ { 1199, 0b011011, 153, 57, 125, 41 }, ++ { 1249, 0b101011, 158, 58, 130, 42 }, ++ { 1299, 0b111011, 163, 58, 135, 44 }, ++ { 1349, 0b001100, 168, 60, 140, 45 }, ++ { 1399, 0b011100, 172, 64, 144, 47 }, ++ { 1449, 0b101100, 176, 65, 148, 48 }, ++ { 1500, 0b111100, 181, 66, 153, 50 }, ++}; ++ ++static void dphy_set_hsfreqrange(struct rp1_dsi *dsi, u32 freq_mhz) ++{ ++ unsigned int i; ++ ++ if (freq_mhz < 80 || freq_mhz > 1500) ++ drm_err(dsi->drm, "DPHY: Frequency %u MHz out of range\n", ++ freq_mhz); ++ ++ for (i = 0; i < ARRAY_SIZE(hsfreq_table) - 1; i++) { ++ if (freq_mhz <= hsfreq_table[i].mhz_max) ++ break; ++ } ++ ++ dsi->hsfreq_index = i; ++ dphy_transaction(dsi, DPHY_HS_RX_CTRL_LANE0_OFFSET, ++ hsfreq_table[i].hsfreqrange << 1); ++} ++ ++static void dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk_khz, u32 vco_freq_khz) ++{ ++ u32 m = 0; ++ u32 n = 0; ++ ++ if (dphy_get_div(refclk_khz, vco_freq_khz, &m, &n)) { ++ dphy_set_hsfreqrange(dsi, vco_freq_khz / 1000); ++ /* Program m,n from registers */ ++ dphy_transaction(dsi, DPHY_PLL_DIV_CTRL_OFFSET, 0x30); ++ /* N (program N-1) */ ++ dphy_transaction(dsi, DPHY_PLL_INPUT_DIV_OFFSET, n - 1); ++ /* M[8:5] ?? */ ++ dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, 0x80 | ((m - 1) >> 5)); ++ /* M[4:0] (program M-1) */ ++ dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, ((m - 1) & 0x1F)); ++ drm_dbg_driver(dsi->drm, ++ "DPHY: vco freq want %dkHz got %dkHz = %d * (%dkHz / %d), hsfreqrange = 0x%02x\r\n", ++ vco_freq_khz, refclk_khz * m / n, m, refclk_khz, ++ n, hsfreq_table[dsi->hsfreq_index].hsfreqrange); ++ } else { ++ drm_info(dsi->drm, ++ "rp1dsi: Error configuring DPHY PLL! %dkHz = %d * (%dkHz / %d)\r\n", ++ vco_freq_khz, m, refclk_khz, n); ++ } ++} ++ ++static void dphy_init_khz(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq) ++{ ++ /* Reset the PHY */ ++ DSI_WRITE(DSI_PHYRSTZ, 0); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); ++ DSI_WRITE(DSI_PHY_TST_CTRL1, 0); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, (DPHY_CTRL0_PHY_TESTCLK_BITS | DPHY_CTRL0_PHY_TESTCLR_BITS)); ++ udelay(1); ++ DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); ++ udelay(1); ++ /* Since we are in DSI (not CSI2) mode here, start the PLL */ ++ dphy_configure_pll(dsi, ref_freq, vco_freq); ++ udelay(1); ++ /* Unreset */ ++ DSI_WRITE(DSI_PHYRSTZ, DSI_PHYRSTZ_SHUTDOWNZ_BITS); ++ udelay(1); ++ DSI_WRITE(DSI_PHYRSTZ, (DSI_PHYRSTZ_SHUTDOWNZ_BITS | DSI_PHYRSTZ_RSTZ_BITS)); ++ udelay(1); /* so we can see PLL coming up? */ ++} ++ ++void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi) ++{ ++ /* Select DSI rather than CSI-2 */ ++ CFG_WRITE(RPI_MIPICFG_CFG, 0); ++ /* Enable DSIDMA interrupt only */ ++ CFG_WRITE(RPI_MIPICFG_INTE, RPI_MIPICFG_INTE_DSI_DMA_BITS); ++} ++ ++static unsigned long rp1dsi_refclk_freq(struct rp1_dsi *dsi) ++{ ++ unsigned long u; ++ ++ u = (dsi->clocks[RP1DSI_CLOCK_REF]) ? clk_get_rate(dsi->clocks[RP1DSI_CLOCK_REF]) : 0; ++ if (u < 1 || u >= (1ul << 30)) ++ u = 50000000ul; /* default XOSC frequency */ ++ return u; ++} ++ ++static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, unsigned int bpp, unsigned int lanes) ++{ ++ unsigned long u; ++ ++ if (dsi->clocks[RP1DSI_CLOCK_DPI]) { ++ u = (dsi->clocks[RP1DSI_CLOCK_BYTE]) ? ++ clk_get_rate(dsi->clocks[RP1DSI_CLOCK_BYTE]) : 0; ++ drm_info(dsi->drm, ++ "rp1dsi: Nominal byte clock %lu; scale by %u/%u", ++ u, 4 * lanes, (bpp >> 1)); ++ if (u < 1 || u >= (1ul << 28)) ++ u = 72000000ul; /* default DUMMY frequency for byteclock */ ++ ++ clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_BYTE]); ++ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * u) / (bpp >> 1)); ++ clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]); ++ } ++} ++ ++static void rp1dsi_dpiclk_stop(struct rp1_dsi *dsi) ++{ ++ if (dsi->clocks[RP1DSI_CLOCK_DPI]) ++ clk_disable_unprepare(dsi->clocks[RP1DSI_CLOCK_DPI]); ++} ++ ++/* Choose the internal on-the-bus DPI format, and DSI packing flag. */ ++static u32 get_colorcode(enum mipi_dsi_pixel_format fmt) ++{ ++ switch (fmt) { ++ case MIPI_DSI_FMT_RGB666: ++ return 0x104; ++ case MIPI_DSI_FMT_RGB666_PACKED: ++ return 0x003; ++ case MIPI_DSI_FMT_RGB565: ++ return 0x000; ++ case MIPI_DSI_FMT_RGB888: ++ return 0x005; ++ } ++ ++ /* This should be impossible as the format is validated in ++ * rp1dsi_host_attach ++ */ ++ WARN_ONCE(1, "Invalid colour format configured for DSI"); ++ return 0x005; ++} ++ ++void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode) ++{ ++ u32 timeout, mask, vid_mode_cfg; ++ u32 freq_khz; ++ unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format); ++ ++ DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1); ++ DSI_WRITE(DSI_DPI_CFG_POL, 0); ++ DSI_WRITE(DSI_GEN_VCID, dsi->vc); ++ DSI_WRITE(DSI_DPI_COLOR_CODING, get_colorcode(dsi->display_format)); ++ /* a conservative guess (LP escape is slow!) */ ++ DSI_WRITE(DSI_DPI_LP_CMD_TIM, 0x00100000); ++ ++ /* Drop to LP where possible */ ++ vid_mode_cfg = 0xbf00; ++ if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) ++ vid_mode_cfg |= 0x01; ++ if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST) ++ vid_mode_cfg |= 0x02; ++ DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg); ++ ++ /* Use LP Escape Data signalling for all commands */ ++ DSI_WRITE(DSI_CMD_MODE_CFG, 0x10F7F00); ++ /* Select Command Mode */ ++ DSI_WRITE(DSI_MODE_CFG, 1); ++ /* XXX magic number */ ++ DSI_WRITE(DSI_TO_CNT_CFG, 0x02000200); ++ /* XXX magic number */ ++ DSI_WRITE(DSI_BTA_TO_CNT, 0x800); ++ ++ DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay); ++ DSI_WRITE(DSI_VID_NUM_CHUNKS, 0); ++ DSI_WRITE(DSI_VID_NULL_SIZE, 0); ++ ++ /* Note, unlike Argon firmware, here we DON'T consider sync to be concurrent with porch */ ++ DSI_WRITE(DSI_VID_HSA_TIME, ++ (bpp * (mode->hsync_end - mode->hsync_start)) / (8 * dsi->lanes)); ++ DSI_WRITE(DSI_VID_HBP_TIME, ++ (bpp * (mode->htotal - mode->hsync_end)) / (8 * dsi->lanes)); ++ DSI_WRITE(DSI_VID_HLINE_TIME, (bpp * mode->htotal) / (8 * dsi->lanes)); ++ DSI_WRITE(DSI_VID_VSA_LINES, (mode->vsync_end - mode->vsync_start)); ++ DSI_WRITE(DSI_VID_VBP_LINES, (mode->vtotal - mode->vsync_end)); ++ DSI_WRITE(DSI_VID_VFP_LINES, (mode->vsync_start - mode->vdisplay)); ++ DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay); ++ ++ freq_khz = (bpp * mode->clock) / dsi->lanes; ++ ++ dphy_init_khz(dsi, rp1dsi_refclk_freq(dsi) / 1000, freq_khz); ++ ++ DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG, ++ (hsfreq_table[dsi->hsfreq_index].clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | ++ (hsfreq_table[dsi->hsfreq_index].clk_hs2lp << DSI_PHY_TMR_HS2LP_LSB)); ++ DSI_WRITE(DSI_PHY_TMR_CFG, ++ (hsfreq_table[dsi->hsfreq_index].data_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | ++ (hsfreq_table[dsi->hsfreq_index].data_hs2lp << DSI_PHY_TMR_HS2LP_LSB)); ++ ++ DSI_WRITE(DSI_CLKMGR_CFG, 0x00000505); ++ ++ /* Wait for PLL lock */ ++ for (timeout = (1 << 14); timeout != 0; --timeout) { ++ usleep_range(10, 50); ++ if (DSI_READ(DSI_PHY_STATUS) & (1 << 0)) ++ break; ++ } ++ if (timeout == 0) ++ drm_err(dsi->drm, "RP1DSI: Time out waiting for PLL\n"); ++ ++ DSI_WRITE(DSI_LPCLK_CTRL, 0x1); /* configure the requesthsclk */ ++ DSI_WRITE(DSI_PHY_TST_CTRL0, 0x2); ++ DSI_WRITE(DSI_PCKHDL_CFG, 1 << 2); /* allow bus turnaround */ ++ DSI_WRITE(DSI_PWR_UP, 0x1); /* power up */ ++ ++ /* Now it should be safe to start the external DPI clock divider */ ++ rp1dsi_dpiclk_start(dsi, bpp, dsi->lanes); ++ ++ /* Wait for all lane(s) to be in Stopstate */ ++ mask = (1 << 4); ++ if (dsi->lanes >= 2) ++ mask |= (1 << 7); ++ if (dsi->lanes >= 3) ++ mask |= (1 << 9); ++ if (dsi->lanes >= 4) ++ mask |= (1 << 11); ++ for (timeout = (1 << 10); timeout != 0; --timeout) { ++ usleep_range(10, 50); ++ if ((DSI_READ(DSI_PHY_STATUS) & mask) == mask) ++ break; ++ } ++ if (timeout == 0) ++ drm_err(dsi->drm, "RP1DSI: Time out waiting for lanes (%x %x)\n", ++ mask, DSI_READ(DSI_PHY_STATUS)); ++} ++ ++void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 hdr, int len, const u8 *buf) ++{ ++ u32 val; ++ ++ /* Wait for both FIFOs empty */ ++ for (val = 256; val > 0; --val) { ++ if ((DSI_READ(DSI_CMD_PKT_STATUS) & 0xF) == 0x5) ++ break; ++ usleep_range(100, 150); ++ } ++ ++ /* Write payload (in 32-bit words) and header */ ++ for (; len > 0; len -= 4) { ++ val = *buf++; ++ if (len > 1) ++ val |= (*buf++) << 8; ++ if (len > 2) ++ val |= (*buf++) << 16; ++ if (len > 3) ++ val |= (*buf++) << 24; ++ DSI_WRITE(DSI_GEN_PLD_DATA, val); ++ } ++ DSI_WRITE(DSI_GEN_HDR, hdr); ++ ++ /* Wait for both FIFOs empty */ ++ for (val = 256; val > 0; --val) { ++ if ((DSI_READ(DSI_CMD_PKT_STATUS) & 0xF) == 0x5) ++ break; ++ usleep_range(100, 150); ++ } ++} ++ ++int rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf) ++{ ++ int i, j; ++ u32 val; ++ ++ /* Wait until not busy and FIFO not empty */ ++ for (i = 1024; i > 0; --i) { ++ val = DSI_READ(DSI_CMD_PKT_STATUS); ++ if ((val & ((1 << 6) | (1 << 4))) == 0) ++ break; ++ usleep_range(100, 150); ++ } ++ if (i == 0) ++ return -EIO; ++ ++ for (i = 0; i < len; i += 4) { ++ /* Read fifo must not be empty before all bytes are read */ ++ if (DSI_READ(DSI_CMD_PKT_STATUS) & (1 << 4)) ++ break; ++ ++ val = DSI_READ(DSI_GEN_PLD_DATA); ++ for (j = 0; j < 4 && j + i < len; j++) ++ *buf++ = val >> (8 * j); ++ } ++ ++ return (i >= len) ? len : (i > 0) ? i : -EIO; ++} ++ ++void rp1dsi_dsi_stop(struct rp1_dsi *dsi) ++{ ++ DSI_WRITE(DSI_MODE_CFG, 1); /* Return to Command Mode */ ++ DSI_WRITE(DSI_LPCLK_CTRL, 2); /* Stop the HS clock */ ++ DSI_WRITE(DSI_PWR_UP, 0x0); /* Power down host controller */ ++ DSI_WRITE(DSI_PHYRSTZ, 0); /* PHY into reset. */ ++ rp1dsi_dpiclk_stop(dsi); ++} ++ ++void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int mode) ++{ ++ DSI_WRITE(DSI_MODE_CFG, mode); ++} diff --git a/target/linux/bcm27xx/patches-6.1/950-0886-drm-Add-RP1-DPI-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0886-drm-Add-RP1-DPI-driver.patch new file mode 100644 index 0000000000..2023bf73e8 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0886-drm-Add-RP1-DPI-driver.patch @@ -0,0 +1,1552 @@ +From 61c3065f89d4447c7e4cf61a466ebc3c4a834ad2 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Tue, 19 Sep 2023 17:51:49 +0100 +Subject: [PATCH] drm: Add RP1 DPI driver + +Add support for the RP1 DPI hardware. + +Signed-off-by: Nick Hollinghurst +--- + drivers/gpu/drm/rp1/rp1-dpi/Kconfig | 12 + + drivers/gpu/drm/rp1/rp1-dpi/Makefile | 5 + + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c | 429 ++++++++++++++++++ + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h | 69 +++ + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_cfg.c | 510 ++++++++++++++++++++++ + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 486 +++++++++++++++++++++ + 6 files changed, 1511 insertions(+) + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/Kconfig + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/Makefile + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_cfg.c + create mode 100644 drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c + +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/Kconfig +@@ -0,0 +1,12 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config DRM_RP1_DPI ++ tristate "DRM Support for RP1 DPI" ++ depends on DRM ++ select MFD_RP1 ++ select DRM_GEM_DMA_HELPER ++ select DRM_KMS_HELPER ++ select DRM_VRAM_HELPER ++ select DRM_TTM ++ select DRM_TTM_HELPER ++ help ++ Choose this option to enable Video Out on RP1 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++drm-rp1-dpi-y := rp1_dpi.o rp1_dpi_hw.o rp1_dpi_cfg.o ++ ++obj-$(CONFIG_DRM_RP1_DPI) += drm-rp1-dpi.o +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c +@@ -0,0 +1,429 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DPI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rp1_dpi.h" ++ ++/* ++ * Default bus format, where not specified by a connector/bridge ++ * and not overridden by the OF property "default_bus_fmt". ++ * This value is for compatibility with vc4 and VGA666-style boards, ++ * even though RP1 hardware cannot achieve the full 18-bit depth ++ * with that pinout (MEDIA_BUS_FMT_RGB666_1X24_CPADHI is preferred). ++ */ ++static unsigned int default_bus_fmt = MEDIA_BUS_FMT_RGB666_1X18; ++module_param(default_bus_fmt, uint, 0644); ++ ++/* -------------------------------------------------------------- */ ++ ++static void rp1dpi_pipe_update(struct drm_simple_display_pipe *pipe, ++ struct drm_plane_state *old_state) ++{ ++ struct drm_pending_vblank_event *event; ++ unsigned long flags; ++ struct drm_framebuffer *fb = pipe->plane.state->fb; ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ struct drm_gem_object *gem = fb ? drm_gem_fb_get_obj(fb, 0) : NULL; ++ struct drm_gem_dma_object *dma_obj = gem ? to_drm_gem_dma_obj(gem) : NULL; ++ bool can_update = fb && dma_obj && dpi && dpi->pipe_enabled; ++ ++ /* (Re-)start DPI-DMA where required; and update FB address */ ++ if (can_update) { ++ if (!dpi->dpi_running || fb->format->format != dpi->cur_fmt) { ++ if (dpi->dpi_running && ++ fb->format->format != dpi->cur_fmt) { ++ rp1dpi_hw_stop(dpi); ++ dpi->dpi_running = false; ++ } ++ if (!dpi->dpi_running) { ++ rp1dpi_hw_setup(dpi, ++ fb->format->format, ++ dpi->bus_fmt, ++ dpi->de_inv, ++ &pipe->crtc.state->mode); ++ dpi->dpi_running = true; ++ } ++ dpi->cur_fmt = fb->format->format; ++ drm_crtc_vblank_on(&pipe->crtc); ++ } ++ rp1dpi_hw_update(dpi, dma_obj->dma_addr, fb->offsets[0], fb->pitches[0]); ++ } ++ ++ /* Arm VBLANK event (or call it immediately in some error cases) */ ++ spin_lock_irqsave(&pipe->crtc.dev->event_lock, flags); ++ event = pipe->crtc.state->event; ++ if (event) { ++ pipe->crtc.state->event = NULL; ++ if (can_update && drm_crtc_vblank_get(&pipe->crtc) == 0) ++ drm_crtc_arm_vblank_event(&pipe->crtc, event); ++ else ++ drm_crtc_send_vblank_event(&pipe->crtc, event); ++ } ++ spin_unlock_irqrestore(&pipe->crtc.dev->event_lock, flags); ++} ++ ++static void rp1dpi_pipe_enable(struct drm_simple_display_pipe *pipe, ++ struct drm_crtc_state *crtc_state, ++ struct drm_plane_state *plane_state) ++{ ++ static const unsigned int M = 1000000; ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ struct drm_connector *conn; ++ struct drm_connector_list_iter conn_iter; ++ unsigned int fpix, fdiv, fvco; ++ int ret; ++ ++ /* Look up the connector attached to DPI so we can get the ++ * bus_format. Ideally the bridge would tell us the ++ * bus_format we want, but it doesn't yet, so assume that it's ++ * uniform throughout the bridge chain. ++ */ ++ dev_info(&dpi->pdev->dev, __func__); ++ drm_connector_list_iter_begin(pipe->encoder.dev, &conn_iter); ++ drm_for_each_connector_iter(conn, &conn_iter) { ++ if (conn->encoder == &pipe->encoder) { ++ dpi->de_inv = !!(conn->display_info.bus_flags & ++ DRM_BUS_FLAG_DE_LOW); ++ dpi->clk_inv = !!(conn->display_info.bus_flags & ++ DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE); ++ if (conn->display_info.num_bus_formats) ++ dpi->bus_fmt = conn->display_info.bus_formats[0]; ++ break; ++ } ++ } ++ drm_connector_list_iter_end(&conn_iter); ++ ++ /* Set DPI clock to desired frequency. Currently (experimentally) ++ * we take control of the VideoPLL, to ensure we can generate it ++ * accurately. NB: this prevents concurrent use of DPI and VEC! ++ * Magic numbers ensure the parent clock is within [100MHz, 200MHz] ++ * with VCO in [1GHz, 1.33GHz]. The initial divide is by 6, 8 or 10. ++ */ ++ fpix = 1000 * pipe->crtc.state->mode.clock; ++ fpix = clamp(fpix, 1 * M, 200 * M); ++ fdiv = fpix; ++ while (fdiv < 100 * M) ++ fdiv *= 2; ++ fvco = fdiv * 2 * DIV_ROUND_UP(500 * M, fdiv); ++ ret = clk_set_rate(dpi->clocks[RP1DPI_CLK_PLLCORE], fvco); ++ if (ret) ++ dev_err(&dpi->pdev->dev, "Failed to set PLL VCO to %u (%d)", fvco, ret); ++ ret = clk_set_rate(dpi->clocks[RP1DPI_CLK_PLLDIV], fdiv); ++ if (ret) ++ dev_err(&dpi->pdev->dev, "Failed to set PLL output to %u (%d)", fdiv, ret); ++ ret = clk_set_rate(dpi->clocks[RP1DPI_CLK_DPI], fpix); ++ if (ret) ++ dev_err(&dpi->pdev->dev, "Failed to set DPI clock to %u (%d)", fpix, ret); ++ ++ rp1dpi_vidout_setup(dpi, dpi->clk_inv); ++ clk_prepare_enable(dpi->clocks[RP1DPI_CLK_PLLCORE]); ++ clk_prepare_enable(dpi->clocks[RP1DPI_CLK_PLLDIV]); ++ pinctrl_pm_select_default_state(&dpi->pdev->dev); ++ clk_prepare_enable(dpi->clocks[RP1DPI_CLK_DPI]); ++ dev_info(&dpi->pdev->dev, "Want %u /%u %u /%u %u; got VCO=%lu DIV=%lu DPI=%lu", ++ fvco, fvco / fdiv, fdiv, fdiv / fpix, fpix, ++ clk_get_rate(dpi->clocks[RP1DPI_CLK_PLLCORE]), ++ clk_get_rate(dpi->clocks[RP1DPI_CLK_PLLDIV]), ++ clk_get_rate(dpi->clocks[RP1DPI_CLK_DPI])); ++ ++ /* Start DPI-DMA. pipe already has the new crtc and plane state. */ ++ dpi->pipe_enabled = true; ++ dpi->cur_fmt = 0xdeadbeef; ++ rp1dpi_pipe_update(pipe, 0); ++} ++ ++static void rp1dpi_pipe_disable(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ ++ dev_info(&dpi->pdev->dev, __func__); ++ drm_crtc_vblank_off(&pipe->crtc); ++ if (dpi->dpi_running) { ++ rp1dpi_hw_stop(dpi); ++ dpi->dpi_running = false; ++ } ++ clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_DPI]); ++ pinctrl_pm_select_sleep_state(&dpi->pdev->dev); ++ clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_PLLDIV]); ++ clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_PLLCORE]); ++ dpi->pipe_enabled = false; ++} ++ ++static int rp1dpi_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ ++ if (dpi) ++ rp1dpi_hw_vblank_ctrl(dpi, 1); ++ ++ return 0; ++} ++ ++static void rp1dpi_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_dpi *dpi = pipe->crtc.dev->dev_private; ++ ++ if (dpi) ++ rp1dpi_hw_vblank_ctrl(dpi, 0); ++} ++ ++static const struct drm_simple_display_pipe_funcs rp1dpi_pipe_funcs = { ++ .enable = rp1dpi_pipe_enable, ++ .update = rp1dpi_pipe_update, ++ .disable = rp1dpi_pipe_disable, ++ .prepare_fb = drm_gem_simple_display_pipe_prepare_fb, ++ .enable_vblank = rp1dpi_pipe_enable_vblank, ++ .disable_vblank = rp1dpi_pipe_disable_vblank, ++}; ++ ++static const struct drm_mode_config_funcs rp1dpi_mode_funcs = { ++ .fb_create = drm_gem_fb_create, ++ .atomic_check = drm_atomic_helper_check, ++ .atomic_commit = drm_atomic_helper_commit, ++}; ++ ++static void rp1dpi_stopall(struct drm_device *drm) ++{ ++ if (drm->dev_private) { ++ struct rp1_dpi *dpi = drm->dev_private; ++ ++ if (dpi->dpi_running || rp1dpi_hw_busy(dpi)) { ++ rp1dpi_hw_stop(dpi); ++ clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_DPI]); ++ dpi->dpi_running = false; ++ } ++ rp1dpi_vidout_poweroff(dpi); ++ pinctrl_pm_select_sleep_state(&dpi->pdev->dev); ++ } ++} ++ ++DEFINE_DRM_GEM_DMA_FOPS(rp1dpi_fops); ++ ++static struct drm_driver rp1dpi_driver = { ++ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, ++ .fops = &rp1dpi_fops, ++ .name = "drm-rp1-dpi", ++ .desc = "drm-rp1-dpi", ++ .date = "0", ++ .major = 1, ++ .minor = 0, ++ DRM_GEM_DMA_DRIVER_OPS, ++ .release = rp1dpi_stopall, ++}; ++ ++static const u32 rp1dpi_formats[] = { ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_RGB888, ++ DRM_FORMAT_BGR888, ++ DRM_FORMAT_RGB565 ++}; ++ ++static int rp1dpi_platform_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct drm_device *drm; ++ struct rp1_dpi *dpi; ++ struct drm_bridge *bridge = NULL; ++ struct drm_panel *panel; ++ int i, ret; ++ ++ dev_info(dev, __func__); ++ ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 0, 0, ++ &panel, &bridge); ++ if (ret) { ++ dev_info(dev, "%s: bridge not found\n", __func__); ++ return -EPROBE_DEFER; ++ } ++ if (panel) { ++ bridge = devm_drm_panel_bridge_add(dev, panel); ++ if (IS_ERR(bridge)) ++ return PTR_ERR(bridge); ++ } ++ ++ drm = drm_dev_alloc(&rp1dpi_driver, dev); ++ if (IS_ERR(drm)) { ++ dev_info(dev, "%s %d", __func__, (int)__LINE__); ++ ret = PTR_ERR(drm); ++ return ret; ++ } ++ dpi = drmm_kzalloc(drm, sizeof(*dpi), GFP_KERNEL); ++ if (!dpi) { ++ dev_info(dev, "%s %d", __func__, (int)__LINE__); ++ drm_dev_put(drm); ++ return -ENOMEM; ++ } ++ ++ init_completion(&dpi->finished); ++ dpi->drm = drm; ++ dpi->pdev = pdev; ++ drm->dev_private = dpi; ++ platform_set_drvdata(pdev, drm); ++ ++ dpi->bus_fmt = default_bus_fmt; ++ ret = of_property_read_u32(dev->of_node, "default_bus_fmt", &dpi->bus_fmt); ++ ++ for (i = 0; i < RP1DPI_NUM_HW_BLOCKS; i++) { ++ dpi->hw_base[i] = ++ devm_ioremap_resource(dev, ++ platform_get_resource(dpi->pdev, IORESOURCE_MEM, i)); ++ if (IS_ERR(dpi->hw_base[i])) { ++ ret = PTR_ERR(dpi->hw_base[i]); ++ dev_err(dev, "Error memory mapping regs[%d]\n", i); ++ goto err_free_drm; ++ } ++ } ++ ret = platform_get_irq(dpi->pdev, 0); ++ if (ret > 0) ++ ret = devm_request_irq(dev, ret, rp1dpi_hw_isr, ++ IRQF_SHARED, "rp1-dpi", dpi); ++ if (ret) { ++ dev_err(dev, "Unable to request interrupt\n"); ++ ret = -EINVAL; ++ goto err_free_drm; ++ } ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ ++ for (i = 0; i < RP1DPI_NUM_CLOCKS; i++) { ++ static const char * const myclocknames[RP1DPI_NUM_CLOCKS] = { ++ "dpiclk", "plldiv", "pllcore" ++ }; ++ dpi->clocks[i] = devm_clk_get(dev, myclocknames[i]); ++ if (IS_ERR(dpi->clocks[i])) { ++ ret = PTR_ERR(dpi->clocks[i]); ++ goto err_free_drm; ++ } ++ } ++ ++ ret = drmm_mode_config_init(drm); ++ if (ret) ++ goto err_free_drm; ++ ++ drm->mode_config.max_width = 4096; ++ drm->mode_config.max_height = 4096; ++ drm->mode_config.fb_base = 0; ++ drm->mode_config.preferred_depth = 32; ++ drm->mode_config.prefer_shadow = 0; ++ drm->mode_config.prefer_shadow_fbdev = 1; ++ drm->mode_config.quirk_addfb_prefer_host_byte_order = true; ++ drm->mode_config.funcs = &rp1dpi_mode_funcs; ++ drm_vblank_init(drm, 1); ++ ++ ret = drm_simple_display_pipe_init(drm, ++ &dpi->pipe, ++ &rp1dpi_pipe_funcs, ++ rp1dpi_formats, ++ ARRAY_SIZE(rp1dpi_formats), ++ NULL, NULL); ++ if (!ret) ++ ret = drm_simple_display_pipe_attach_bridge(&dpi->pipe, bridge); ++ if (ret) ++ goto err_free_drm; ++ ++ drm_mode_config_reset(drm); ++ ++ ret = drm_dev_register(drm, 0); ++ if (ret) ++ goto err_free_drm; ++ ++ drm_fbdev_generic_setup(drm, 32); ++ ++ dev_info(dev, "%s success\n", __func__); ++ return ret; ++ ++err_free_drm: ++ dev_err(dev, "%s fail %d\n", __func__, ret); ++ drm_dev_put(drm); ++ return ret; ++} ++ ++static int rp1dpi_platform_remove(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1dpi_stopall(drm); ++ drm_dev_unregister(drm); ++ drm_atomic_helper_shutdown(drm); ++ drm_dev_put(drm); ++ ++ return 0; ++} ++ ++static void rp1dpi_platform_shutdown(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1dpi_stopall(drm); ++} ++ ++static const struct of_device_id rp1dpi_of_match[] = { ++ { ++ .compatible = "raspberrypi,rp1dpi", ++ }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rp1dpi_of_match); ++ ++static struct platform_driver rp1dpi_platform_driver = { ++ .probe = rp1dpi_platform_probe, ++ .remove = rp1dpi_platform_remove, ++ .shutdown = rp1dpi_platform_shutdown, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rp1dpi_of_match, ++ }, ++}; ++ ++module_platform_driver(rp1dpi_platform_driver); ++ ++MODULE_AUTHOR("Nick Hollinghurst"); ++MODULE_DESCRIPTION("DRM driver for DPI output on Raspberry Pi RP1"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h +@@ -0,0 +1,69 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define MODULE_NAME "drm-rp1-dpi" ++#define DRIVER_NAME "drm-rp1-dpi" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define RP1DPI_HW_BLOCK_DPI 0 ++#define RP1DPI_HW_BLOCK_CFG 1 ++#define RP1DPI_NUM_HW_BLOCKS 2 ++ ++#define RP1DPI_CLK_DPI 0 ++#define RP1DPI_CLK_PLLDIV 1 ++#define RP1DPI_CLK_PLLCORE 2 ++#define RP1DPI_NUM_CLOCKS 3 ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct rp1_dpi { ++ /* DRM and platform device pointers */ ++ struct drm_device *drm; ++ struct platform_device *pdev; ++ ++ /* Framework and helper objects */ ++ struct drm_simple_display_pipe pipe; ++ struct drm_connector connector; ++ ++ /* Clocks: Video PLL, its primary divider, and DPI clock. */ ++ struct clk *clocks[RP1DPI_NUM_CLOCKS]; ++ ++ /* Block (DPI, VOCFG) base addresses, and current state */ ++ void __iomem *hw_base[RP1DPI_NUM_HW_BLOCKS]; ++ u32 cur_fmt; ++ u32 bus_fmt; ++ bool de_inv, clk_inv; ++ bool dpi_running, pipe_enabled; ++ struct completion finished; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the DPI/DMA block */ ++ ++void rp1dpi_hw_setup(struct rp1_dpi *dpi, ++ u32 in_format, ++ u32 bus_format, ++ bool de_inv, ++ struct drm_display_mode const *mode); ++void rp1dpi_hw_update(struct rp1_dpi *dpi, dma_addr_t addr, u32 offset, u32 stride); ++void rp1dpi_hw_stop(struct rp1_dpi *dpi); ++int rp1dpi_hw_busy(struct rp1_dpi *dpi); ++irqreturn_t rp1dpi_hw_isr(int irq, void *dev); ++void rp1dpi_hw_vblank_ctrl(struct rp1_dpi *dpi, int enable); ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the VIDEO OUT CFG block and check RP1 platform */ ++ ++void rp1dpi_vidout_setup(struct rp1_dpi *dpi, bool drive_negedge); ++void rp1dpi_vidout_poweroff(struct rp1_dpi *dpi); +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_cfg.c +@@ -0,0 +1,510 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DPI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rp1_dpi.h" ++ ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_SEL ++// JTAG access : synchronous ++// Description : Selects source: VEC or DPI ++#define VIDEO_OUT_CFG_SEL_OFFSET 0x00000000 ++#define VIDEO_OUT_CFG_SEL_BITS 0x00000013 ++#define VIDEO_OUT_CFG_SEL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_PCLK_INV ++// Description : Select dpi_pclk output port polarity inversion. ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_BITS 0x00000010 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_MSB 4 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_LSB 4 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_PAD_MUX ++// Description : VEC 1 DPI 0 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_BITS 0x00000002 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_MSB 1 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_LSB 1 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_VDAC_MUX ++// Description : VEC 1 DPI 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_BITS 0x00000001 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_MSB 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_LSB 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_VDAC_CFG ++// JTAG access : synchronous ++// Description : Configure SNPS VDAC ++#define VIDEO_OUT_CFG_VDAC_CFG_OFFSET 0x00000004 ++#define VIDEO_OUT_CFG_VDAC_CFG_BITS 0x1fffffff ++#define VIDEO_OUT_CFG_VDAC_CFG_RESET 0x0003ffff ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENCTR ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_BITS 0x1c000000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_MSB 28 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_LSB 26 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENSC ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_BITS 0x03800000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_MSB 25 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_LSB 23 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENDAC ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_BITS 0x00700000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_MSB 22 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_LSB 20 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENVBG ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_BITS 0x00080000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_MSB 19 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_LSB 19 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_BITS 0x00040000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_MSB 18 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_LSB 18 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC2GC ++// Description : dac2 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_BITS 0x0003f000 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_MSB 17 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_LSB 12 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC1GC ++// Description : dac1 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_BITS 0x00000fc0 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_MSB 11 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_LSB 6 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC0GC ++// Description : dac0 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_BITS 0x0000003f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_MSB 5 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_LSB 0 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_VDAC_STATUS ++// JTAG access : synchronous ++// Description : Read VDAC status ++#define VIDEO_OUT_CFG_VDAC_STATUS_OFFSET 0x00000008 ++#define VIDEO_OUT_CFG_VDAC_STATUS_BITS 0x00000017 ++#define VIDEO_OUT_CFG_VDAC_STATUS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3 ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_BITS 0x00000010 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_MSB 4 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_LSB 4 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_RESET "-" ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_BITS 0x00000007 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_MSB 2 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_LSB 0 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_MEM_PD ++// JTAG access : synchronous ++// Description : Control memory power down ++#define VIDEO_OUT_CFG_MEM_PD_OFFSET 0x0000000c ++#define VIDEO_OUT_CFG_MEM_PD_BITS 0x00000003 ++#define VIDEO_OUT_CFG_MEM_PD_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_MEM_PD_VEC ++// Description : None ++#define VIDEO_OUT_CFG_MEM_PD_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_BITS 0x00000002 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_MSB 1 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_LSB 1 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_MEM_PD_DPI ++// Description : None ++#define VIDEO_OUT_CFG_MEM_PD_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_BITS 0x00000001 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_MSB 0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_LSB 0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_TEST_OVERRIDE ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_OFFSET 0x00000010 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_BITS 0xffffffff ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_PAD ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_RESET 0x0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_BITS 0x80000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_MSB 31 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_LSB 31 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_RESET 0x0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_BITS 0x40000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_MSB 30 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_LSB 30 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_RESET 0x00000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_BITS 0x3fffffff ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_MSB 29 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_LSB 0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTR ++// JTAG access : synchronous ++// Description : Raw Interrupts ++#define VIDEO_OUT_CFG_INTR_OFFSET 0x00000014 ++#define VIDEO_OUT_CFG_INTR_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTR_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTR_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTR_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTR_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTR_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTR_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTR_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTR_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTR_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTR_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTR_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTR_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTR_VEC_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTE ++// JTAG access : synchronous ++// Description : Interrupt Enable ++#define VIDEO_OUT_CFG_INTE_OFFSET 0x00000018 ++#define VIDEO_OUT_CFG_INTE_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTE_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTE_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTE_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTE_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTE_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTE_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTE_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTE_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTE_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTE_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTE_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTE_VEC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTF ++// JTAG access : synchronous ++// Description : Interrupt Force ++#define VIDEO_OUT_CFG_INTF_OFFSET 0x0000001c ++#define VIDEO_OUT_CFG_INTF_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTF_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTF_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTF_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTF_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTF_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTF_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTF_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTF_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTF_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTF_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTF_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTF_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTF_VEC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTS ++// JTAG access : synchronous ++// Description : Interrupt status after masking & forcing ++#define VIDEO_OUT_CFG_INTS_OFFSET 0x00000020 ++#define VIDEO_OUT_CFG_INTS_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTS_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTS_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTS_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTS_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTS_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTS_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTS_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTS_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTS_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTS_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTS_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTS_VEC_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_BLOCK_ID ++// JTAG access : synchronous ++// Description : Block Identifier ++// Hexadecimal representation of "VOCF" ++#define VIDEO_OUT_CFG_BLOCK_ID_OFFSET 0x00000024 ++#define VIDEO_OUT_CFG_BLOCK_ID_BITS 0xffffffff ++#define VIDEO_OUT_CFG_BLOCK_ID_RESET 0x564f4346 ++#define VIDEO_OUT_CFG_BLOCK_ID_MSB 31 ++#define VIDEO_OUT_CFG_BLOCK_ID_LSB 0 ++#define VIDEO_OUT_CFG_BLOCK_ID_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INSTANCE_ID ++// JTAG access : synchronous ++// Description : Block Instance Identifier ++#define VIDEO_OUT_CFG_INSTANCE_ID_OFFSET 0x00000028 ++#define VIDEO_OUT_CFG_INSTANCE_ID_BITS 0x0000000f ++#define VIDEO_OUT_CFG_INSTANCE_ID_RESET 0x00000000 ++#define VIDEO_OUT_CFG_INSTANCE_ID_MSB 3 ++#define VIDEO_OUT_CFG_INSTANCE_ID_LSB 0 ++#define VIDEO_OUT_CFG_INSTANCE_ID_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_AUTO ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_OFFSET 0x0000002c ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_RESET 0x00000007 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_PARALLEL ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_OFFSET 0x00000030 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_RESET 0x00000006 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_CTRL ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_OFFSET 0x00000034 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_TRIG ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_OFFSET 0x00000038 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_ACCESS "SC" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_ACCESS "SC" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_ACCESS "SC" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_DONE ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_OFFSET 0x0000003c ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_VEC ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_DPI ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_ACCESS "RO" ++// ============================================================================= ++ ++#define CFG_WRITE(reg, val) writel((val), dpi->hw_base[RP1DPI_HW_BLOCK_CFG] + (reg ## _OFFSET)) ++#define CFG_READ(reg) readl(dpi->hw_base[RP1DPI_HW_BLOCK_CFG] + (reg ## _OFFSET)) ++ ++void rp1dpi_vidout_setup(struct rp1_dpi *dpi, bool drive_negedge) ++{ ++ /* ++ * We assume DPI and VEC can't be used at the same time (due to ++ * clashing requirements for PLL_VIDEO, and potentially for VDAC). ++ * We therefore leave VEC memories powered down. ++ */ ++ CFG_WRITE(VIDEO_OUT_CFG_MEM_PD, VIDEO_OUT_CFG_MEM_PD_VEC_BITS); ++ CFG_WRITE(VIDEO_OUT_CFG_TEST_OVERRIDE, ++ VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_BITS); ++ ++ /* DPI->Pads; DPI->VDAC; optionally flip PCLK polarity */ ++ CFG_WRITE(VIDEO_OUT_CFG_SEL, ++ drive_negedge ? VIDEO_OUT_CFG_SEL_PCLK_INV_BITS : 0); ++ ++ /* configure VDAC for 3 channels, bandgap on, 710mV swing */ ++ CFG_WRITE(VIDEO_OUT_CFG_VDAC_CFG, 0); ++ ++ /* enable DPI interrupt */ ++ CFG_WRITE(VIDEO_OUT_CFG_INTE, VIDEO_OUT_CFG_INTE_DPI_BITS); ++} ++ ++void rp1dpi_vidout_poweroff(struct rp1_dpi *dpi) ++{ ++ /* disable DPI interrupt */ ++ CFG_WRITE(VIDEO_OUT_CFG_INTE, 0); ++ ++ /* Ensure VDAC is turned off; power down DPI,VEC memories */ ++ CFG_WRITE(VIDEO_OUT_CFG_VDAC_CFG, 0); ++ CFG_WRITE(VIDEO_OUT_CFG_MEM_PD, VIDEO_OUT_CFG_MEM_PD_BITS); ++} +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DPI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rp1_dpi.h" ++ ++// --- DPI DMA REGISTERS --- ++ ++// Control ++#define DPI_DMA_CONTROL 0x0 ++#define DPI_DMA_CONTROL_ARM_SHIFT 0 ++#define DPI_DMA_CONTROL_ARM_MASK BIT(DPI_DMA_CONTROL_ARM_SHIFT) ++#define DPI_DMA_CONTROL_ALIGN16_SHIFT 2 ++#define DPI_DMA_CONTROL_ALIGN16_MASK BIT(DPI_DMA_CONTROL_ALIGN16_SHIFT) ++#define DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT 1 ++#define DPI_DMA_CONTROL_AUTO_REPEAT_MASK BIT(DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT) ++#define DPI_DMA_CONTROL_HIGH_WATER_SHIFT 3 ++#define DPI_DMA_CONTROL_HIGH_WATER_MASK (0x1FF << DPI_DMA_CONTROL_HIGH_WATER_SHIFT) ++#define DPI_DMA_CONTROL_DEN_POL_SHIFT 12 ++#define DPI_DMA_CONTROL_DEN_POL_MASK BIT(DPI_DMA_CONTROL_DEN_POL_SHIFT) ++#define DPI_DMA_CONTROL_HSYNC_POL_SHIFT 13 ++#define DPI_DMA_CONTROL_HSYNC_POL_MASK BIT(DPI_DMA_CONTROL_HSYNC_POL_SHIFT) ++#define DPI_DMA_CONTROL_VSYNC_POL_SHIFT 14 ++#define DPI_DMA_CONTROL_VSYNC_POL_MASK BIT(DPI_DMA_CONTROL_VSYNC_POL_SHIFT) ++#define DPI_DMA_CONTROL_COLORM_SHIFT 15 ++#define DPI_DMA_CONTROL_COLORM_MASK BIT(DPI_DMA_CONTROL_COLORM_SHIFT) ++#define DPI_DMA_CONTROL_SHUTDN_SHIFT 16 ++#define DPI_DMA_CONTROL_SHUTDN_MASK BIT(DPI_DMA_CONTROL_SHUTDN_SHIFT) ++#define DPI_DMA_CONTROL_HBP_EN_SHIFT 17 ++#define DPI_DMA_CONTROL_HBP_EN_MASK BIT(DPI_DMA_CONTROL_HBP_EN_SHIFT) ++#define DPI_DMA_CONTROL_HFP_EN_SHIFT 18 ++#define DPI_DMA_CONTROL_HFP_EN_MASK BIT(DPI_DMA_CONTROL_HFP_EN_SHIFT) ++#define DPI_DMA_CONTROL_VBP_EN_SHIFT 19 ++#define DPI_DMA_CONTROL_VBP_EN_MASK BIT(DPI_DMA_CONTROL_VBP_EN_SHIFT) ++#define DPI_DMA_CONTROL_VFP_EN_SHIFT 20 ++#define DPI_DMA_CONTROL_VFP_EN_MASK BIT(DPI_DMA_CONTROL_VFP_EN_SHIFT) ++#define DPI_DMA_CONTROL_HSYNC_EN_SHIFT 21 ++#define DPI_DMA_CONTROL_HSYNC_EN_MASK BIT(DPI_DMA_CONTROL_HSYNC_EN_SHIFT) ++#define DPI_DMA_CONTROL_VSYNC_EN_SHIFT 22 ++#define DPI_DMA_CONTROL_VSYNC_EN_MASK BIT(DPI_DMA_CONTROL_VSYNC_EN_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_IMMED_SHIFT 23 ++#define DPI_DMA_CONTROL_FORCE_IMMED_MASK BIT(DPI_DMA_CONTROL_FORCE_IMMED_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT 24 ++#define DPI_DMA_CONTROL_FORCE_DRAIN_MASK BIT(DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT) ++#define DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT 25 ++#define DPI_DMA_CONTROL_FORCE_EMPTY_MASK BIT(DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT) ++ ++// IRQ_ENABLES ++#define DPI_DMA_IRQ_EN 0x04 ++#define DPI_DMA_IRQ_EN_DMA_READY_SHIFT 0 ++#define DPI_DMA_IRQ_EN_DMA_READY_MASK BIT(DPI_DMA_IRQ_EN_DMA_READY_SHIFT) ++#define DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT 1 ++#define DPI_DMA_IRQ_EN_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT) ++#define DPI_DMA_IRQ_EN_FRAME_START_SHIFT 2 ++#define DPI_DMA_IRQ_EN_FRAME_START_MASK BIT(DPI_DMA_IRQ_EN_FRAME_START_SHIFT) ++#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT 3 ++#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT) ++#define DPI_DMA_IRQ_EN_TE_SHIFT 4 ++#define DPI_DMA_IRQ_EN_TE_MASK BIT(DPI_DMA_IRQ_EN_TE_SHIFT) ++#define DPI_DMA_IRQ_EN_ERROR_SHIFT 5 ++#define DPI_DMA_IRQ_EN_ERROR_MASK BIT(DPI_DMA_IRQ_EN_ERROR_SHIFT) ++#define DPI_DMA_IRQ_EN_MATCH_SHIFT 6 ++#define DPI_DMA_IRQ_EN_MATCH_MASK BIT(DPI_DMA_IRQ_EN_MATCH_SHIFT) ++#define DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT 16 ++#define DPI_DMA_IRQ_EN_MATCH_LINE_MASK (0xFFF << DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT) ++ ++// IRQ_FLAGS ++#define DPI_DMA_IRQ_FLAGS 0x08 ++#define DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT 0 ++#define DPI_DMA_IRQ_FLAGS_DMA_READY_MASK BIT(DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT 1 ++#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT 2 ++#define DPI_DMA_IRQ_FLAGS_FRAME_START_MASK BIT(DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT 3 ++#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_TE_SHIFT 4 ++#define DPI_DMA_IRQ_FLAGS_TE_MASK BIT(DPI_DMA_IRQ_FLAGS_TE_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_ERROR_SHIFT 5 ++#define DPI_DMA_IRQ_FLAGS_ERROR_MASK BIT(DPI_DMA_IRQ_FLAGS_ERROR_SHIFT) ++#define DPI_DMA_IRQ_FLAGS_MATCH_SHIFT 6 ++#define DPI_DMA_IRQ_FLAGS_MATCH_MASK BIT(DPI_DMA_IRQ_FLAGS_MATCH_SHIFT) ++ ++// QOS ++#define DPI_DMA_QOS 0xC ++#define DPI_DMA_QOS_DQOS_SHIFT 0 ++#define DPI_DMA_QOS_DQOS_MASK (0xF << DPI_DMA_QOS_DQOS_SHIFT) ++#define DPI_DMA_QOS_ULEV_SHIFT 4 ++#define DPI_DMA_QOS_ULEV_MASK (0xF << DPI_DMA_QOS_ULEV_SHIFT) ++#define DPI_DMA_QOS_UQOS_SHIFT 8 ++#define DPI_DMA_QOS_UQOS_MASK (0xF << DPI_DMA_QOS_UQOS_SHIFT) ++#define DPI_DMA_QOS_LLEV_SHIFT 12 ++#define DPI_DMA_QOS_LLEV_MASK (0xF << DPI_DMA_QOS_LLEV_SHIFT) ++#define DPI_DMA_QOS_LQOS_SHIFT 16 ++#define DPI_DMA_QOS_LQOS_MASK (0xF << DPI_DMA_QOS_LQOS_SHIFT) ++ ++// Panics ++#define DPI_DMA_PANICS 0x38 ++#define DPI_DMA_PANICS_UPPER_COUNT_SHIFT 0 ++#define DPI_DMA_PANICS_UPPER_COUNT_MASK \ ++ (0x0000FFFF << DPI_DMA_PANICS_UPPER_COUNT_SHIFT) ++#define DPI_DMA_PANICS_LOWER_COUNT_SHIFT 16 ++#define DPI_DMA_PANICS_LOWER_COUNT_MASK \ ++ (0x0000FFFF << DPI_DMA_PANICS_LOWER_COUNT_SHIFT) ++ ++// DMA Address Lower: ++#define DPI_DMA_DMA_ADDR_L 0x10 ++ ++// DMA Address Upper: ++#define DPI_DMA_DMA_ADDR_H 0x40 ++ ++// DMA stride ++#define DPI_DMA_DMA_STRIDE 0x14 ++ ++// Visible Area ++#define DPI_DMA_VISIBLE_AREA 0x18 ++#define DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT 0 ++#define DPI_DMA_VISIBLE_AREA_ROWSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT) ++#define DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT 16 ++#define DPI_DMA_VISIBLE_AREA_COLSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT) ++ ++// Sync width ++#define DPI_DMA_SYNC_WIDTH 0x1C ++#define DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT 0 ++#define DPI_DMA_SYNC_WIDTH_ROWSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT) ++#define DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT 16 ++#define DPI_DMA_SYNC_WIDTH_COLSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT) ++ ++// Back porch ++#define DPI_DMA_BACK_PORCH 0x20 ++#define DPI_DMA_BACK_PORCH_ROWSM1_SHIFT 0 ++#define DPI_DMA_BACK_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_ROWSM1_SHIFT) ++#define DPI_DMA_BACK_PORCH_COLSM1_SHIFT 16 ++#define DPI_DMA_BACK_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_COLSM1_SHIFT) ++ ++// Front porch ++#define DPI_DMA_FRONT_PORCH 0x24 ++#define DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT 0 ++#define DPI_DMA_FRONT_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT) ++#define DPI_DMA_FRONT_PORCH_COLSM1_SHIFT 16 ++#define DPI_DMA_FRONT_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_COLSM1_SHIFT) ++ ++// Input masks ++#define DPI_DMA_IMASK 0x2C ++#define DPI_DMA_IMASK_R_SHIFT 0 ++#define DPI_DMA_IMASK_R_MASK (0x3FF << DPI_DMA_IMASK_R_SHIFT) ++#define DPI_DMA_IMASK_G_SHIFT 10 ++#define DPI_DMA_IMASK_G_MASK (0x3FF << DPI_DMA_IMASK_G_SHIFT) ++#define DPI_DMA_IMASK_B_SHIFT 20 ++#define DPI_DMA_IMASK_B_MASK (0x3FF << DPI_DMA_IMASK_B_SHIFT) ++ ++// Output Masks ++#define DPI_DMA_OMASK 0x30 ++#define DPI_DMA_OMASK_R_SHIFT 0 ++#define DPI_DMA_OMASK_R_MASK (0x3FF << DPI_DMA_OMASK_R_SHIFT) ++#define DPI_DMA_OMASK_G_SHIFT 10 ++#define DPI_DMA_OMASK_G_MASK (0x3FF << DPI_DMA_OMASK_G_SHIFT) ++#define DPI_DMA_OMASK_B_SHIFT 20 ++#define DPI_DMA_OMASK_B_MASK (0x3FF << DPI_DMA_OMASK_B_SHIFT) ++ ++// Shifts ++#define DPI_DMA_SHIFT 0x28 ++#define DPI_DMA_SHIFT_IR_SHIFT 0 ++#define DPI_DMA_SHIFT_IR_MASK (0x1F << DPI_DMA_SHIFT_IR_SHIFT) ++#define DPI_DMA_SHIFT_IG_SHIFT 5 ++#define DPI_DMA_SHIFT_IG_MASK (0x1F << DPI_DMA_SHIFT_IG_SHIFT) ++#define DPI_DMA_SHIFT_IB_SHIFT 10 ++#define DPI_DMA_SHIFT_IB_MASK (0x1F << DPI_DMA_SHIFT_IB_SHIFT) ++#define DPI_DMA_SHIFT_OR_SHIFT 15 ++#define DPI_DMA_SHIFT_OR_MASK (0x1F << DPI_DMA_SHIFT_OR_SHIFT) ++#define DPI_DMA_SHIFT_OG_SHIFT 20 ++#define DPI_DMA_SHIFT_OG_MASK (0x1F << DPI_DMA_SHIFT_OG_SHIFT) ++#define DPI_DMA_SHIFT_OB_SHIFT 25 ++#define DPI_DMA_SHIFT_OB_MASK (0x1F << DPI_DMA_SHIFT_OB_SHIFT) ++ ++// Scaling ++#define DPI_DMA_RGBSZ 0x34 ++#define DPI_DMA_RGBSZ_BPP_SHIFT 16 ++#define DPI_DMA_RGBSZ_BPP_MASK (0x3 << DPI_DMA_RGBSZ_BPP_SHIFT) ++#define DPI_DMA_RGBSZ_R_SHIFT 0 ++#define DPI_DMA_RGBSZ_R_MASK (0xF << DPI_DMA_RGBSZ_R_SHIFT) ++#define DPI_DMA_RGBSZ_G_SHIFT 4 ++#define DPI_DMA_RGBSZ_G_MASK (0xF << DPI_DMA_RGBSZ_G_SHIFT) ++#define DPI_DMA_RGBSZ_B_SHIFT 8 ++#define DPI_DMA_RGBSZ_B_MASK (0xF << DPI_DMA_RGBSZ_B_SHIFT) ++ ++// Status ++#define DPI_DMA_STATUS 0x3c ++ ++#define BITS(field, val) (((val) << (field ## _SHIFT)) & (field ## _MASK)) ++ ++static unsigned int rp1dpi_hw_read(struct rp1_dpi *dpi, unsigned int reg) ++{ ++ void __iomem *addr = dpi->hw_base[RP1DPI_HW_BLOCK_DPI] + reg; ++ ++ return readl(addr); ++} ++ ++static void rp1dpi_hw_write(struct rp1_dpi *dpi, unsigned int reg, unsigned int val) ++{ ++ void __iomem *addr = dpi->hw_base[RP1DPI_HW_BLOCK_DPI] + reg; ++ ++ writel(val, addr); ++} ++ ++int rp1dpi_hw_busy(struct rp1_dpi *dpi) ++{ ++ return (rp1dpi_hw_read(dpi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0; ++} ++ ++/* Table of supported input (in-memory/DMA) pixel formats. */ ++struct rp1dpi_ipixfmt { ++ u32 format; /* DRM format code */ ++ u32 mask; /* RGB masks (10 bits each, left justified) */ ++ u32 shift; /* RGB MSB positions in the memory word */ ++ u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */ ++}; ++ ++#define IMASK_RGB(r, g, b) (BITS(DPI_DMA_IMASK_R, r) | \ ++ BITS(DPI_DMA_IMASK_G, g) | \ ++ BITS(DPI_DMA_IMASK_B, b)) ++#define OMASK_RGB(r, g, b) (BITS(DPI_DMA_OMASK_R, r) | \ ++ BITS(DPI_DMA_OMASK_G, g) | \ ++ BITS(DPI_DMA_OMASK_B, b)) ++#define ISHIFT_RGB(r, g, b) (BITS(DPI_DMA_SHIFT_IR, r) | \ ++ BITS(DPI_DMA_SHIFT_IG, g) | \ ++ BITS(DPI_DMA_SHIFT_IB, b)) ++#define OSHIFT_RGB(r, g, b) (BITS(DPI_DMA_SHIFT_OR, r) | \ ++ BITS(DPI_DMA_SHIFT_OG, g) | \ ++ BITS(DPI_DMA_SHIFT_OB, b)) ++ ++static const struct rp1dpi_ipixfmt my_formats[] = { ++ { ++ .format = DRM_FORMAT_XRGB8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_XBGR8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_RGB888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), ++ }, ++ { ++ .format = DRM_FORMAT_BGR888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), ++ }, ++ { ++ .format = DRM_FORMAT_RGB565, ++ .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0), ++ .shift = ISHIFT_RGB(15, 10, 4), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_R, 5) | BITS(DPI_DMA_RGBSZ_G, 6) | ++ BITS(DPI_DMA_RGBSZ_B, 5) | BITS(DPI_DMA_RGBSZ_BPP, 1), ++ }, ++ { ++ .format = DRM_FORMAT_BGR565, ++ .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0), ++ .shift = ISHIFT_RGB(4, 10, 15), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_R, 5) | BITS(DPI_DMA_RGBSZ_G, 6) | ++ BITS(DPI_DMA_RGBSZ_B, 5) | BITS(DPI_DMA_RGBSZ_BPP, 1), ++ } ++}; ++ ++static u32 set_output_format(u32 bus_format, u32 *shift, u32 *imask, u32 *rgbsz) ++{ ++ switch (bus_format) { ++ case MEDIA_BUS_FMT_RGB565_1X16: ++ if (*shift == ISHIFT_RGB(15, 10, 4)) { ++ /* When framebuffer is RGB565, we can output RGB565 */ ++ *shift = ISHIFT_RGB(15, 7, 0) | OSHIFT_RGB(19, 9, 0); ++ *rgbsz &= DPI_DMA_RGBSZ_BPP_MASK; ++ return OMASK_RGB(0x3fc, 0x3fc, 0); ++ } ++ ++ /* due to a HW limitation, bit-depth is effectively RGB535 */ ++ *shift |= OSHIFT_RGB(19, 14, 6); ++ *imask &= IMASK_RGB(0x3e0, 0x380, 0x3e0); ++ *rgbsz = BITS(DPI_DMA_RGBSZ_G, 5) | (*rgbsz & DPI_DMA_RGBSZ_BPP_MASK); ++ return OMASK_RGB(0x3e0, 0x39c, 0x3e0); ++ ++ case MEDIA_BUS_FMT_RGB666_1X18: ++ case MEDIA_BUS_FMT_BGR666_1X18: ++ /* due to a HW limitation, bit-depth is effectively RGB444 */ ++ *shift |= OSHIFT_RGB(23, 15, 7); ++ *imask &= IMASK_RGB(0x3c0, 0x3c0, 0x3c0); ++ *rgbsz = BITS(DPI_DMA_RGBSZ_R, 2) | (*rgbsz & DPI_DMA_RGBSZ_BPP_MASK); ++ return OMASK_RGB(0x330, 0x3c0, 0x3c0); ++ ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ case MEDIA_BUS_FMT_BGR888_1X24: ++ case MEDIA_BUS_FMT_RGB101010_1X30: ++ /* The full 24 bits can be output. Note that RP1's internal wiring means ++ * that 8.8.8 to GPIO pads can share with 10.10.10 to the onboard VDAC. ++ */ ++ *shift |= OSHIFT_RGB(29, 19, 9); ++ return OMASK_RGB(0x3fc, 0x3fc, 0x3fc); ++ ++ default: ++ /* RGB666_1x24_CPADHI, BGR666_1X24_CPADHI and "RGB565_666" formats */ ++ *shift |= OSHIFT_RGB(27, 17, 7); ++ *rgbsz &= DPI_DMA_RGBSZ_BPP_MASK; ++ return OMASK_RGB(0x3f0, 0x3f0, 0x3f0); ++ } ++} ++ ++#define BUS_FMT_IS_BGR(fmt) ( \ ++ ((fmt) == MEDIA_BUS_FMT_BGR666_1X18) || \ ++ ((fmt) == MEDIA_BUS_FMT_BGR666_1X24_CPADHI) || \ ++ ((fmt) == MEDIA_BUS_FMT_BGR888_1X24)) ++ ++void rp1dpi_hw_setup(struct rp1_dpi *dpi, ++ u32 in_format, u32 bus_format, bool de_inv, ++ struct drm_display_mode const *mode) ++{ ++ u32 shift, imask, omask, rgbsz; ++ int i; ++ ++ pr_info("%s: in_fmt=\'%c%c%c%c\' bus_fmt=0x%x mode=%dx%d total=%dx%d %dkHz %cH%cV%cD%cC", ++ __func__, in_format, in_format >> 8, in_format >> 16, in_format >> 24, bus_format, ++ mode->hdisplay, mode->vdisplay, ++ mode->htotal, mode->vtotal, ++ mode->clock, ++ (mode->flags & DRM_MODE_FLAG_NHSYNC) ? '-' : '+', ++ (mode->flags & DRM_MODE_FLAG_NVSYNC) ? '-' : '+', ++ de_inv ? '-' : '+', ++ dpi->clk_inv ? '-' : '+'); ++ ++ /* ++ * Configure all DPI/DMA block registers, except base address. ++ * DMA will not actually start until a FB base address is specified ++ * using rp1dpi_hw_update(). ++ */ ++ rp1dpi_hw_write(dpi, DPI_DMA_VISIBLE_AREA, ++ BITS(DPI_DMA_VISIBLE_AREA_ROWSM1, mode->vdisplay - 1) | ++ BITS(DPI_DMA_VISIBLE_AREA_COLSM1, mode->hdisplay - 1)); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_SYNC_WIDTH, ++ BITS(DPI_DMA_SYNC_WIDTH_ROWSM1, mode->vsync_end - mode->vsync_start - 1) | ++ BITS(DPI_DMA_SYNC_WIDTH_COLSM1, mode->hsync_end - mode->hsync_start - 1)); ++ ++ /* In these registers, "back porch" time includes sync width */ ++ rp1dpi_hw_write(dpi, DPI_DMA_BACK_PORCH, ++ BITS(DPI_DMA_BACK_PORCH_ROWSM1, mode->vtotal - mode->vsync_start - 1) | ++ BITS(DPI_DMA_BACK_PORCH_COLSM1, mode->htotal - mode->hsync_start - 1)); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_FRONT_PORCH, ++ BITS(DPI_DMA_FRONT_PORCH_ROWSM1, mode->vsync_start - mode->vdisplay - 1) | ++ BITS(DPI_DMA_FRONT_PORCH_COLSM1, mode->hsync_start - mode->hdisplay - 1)); ++ ++ /* Input to output pixel format conversion */ ++ for (i = 0; i < ARRAY_SIZE(my_formats); ++i) { ++ if (my_formats[i].format == in_format) ++ break; ++ } ++ if (i >= ARRAY_SIZE(my_formats)) { ++ pr_err("%s: bad input format\n", __func__); ++ i = 4; ++ } ++ if (BUS_FMT_IS_BGR(bus_format)) ++ i ^= 1; ++ shift = my_formats[i].shift; ++ imask = my_formats[i].mask; ++ rgbsz = my_formats[i].rgbsz; ++ omask = set_output_format(bus_format, &shift, &imask, &rgbsz); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_IMASK, imask); ++ rp1dpi_hw_write(dpi, DPI_DMA_OMASK, omask); ++ rp1dpi_hw_write(dpi, DPI_DMA_SHIFT, shift); ++ rp1dpi_hw_write(dpi, DPI_DMA_RGBSZ, rgbsz); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_QOS, ++ BITS(DPI_DMA_QOS_DQOS, 0x0) | ++ BITS(DPI_DMA_QOS_ULEV, 0xb) | ++ BITS(DPI_DMA_QOS_UQOS, 0x2) | ++ BITS(DPI_DMA_QOS_LLEV, 0x8) | ++ BITS(DPI_DMA_QOS_LQOS, 0x7)); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_IRQ_FLAGS, -1); ++ rp1dpi_hw_vblank_ctrl(dpi, 1); ++ ++ i = rp1dpi_hw_busy(dpi); ++ if (i) ++ pr_warn("%s: Unexpectedly busy at start!", __func__); ++ ++ rp1dpi_hw_write(dpi, DPI_DMA_CONTROL, ++ BITS(DPI_DMA_CONTROL_ARM, !i) | ++ BITS(DPI_DMA_CONTROL_AUTO_REPEAT, 1) | ++ BITS(DPI_DMA_CONTROL_HIGH_WATER, 448) | ++ BITS(DPI_DMA_CONTROL_DEN_POL, de_inv) | ++ BITS(DPI_DMA_CONTROL_HSYNC_POL, !!(mode->flags & DRM_MODE_FLAG_NHSYNC)) | ++ BITS(DPI_DMA_CONTROL_VSYNC_POL, !!(mode->flags & DRM_MODE_FLAG_NVSYNC)) | ++ BITS(DPI_DMA_CONTROL_COLORM, 0) | ++ BITS(DPI_DMA_CONTROL_SHUTDN, 0) | ++ BITS(DPI_DMA_CONTROL_HBP_EN, (mode->htotal != mode->hsync_end)) | ++ BITS(DPI_DMA_CONTROL_HFP_EN, (mode->hsync_start != mode->hdisplay)) | ++ BITS(DPI_DMA_CONTROL_VBP_EN, (mode->vtotal != mode->vsync_end)) | ++ BITS(DPI_DMA_CONTROL_VFP_EN, (mode->vsync_start != mode->vdisplay)) | ++ BITS(DPI_DMA_CONTROL_HSYNC_EN, (mode->hsync_end != mode->hsync_start)) | ++ BITS(DPI_DMA_CONTROL_VSYNC_EN, (mode->vsync_end != mode->vsync_start))); ++} ++ ++void rp1dpi_hw_update(struct rp1_dpi *dpi, dma_addr_t addr, u32 offset, u32 stride) ++{ ++ u64 a = addr + offset; ++ ++ /* ++ * Update STRIDE, DMAH and DMAL only. When called after rp1dpi_hw_setup(), ++ * DMA starts immediately; if already running, the buffer will flip at ++ * the next vertical sync event. ++ */ ++ rp1dpi_hw_write(dpi, DPI_DMA_DMA_STRIDE, stride); ++ rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_H, a >> 32); ++ rp1dpi_hw_write(dpi, DPI_DMA_DMA_ADDR_L, a & 0xFFFFFFFFu); ++} ++ ++void rp1dpi_hw_stop(struct rp1_dpi *dpi) ++{ ++ u32 ctrl; ++ ++ /* ++ * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for ++ * the current and any queued frame to end. "Force drain" flags are not used, ++ * as they seem to prevent DMA from re-starting properly; it's safer to wait. ++ */ ++ reinit_completion(&dpi->finished); ++ ctrl = rp1dpi_hw_read(dpi, DPI_DMA_CONTROL); ++ ctrl &= ~(DPI_DMA_CONTROL_ARM_MASK | DPI_DMA_CONTROL_AUTO_REPEAT_MASK); ++ rp1dpi_hw_write(dpi, DPI_DMA_CONTROL, ctrl); ++ if (!wait_for_completion_timeout(&dpi->finished, HZ / 10)) ++ drm_err(dpi->drm, "%s: timed out waiting for idle\n", __func__); ++ rp1dpi_hw_write(dpi, DPI_DMA_IRQ_EN, 0); ++} ++ ++void rp1dpi_hw_vblank_ctrl(struct rp1_dpi *dpi, int enable) ++{ ++ rp1dpi_hw_write(dpi, DPI_DMA_IRQ_EN, ++ BITS(DPI_DMA_IRQ_EN_AFIFO_EMPTY, 1) | ++ BITS(DPI_DMA_IRQ_EN_UNDERFLOW, 1) | ++ BITS(DPI_DMA_IRQ_EN_DMA_READY, !!enable) | ++ BITS(DPI_DMA_IRQ_EN_MATCH_LINE, 4095)); ++} ++ ++irqreturn_t rp1dpi_hw_isr(int irq, void *dev) ++{ ++ struct rp1_dpi *dpi = dev; ++ u32 u = rp1dpi_hw_read(dpi, DPI_DMA_IRQ_FLAGS); ++ ++ if (u) { ++ rp1dpi_hw_write(dpi, DPI_DMA_IRQ_FLAGS, u); ++ if (dpi) { ++ if (u & DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK) ++ drm_err_ratelimited(dpi->drm, ++ "Underflow! (panics=0x%08x)\n", ++ rp1dpi_hw_read(dpi, DPI_DMA_PANICS)); ++ if (u & DPI_DMA_IRQ_FLAGS_DMA_READY_MASK) ++ drm_crtc_handle_vblank(&dpi->pipe.crtc); ++ if (u & DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK) ++ complete(&dpi->finished); ++ } ++ } ++ return u ? IRQ_HANDLED : IRQ_NONE; ++} diff --git a/target/linux/bcm27xx/patches-6.1/950-0887-drm-Add-RP1-VEC-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0887-drm-Add-RP1-VEC-driver.patch new file mode 100644 index 0000000000..5bf657ab24 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0887-drm-Add-RP1-VEC-driver.patch @@ -0,0 +1,3078 @@ +From 09c2c6aad0fed44182defecd274579770feb0ae2 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Tue, 19 Sep 2023 17:54:41 +0100 +Subject: [PATCH] drm: Add RP1 VEC driver + +Add support for the RP1 VEC hardware. + +Signed-off-by: Nick Hollinghurst +--- + drivers/gpu/drm/rp1/rp1-vec/Kconfig | 12 + + drivers/gpu/drm/rp1/rp1-vec/Makefile | 5 + + drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c | 539 ++++++++ + drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h | 79 ++ + drivers/gpu/drm/rp1/rp1-vec/rp1_vec_cfg.c | 508 ++++++++ + drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 469 +++++++ + drivers/gpu/drm/rp1/rp1-vec/vec_regs.h | 1420 +++++++++++++++++++++ + 7 files changed, 3032 insertions(+) + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/Kconfig + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/Makefile + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/rp1_vec_cfg.c + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c + create mode 100644 drivers/gpu/drm/rp1/rp1-vec/vec_regs.h + +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/Kconfig +@@ -0,0 +1,12 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config DRM_RP1_VEC ++ tristate "DRM Support for RP1 VEC" ++ depends on DRM ++ select MFD_RP1 ++ select DRM_GEM_DMA_HELPER ++ select DRM_KMS_HELPER ++ select DRM_VRAM_HELPER ++ select DRM_TTM ++ select DRM_TTM_HELPER ++ help ++ Choose this option to enable Video Out on RP1 +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++drm-rp1-vec-y := rp1_vec.o rp1_vec_hw.o rp1_vec_cfg.o ++ ++obj-$(CONFIG_DRM_RP1_VEC) += drm-rp1-vec.o +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c +@@ -0,0 +1,539 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for VEC output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rp1_vec.h" ++ ++/* ++ * Default TV standard parameter; it may be overridden by the OF ++ * property "tv_norm" (which should be one of the strings below). ++ * ++ * The default (empty string) supports various 60Hz and 50Hz modes, ++ * and will automatically select NTSC[-M] or PAL[-BDGHIKL]; the two ++ * "fake" 60Hz standards NTSC-443 and PAL60 also support 50Hz PAL. ++ * Other values will restrict the set of video modes offered. ++ * ++ * Finally, the DRM connector property "mode" (which is an integer) ++ * can be used to override this value, but it does not prevent the ++ * selection of an inapplicable video mode. ++ */ ++ ++static char *rp1vec_tv_norm_str; ++module_param_named(tv_norm, rp1vec_tv_norm_str, charp, 0600); ++MODULE_PARM_DESC(tv_norm, "Default TV norm.\n" ++ "\t\tSupported: NTSC, NTSC-J, NTSC-443, PAL, PAL-M, PAL-N,\n" ++ "\t\t\tPAL60.\n" ++ "\t\tDefault: empty string: infer PAL for a 50 Hz mode,\n" ++ "\t\t\tNTSC otherwise"); ++ ++const char * const rp1vec_tvstd_names[] = { ++ [RP1VEC_TVSTD_NTSC] = "NTSC", ++ [RP1VEC_TVSTD_NTSC_J] = "NTSC-J", ++ [RP1VEC_TVSTD_NTSC_443] = "NTSC-443", ++ [RP1VEC_TVSTD_PAL] = "PAL", ++ [RP1VEC_TVSTD_PAL_M] = "PAL-M", ++ [RP1VEC_TVSTD_PAL_N] = "PAL-N", ++ [RP1VEC_TVSTD_PAL60] = "PAL60", ++ [RP1VEC_TVSTD_DEFAULT] = "", ++}; ++ ++static int rp1vec_parse_tv_norm(const char *str) ++{ ++ int i; ++ ++ if (str && *str) { ++ for (i = 0; i < ARRAY_SIZE(rp1vec_tvstd_names); ++i) { ++ if (strcasecmp(str, rp1vec_tvstd_names[i]) == 0) ++ return i; ++ } ++ } ++ return RP1VEC_TVSTD_DEFAULT; ++} ++ ++static void rp1vec_pipe_update(struct drm_simple_display_pipe *pipe, ++ struct drm_plane_state *old_state) ++{ ++ struct drm_pending_vblank_event *event; ++ unsigned long flags; ++ struct drm_framebuffer *fb = pipe->plane.state->fb; ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ struct drm_gem_object *gem = fb ? drm_gem_fb_get_obj(fb, 0) : NULL; ++ struct drm_gem_dma_object *dma_obj = gem ? to_drm_gem_dma_obj(gem) : NULL; ++ bool can_update = fb && dma_obj && vec && vec->pipe_enabled; ++ ++ /* (Re-)start VEC where required; and update FB address */ ++ if (can_update) { ++ if (!vec->vec_running || fb->format->format != vec->cur_fmt) { ++ if (vec->vec_running && fb->format->format != vec->cur_fmt) { ++ rp1vec_hw_stop(vec); ++ vec->vec_running = false; ++ } ++ if (!vec->vec_running) { ++ rp1vec_hw_setup(vec, ++ fb->format->format, ++ &pipe->crtc.state->mode, ++ vec->connector.state->tv.mode); ++ vec->vec_running = true; ++ } ++ vec->cur_fmt = fb->format->format; ++ drm_crtc_vblank_on(&pipe->crtc); ++ } ++ rp1vec_hw_update(vec, dma_obj->dma_addr, fb->offsets[0], fb->pitches[0]); ++ } ++ ++ /* Check if VBLANK callback needs to be armed (or sent immediately in some error cases). ++ * Note there is a tiny probability of a race between rp1vec_dma_update() and IRQ; ++ * ordering it this way around is safe, but theoretically might delay an extra frame. ++ */ ++ spin_lock_irqsave(&pipe->crtc.dev->event_lock, flags); ++ event = pipe->crtc.state->event; ++ if (event) { ++ pipe->crtc.state->event = NULL; ++ if (can_update && drm_crtc_vblank_get(&pipe->crtc) == 0) ++ drm_crtc_arm_vblank_event(&pipe->crtc, event); ++ else ++ drm_crtc_send_vblank_event(&pipe->crtc, event); ++ } ++ spin_unlock_irqrestore(&pipe->crtc.dev->event_lock, flags); ++} ++ ++static void rp1vec_pipe_enable(struct drm_simple_display_pipe *pipe, ++ struct drm_crtc_state *crtc_state, ++ struct drm_plane_state *plane_state) ++{ ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ ++ dev_info(&vec->pdev->dev, __func__); ++ vec->pipe_enabled = true; ++ vec->cur_fmt = 0xdeadbeef; ++ rp1vec_vidout_setup(vec); ++ rp1vec_pipe_update(pipe, 0); ++} ++ ++static void rp1vec_pipe_disable(struct drm_simple_display_pipe *pipe) ++{ ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ ++ dev_info(&vec->pdev->dev, __func__); ++ drm_crtc_vblank_off(&pipe->crtc); ++ if (vec) { ++ if (vec->vec_running) { ++ rp1vec_hw_stop(vec); ++ vec->vec_running = false; ++ } ++ vec->pipe_enabled = false; ++ } ++} ++ ++static int rp1vec_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ if (pipe && pipe->crtc.dev) { ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ ++ if (vec) ++ rp1vec_hw_vblank_ctrl(vec, 1); ++ } ++ return 0; ++} ++ ++static void rp1vec_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) ++{ ++ if (pipe && pipe->crtc.dev) { ++ struct rp1_vec *vec = pipe->crtc.dev->dev_private; ++ ++ if (vec) ++ rp1vec_hw_vblank_ctrl(vec, 0); ++ } ++} ++ ++static const struct drm_simple_display_pipe_funcs rp1vec_pipe_funcs = { ++ .enable = rp1vec_pipe_enable, ++ .update = rp1vec_pipe_update, ++ .disable = rp1vec_pipe_disable, ++ .prepare_fb = drm_gem_simple_display_pipe_prepare_fb, ++ .enable_vblank = rp1vec_pipe_enable_vblank, ++ .disable_vblank = rp1vec_pipe_disable_vblank, ++}; ++ ++static void rp1vec_connector_destroy(struct drm_connector *connector) ++{ ++ drm_connector_unregister(connector); ++ drm_connector_cleanup(connector); ++} ++ ++static const struct drm_display_mode rp1vec_modes[4] = { ++ { /* Full size 525/60i with Rec.601 pixel rate */ ++ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, ++ 720, 720 + 14, 720 + 14 + 64, 858, 0, ++ 480, 480 + 7, 480 + 7 + 6, 525, 0, ++ DRM_MODE_FLAG_INTERLACE) ++ }, ++ { /* Cropped and horizontally squashed to be TV-safe */ ++ DRM_MODE("704x432i", DRM_MODE_TYPE_DRIVER, 15429, ++ 704, 704 + 72, 704 + 72 + 72, 980, 0, ++ 432, 432 + 31, 432 + 31 + 6, 525, 0, ++ DRM_MODE_FLAG_INTERLACE) ++ }, ++ { /* Full size 625/50i with Rec.601 pixel rate */ ++ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, ++ 720, 720 + 20, 720 + 20 + 64, 864, 0, ++ 576, 576 + 4, 576 + 4 + 6, 625, 0, ++ DRM_MODE_FLAG_INTERLACE) ++ }, ++ { /* Cropped and squashed, for square(ish) pixels */ ++ DRM_MODE("704x512i", DRM_MODE_TYPE_DRIVER, 15429, ++ 704, 704 + 80, 704 + 80 + 72, 987, 0, ++ 512, 512 + 36, 512 + 36 + 6, 625, 0, ++ DRM_MODE_FLAG_INTERLACE) ++ } ++}; ++ ++static int rp1vec_connector_get_modes(struct drm_connector *connector) ++{ ++ struct rp1_vec *vec = container_of(connector, struct rp1_vec, connector); ++ bool ok525 = RP1VEC_TVSTD_SUPPORT_525(vec->tv_norm); ++ bool ok625 = RP1VEC_TVSTD_SUPPORT_625(vec->tv_norm); ++ int i, prog, n = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(rp1vec_modes); i++) { ++ if ((rp1vec_modes[i].vtotal == 625) ? ok625 : ok525) { ++ for (prog = 0; prog < 2; prog++) { ++ struct drm_display_mode *mode = ++ drm_mode_duplicate(connector->dev, ++ &rp1vec_modes[i]); ++ ++ if (prog) { ++ mode->flags &= ~DRM_MODE_FLAG_INTERLACE; ++ mode->vdisplay >>= 1; ++ mode->vsync_start >>= 1; ++ mode->vsync_end >>= 1; ++ mode->vtotal >>= 1; ++ } ++ ++ if (mode->hdisplay == 704 && ++ mode->vtotal == ((ok525) ? 525 : 625)) ++ mode->type |= DRM_MODE_TYPE_PREFERRED; ++ ++ drm_mode_set_name(mode); ++ drm_mode_probed_add(connector, mode); ++ n++; ++ } ++ } ++ } ++ ++ return n; ++} ++ ++static void rp1vec_connector_reset(struct drm_connector *connector) ++{ ++ struct rp1_vec *vec = container_of(connector, struct rp1_vec, connector); ++ ++ drm_atomic_helper_connector_reset(connector); ++ if (connector->state) ++ connector->state->tv.mode = vec->tv_norm; ++} ++ ++static int rp1vec_connector_atomic_check(struct drm_connector *conn, ++ struct drm_atomic_state *state) ++{ struct drm_connector_state *old_state = ++ drm_atomic_get_old_connector_state(state, conn); ++ struct drm_connector_state *new_state = ++ drm_atomic_get_new_connector_state(state, conn); ++ ++ if (new_state->crtc && old_state->tv.mode != new_state->tv.mode) { ++ struct drm_crtc_state *crtc_state = ++ drm_atomic_get_new_crtc_state(state, new_state->crtc); ++ ++ crtc_state->mode_changed = true; ++ } ++ ++ return 0; ++} ++ ++static enum drm_mode_status rp1vec_mode_valid(struct drm_device *dev, ++ const struct drm_display_mode *mode) ++{ ++ /* ++ * Check the mode roughly matches one of our standard modes ++ * (optionally half-height and progressive). Ignore H/V sync ++ * timings which for interlaced TV are approximate at best. ++ */ ++ int i, prog; ++ ++ prog = !(mode->flags & DRM_MODE_FLAG_INTERLACE); ++ ++ for (i = 0; i < ARRAY_SIZE(rp1vec_modes); i++) { ++ const struct drm_display_mode *ref = rp1vec_modes + i; ++ ++ if (mode->hdisplay == ref->hdisplay && ++ mode->vdisplay == (ref->vdisplay >> prog) && ++ mode->clock + 2 >= ref->clock && ++ mode->clock <= ref->clock + 2 && ++ mode->htotal + 2 >= ref->htotal && ++ mode->htotal <= ref->htotal + 2 && ++ mode->vtotal + 2 >= (ref->vtotal >> prog) && ++ mode->vtotal <= (ref->vtotal >> prog) + 2) ++ return MODE_OK; ++ } ++ return MODE_BAD; ++} ++ ++static const struct drm_connector_helper_funcs rp1vec_connector_helper_funcs = { ++ .get_modes = rp1vec_connector_get_modes, ++ .atomic_check = rp1vec_connector_atomic_check, ++}; ++ ++static const struct drm_connector_funcs rp1vec_connector_funcs = { ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = rp1vec_connector_destroy, ++ .reset = rp1vec_connector_reset, ++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++}; ++ ++static const struct drm_mode_config_funcs rp1vec_mode_funcs = { ++ .fb_create = drm_gem_fb_create, ++ .atomic_check = drm_atomic_helper_check, ++ .atomic_commit = drm_atomic_helper_commit, ++ .mode_valid = rp1vec_mode_valid, ++}; ++ ++static const u32 rp1vec_formats[] = { ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_RGB888, ++ DRM_FORMAT_BGR888, ++ DRM_FORMAT_RGB565 ++}; ++ ++static void rp1vec_stopall(struct drm_device *drm) ++{ ++ if (drm->dev_private) { ++ struct rp1_vec *vec = drm->dev_private; ++ ++ if (vec->vec_running || rp1vec_hw_busy(vec)) { ++ rp1vec_hw_stop(vec); ++ vec->vec_running = false; ++ } ++ rp1vec_vidout_poweroff(vec); ++ } ++} ++ ++DEFINE_DRM_GEM_DMA_FOPS(rp1vec_fops); ++ ++static struct drm_driver rp1vec_driver = { ++ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, ++ .fops = &rp1vec_fops, ++ .name = "drm-rp1-vec", ++ .desc = "drm-rp1-vec", ++ .date = "0", ++ .major = 1, ++ .minor = 0, ++ DRM_GEM_DMA_DRIVER_OPS, ++ .release = rp1vec_stopall, ++}; ++ ++static int rp1vec_platform_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct drm_device *drm; ++ struct rp1_vec *vec; ++ const char *str; ++ int i, ret; ++ ++ dev_info(dev, __func__); ++ drm = drm_dev_alloc(&rp1vec_driver, dev); ++ if (IS_ERR(drm)) { ++ ret = PTR_ERR(drm); ++ dev_err(dev, "%s drm_dev_alloc %d", __func__, ret); ++ return ret; ++ } ++ ++ vec = drmm_kzalloc(drm, sizeof(*vec), GFP_KERNEL); ++ if (!vec) { ++ dev_err(dev, "%s drmm_kzalloc failed", __func__); ++ ret = -ENOMEM; ++ goto err_free_drm; ++ } ++ init_completion(&vec->finished); ++ vec->drm = drm; ++ vec->pdev = pdev; ++ drm->dev_private = vec; ++ platform_set_drvdata(pdev, drm); ++ ++ str = rp1vec_tv_norm_str; ++ of_property_read_string(dev->of_node, "tv_norm", &str); ++ vec->tv_norm = rp1vec_parse_tv_norm(str); ++ ++ for (i = 0; i < RP1VEC_NUM_HW_BLOCKS; i++) { ++ vec->hw_base[i] = ++ devm_ioremap_resource(dev, ++ platform_get_resource(vec->pdev, IORESOURCE_MEM, i)); ++ if (IS_ERR(vec->hw_base[i])) { ++ ret = PTR_ERR(vec->hw_base[i]); ++ dev_err(dev, "Error memory mapping regs[%d]\n", i); ++ goto err_free_drm; ++ } ++ } ++ ret = platform_get_irq(vec->pdev, 0); ++ if (ret > 0) ++ ret = devm_request_irq(dev, ret, rp1vec_hw_isr, ++ IRQF_SHARED, "rp1-vec", vec); ++ if (ret) { ++ dev_err(dev, "Unable to request interrupt\n"); ++ ret = -EINVAL; ++ goto err_free_drm; ++ } ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ ++ vec->vec_clock = devm_clk_get(dev, NULL); ++ if (IS_ERR(vec->vec_clock)) { ++ ret = PTR_ERR(vec->vec_clock); ++ goto err_free_drm; ++ } ++ ret = clk_prepare_enable(vec->vec_clock); ++ ++ ret = drmm_mode_config_init(drm); ++ if (ret) ++ goto err_free_drm; ++ drm->mode_config.max_width = 768; ++ drm->mode_config.max_height = 576; ++ drm->mode_config.fb_base = 0; ++ drm->mode_config.preferred_depth = 32; ++ drm->mode_config.prefer_shadow = 0; ++ drm->mode_config.prefer_shadow_fbdev = 1; ++ //drm->mode_config.fbdev_use_iomem = false; ++ drm->mode_config.quirk_addfb_prefer_host_byte_order = true; ++ drm->mode_config.funcs = &rp1vec_mode_funcs; ++ drm_vblank_init(drm, 1); ++ ++ ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(rp1vec_tvstd_names), ++ rp1vec_tvstd_names); ++ if (ret) ++ goto err_free_drm; ++ ++ drm_connector_init(drm, &vec->connector, &rp1vec_connector_funcs, ++ DRM_MODE_CONNECTOR_Composite); ++ if (ret) ++ goto err_free_drm; ++ ++ vec->connector.interlace_allowed = true; ++ drm_connector_helper_add(&vec->connector, &rp1vec_connector_helper_funcs); ++ ++ drm_object_attach_property(&vec->connector.base, ++ drm->mode_config.tv_mode_property, ++ vec->tv_norm); ++ ++ ret = drm_simple_display_pipe_init(drm, ++ &vec->pipe, ++ &rp1vec_pipe_funcs, ++ rp1vec_formats, ++ ARRAY_SIZE(rp1vec_formats), ++ NULL, ++ &vec->connector); ++ if (ret) ++ goto err_free_drm; ++ ++ drm_mode_config_reset(drm); ++ ++ ret = drm_dev_register(drm, 0); ++ if (ret) ++ goto err_free_drm; ++ ++ drm_fbdev_generic_setup(drm, 32); /* the "32" is preferred BPP */ ++ return ret; ++ ++err_free_drm: ++ dev_info(dev, "%s fail %d", __func__, ret); ++ drm_dev_put(drm); ++ return ret; ++} ++ ++static int rp1vec_platform_remove(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1vec_stopall(drm); ++ drm_dev_unregister(drm); ++ drm_atomic_helper_shutdown(drm); ++ drm_dev_put(drm); ++ ++ return 0; ++} ++ ++static void rp1vec_platform_shutdown(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ rp1vec_stopall(drm); ++} ++ ++static const struct of_device_id rp1vec_of_match[] = { ++ { ++ .compatible = "raspberrypi,rp1vec", ++ }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rp1vec_of_match); ++ ++static struct platform_driver rp1vec_platform_driver = { ++ .probe = rp1vec_platform_probe, ++ .remove = rp1vec_platform_remove, ++ .shutdown = rp1vec_platform_shutdown, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rp1vec_of_match, ++ }, ++}; ++ ++module_platform_driver(rp1vec_platform_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("DRM driver for Composite Video on Raspberry Pi RP1"); ++MODULE_AUTHOR("Nick Hollinghurst"); +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h +@@ -0,0 +1,79 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define MODULE_NAME "drm-rp1-vec" ++#define DRIVER_NAME "drm-rp1-vec" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define RP1VEC_HW_BLOCK_VEC 0 ++#define RP1VEC_HW_BLOCK_CFG 1 ++#define RP1VEC_NUM_HW_BLOCKS 2 ++ ++enum { ++ RP1VEC_TVSTD_NTSC = 0, /* +525 => NTSC 625 => PAL */ ++ RP1VEC_TVSTD_NTSC_J, /* +525 => NTSC-J 625 => PAL */ ++ RP1VEC_TVSTD_NTSC_443, /* +525 => NTSC-443 +625 => PAL */ ++ RP1VEC_TVSTD_PAL, /* 525 => NTSC +625 => PAL */ ++ RP1VEC_TVSTD_PAL_M, /* +525 => PAL-M 625 => PAL */ ++ RP1VEC_TVSTD_PAL_N, /* 525 => NTSC +625 => PAL-N */ ++ RP1VEC_TVSTD_PAL60, /* +525 => PAL60 +625 => PAL */ ++ RP1VEC_TVSTD_DEFAULT, /* +525 => NTSC +625 => PAL */ ++}; ++ ++/* Which standards support which modes? Those marked with + above */ ++#define RP1VEC_TVSTD_SUPPORT_525(n) ((0xD7 >> (n)) & 1) ++#define RP1VEC_TVSTD_SUPPORT_625(n) ((0xEC >> (n)) & 1) ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct rp1_vec { ++ /* DRM and platform device pointers */ ++ struct drm_device *drm; ++ struct platform_device *pdev; ++ ++ /* Framework and helper objects */ ++ struct drm_simple_display_pipe pipe; ++ struct drm_connector connector; ++ ++ /* Clock. We assume this is always at 108 MHz. */ ++ struct clk *vec_clock; ++ ++ /* Block (VCC, CFG) base addresses, and current state */ ++ void __iomem *hw_base[RP1VEC_NUM_HW_BLOCKS]; ++ u32 cur_fmt; ++ int tv_norm; ++ bool vec_running, pipe_enabled; ++ struct completion finished; ++}; ++ ++extern const char * const rp1vec_tvstd_names[]; ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the VEC/DMA block */ ++ ++void rp1vec_hw_setup(struct rp1_vec *vec, ++ u32 in_format, ++ struct drm_display_mode const *mode, ++ int tvstd); ++void rp1vec_hw_update(struct rp1_vec *vec, dma_addr_t addr, u32 offset, u32 stride); ++void rp1vec_hw_stop(struct rp1_vec *vec); ++int rp1vec_hw_busy(struct rp1_vec *vec); ++irqreturn_t rp1vec_hw_isr(int irq, void *dev); ++void rp1vec_hw_vblank_ctrl(struct rp1_vec *vec, int enable); ++ ++/* ---------------------------------------------------------------------- */ ++/* Functions to control the VIDEO OUT CFG block and check RP1 platform */ ++ ++void rp1vec_vidout_setup(struct rp1_vec *vec); ++void rp1vec_vidout_poweroff(struct rp1_vec *vec); +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_cfg.c +@@ -0,0 +1,508 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for DSI output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rp1_vec.h" ++ ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_SEL ++// JTAG access : synchronous ++// Description : Selects source: VEC or DPI ++#define VIDEO_OUT_CFG_SEL_OFFSET 0x00000000 ++#define VIDEO_OUT_CFG_SEL_BITS 0x00000013 ++#define VIDEO_OUT_CFG_SEL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_PCLK_INV ++// Description : Select dpi_pclk output port polarity inversion. ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_BITS 0x00000010 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_MSB 4 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_LSB 4 ++#define VIDEO_OUT_CFG_SEL_PCLK_INV_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_PAD_MUX ++// Description : VEC 1 DPI 0 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_BITS 0x00000002 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_MSB 1 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_LSB 1 ++#define VIDEO_OUT_CFG_SEL_PAD_MUX_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_SEL_VDAC_MUX ++// Description : VEC 1 DPI 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_RESET 0x0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_BITS 0x00000001 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_MSB 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_LSB 0 ++#define VIDEO_OUT_CFG_SEL_VDAC_MUX_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_VDAC_CFG ++// JTAG access : synchronous ++// Description : Configure SNPS VDAC ++#define VIDEO_OUT_CFG_VDAC_CFG_OFFSET 0x00000004 ++#define VIDEO_OUT_CFG_VDAC_CFG_BITS 0x1fffffff ++#define VIDEO_OUT_CFG_VDAC_CFG_RESET 0x0003ffff ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENCTR ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_BITS 0x1c000000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_MSB 28 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_LSB 26 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENCTR_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENSC ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_BITS 0x03800000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_MSB 25 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_LSB 23 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENSC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENDAC ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_BITS 0x00700000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_MSB 22 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_LSB 20 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENVBG ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_BITS 0x00080000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_MSB 19 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_LSB 19 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENVBG_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_BITS 0x00040000 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_MSB 18 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_LSB 18 ++#define VIDEO_OUT_CFG_VDAC_CFG_ENEXTREF_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC2GC ++// Description : dac2 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_BITS 0x0003f000 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_MSB 17 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_LSB 12 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC2GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC1GC ++// Description : dac1 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_BITS 0x00000fc0 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_MSB 11 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_LSB 6 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC1GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_CFG_DAC0GC ++// Description : dac0 gain control ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_RESET 0x3f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_BITS 0x0000003f ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_MSB 5 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_LSB 0 ++#define VIDEO_OUT_CFG_VDAC_CFG_DAC0GC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_VDAC_STATUS ++// JTAG access : synchronous ++// Description : Read VDAC status ++#define VIDEO_OUT_CFG_VDAC_STATUS_OFFSET 0x00000008 ++#define VIDEO_OUT_CFG_VDAC_STATUS_BITS 0x00000017 ++#define VIDEO_OUT_CFG_VDAC_STATUS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3 ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_RESET 0x0 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_BITS 0x00000010 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_MSB 4 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_LSB 4 ++#define VIDEO_OUT_CFG_VDAC_STATUS_ENCTR3_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT ++// Description : None ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_RESET "-" ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_BITS 0x00000007 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_MSB 2 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_LSB 0 ++#define VIDEO_OUT_CFG_VDAC_STATUS_CABLEOUT_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_MEM_PD ++// JTAG access : synchronous ++// Description : Control memory power down ++#define VIDEO_OUT_CFG_MEM_PD_OFFSET 0x0000000c ++#define VIDEO_OUT_CFG_MEM_PD_BITS 0x00000003 ++#define VIDEO_OUT_CFG_MEM_PD_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_MEM_PD_VEC ++// Description : None ++#define VIDEO_OUT_CFG_MEM_PD_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_BITS 0x00000002 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_MSB 1 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_LSB 1 ++#define VIDEO_OUT_CFG_MEM_PD_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_MEM_PD_DPI ++// Description : None ++#define VIDEO_OUT_CFG_MEM_PD_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_BITS 0x00000001 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_MSB 0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_LSB 0 ++#define VIDEO_OUT_CFG_MEM_PD_DPI_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_TEST_OVERRIDE ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_OFFSET 0x00000010 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_BITS 0xffffffff ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_PAD ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_RESET 0x0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_BITS 0x80000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_MSB 31 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_LSB 31 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_PAD_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_RESET 0x0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_BITS 0x40000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_MSB 30 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_LSB 30 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_VDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL ++// Description : None ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_RESET 0x00000000 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_BITS 0x3fffffff ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_MSB 29 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_LSB 0 ++#define VIDEO_OUT_CFG_TEST_OVERRIDE_RGBVAL_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTR ++// JTAG access : synchronous ++// Description : Raw Interrupts ++#define VIDEO_OUT_CFG_INTR_OFFSET 0x00000014 ++#define VIDEO_OUT_CFG_INTR_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTR_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTR_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTR_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTR_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTR_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTR_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTR_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTR_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTR_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTR_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTR_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTR_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTR_VEC_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTE ++// JTAG access : synchronous ++// Description : Interrupt Enable ++#define VIDEO_OUT_CFG_INTE_OFFSET 0x00000018 ++#define VIDEO_OUT_CFG_INTE_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTE_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTE_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTE_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTE_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTE_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTE_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTE_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTE_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTE_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTE_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTE_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTE_VEC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTF ++// JTAG access : synchronous ++// Description : Interrupt Force ++#define VIDEO_OUT_CFG_INTF_OFFSET 0x0000001c ++#define VIDEO_OUT_CFG_INTF_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTF_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTF_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTF_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTF_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTF_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTF_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTF_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTF_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTF_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTF_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTF_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTF_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTF_VEC_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INTS ++// JTAG access : synchronous ++// Description : Interrupt status after masking & forcing ++#define VIDEO_OUT_CFG_INTS_OFFSET 0x00000020 ++#define VIDEO_OUT_CFG_INTS_BITS 0x00000003 ++#define VIDEO_OUT_CFG_INTS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTS_DPI ++// Description : None ++#define VIDEO_OUT_CFG_INTS_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_INTS_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_INTS_DPI_MSB 1 ++#define VIDEO_OUT_CFG_INTS_DPI_LSB 1 ++#define VIDEO_OUT_CFG_INTS_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_INTS_VEC ++// Description : None ++#define VIDEO_OUT_CFG_INTS_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_INTS_VEC_BITS 0x00000001 ++#define VIDEO_OUT_CFG_INTS_VEC_MSB 0 ++#define VIDEO_OUT_CFG_INTS_VEC_LSB 0 ++#define VIDEO_OUT_CFG_INTS_VEC_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_BLOCK_ID ++// JTAG access : synchronous ++// Description : Block Identifier ++// Hexadecimal representation of "VOCF" ++#define VIDEO_OUT_CFG_BLOCK_ID_OFFSET 0x00000024 ++#define VIDEO_OUT_CFG_BLOCK_ID_BITS 0xffffffff ++#define VIDEO_OUT_CFG_BLOCK_ID_RESET 0x564f4346 ++#define VIDEO_OUT_CFG_BLOCK_ID_MSB 31 ++#define VIDEO_OUT_CFG_BLOCK_ID_LSB 0 ++#define VIDEO_OUT_CFG_BLOCK_ID_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_INSTANCE_ID ++// JTAG access : synchronous ++// Description : Block Instance Identifier ++#define VIDEO_OUT_CFG_INSTANCE_ID_OFFSET 0x00000028 ++#define VIDEO_OUT_CFG_INSTANCE_ID_BITS 0x0000000f ++#define VIDEO_OUT_CFG_INSTANCE_ID_RESET 0x00000000 ++#define VIDEO_OUT_CFG_INSTANCE_ID_MSB 3 ++#define VIDEO_OUT_CFG_INSTANCE_ID_LSB 0 ++#define VIDEO_OUT_CFG_INSTANCE_ID_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_AUTO ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_OFFSET 0x0000002c ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_RESET 0x00000007 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER ++// Description : 1 = reset is controlled by the sequencer ++// 0 = reset is controlled by rstseq_ctrl ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_AUTO_BUSADAPTER_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_PARALLEL ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_OFFSET 0x00000030 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_RESET 0x00000006 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_VEC_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_RESET 0x1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER ++// Description : Is this reset parallel (i.e. not part of the sequence) ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_PARALLEL_BUSADAPTER_ACCESS "RO" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_CTRL ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_OFFSET 0x00000034 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_VEC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_DPI_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER ++// Description : 1 = keep the reset asserted ++// 0 = keep the reset deasserted ++// This is ignored if rstseq_auto=1 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_CTRL_BUSADAPTER_ACCESS "RW" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_TRIG ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_OFFSET 0x00000038 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_VEC_ACCESS "SC" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_DPI_ACCESS "SC" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER ++// Description : Pulses the reset output ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_TRIG_BUSADAPTER_ACCESS "SC" ++// ============================================================================= ++// Register : VIDEO_OUT_CFG_RSTSEQ_DONE ++// JTAG access : synchronous ++// Description : None ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_OFFSET 0x0000003c ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BITS 0x00000007 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_VEC ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_BITS 0x00000004 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_MSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_LSB 2 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_VEC_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_DPI ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_BITS 0x00000002 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_MSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_LSB 1 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_DPI_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER ++// Description : Indicates the current state of the reset ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_RESET 0x0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_BITS 0x00000001 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_MSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_LSB 0 ++#define VIDEO_OUT_CFG_RSTSEQ_DONE_BUSADAPTER_ACCESS "RO" ++// ============================================================================= ++ ++#define CFG_WRITE(reg, val) writel((val), vec->hw_base[RP1VEC_HW_BLOCK_CFG] + (reg ## _OFFSET)) ++#define CFG_READ(reg) readl(vec->hw_base[RP1VEC_HW_BLOCK_CFG] + (reg ## _OFFSET)) ++ ++void rp1vec_vidout_setup(struct rp1_vec *vec) ++{ ++ /* ++ * We assume DPI and VEC can't be used at the same time (due to ++ * clashing requirements for PLL_VIDEO, and potentially for VDAC). ++ * We therefore leave DPI memories powered down. ++ */ ++ CFG_WRITE(VIDEO_OUT_CFG_MEM_PD, VIDEO_OUT_CFG_MEM_PD_DPI_BITS); ++ CFG_WRITE(VIDEO_OUT_CFG_TEST_OVERRIDE, 0x00000000); ++ ++ /* DPI->Pads; VEC->VDAC */ ++ CFG_WRITE(VIDEO_OUT_CFG_SEL, VIDEO_OUT_CFG_SEL_VDAC_MUX_BITS); ++ ++ /* configure VDAC for 1 channel, bandgap on, 1.28V swing */ ++ CFG_WRITE(VIDEO_OUT_CFG_VDAC_CFG, 0x0019ffff); ++ ++ /* enable VEC interrupt */ ++ CFG_WRITE(VIDEO_OUT_CFG_INTE, VIDEO_OUT_CFG_INTE_VEC_BITS); ++} ++ ++void rp1vec_vidout_poweroff(struct rp1_vec *vec) ++{ ++ /* disable VEC interrupt */ ++ CFG_WRITE(VIDEO_OUT_CFG_INTE, 0); ++ ++ /* Ensure VDAC is turned off; power down DPI,VEC memories */ ++ CFG_WRITE(VIDEO_OUT_CFG_VDAC_CFG, 0); ++ CFG_WRITE(VIDEO_OUT_CFG_MEM_PD, VIDEO_OUT_CFG_MEM_PD_BITS); ++} +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c +@@ -0,0 +1,469 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * DRM Driver for VEC output on Raspberry Pi RP1 ++ * ++ * Copyright (c) 2023 Raspberry Pi Limited. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rp1_vec.h" ++#include "vec_regs.h" ++ ++#define BITS(field, val) (((val) << (field ## _LSB)) & (field ## _BITS)) ++ ++#define VEC_WRITE(reg, val) writel((val), vec->hw_base[RP1VEC_HW_BLOCK_VEC] + (reg ## _OFFSET)) ++#define VEC_READ(reg) readl(vec->hw_base[RP1VEC_HW_BLOCK_VEC] + (reg ## _OFFSET)) ++ ++int rp1vec_hw_busy(struct rp1_vec *vec) ++{ ++ /* Read the undocumented "pline_busy" flag */ ++ return VEC_READ(VEC_STATUS) & 1; ++} ++ ++/* Table of supported input (in-memory/DMA) pixel formats. */ ++struct rp1vec_ipixfmt { ++ u32 format; /* DRM format code */ ++ u32 mask; /* RGB masks (10 bits each, left justified) */ ++ u32 shift; /* RGB MSB positions in the memory word */ ++ u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */ ++}; ++ ++#define MASK_RGB(r, g, b) \ ++ (BITS(VEC_IMASK_MASK_R, r) | BITS(VEC_IMASK_MASK_G, g) | BITS(VEC_IMASK_MASK_B, b)) ++#define SHIFT_RGB(r, g, b) \ ++ (BITS(VEC_SHIFT_SHIFT_R, r) | BITS(VEC_SHIFT_SHIFT_G, g) | BITS(VEC_SHIFT_SHIFT_B, b)) ++ ++static const struct rp1vec_ipixfmt my_formats[] = { ++ { ++ .format = DRM_FORMAT_XRGB8888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), ++ }, ++ { ++ .format = DRM_FORMAT_XBGR8888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), ++ }, ++ { ++ .format = DRM_FORMAT_RGB888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 2), ++ }, ++ { ++ .format = DRM_FORMAT_BGR888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 2), ++ }, ++ { ++ .format = DRM_FORMAT_RGB565, ++ .mask = MASK_RGB(0x3e0, 0x3f0, 0x3e0), ++ .shift = SHIFT_RGB(15, 10, 4), ++ .rgbsz = BITS(VEC_RGBSZ_SCALE_R, 5) | ++ BITS(VEC_RGBSZ_SCALE_G, 6) | ++ BITS(VEC_RGBSZ_SCALE_B, 5) | ++ BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 1), ++ } ++}; ++ ++/* ++ * Hardware mode descriptions (@ 108 MHz clock rate). ++ * These rely largely on "canned" register settings. ++ * TODO: Port the generating software from FP to integer, ++ * or better factorize the differences between modes. ++ */ ++ ++struct rp1vec_hwmode { ++ u16 total_cols; /* active columns, plus padding for filter context */ ++ u16 rows_per_field; /* active lines per field (including partial ones) */ ++ bool interlaced; /* set for interlaced */ ++ bool first_field_odd; /* set for interlaced and 30fps */ ++ u32 yuv_scaling; /* three 10-bit fields {Y, U, V} in 2.8 format */ ++ u32 back_end_regs[28]; /* All registers 0x80 .. 0xEC */ ++}; ++ ++/* { NTSC, PAL, PAL-M } x { progressive, interlaced } x { 13.5 MHz, 15.428571 MHz } */ ++static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = { ++ { ++ /* NTSC */ ++ { ++ { ++ .total_cols = 724, ++ .rows_per_field = 240, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1071d0cf, ++ .back_end_regs = { ++ 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023d034c, ++ 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0106, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170106, 0x00000000, 0x004c020e, ++ 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561, ++ 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ec, ++ }, ++ }, { ++ .total_cols = 815, ++ .rows_per_field = 240, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1c131962, ++ .back_end_regs = { ++ 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023d034c, ++ 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0106, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170106, 0x00000000, 0x004c020e, ++ 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561, ++ 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ac, ++ }, ++ }, ++ }, { ++ { ++ .total_cols = 724, ++ .rows_per_field = 243, ++ .interlaced = true, ++ .first_field_odd = true, ++ .yuv_scaling = 0x1071d0cf, ++ .back_end_regs = { ++ 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023d034c, ++ 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0107, 0x0111020d, 0x00000000, 0x00000000, ++ 0x011c020d, 0x00150106, 0x0107011b, 0x004c020d, ++ 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561, ++ 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x00094dee, ++ }, ++ }, { ++ .total_cols = 815, ++ .rows_per_field = 243, ++ .interlaced = true, ++ .first_field_odd = true, ++ .yuv_scaling = 0x1c131962, ++ .back_end_regs = { ++ 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023d034c, ++ 0x00f80b6d, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0107, 0x0111020d, 0x00000000, 0x00000000, ++ 0x011c020d, 0x00150106, 0x0107011b, 0x004c020d, ++ 0x00000000, 0x007bffff, 0x38518c9a, 0x11195561, ++ 0x02000200, 0xc1f07c1f, 0x087c1f07, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x00094dae, ++ }, ++ }, ++ }, ++ }, { ++ /* PAL */ ++ { ++ { ++ .total_cols = 724, ++ .rows_per_field = 288, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x11c1f8e0, ++ .back_end_regs = { ++ 0x04061aa6, 0x046e0cee, 0x0d8001fb, 0x025c034f, ++ 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009, ++ 0x00070135, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170136, 0x00000000, 0x000a0270, ++ 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5, ++ 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ed, ++ }, ++ }, { ++ .total_cols = 804, ++ .rows_per_field = 288, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1e635d7f, ++ .back_end_regs = { ++ 0x045b1a57, 0x046e0cee, 0x0d8001fb, 0x025c034f, ++ 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009, ++ 0x00070135, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170136, 0x00000000, 0x000a0270, ++ 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5, ++ 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ad, ++ }, ++ }, ++ }, { ++ { ++ .total_cols = 724, ++ .rows_per_field = 288, ++ .interlaced = true, ++ .first_field_odd = false, ++ .yuv_scaling = 0x11c1f8e0, ++ .back_end_regs = { ++ 0x04061aa6, 0x046e0cee, 0x0d8001fb, 0x025c034f, ++ 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009, ++ 0x00070135, 0x013f026d, 0x00060136, 0x0140026e, ++ 0x0150026e, 0x00180136, 0x026f0017, 0x000a0271, ++ 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5, ++ 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddef, ++ }, ++ }, { ++ .total_cols = 804, ++ .rows_per_field = 288, ++ .interlaced = true, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1e635d7f, ++ .back_end_regs = { ++ 0x045b1a57, 0x046e0cee, 0x0d8001fb, 0x025c034f, ++ 0x00fd0b84, 0x026c0270, 0x00000004, 0x00050009, ++ 0x00070135, 0x013f026d, 0x00060136, 0x0140026e, ++ 0x0150026e, 0x00180136, 0x026f0017, 0x000a0271, ++ 0x00000000, 0x007bffff, 0x3b1389d8, 0x0caf53b5, ++ 0x02000200, 0xcc48c1d1, 0x0a8262b2, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddaf, ++ }, ++ }, ++ }, ++ }, { ++ /* PAL-M */ ++ { ++ { ++ .total_cols = 724, ++ .rows_per_field = 240, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x11c1f8e0, ++ .back_end_regs = { ++ 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023c034c, ++ 0x00f80b6e, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0106, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170106, 0x00000000, 0x000a020c, ++ 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5, ++ 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ed, ++ }, ++ }, { ++ .total_cols = 815, ++ .rows_per_field = 240, ++ .interlaced = false, ++ .first_field_odd = false, ++ .yuv_scaling = 0x1e635d7f, ++ .back_end_regs = { ++ 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023c034c, ++ 0x00f80b6e, 0x00000005, 0x0006000b, 0x000c0011, ++ 0x000a0106, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00170106, 0x00000000, 0x000a020c, ++ 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5, ++ 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x000801ad, ++ }, ++ }, ++ }, { ++ { ++ .total_cols = 724, ++ .rows_per_field = 243, ++ .interlaced = true, ++ .first_field_odd = true, ++ .yuv_scaling = 0x11c1f8e0, ++ .back_end_regs = { ++ 0x039f1a3f, 0x03e10cc6, 0x0d6801fb, 0x023c034c, ++ 0x00f80b6e, 0x00140019, 0x00000005, 0x0006000b, ++ 0x00090103, 0x010f0209, 0x00080102, 0x010e020a, ++ 0x0119020a, 0x00120103, 0x01040118, 0x000a020d, ++ 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5, ++ 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddef, ++ }, ++ }, { ++ .total_cols = 815, ++ .rows_per_field = 243, ++ .interlaced = true, ++ .first_field_odd = true, ++ .yuv_scaling = 0x1e635d7f, ++ .back_end_regs = { ++ 0x03ce1a17, 0x03e10cc6, 0x0d6801fb, 0x023c034c, ++ 0x00f80b6e, 0x00140019, 0x00000005, 0x0006000b, ++ 0x00090103, 0x010f0209, 0x00080102, 0x010e020a, ++ 0x0119020a, 0x00120103, 0x01040118, 0x000a020d, ++ 0x00000000, 0x007bffff, 0x385189d8, 0x0d5c53b5, ++ 0x02000200, 0xd6d33ea8, 0x0879bbf8, 0x00000000, ++ 0x0be20200, 0x20f0f800, 0x265c7f00, 0x0009ddaf, ++ }, ++ }, ++ }, ++ }, ++}; ++ ++void rp1vec_hw_setup(struct rp1_vec *vec, ++ u32 in_format, ++ struct drm_display_mode const *mode, ++ int tvstd) ++{ ++ unsigned int i, mode_family, mode_ilaced, mode_narrow; ++ const struct rp1vec_hwmode *hwm; ++ unsigned int w, h; ++ ++ /* Pick the appropriate "base" mode, which we may modify */ ++ mode_ilaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); ++ if (mode->vtotal > 263 * (1 + mode_ilaced)) ++ mode_family = 1; ++ else ++ mode_family = (tvstd == RP1VEC_TVSTD_PAL_M || tvstd == RP1VEC_TVSTD_PAL60) ? 2 : 0; ++ mode_narrow = (mode->clock >= 14336); ++ hwm = &rp1vec_hwmodes[mode_family][mode_ilaced][mode_narrow]; ++ dev_info(&vec->pdev->dev, ++ "%s: in_fmt=\'%c%c%c%c\' mode=%dx%d%s [%d%d%d] tvstd=%d (%s)", ++ __func__, in_format, in_format >> 8, in_format >> 16, in_format >> 24, ++ mode->hdisplay, mode->vdisplay, (mode_ilaced) ? "i" : "", ++ mode_family, mode_ilaced, mode_narrow, ++ tvstd, rp1vec_tvstd_names[tvstd]); ++ ++ w = mode->hdisplay; ++ h = mode->vdisplay; ++ if (mode_ilaced) ++ h >>= 1; ++ if (w > hwm->total_cols) ++ w = hwm->total_cols; ++ if (h > hwm->rows_per_field) ++ w = hwm->rows_per_field; ++ ++ /* Configure the hardware */ ++ VEC_WRITE(VEC_APB_TIMEOUT, 0x38); ++ VEC_WRITE(VEC_QOS, ++ BITS(VEC_QOS_DQOS, 0x0) | ++ BITS(VEC_QOS_ULEV, 0x8) | ++ BITS(VEC_QOS_UQOS, 0x2) | ++ BITS(VEC_QOS_LLEV, 0x4) | ++ BITS(VEC_QOS_LQOS, 0x7)); ++ VEC_WRITE(VEC_DMA_AREA, ++ BITS(VEC_DMA_AREA_COLS_MINUS1, w - 1) | ++ BITS(VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1, h - 1)); ++ VEC_WRITE(VEC_YUV_SCALING, hwm->yuv_scaling); ++ VEC_WRITE(VEC_BACK_PORCH, ++ BITS(VEC_BACK_PORCH_HBP_MINUS1, (hwm->total_cols - w - 1) >> 1) | ++ BITS(VEC_BACK_PORCH_VBP_MINUS1, (hwm->rows_per_field - h - 1) >> 1)); ++ VEC_WRITE(VEC_FRONT_PORCH, ++ BITS(VEC_FRONT_PORCH_HFP_MINUS1, (hwm->total_cols - w - 2) >> 1) | ++ BITS(VEC_FRONT_PORCH_VFP_MINUS1, (hwm->rows_per_field - h - 2) >> 1)); ++ VEC_WRITE(VEC_MODE, ++ BITS(VEC_MODE_HIGH_WATER, 0xE0) | ++ BITS(VEC_MODE_ALIGN16, !((w | mode->hdisplay) & 15)) | ++ BITS(VEC_MODE_VFP_EN, (hwm->rows_per_field > h + 1)) | ++ BITS(VEC_MODE_VBP_EN, (hwm->rows_per_field > h)) | ++ BITS(VEC_MODE_HFP_EN, (hwm->total_cols > w + 1)) | ++ BITS(VEC_MODE_HBP_EN, (hwm->total_cols > w)) | ++ BITS(VEC_MODE_FIELDS_PER_FRAME_MINUS1, hwm->interlaced) | ++ BITS(VEC_MODE_FIRST_FIELD_ODD, hwm->first_field_odd)); ++ for (i = 0; i < ARRAY_SIZE(hwm->back_end_regs); ++i) { ++ writel(hwm->back_end_regs[i], ++ vec->hw_base[RP1VEC_HW_BLOCK_VEC] + 0x80 + 4 * i); ++ } ++ ++ /* Apply modifications */ ++ if (tvstd == RP1VEC_TVSTD_NTSC_J && mode_family == 0) { ++ /* Reduce pedestal (not quite to zero, for FIR overshoot); increase gain */ ++ VEC_WRITE(VEC_DAC_BC, ++ BITS(VEC_DAC_BC_S11_PEDESTAL, 10) | ++ (hwm->back_end_regs[(0xBC - 0x80) / 4] & ~VEC_DAC_BC_S11_PEDESTAL_BITS)); ++ VEC_WRITE(VEC_DAC_C8, ++ BITS(VEC_DAC_C8_U16_SCALE_LUMA, 0x9400) | ++ (hwm->back_end_regs[(0xC8 - 0x80) / 4] & ++ ~VEC_DAC_C8_U16_SCALE_LUMA_BITS)); ++ } else if ((tvstd == RP1VEC_TVSTD_NTSC_443 || tvstd == RP1VEC_TVSTD_PAL60) && ++ mode_family != 1) { ++ /* Change colour carrier frequency to 4433618.75 Hz; disable hard sync */ ++ VEC_WRITE(VEC_DAC_D4, 0xcc48c1d1); ++ VEC_WRITE(VEC_DAC_D8, 0x0a8262b2); ++ VEC_WRITE(VEC_DAC_EC, ++ hwm->back_end_regs[(0xEC - 0x80) / 4] & ~VEC_DAC_EC_SEQ_EN_BITS); ++ } else if (tvstd == RP1VEC_TVSTD_PAL_N && mode_family == 1) { ++ /* Change colour carrier frequency to 3582056.25 Hz */ ++ VEC_WRITE(VEC_DAC_D4, 0x9ce075f7); ++ VEC_WRITE(VEC_DAC_D8, 0x087da511); ++ } ++ ++ /* Input pixel format conversion */ ++ for (i = 0; i < ARRAY_SIZE(my_formats); ++i) { ++ if (my_formats[i].format == in_format) ++ break; ++ } ++ if (i >= ARRAY_SIZE(my_formats)) { ++ dev_err(&vec->pdev->dev, "%s: bad input format\n", __func__); ++ i = 0; ++ } ++ VEC_WRITE(VEC_IMASK, my_formats[i].mask); ++ VEC_WRITE(VEC_SHIFT, my_formats[i].shift); ++ VEC_WRITE(VEC_RGBSZ, my_formats[i].rgbsz); ++ ++ VEC_WRITE(VEC_IRQ_FLAGS, 0xffffffff); ++ rp1vec_hw_vblank_ctrl(vec, 1); ++ ++ i = rp1vec_hw_busy(vec); ++ if (i) ++ dev_warn(&vec->pdev->dev, ++ "%s: VEC unexpectedly busy at start (0x%08x)", ++ __func__, VEC_READ(VEC_STATUS)); ++ ++ VEC_WRITE(VEC_CONTROL, ++ BITS(VEC_CONTROL_START_ARM, (!i)) | ++ BITS(VEC_CONTROL_AUTO_REPEAT, 1)); ++} ++ ++void rp1vec_hw_update(struct rp1_vec *vec, dma_addr_t addr, u32 offset, u32 stride) ++{ ++ /* ++ * Update STRIDE, DMAH and DMAL only. When called after rp1vec_hw_setup(), ++ * DMA starts immediately; if already running, the buffer will flip at ++ * the next vertical sync event. ++ */ ++ u64 a = addr + offset; ++ ++ VEC_WRITE(VEC_DMA_STRIDE, stride); ++ VEC_WRITE(VEC_DMA_ADDR_H, a >> 32); ++ VEC_WRITE(VEC_DMA_ADDR_L, a & 0xFFFFFFFFu); ++} ++ ++void rp1vec_hw_stop(struct rp1_vec *vec) ++{ ++ /* ++ * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for ++ * the current and any queued frame to end. "Force drain" flags are not used, ++ * as they seem to prevent DMA from re-starting properly; it's safer to wait. ++ */ ++ ++ reinit_completion(&vec->finished); ++ VEC_WRITE(VEC_CONTROL, 0); ++ if (!wait_for_completion_timeout(&vec->finished, HZ / 10)) ++ drm_err(vec->drm, "%s: timed out waiting for idle\n", __func__); ++ VEC_WRITE(VEC_IRQ_ENABLES, 0); ++} ++ ++void rp1vec_hw_vblank_ctrl(struct rp1_vec *vec, int enable) ++{ ++ VEC_WRITE(VEC_IRQ_ENABLES, ++ BITS(VEC_IRQ_ENABLES_DONE, 1) | ++ BITS(VEC_IRQ_ENABLES_DMA, (enable ? 1 : 0)) | ++ BITS(VEC_IRQ_ENABLES_MATCH_ROW, 1023)); ++} ++ ++irqreturn_t rp1vec_hw_isr(int irq, void *dev) ++{ ++ struct rp1_vec *vec = dev; ++ u32 u = VEC_READ(VEC_IRQ_FLAGS); ++ ++ if (u) { ++ VEC_WRITE(VEC_IRQ_FLAGS, u); ++ if (u & VEC_IRQ_FLAGS_DMA_BITS) ++ drm_crtc_handle_vblank(&vec->pipe.crtc); ++ if (u & VEC_IRQ_FLAGS_DONE_BITS) ++ complete(&vec->finished); ++ } ++ return u ? IRQ_HANDLED : IRQ_NONE; ++} +--- /dev/null ++++ b/drivers/gpu/drm/rp1/rp1-vec/vec_regs.h +@@ -0,0 +1,1420 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++// ============================================================================= ++// Copyright Raspberry Pi Ltd. 2023 ++// vrbuild version: 56aac1a23c016cbbd229108f3b6efc1343842156-clean ++// THIS FILE IS GENERATED BY VRBUILD - DO NOT EDIT ++// ============================================================================= ++// Register block : VEC ++// Version : 1 ++// Bus type : apb ++// Description : None ++// ============================================================================= ++#ifndef VEC_REGS_DEFINED ++#define VEC_REGS_DEFINED ++#define VEC_REGS_RWTYPE_MSB 13 ++#define VEC_REGS_RWTYPE_LSB 12 ++// ============================================================================= ++// Register : VEC_CONTROL ++// JTAG access : synchronous ++// Description : None ++#define VEC_CONTROL_OFFSET 0x00000000 ++#define VEC_CONTROL_BITS 0x00000007 ++#define VEC_CONTROL_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_CONTROL_BARS ++// Description : Write '1' to display colour bar test pattern ++#define VEC_CONTROL_BARS_RESET 0x0 ++#define VEC_CONTROL_BARS_BITS 0x00000004 ++#define VEC_CONTROL_BARS_MSB 2 ++#define VEC_CONTROL_BARS_LSB 2 ++#define VEC_CONTROL_BARS_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_CONTROL_AUTO_REPEAT ++// Description : Write '1' to re-display same frame continuously ++#define VEC_CONTROL_AUTO_REPEAT_RESET 0x0 ++#define VEC_CONTROL_AUTO_REPEAT_BITS 0x00000002 ++#define VEC_CONTROL_AUTO_REPEAT_MSB 1 ++#define VEC_CONTROL_AUTO_REPEAT_LSB 1 ++#define VEC_CONTROL_AUTO_REPEAT_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_CONTROL_START_ARM ++// Description : Write '1' before first DMA address is written This bit always ++// reads back as '0' ++#define VEC_CONTROL_START_ARM_RESET 0x0 ++#define VEC_CONTROL_START_ARM_BITS 0x00000001 ++#define VEC_CONTROL_START_ARM_MSB 0 ++#define VEC_CONTROL_START_ARM_LSB 0 ++#define VEC_CONTROL_START_ARM_ACCESS "SC" ++// ============================================================================= ++// Register : VEC_IRQ_ENABLES ++// JTAG access : synchronous ++// Description : None ++#define VEC_IRQ_ENABLES_OFFSET 0x00000004 ++#define VEC_IRQ_ENABLES_BITS 0x03ff003f ++#define VEC_IRQ_ENABLES_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_MATCH_ROW ++// Description : Raster line at which MATCH interrupt is signalled ++#define VEC_IRQ_ENABLES_MATCH_ROW_RESET 0x000 ++#define VEC_IRQ_ENABLES_MATCH_ROW_BITS 0x03ff0000 ++#define VEC_IRQ_ENABLES_MATCH_ROW_MSB 25 ++#define VEC_IRQ_ENABLES_MATCH_ROW_LSB 16 ++#define VEC_IRQ_ENABLES_MATCH_ROW_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_MATCH ++// Description : Output raster == match_row reached ++#define VEC_IRQ_ENABLES_MATCH_RESET 0x0 ++#define VEC_IRQ_ENABLES_MATCH_BITS 0x00000020 ++#define VEC_IRQ_ENABLES_MATCH_MSB 5 ++#define VEC_IRQ_ENABLES_MATCH_LSB 5 ++#define VEC_IRQ_ENABLES_MATCH_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_ERROR ++// Description : DMA address overwritten before it was taken ++#define VEC_IRQ_ENABLES_ERROR_RESET 0x0 ++#define VEC_IRQ_ENABLES_ERROR_BITS 0x00000010 ++#define VEC_IRQ_ENABLES_ERROR_MSB 4 ++#define VEC_IRQ_ENABLES_ERROR_LSB 4 ++#define VEC_IRQ_ENABLES_ERROR_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_DONE ++// Description : Last word sent to DAC after end of video (= all clear) ++#define VEC_IRQ_ENABLES_DONE_RESET 0x0 ++#define VEC_IRQ_ENABLES_DONE_BITS 0x00000008 ++#define VEC_IRQ_ENABLES_DONE_MSB 3 ++#define VEC_IRQ_ENABLES_DONE_LSB 3 ++#define VEC_IRQ_ENABLES_DONE_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_FRAME ++// Description : Start of frame ++#define VEC_IRQ_ENABLES_FRAME_RESET 0x0 ++#define VEC_IRQ_ENABLES_FRAME_BITS 0x00000004 ++#define VEC_IRQ_ENABLES_FRAME_MSB 2 ++#define VEC_IRQ_ENABLES_FRAME_LSB 2 ++#define VEC_IRQ_ENABLES_FRAME_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_UNDERFLOW ++// Description : Underflow has occurred ++#define VEC_IRQ_ENABLES_UNDERFLOW_RESET 0x0 ++#define VEC_IRQ_ENABLES_UNDERFLOW_BITS 0x00000002 ++#define VEC_IRQ_ENABLES_UNDERFLOW_MSB 1 ++#define VEC_IRQ_ENABLES_UNDERFLOW_LSB 1 ++#define VEC_IRQ_ENABLES_UNDERFLOW_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_ENABLES_DMA ++// Description : DMA ready to accept next frame start address ++#define VEC_IRQ_ENABLES_DMA_RESET 0x0 ++#define VEC_IRQ_ENABLES_DMA_BITS 0x00000001 ++#define VEC_IRQ_ENABLES_DMA_MSB 0 ++#define VEC_IRQ_ENABLES_DMA_LSB 0 ++#define VEC_IRQ_ENABLES_DMA_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_IRQ_FLAGS ++// JTAG access : synchronous ++// Description : None ++#define VEC_IRQ_FLAGS_OFFSET 0x00000008 ++#define VEC_IRQ_FLAGS_BITS 0x0000003f ++#define VEC_IRQ_FLAGS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_MATCH ++// Description : Output raster == match_row reached ++#define VEC_IRQ_FLAGS_MATCH_RESET 0x0 ++#define VEC_IRQ_FLAGS_MATCH_BITS 0x00000020 ++#define VEC_IRQ_FLAGS_MATCH_MSB 5 ++#define VEC_IRQ_FLAGS_MATCH_LSB 5 ++#define VEC_IRQ_FLAGS_MATCH_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_ERROR ++// Description : DMA address overwritten before it was taken ++#define VEC_IRQ_FLAGS_ERROR_RESET 0x0 ++#define VEC_IRQ_FLAGS_ERROR_BITS 0x00000010 ++#define VEC_IRQ_FLAGS_ERROR_MSB 4 ++#define VEC_IRQ_FLAGS_ERROR_LSB 4 ++#define VEC_IRQ_FLAGS_ERROR_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_DONE ++// Description : Last word sent to DAC after end of video (= all clear) ++#define VEC_IRQ_FLAGS_DONE_RESET 0x0 ++#define VEC_IRQ_FLAGS_DONE_BITS 0x00000008 ++#define VEC_IRQ_FLAGS_DONE_MSB 3 ++#define VEC_IRQ_FLAGS_DONE_LSB 3 ++#define VEC_IRQ_FLAGS_DONE_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_FRAME ++// Description : Start of frame ++#define VEC_IRQ_FLAGS_FRAME_RESET 0x0 ++#define VEC_IRQ_FLAGS_FRAME_BITS 0x00000004 ++#define VEC_IRQ_FLAGS_FRAME_MSB 2 ++#define VEC_IRQ_FLAGS_FRAME_LSB 2 ++#define VEC_IRQ_FLAGS_FRAME_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_UNDERFLOW ++// Description : Underflow has occurred ++#define VEC_IRQ_FLAGS_UNDERFLOW_RESET 0x0 ++#define VEC_IRQ_FLAGS_UNDERFLOW_BITS 0x00000002 ++#define VEC_IRQ_FLAGS_UNDERFLOW_MSB 1 ++#define VEC_IRQ_FLAGS_UNDERFLOW_LSB 1 ++#define VEC_IRQ_FLAGS_UNDERFLOW_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IRQ_FLAGS_DMA ++// Description : DMA ready to accept next frame start address ++#define VEC_IRQ_FLAGS_DMA_RESET 0x0 ++#define VEC_IRQ_FLAGS_DMA_BITS 0x00000001 ++#define VEC_IRQ_FLAGS_DMA_MSB 0 ++#define VEC_IRQ_FLAGS_DMA_LSB 0 ++#define VEC_IRQ_FLAGS_DMA_ACCESS "WC" ++// ============================================================================= ++// Register : VEC_QOS ++// JTAG access : synchronous ++// Description : This register configures panic levels for the AXI ar_qos ++// quality of service field. Panic status is driven by the number ++// of rows held in the SRAM cache: ++#define VEC_QOS_OFFSET 0x0000000c ++#define VEC_QOS_BITS 0x000fffff ++#define VEC_QOS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_UQOS ++// Description : Upper AXI QOS ++#define VEC_QOS_UQOS_RESET 0x0 ++#define VEC_QOS_UQOS_BITS 0x000f0000 ++#define VEC_QOS_UQOS_MSB 19 ++#define VEC_QOS_UQOS_LSB 16 ++#define VEC_QOS_UQOS_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_ULEV ++// Description : Upper trip level (resolution = 1 / 16 of cache size) ++#define VEC_QOS_ULEV_RESET 0x0 ++#define VEC_QOS_ULEV_BITS 0x0000f000 ++#define VEC_QOS_ULEV_MSB 15 ++#define VEC_QOS_ULEV_LSB 12 ++#define VEC_QOS_ULEV_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_LQOS ++// Description : Lower AXI QOS ++#define VEC_QOS_LQOS_RESET 0x0 ++#define VEC_QOS_LQOS_BITS 0x00000f00 ++#define VEC_QOS_LQOS_MSB 11 ++#define VEC_QOS_LQOS_LSB 8 ++#define VEC_QOS_LQOS_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_LLEV ++// Description : Lower trip level (resolution = 1 / 16 of cache size) ++#define VEC_QOS_LLEV_RESET 0x0 ++#define VEC_QOS_LLEV_BITS 0x000000f0 ++#define VEC_QOS_LLEV_MSB 7 ++#define VEC_QOS_LLEV_LSB 4 ++#define VEC_QOS_LLEV_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_QOS_DQOS ++// Description : Default QOS ++#define VEC_QOS_DQOS_RESET 0x0 ++#define VEC_QOS_DQOS_BITS 0x0000000f ++#define VEC_QOS_DQOS_MSB 3 ++#define VEC_QOS_DQOS_LSB 0 ++#define VEC_QOS_DQOS_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DMA_ADDR_L ++// JTAG access : synchronous ++// Description : Lower 32-bits ++#define VEC_DMA_ADDR_L_OFFSET 0x00000010 ++#define VEC_DMA_ADDR_L_BITS 0xffffffff ++#define VEC_DMA_ADDR_L_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_ADDR_L_AXI_ADDR ++// Description : Byte address of DMA transfer frame buffer. ++#define VEC_DMA_ADDR_L_AXI_ADDR_RESET 0x00000000 ++#define VEC_DMA_ADDR_L_AXI_ADDR_BITS 0xffffffff ++#define VEC_DMA_ADDR_L_AXI_ADDR_MSB 31 ++#define VEC_DMA_ADDR_L_AXI_ADDR_LSB 0 ++#define VEC_DMA_ADDR_L_AXI_ADDR_ACCESS "RWF" ++// ============================================================================= ++// Register : VEC_DMA_STRIDE ++// JTAG access : synchronous ++// Description : This register sets the line byte stride. ++#define VEC_DMA_STRIDE_OFFSET 0x00000014 ++#define VEC_DMA_STRIDE_BITS 0xffffffff ++#define VEC_DMA_STRIDE_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_STRIDE_STRIDE ++// Description : Byte stride ++#define VEC_DMA_STRIDE_STRIDE_RESET 0x00000000 ++#define VEC_DMA_STRIDE_STRIDE_BITS 0xffffffff ++#define VEC_DMA_STRIDE_STRIDE_MSB 31 ++#define VEC_DMA_STRIDE_STRIDE_LSB 0 ++#define VEC_DMA_STRIDE_STRIDE_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DMA_AREA ++// JTAG access : synchronous ++// Description : Interlaced pixel area. See example driver code. ++#define VEC_DMA_AREA_OFFSET 0x00000018 ++#define VEC_DMA_AREA_BITS 0x03ff03ff ++#define VEC_DMA_AREA_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_AREA_COLS_MINUS1 ++// Description : Width ++#define VEC_DMA_AREA_COLS_MINUS1_RESET 0x000 ++#define VEC_DMA_AREA_COLS_MINUS1_BITS 0x03ff0000 ++#define VEC_DMA_AREA_COLS_MINUS1_MSB 25 ++#define VEC_DMA_AREA_COLS_MINUS1_LSB 16 ++#define VEC_DMA_AREA_COLS_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1 ++// Description : Lines per field = half of lines per interlaced frame ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_RESET 0x000 ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_BITS 0x000003ff ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_MSB 9 ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_LSB 0 ++#define VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_YUV_SCALING ++// JTAG access : synchronous ++// Description : None ++#define VEC_YUV_SCALING_OFFSET 0x0000001c ++#define VEC_YUV_SCALING_BITS 0x3fffffff ++#define VEC_YUV_SCALING_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_YUV_SCALING_U10_SCALE_Y ++// Description : Y unsigned scaling factor - 8 binary places ++#define VEC_YUV_SCALING_U10_SCALE_Y_RESET 0x000 ++#define VEC_YUV_SCALING_U10_SCALE_Y_BITS 0x3ff00000 ++#define VEC_YUV_SCALING_U10_SCALE_Y_MSB 29 ++#define VEC_YUV_SCALING_U10_SCALE_Y_LSB 20 ++#define VEC_YUV_SCALING_U10_SCALE_Y_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_YUV_SCALING_S10_SCALE_U ++// Description : U signed scaling factor - 8 binary places ++#define VEC_YUV_SCALING_S10_SCALE_U_RESET 0x000 ++#define VEC_YUV_SCALING_S10_SCALE_U_BITS 0x000ffc00 ++#define VEC_YUV_SCALING_S10_SCALE_U_MSB 19 ++#define VEC_YUV_SCALING_S10_SCALE_U_LSB 10 ++#define VEC_YUV_SCALING_S10_SCALE_U_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_YUV_SCALING_S10_SCALE_V ++// Description : V signed scaling factor - 8 binary please ++#define VEC_YUV_SCALING_S10_SCALE_V_RESET 0x000 ++#define VEC_YUV_SCALING_S10_SCALE_V_BITS 0x000003ff ++#define VEC_YUV_SCALING_S10_SCALE_V_MSB 9 ++#define VEC_YUV_SCALING_S10_SCALE_V_LSB 0 ++#define VEC_YUV_SCALING_S10_SCALE_V_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_BACK_PORCH ++// JTAG access : synchronous ++// Description : None ++#define VEC_BACK_PORCH_OFFSET 0x00000020 ++#define VEC_BACK_PORCH_BITS 0x03ff03ff ++#define VEC_BACK_PORCH_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_BACK_PORCH_HBP_MINUS1 ++// Description : Horizontal back porch ++#define VEC_BACK_PORCH_HBP_MINUS1_RESET 0x000 ++#define VEC_BACK_PORCH_HBP_MINUS1_BITS 0x03ff0000 ++#define VEC_BACK_PORCH_HBP_MINUS1_MSB 25 ++#define VEC_BACK_PORCH_HBP_MINUS1_LSB 16 ++#define VEC_BACK_PORCH_HBP_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_BACK_PORCH_VBP_MINUS1 ++// Description : Vertical back porch ++#define VEC_BACK_PORCH_VBP_MINUS1_RESET 0x000 ++#define VEC_BACK_PORCH_VBP_MINUS1_BITS 0x000003ff ++#define VEC_BACK_PORCH_VBP_MINUS1_MSB 9 ++#define VEC_BACK_PORCH_VBP_MINUS1_LSB 0 ++#define VEC_BACK_PORCH_VBP_MINUS1_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_FRONT_PORCH ++// JTAG access : synchronous ++// Description : None ++#define VEC_FRONT_PORCH_OFFSET 0x00000024 ++#define VEC_FRONT_PORCH_BITS 0x03ff03ff ++#define VEC_FRONT_PORCH_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_FRONT_PORCH_HFP_MINUS1 ++// Description : Horizontal front porch ++#define VEC_FRONT_PORCH_HFP_MINUS1_RESET 0x000 ++#define VEC_FRONT_PORCH_HFP_MINUS1_BITS 0x03ff0000 ++#define VEC_FRONT_PORCH_HFP_MINUS1_MSB 25 ++#define VEC_FRONT_PORCH_HFP_MINUS1_LSB 16 ++#define VEC_FRONT_PORCH_HFP_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_FRONT_PORCH_VFP_MINUS1 ++// Description : Vertical front porch ++#define VEC_FRONT_PORCH_VFP_MINUS1_RESET 0x000 ++#define VEC_FRONT_PORCH_VFP_MINUS1_BITS 0x000003ff ++#define VEC_FRONT_PORCH_VFP_MINUS1_MSB 9 ++#define VEC_FRONT_PORCH_VFP_MINUS1_LSB 0 ++#define VEC_FRONT_PORCH_VFP_MINUS1_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_SHIFT ++// JTAG access : synchronous ++// Description : Positions of R,G,B MS bits in the memory word. Note: due to an ++// unintended red/blue swap, these fields have been renamed since ++// a previous version. There is no functional change. ++#define VEC_SHIFT_OFFSET 0x00000028 ++#define VEC_SHIFT_BITS 0x00007fff ++#define VEC_SHIFT_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_SHIFT_SHIFT_R ++// Description : Red MSB ++#define VEC_SHIFT_SHIFT_R_RESET 0x00 ++#define VEC_SHIFT_SHIFT_R_BITS 0x00007c00 ++#define VEC_SHIFT_SHIFT_R_MSB 14 ++#define VEC_SHIFT_SHIFT_R_LSB 10 ++#define VEC_SHIFT_SHIFT_R_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_SHIFT_SHIFT_G ++// Description : Green MSB ++#define VEC_SHIFT_SHIFT_G_RESET 0x00 ++#define VEC_SHIFT_SHIFT_G_BITS 0x000003e0 ++#define VEC_SHIFT_SHIFT_G_MSB 9 ++#define VEC_SHIFT_SHIFT_G_LSB 5 ++#define VEC_SHIFT_SHIFT_G_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_SHIFT_SHIFT_B ++// Description : Blue MSB ++#define VEC_SHIFT_SHIFT_B_RESET 0x00 ++#define VEC_SHIFT_SHIFT_B_BITS 0x0000001f ++#define VEC_SHIFT_SHIFT_B_MSB 4 ++#define VEC_SHIFT_SHIFT_B_LSB 0 ++#define VEC_SHIFT_SHIFT_B_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_IMASK ++// JTAG access : synchronous ++// Description : Masks for R,G,B significant bits, left-justified within 10-bit ++// fields. ++#define VEC_IMASK_OFFSET 0x0000002c ++#define VEC_IMASK_BITS 0x3fffffff ++#define VEC_IMASK_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_IMASK_MASK_R ++// Description : Red mask ++#define VEC_IMASK_MASK_R_RESET 0x000 ++#define VEC_IMASK_MASK_R_BITS 0x3ff00000 ++#define VEC_IMASK_MASK_R_MSB 29 ++#define VEC_IMASK_MASK_R_LSB 20 ++#define VEC_IMASK_MASK_R_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IMASK_MASK_G ++// Description : Green mask ++#define VEC_IMASK_MASK_G_RESET 0x000 ++#define VEC_IMASK_MASK_G_BITS 0x000ffc00 ++#define VEC_IMASK_MASK_G_MSB 19 ++#define VEC_IMASK_MASK_G_LSB 10 ++#define VEC_IMASK_MASK_G_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_IMASK_MASK_B ++// Description : Blue mask ++#define VEC_IMASK_MASK_B_RESET 0x000 ++#define VEC_IMASK_MASK_B_BITS 0x000003ff ++#define VEC_IMASK_MASK_B_MSB 9 ++#define VEC_IMASK_MASK_B_LSB 0 ++#define VEC_IMASK_MASK_B_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_MODE ++// JTAG access : synchronous ++// Description : None ++#define VEC_MODE_OFFSET 0x00000030 ++#define VEC_MODE_BITS 0x01ff003f ++#define VEC_MODE_RESET 0x01c00000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_HIGH_WATER ++// Description : ALWAYS WRITE 8'hE0 ++#define VEC_MODE_HIGH_WATER_RESET 0xe0 ++#define VEC_MODE_HIGH_WATER_BITS 0x01fe0000 ++#define VEC_MODE_HIGH_WATER_MSB 24 ++#define VEC_MODE_HIGH_WATER_LSB 17 ++#define VEC_MODE_HIGH_WATER_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_ALIGN16 ++// Description : Data: 0=BYTE aligned; 1=BEAT aligned ++#define VEC_MODE_ALIGN16_RESET 0x0 ++#define VEC_MODE_ALIGN16_BITS 0x00010000 ++#define VEC_MODE_ALIGN16_MSB 16 ++#define VEC_MODE_ALIGN16_LSB 16 ++#define VEC_MODE_ALIGN16_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_VFP_EN ++// Description : Enable vertical front porch ++#define VEC_MODE_VFP_EN_RESET 0x0 ++#define VEC_MODE_VFP_EN_BITS 0x00000020 ++#define VEC_MODE_VFP_EN_MSB 5 ++#define VEC_MODE_VFP_EN_LSB 5 ++#define VEC_MODE_VFP_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_VBP_EN ++// Description : Enable vertical back porch ++#define VEC_MODE_VBP_EN_RESET 0x0 ++#define VEC_MODE_VBP_EN_BITS 0x00000010 ++#define VEC_MODE_VBP_EN_MSB 4 ++#define VEC_MODE_VBP_EN_LSB 4 ++#define VEC_MODE_VBP_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_HFP_EN ++// Description : Enable horizontal front porch ++#define VEC_MODE_HFP_EN_RESET 0x0 ++#define VEC_MODE_HFP_EN_BITS 0x00000008 ++#define VEC_MODE_HFP_EN_MSB 3 ++#define VEC_MODE_HFP_EN_LSB 3 ++#define VEC_MODE_HFP_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_HBP_EN ++// Description : Enable horizontal back porch ++#define VEC_MODE_HBP_EN_RESET 0x0 ++#define VEC_MODE_HBP_EN_BITS 0x00000004 ++#define VEC_MODE_HBP_EN_MSB 2 ++#define VEC_MODE_HBP_EN_LSB 2 ++#define VEC_MODE_HBP_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_FIELDS_PER_FRAME_MINUS1 ++// Description : Interlaced / progressive ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_RESET 0x0 ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_BITS 0x00000002 ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_MSB 1 ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_LSB 1 ++#define VEC_MODE_FIELDS_PER_FRAME_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_MODE_FIRST_FIELD_ODD ++// Description : Interlacing order: odd/even or even/odd ++#define VEC_MODE_FIRST_FIELD_ODD_RESET 0x0 ++#define VEC_MODE_FIRST_FIELD_ODD_BITS 0x00000001 ++#define VEC_MODE_FIRST_FIELD_ODD_MSB 0 ++#define VEC_MODE_FIRST_FIELD_ODD_LSB 0 ++#define VEC_MODE_FIRST_FIELD_ODD_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_RGBSZ ++// JTAG access : synchronous ++// Description : None ++#define VEC_RGBSZ_OFFSET 0x00000034 ++#define VEC_RGBSZ_BITS 0x00030fff ++#define VEC_RGBSZ_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1 ++// Description : Pixel stride ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_RESET 0x0 ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_BITS 0x00030000 ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_MSB 17 ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_LSB 16 ++#define VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_RGBSZ_SCALE_R ++// Description : Red number of bits for shift-and-OR scaling ++#define VEC_RGBSZ_SCALE_R_RESET 0x0 ++#define VEC_RGBSZ_SCALE_R_BITS 0x00000f00 ++#define VEC_RGBSZ_SCALE_R_MSB 11 ++#define VEC_RGBSZ_SCALE_R_LSB 8 ++#define VEC_RGBSZ_SCALE_R_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_RGBSZ_SCALE_G ++// Description : Green number of bits for shift-and-OR scaling ++#define VEC_RGBSZ_SCALE_G_RESET 0x0 ++#define VEC_RGBSZ_SCALE_G_BITS 0x000000f0 ++#define VEC_RGBSZ_SCALE_G_MSB 7 ++#define VEC_RGBSZ_SCALE_G_LSB 4 ++#define VEC_RGBSZ_SCALE_G_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_RGBSZ_SCALE_B ++// Description : Blue number of bits for shift-and-OR scaling ++#define VEC_RGBSZ_SCALE_B_RESET 0x0 ++#define VEC_RGBSZ_SCALE_B_BITS 0x0000000f ++#define VEC_RGBSZ_SCALE_B_MSB 3 ++#define VEC_RGBSZ_SCALE_B_LSB 0 ++#define VEC_RGBSZ_SCALE_B_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_PANICS ++// JTAG access : synchronous ++// Description : None ++#define VEC_PANICS_OFFSET 0x00000038 ++#define VEC_PANICS_BITS 0xffffffff ++#define VEC_PANICS_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_PANICS_UCOUNT ++// Description : Upper panic count ++#define VEC_PANICS_UCOUNT_RESET 0x0000 ++#define VEC_PANICS_UCOUNT_BITS 0xffff0000 ++#define VEC_PANICS_UCOUNT_MSB 31 ++#define VEC_PANICS_UCOUNT_LSB 16 ++#define VEC_PANICS_UCOUNT_ACCESS "WC" ++// ----------------------------------------------------------------------------- ++// Field : VEC_PANICS_LCOUNT ++// Description : Lower panic count ++#define VEC_PANICS_LCOUNT_RESET 0x0000 ++#define VEC_PANICS_LCOUNT_BITS 0x0000ffff ++#define VEC_PANICS_LCOUNT_MSB 15 ++#define VEC_PANICS_LCOUNT_LSB 0 ++#define VEC_PANICS_LCOUNT_ACCESS "WC" ++// ============================================================================= ++// Register : VEC_STATUS ++// JTAG access : synchronous ++// Description : None ++#define VEC_STATUS_OFFSET 0x0000003c ++#define VEC_STATUS_BITS 0xff000000 ++#define VEC_STATUS_RESET 0x0d000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_STATUS_VERSION ++// Description : VEC module version code ++#define VEC_STATUS_VERSION_RESET 0x0d ++#define VEC_STATUS_VERSION_BITS 0xff000000 ++#define VEC_STATUS_VERSION_MSB 31 ++#define VEC_STATUS_VERSION_LSB 24 ++#define VEC_STATUS_VERSION_ACCESS "RO" ++// ============================================================================= ++// Register : VEC_DMA_ADDR_H ++// JTAG access : synchronous ++// Description : Upper 32-bits ++#define VEC_DMA_ADDR_H_OFFSET 0x00000040 ++#define VEC_DMA_ADDR_H_BITS 0xffffffff ++#define VEC_DMA_ADDR_H_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DMA_ADDR_H_AXI_ADDR ++// Description : Byte address of DMA transfer frame buffer. ++#define VEC_DMA_ADDR_H_AXI_ADDR_RESET 0x00000000 ++#define VEC_DMA_ADDR_H_AXI_ADDR_BITS 0xffffffff ++#define VEC_DMA_ADDR_H_AXI_ADDR_MSB 31 ++#define VEC_DMA_ADDR_H_AXI_ADDR_LSB 0 ++#define VEC_DMA_ADDR_H_AXI_ADDR_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_BURST_ADDR_L ++// JTAG access : synchronous ++// Description : None ++#define VEC_BURST_ADDR_L_OFFSET 0x00000044 ++#define VEC_BURST_ADDR_L_BITS 0xffffffff ++#define VEC_BURST_ADDR_L_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_BURST_ADDR_L_BURST_ADDR ++// Description : the lower 32-bits of the most recent read request sent to AXI ++// memory. ++#define VEC_BURST_ADDR_L_BURST_ADDR_RESET 0x00000000 ++#define VEC_BURST_ADDR_L_BURST_ADDR_BITS 0xffffffff ++#define VEC_BURST_ADDR_L_BURST_ADDR_MSB 31 ++#define VEC_BURST_ADDR_L_BURST_ADDR_LSB 0 ++#define VEC_BURST_ADDR_L_BURST_ADDR_ACCESS "RO" ++// ============================================================================= ++// Register : VEC_APB_TIMEOUT ++// JTAG access : synchronous ++// Description : None ++#define VEC_APB_TIMEOUT_OFFSET 0x00000048 ++#define VEC_APB_TIMEOUT_BITS 0x000103ff ++#define VEC_APB_TIMEOUT_RESET 0x00000014 ++// ----------------------------------------------------------------------------- ++// Field : VEC_APB_TIMEOUT_SLVERR_EN ++// Description : 1 = Assert PREADY and PSLVERR on timeout 0 = Assert PREADY only ++#define VEC_APB_TIMEOUT_SLVERR_EN_RESET 0x0 ++#define VEC_APB_TIMEOUT_SLVERR_EN_BITS 0x00010000 ++#define VEC_APB_TIMEOUT_SLVERR_EN_MSB 16 ++#define VEC_APB_TIMEOUT_SLVERR_EN_LSB 16 ++#define VEC_APB_TIMEOUT_SLVERR_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_APB_TIMEOUT_TIMEOUT ++// Description : Maximum AXI clock cycles to wait for responses from DAC clock ++// domain APB block ++#define VEC_APB_TIMEOUT_TIMEOUT_RESET 0x014 ++#define VEC_APB_TIMEOUT_TIMEOUT_BITS 0x000003ff ++#define VEC_APB_TIMEOUT_TIMEOUT_MSB 9 ++#define VEC_APB_TIMEOUT_TIMEOUT_LSB 0 ++#define VEC_APB_TIMEOUT_TIMEOUT_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_80 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_80_OFFSET 0x00000080 ++#define VEC_DAC_80_BITS 0x3fff3fff ++#define VEC_DAC_80_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_80_U14_DE_BGN ++// Description : Beginning of active data enable within each visible line ++#define VEC_DAC_80_U14_DE_BGN_RESET 0x0000 ++#define VEC_DAC_80_U14_DE_BGN_BITS 0x3fff0000 ++#define VEC_DAC_80_U14_DE_BGN_MSB 29 ++#define VEC_DAC_80_U14_DE_BGN_LSB 16 ++#define VEC_DAC_80_U14_DE_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_80_U14_DE_END ++// Description : End of active data enable within each visible line ++#define VEC_DAC_80_U14_DE_END_RESET 0x0000 ++#define VEC_DAC_80_U14_DE_END_BITS 0x00003fff ++#define VEC_DAC_80_U14_DE_END_MSB 13 ++#define VEC_DAC_80_U14_DE_END_LSB 0 ++#define VEC_DAC_80_U14_DE_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_84 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_84_OFFSET 0x00000084 ++#define VEC_DAC_84_BITS 0x1fff1fff ++#define VEC_DAC_84_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_84_U13_ACTIVE_RISE ++// Description : Horizontal blanking interval ++#define VEC_DAC_84_U13_ACTIVE_RISE_RESET 0x0000 ++#define VEC_DAC_84_U13_ACTIVE_RISE_BITS 0x1fff0000 ++#define VEC_DAC_84_U13_ACTIVE_RISE_MSB 28 ++#define VEC_DAC_84_U13_ACTIVE_RISE_LSB 16 ++#define VEC_DAC_84_U13_ACTIVE_RISE_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_84_U13_ACTIVE_FALL ++// Description : Horizontal blanking interval ++#define VEC_DAC_84_U13_ACTIVE_FALL_RESET 0x0000 ++#define VEC_DAC_84_U13_ACTIVE_FALL_BITS 0x00001fff ++#define VEC_DAC_84_U13_ACTIVE_FALL_MSB 12 ++#define VEC_DAC_84_U13_ACTIVE_FALL_LSB 0 ++#define VEC_DAC_84_U13_ACTIVE_FALL_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_88 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_88_OFFSET 0x00000088 ++#define VEC_DAC_88_BITS 0x1fff1fff ++#define VEC_DAC_88_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_88_U13_HALF_LINE_PERIOD ++// Description : Ratio of DAC clock to horizontal line rate, halved ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_RESET 0x0000 ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_BITS 0x1fff0000 ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_MSB 28 ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_LSB 16 ++#define VEC_DAC_88_U13_HALF_LINE_PERIOD_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_88_U13_HORZ_SYNC ++// Description : Width of horizontal sync pulses ++#define VEC_DAC_88_U13_HORZ_SYNC_RESET 0x0000 ++#define VEC_DAC_88_U13_HORZ_SYNC_BITS 0x00001fff ++#define VEC_DAC_88_U13_HORZ_SYNC_MSB 12 ++#define VEC_DAC_88_U13_HORZ_SYNC_LSB 0 ++#define VEC_DAC_88_U13_HORZ_SYNC_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_8C ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_8C_OFFSET 0x0000008c ++#define VEC_DAC_8C_BITS 0x1fff1fff ++#define VEC_DAC_8C_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_8C_U13_BURST_RISE ++// Description : Start of raised-cosine colour burst envelope ++#define VEC_DAC_8C_U13_BURST_RISE_RESET 0x0000 ++#define VEC_DAC_8C_U13_BURST_RISE_BITS 0x1fff0000 ++#define VEC_DAC_8C_U13_BURST_RISE_MSB 28 ++#define VEC_DAC_8C_U13_BURST_RISE_LSB 16 ++#define VEC_DAC_8C_U13_BURST_RISE_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_8C_U13_BURST_FALL ++// Description : End of raised-cosine colour burst envelope ++#define VEC_DAC_8C_U13_BURST_FALL_RESET 0x0000 ++#define VEC_DAC_8C_U13_BURST_FALL_BITS 0x00001fff ++#define VEC_DAC_8C_U13_BURST_FALL_MSB 12 ++#define VEC_DAC_8C_U13_BURST_FALL_LSB 0 ++#define VEC_DAC_8C_U13_BURST_FALL_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_90 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_90_OFFSET 0x00000090 ++#define VEC_DAC_90_BITS 0x1fff3fff ++#define VEC_DAC_90_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_90_U13_VERT_EQ ++// Description : Width of vertical equalisation pulses (= half line minus ++// serration) ++#define VEC_DAC_90_U13_VERT_EQ_RESET 0x0000 ++#define VEC_DAC_90_U13_VERT_EQ_BITS 0x1fff0000 ++#define VEC_DAC_90_U13_VERT_EQ_MSB 28 ++#define VEC_DAC_90_U13_VERT_EQ_LSB 16 ++#define VEC_DAC_90_U13_VERT_EQ_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_90_U14_VERT_SYNC ++// Description : Width of vertical sync pulses ++#define VEC_DAC_90_U14_VERT_SYNC_RESET 0x0000 ++#define VEC_DAC_90_U14_VERT_SYNC_BITS 0x00003fff ++#define VEC_DAC_90_U14_VERT_SYNC_MSB 13 ++#define VEC_DAC_90_U14_VERT_SYNC_LSB 0 ++#define VEC_DAC_90_U14_VERT_SYNC_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_94 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_94_OFFSET 0x00000094 ++#define VEC_DAC_94_BITS 0x03ff03ff ++#define VEC_DAC_94_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_94_U10_PRE_EQ_BGN ++// Description : Half-lines, inclusive, relative to field datum, where vertical ++// pre-equalisation pulses start ++#define VEC_DAC_94_U10_PRE_EQ_BGN_RESET 0x000 ++#define VEC_DAC_94_U10_PRE_EQ_BGN_BITS 0x03ff0000 ++#define VEC_DAC_94_U10_PRE_EQ_BGN_MSB 25 ++#define VEC_DAC_94_U10_PRE_EQ_BGN_LSB 16 ++#define VEC_DAC_94_U10_PRE_EQ_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_94_U10_PRE_EQ_END ++// Description : Half-lines, inclusive, relative to field datum, where vertical ++// pre-equalisation pulses end ++#define VEC_DAC_94_U10_PRE_EQ_END_RESET 0x000 ++#define VEC_DAC_94_U10_PRE_EQ_END_BITS 0x000003ff ++#define VEC_DAC_94_U10_PRE_EQ_END_MSB 9 ++#define VEC_DAC_94_U10_PRE_EQ_END_LSB 0 ++#define VEC_DAC_94_U10_PRE_EQ_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_98 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_98_OFFSET 0x00000098 ++#define VEC_DAC_98_BITS 0x03ff03ff ++#define VEC_DAC_98_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_98_U10_FIELD_SYNC_BGN ++// Description : Half-lines containing vertical sync pulses (inclusive) ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_RESET 0x000 ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_BITS 0x03ff0000 ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_MSB 25 ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_LSB 16 ++#define VEC_DAC_98_U10_FIELD_SYNC_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_98_U10_FIELD_SYNC_END ++// Description : Half-lines containing vertical sync pulses (inclusive) ++#define VEC_DAC_98_U10_FIELD_SYNC_END_RESET 0x000 ++#define VEC_DAC_98_U10_FIELD_SYNC_END_BITS 0x000003ff ++#define VEC_DAC_98_U10_FIELD_SYNC_END_MSB 9 ++#define VEC_DAC_98_U10_FIELD_SYNC_END_LSB 0 ++#define VEC_DAC_98_U10_FIELD_SYNC_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_9C ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_9C_OFFSET 0x0000009c ++#define VEC_DAC_9C_BITS 0x03ff03ff ++#define VEC_DAC_9C_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_9C_U10_POST_EQ_BGN ++// Description : Half-lines containing vertical post-equalisation pulses ++#define VEC_DAC_9C_U10_POST_EQ_BGN_RESET 0x000 ++#define VEC_DAC_9C_U10_POST_EQ_BGN_BITS 0x03ff0000 ++#define VEC_DAC_9C_U10_POST_EQ_BGN_MSB 25 ++#define VEC_DAC_9C_U10_POST_EQ_BGN_LSB 16 ++#define VEC_DAC_9C_U10_POST_EQ_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_9C_U10_POST_EQ_END ++// Description : Half-lines containing vertical post-equalisation pulses ++#define VEC_DAC_9C_U10_POST_EQ_END_RESET 0x000 ++#define VEC_DAC_9C_U10_POST_EQ_END_BITS 0x000003ff ++#define VEC_DAC_9C_U10_POST_EQ_END_MSB 9 ++#define VEC_DAC_9C_U10_POST_EQ_END_LSB 0 ++#define VEC_DAC_9C_U10_POST_EQ_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_A0 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_A0_OFFSET 0x000000a0 ++#define VEC_DAC_A0_BITS 0x03ff03ff ++#define VEC_DAC_A0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A0_U10_FLD1_BURST_BGN ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_RESET 0x000 ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_BITS 0x03ff0000 ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_MSB 25 ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_LSB 16 ++#define VEC_DAC_A0_U10_FLD1_BURST_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A0_U10_FLD1_BURST_END ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A0_U10_FLD1_BURST_END_RESET 0x000 ++#define VEC_DAC_A0_U10_FLD1_BURST_END_BITS 0x000003ff ++#define VEC_DAC_A0_U10_FLD1_BURST_END_MSB 9 ++#define VEC_DAC_A0_U10_FLD1_BURST_END_LSB 0 ++#define VEC_DAC_A0_U10_FLD1_BURST_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_A4 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_A4_OFFSET 0x000000a4 ++#define VEC_DAC_A4_BITS 0x03ff03ff ++#define VEC_DAC_A4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A4_U10_FLD2_BURST_BGN ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_RESET 0x000 ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_BITS 0x03ff0000 ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_MSB 25 ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_LSB 16 ++#define VEC_DAC_A4_U10_FLD2_BURST_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A4_U10_FLD2_BURST_END ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A4_U10_FLD2_BURST_END_RESET 0x000 ++#define VEC_DAC_A4_U10_FLD2_BURST_END_BITS 0x000003ff ++#define VEC_DAC_A4_U10_FLD2_BURST_END_MSB 9 ++#define VEC_DAC_A4_U10_FLD2_BURST_END_LSB 0 ++#define VEC_DAC_A4_U10_FLD2_BURST_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_A8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_A8_OFFSET 0x000000a8 ++#define VEC_DAC_A8_BITS 0x03ff03ff ++#define VEC_DAC_A8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A8_U10_FLD3_BURST_BGN ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_RESET 0x000 ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_BITS 0x03ff0000 ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_MSB 25 ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_LSB 16 ++#define VEC_DAC_A8_U10_FLD3_BURST_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_A8_U10_FLD3_BURST_END ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_A8_U10_FLD3_BURST_END_RESET 0x000 ++#define VEC_DAC_A8_U10_FLD3_BURST_END_BITS 0x000003ff ++#define VEC_DAC_A8_U10_FLD3_BURST_END_MSB 9 ++#define VEC_DAC_A8_U10_FLD3_BURST_END_LSB 0 ++#define VEC_DAC_A8_U10_FLD3_BURST_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_AC ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_AC_OFFSET 0x000000ac ++#define VEC_DAC_AC_BITS 0x03ff03ff ++#define VEC_DAC_AC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_AC_U10_FLD4_BURST_BGN ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_RESET 0x000 ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_BITS 0x03ff0000 ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_MSB 25 ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_LSB 16 ++#define VEC_DAC_AC_U10_FLD4_BURST_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_AC_U10_FLD4_BURST_END ++// Description : First and last full frame lines (1-based numbering) within the ++// PAL/NTSC four field sequence which require a colour burst ++#define VEC_DAC_AC_U10_FLD4_BURST_END_RESET 0x000 ++#define VEC_DAC_AC_U10_FLD4_BURST_END_BITS 0x000003ff ++#define VEC_DAC_AC_U10_FLD4_BURST_END_MSB 9 ++#define VEC_DAC_AC_U10_FLD4_BURST_END_LSB 0 ++#define VEC_DAC_AC_U10_FLD4_BURST_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_B0 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_B0_OFFSET 0x000000b0 ++#define VEC_DAC_B0_BITS 0x03ff03ff ++#define VEC_DAC_B0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN ++// Description : First and last full visible lines (1-based numbering) in the ++// PAL/NTSC four field sequence ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_RESET 0x000 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_BITS 0x03ff0000 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_MSB 25 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_LSB 16 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B0_U10_FLD24_FULL_LINE_END ++// Description : First and last full visible lines (1-based numbering) in the ++// PAL/NTSC four field sequence ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_RESET 0x000 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_BITS 0x000003ff ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_MSB 9 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_LSB 0 ++#define VEC_DAC_B0_U10_FLD24_FULL_LINE_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_B4 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_B4_OFFSET 0x000000b4 ++#define VEC_DAC_B4_BITS 0x03ff03ff ++#define VEC_DAC_B4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN ++// Description : First and last full visible lines (1-based numbering) in the ++// PAL/NTSC four field sequence ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_RESET 0x000 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_BITS 0x03ff0000 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_MSB 25 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_LSB 16 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_BGN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B4_U10_FLD13_FULL_LINE_END ++// Description : First and last full visible lines (1-based numbering) in the ++// PAL/NTSC four field sequence ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_RESET 0x000 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_BITS 0x000003ff ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_MSB 9 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_LSB 0 ++#define VEC_DAC_B4_U10_FLD13_FULL_LINE_END_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_B8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_B8_OFFSET 0x000000b8 ++#define VEC_DAC_B8_BITS 0x03ff03ff ++#define VEC_DAC_B8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B8_U10_BOT_HALF_LINE ++// Description : Top and bottom visible half-lines in 1-based standard full ++// frame numbering, for interlaced modes. Set to zero to disable. ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_RESET 0x000 ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_BITS 0x03ff0000 ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_MSB 25 ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_LSB 16 ++#define VEC_DAC_B8_U10_BOT_HALF_LINE_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_B8_U10_TOP_HALF_LINE ++// Description : Top and bottom visible half-lines in 1-based standard full ++// frame numbering, for interlaced modes. Set to zero to disable. ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_RESET 0x000 ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_BITS 0x000003ff ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_MSB 9 ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_LSB 0 ++#define VEC_DAC_B8_U10_TOP_HALF_LINE_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_BC ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_BC_OFFSET 0x000000bc ++#define VEC_DAC_BC_BITS 0x07ff07ff ++#define VEC_DAC_BC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_BC_S11_PEDESTAL ++// Description : NTSC pedestal. For 7.5 IRE, this field is 1024 * 7.5/100. For ++// PAL, or Japanese NTSC, this field should be zero. ++#define VEC_DAC_BC_S11_PEDESTAL_RESET 0x000 ++#define VEC_DAC_BC_S11_PEDESTAL_BITS 0x07ff0000 ++#define VEC_DAC_BC_S11_PEDESTAL_MSB 26 ++#define VEC_DAC_BC_S11_PEDESTAL_LSB 16 ++#define VEC_DAC_BC_S11_PEDESTAL_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_BC_U11_HALF_LINES_PER_FIELD ++// Description : Mode = 625 PAL, Lines per field = 312.5, ++// u11_half_lines_per_field = 1+2*312 Mode = 525 NTSC, Lines per ++// field = 262.5, u11_half_lines_per_field = 1+2*262 ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_RESET 0x000 ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_BITS 0x000007ff ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_MSB 10 ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_LSB 0 ++#define VEC_DAC_BC_U11_HALF_LINES_PER_FIELD_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_C0 ++// JTAG access : synchronous ++// Description : Synopsis DesignWare control ++#define VEC_DAC_C0_OFFSET 0x000000c0 ++#define VEC_DAC_C0_BITS 0x000fffff ++#define VEC_DAC_C0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_CABLE_ENCTR3 ++// Description : Synopsis test input ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_RESET 0x0 ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_BITS 0x00080000 ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_MSB 19 ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_LSB 19 ++#define VEC_DAC_C0_DWC_CABLE_ENCTR3_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_CABLE_CABLEOUT ++// Description : cable detect state ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_RESET 0x0 ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_BITS 0x00070000 ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_MSB 18 ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_LSB 16 ++#define VEC_DAC_C0_DWC_CABLE_CABLEOUT_ACCESS "RO" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_MUX_2 ++// Description : Select DAC channel 2 output ++#define VEC_DAC_C0_DWC_MUX_2_RESET 0x0 ++#define VEC_DAC_C0_DWC_MUX_2_BITS 0x0000c000 ++#define VEC_DAC_C0_DWC_MUX_2_MSB 15 ++#define VEC_DAC_C0_DWC_MUX_2_LSB 14 ++#define VEC_DAC_C0_DWC_MUX_2_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_MUX_1 ++// Description : Select DAC channel 1 output ++#define VEC_DAC_C0_DWC_MUX_1_RESET 0x0 ++#define VEC_DAC_C0_DWC_MUX_1_BITS 0x00003000 ++#define VEC_DAC_C0_DWC_MUX_1_MSB 13 ++#define VEC_DAC_C0_DWC_MUX_1_LSB 12 ++#define VEC_DAC_C0_DWC_MUX_1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_MUX_0 ++// Description : Select DAC channel 0 output ++#define VEC_DAC_C0_DWC_MUX_0_RESET 0x0 ++#define VEC_DAC_C0_DWC_MUX_0_BITS 0x00000c00 ++#define VEC_DAC_C0_DWC_MUX_0_MSB 11 ++#define VEC_DAC_C0_DWC_MUX_0_LSB 10 ++#define VEC_DAC_C0_DWC_MUX_0_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C0_DWC_TEST ++// Description : Fixed DAC command word ++#define VEC_DAC_C0_DWC_TEST_RESET 0x000 ++#define VEC_DAC_C0_DWC_TEST_BITS 0x000003ff ++#define VEC_DAC_C0_DWC_TEST_MSB 9 ++#define VEC_DAC_C0_DWC_TEST_LSB 0 ++#define VEC_DAC_C0_DWC_TEST_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_C4 ++// JTAG access : synchronous ++// Description : Synopsis DAC control ++#define VEC_DAC_C4_OFFSET 0x000000c4 ++#define VEC_DAC_C4_BITS 0x1fffffff ++#define VEC_DAC_C4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENCTR ++// Description : Always write3'b000 ++#define VEC_DAC_C4_ENCTR_RESET 0x0 ++#define VEC_DAC_C4_ENCTR_BITS 0x1c000000 ++#define VEC_DAC_C4_ENCTR_MSB 28 ++#define VEC_DAC_C4_ENCTR_LSB 26 ++#define VEC_DAC_C4_ENCTR_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENSC ++// Description : Enable cable detect - write 3'b000 ++#define VEC_DAC_C4_ENSC_RESET 0x0 ++#define VEC_DAC_C4_ENSC_BITS 0x03800000 ++#define VEC_DAC_C4_ENSC_MSB 25 ++#define VEC_DAC_C4_ENSC_LSB 23 ++#define VEC_DAC_C4_ENSC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENDAC ++// Description : Enable DAC channel ++#define VEC_DAC_C4_ENDAC_RESET 0x0 ++#define VEC_DAC_C4_ENDAC_BITS 0x00700000 ++#define VEC_DAC_C4_ENDAC_MSB 22 ++#define VEC_DAC_C4_ENDAC_LSB 20 ++#define VEC_DAC_C4_ENDAC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENVBG ++// Description : Enable internal bandgap reference - write '1' ++#define VEC_DAC_C4_ENVBG_RESET 0x0 ++#define VEC_DAC_C4_ENVBG_BITS 0x00080000 ++#define VEC_DAC_C4_ENVBG_MSB 19 ++#define VEC_DAC_C4_ENVBG_LSB 19 ++#define VEC_DAC_C4_ENVBG_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_ENEXTREF ++// Description : Enable external reference - write '0' ++#define VEC_DAC_C4_ENEXTREF_RESET 0x0 ++#define VEC_DAC_C4_ENEXTREF_BITS 0x00040000 ++#define VEC_DAC_C4_ENEXTREF_MSB 18 ++#define VEC_DAC_C4_ENEXTREF_LSB 18 ++#define VEC_DAC_C4_ENEXTREF_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_DAC2GC ++// Description : DAC channel 2 gain control - write 6'd63 ++#define VEC_DAC_C4_DAC2GC_RESET 0x00 ++#define VEC_DAC_C4_DAC2GC_BITS 0x0003f000 ++#define VEC_DAC_C4_DAC2GC_MSB 17 ++#define VEC_DAC_C4_DAC2GC_LSB 12 ++#define VEC_DAC_C4_DAC2GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_DAC1GC ++// Description : DAC channel 1 gain control - write 6'd63 ++#define VEC_DAC_C4_DAC1GC_RESET 0x00 ++#define VEC_DAC_C4_DAC1GC_BITS 0x00000fc0 ++#define VEC_DAC_C4_DAC1GC_MSB 11 ++#define VEC_DAC_C4_DAC1GC_LSB 6 ++#define VEC_DAC_C4_DAC1GC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C4_DAC0GC ++// Description : DAC channel 0 gain control - write 6'd63 ++#define VEC_DAC_C4_DAC0GC_RESET 0x00 ++#define VEC_DAC_C4_DAC0GC_BITS 0x0000003f ++#define VEC_DAC_C4_DAC0GC_MSB 5 ++#define VEC_DAC_C4_DAC0GC_LSB 0 ++#define VEC_DAC_C4_DAC0GC_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_C8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_C8_OFFSET 0x000000c8 ++#define VEC_DAC_C8_BITS 0xffffffff ++#define VEC_DAC_C8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C8_U16_SCALE_SYNC ++// Description : Scaling applied prior to final summation to form the DAC ++// command word(s) ++#define VEC_DAC_C8_U16_SCALE_SYNC_RESET 0x0000 ++#define VEC_DAC_C8_U16_SCALE_SYNC_BITS 0xffff0000 ++#define VEC_DAC_C8_U16_SCALE_SYNC_MSB 31 ++#define VEC_DAC_C8_U16_SCALE_SYNC_LSB 16 ++#define VEC_DAC_C8_U16_SCALE_SYNC_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_C8_U16_SCALE_LUMA ++// Description : Scaling applied prior to final summation to form the DAC ++// command word(s) ++#define VEC_DAC_C8_U16_SCALE_LUMA_RESET 0x0000 ++#define VEC_DAC_C8_U16_SCALE_LUMA_BITS 0x0000ffff ++#define VEC_DAC_C8_U16_SCALE_LUMA_MSB 15 ++#define VEC_DAC_C8_U16_SCALE_LUMA_LSB 0 ++#define VEC_DAC_C8_U16_SCALE_LUMA_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_CC ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_CC_OFFSET 0x000000cc ++#define VEC_DAC_CC_BITS 0xffffffff ++#define VEC_DAC_CC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_CC_S16_SCALE_BURST ++// Description : Scaling applied prior to final summation to form the DAC ++// command word(s) ++#define VEC_DAC_CC_S16_SCALE_BURST_RESET 0x0000 ++#define VEC_DAC_CC_S16_SCALE_BURST_BITS 0xffff0000 ++#define VEC_DAC_CC_S16_SCALE_BURST_MSB 31 ++#define VEC_DAC_CC_S16_SCALE_BURST_LSB 16 ++#define VEC_DAC_CC_S16_SCALE_BURST_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_CC_S16_SCALE_CHROMA ++// Description : Scaling applied prior to final summation to form the DAC ++// command word(s) ++#define VEC_DAC_CC_S16_SCALE_CHROMA_RESET 0x0000 ++#define VEC_DAC_CC_S16_SCALE_CHROMA_BITS 0x0000ffff ++#define VEC_DAC_CC_S16_SCALE_CHROMA_MSB 15 ++#define VEC_DAC_CC_S16_SCALE_CHROMA_LSB 0 ++#define VEC_DAC_CC_S16_SCALE_CHROMA_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_D0 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_D0_OFFSET 0x000000d0 ++#define VEC_DAC_D0_BITS 0xffffffff ++#define VEC_DAC_D0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_D0_S16_OFFSET_LUMA ++// Description : These offsets are applied to the chroma and luma channels ++// before the final MUX ++#define VEC_DAC_D0_S16_OFFSET_LUMA_RESET 0x0000 ++#define VEC_DAC_D0_S16_OFFSET_LUMA_BITS 0xffff0000 ++#define VEC_DAC_D0_S16_OFFSET_LUMA_MSB 31 ++#define VEC_DAC_D0_S16_OFFSET_LUMA_LSB 16 ++#define VEC_DAC_D0_S16_OFFSET_LUMA_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_D0_S16_OFFSET_CHRO ++// Description : These offsets are applied to the chroma and luma channels ++// before the final MUX ++#define VEC_DAC_D0_S16_OFFSET_CHRO_RESET 0x0000 ++#define VEC_DAC_D0_S16_OFFSET_CHRO_BITS 0x0000ffff ++#define VEC_DAC_D0_S16_OFFSET_CHRO_MSB 15 ++#define VEC_DAC_D0_S16_OFFSET_CHRO_LSB 0 ++#define VEC_DAC_D0_S16_OFFSET_CHRO_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_D4 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_D4_OFFSET 0x000000d4 ++#define VEC_DAC_D4_BITS 0xffffffff ++#define VEC_DAC_D4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_D4_NCO_FREQ ++// Description : This 64-bit frequency command is applied to the phase ++// accumulator of the NCO (numerically controlled oscillator) ++// which generates the colour sub-carrier. This value is computed ++// as ratio of sub-carrier frequency to DAC clock multiplied by ++// 2^64. ++#define VEC_DAC_D4_NCO_FREQ_RESET 0x00000000 ++#define VEC_DAC_D4_NCO_FREQ_BITS 0xffffffff ++#define VEC_DAC_D4_NCO_FREQ_MSB 31 ++#define VEC_DAC_D4_NCO_FREQ_LSB 0 ++#define VEC_DAC_D4_NCO_FREQ_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_D8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_D8_OFFSET 0x000000d8 ++#define VEC_DAC_D8_BITS 0xffffffff ++#define VEC_DAC_D8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_D8_NCO_FREQ ++// Description : This 64-bit frequency command is applied to the phase ++// accumulator of the NCO (numerically controlled oscillator) ++// which generates the colour sub-carrier. This value is computed ++// as ratio of sub-carrier frequency to DAC clock multiplied by ++// 2^64. ++#define VEC_DAC_D8_NCO_FREQ_RESET 0x00000000 ++#define VEC_DAC_D8_NCO_FREQ_BITS 0xffffffff ++#define VEC_DAC_D8_NCO_FREQ_MSB 31 ++#define VEC_DAC_D8_NCO_FREQ_LSB 0 ++#define VEC_DAC_D8_NCO_FREQ_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_DC ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_DC_OFFSET 0x000000dc ++#define VEC_DAC_DC_BITS 0xffffffff ++#define VEC_DAC_DC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_DC_FIR_COEFF_CHROMA_0_6 ++// Description : FIR filter coefficients ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_RESET 0x0000 ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_BITS 0xffff0000 ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_MSB 31 ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_LSB 16 ++#define VEC_DAC_DC_FIR_COEFF_CHROMA_0_6_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_DC_FIR_COEFF_LUMA_0_6 ++// Description : FIR filter coefficients ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_RESET 0x0000 ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_BITS 0x0000ffff ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_MSB 15 ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_LSB 0 ++#define VEC_DAC_DC_FIR_COEFF_LUMA_0_6_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_E0 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_E0_OFFSET 0x000000e0 ++#define VEC_DAC_E0_BITS 0xffffffff ++#define VEC_DAC_E0_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E0_FIR_COEFF_CHROMA_1_5 ++// Description : FIR filter coefficients ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_RESET 0x0000 ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_BITS 0xffff0000 ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_MSB 31 ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_LSB 16 ++#define VEC_DAC_E0_FIR_COEFF_CHROMA_1_5_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E0_FIR_COEFF_LUMA_1_5 ++// Description : FIR filter coefficients ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_RESET 0x0000 ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_BITS 0x0000ffff ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_MSB 15 ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_LSB 0 ++#define VEC_DAC_E0_FIR_COEFF_LUMA_1_5_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_E4 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_E4_OFFSET 0x000000e4 ++#define VEC_DAC_E4_BITS 0xffffffff ++#define VEC_DAC_E4_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E4_FIR_COEFF_CHROMA_2_4 ++// Description : FIR filter coefficients ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_RESET 0x0000 ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_BITS 0xffff0000 ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_MSB 31 ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_LSB 16 ++#define VEC_DAC_E4_FIR_COEFF_CHROMA_2_4_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E4_FIR_COEFF_LUMA_2_4 ++// Description : FIR filter coefficients ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_RESET 0x0000 ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_BITS 0x0000ffff ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_MSB 15 ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_LSB 0 ++#define VEC_DAC_E4_FIR_COEFF_LUMA_2_4_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_E8 ++// JTAG access : synchronous ++// Description : None ++#define VEC_DAC_E8_OFFSET 0x000000e8 ++#define VEC_DAC_E8_BITS 0xffffffff ++#define VEC_DAC_E8_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E8_FIR_COEFF_CHROMA_3 ++// Description : FIR filter coefficients ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_RESET 0x0000 ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_BITS 0xffff0000 ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_MSB 31 ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_LSB 16 ++#define VEC_DAC_E8_FIR_COEFF_CHROMA_3_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_E8_FIR_COEFF_LUMA_3 ++// Description : FIR filter coefficients ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_RESET 0x0000 ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_BITS 0x0000ffff ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_MSB 15 ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_LSB 0 ++#define VEC_DAC_E8_FIR_COEFF_LUMA_3_ACCESS "RW" ++// ============================================================================= ++// Register : VEC_DAC_EC ++// JTAG access : synchronous ++// Description : Misc. control ++#define VEC_DAC_EC_OFFSET 0x000000ec ++#define VEC_DAC_EC_BITS 0x001fffff ++#define VEC_DAC_EC_RESET 0x00000000 ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_SLOW_CLOCK ++// Description : Doubles the raised-cosine rate ++#define VEC_DAC_EC_SLOW_CLOCK_RESET 0x0 ++#define VEC_DAC_EC_SLOW_CLOCK_BITS 0x00100000 ++#define VEC_DAC_EC_SLOW_CLOCK_MSB 20 ++#define VEC_DAC_EC_SLOW_CLOCK_LSB 20 ++#define VEC_DAC_EC_SLOW_CLOCK_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_FIR_RMINUS1 ++// Description : Select 1, 3, 5 or 7 FIR taps ++#define VEC_DAC_EC_FIR_RMINUS1_RESET 0x0 ++#define VEC_DAC_EC_FIR_RMINUS1_BITS 0x000c0000 ++#define VEC_DAC_EC_FIR_RMINUS1_MSB 19 ++#define VEC_DAC_EC_FIR_RMINUS1_LSB 18 ++#define VEC_DAC_EC_FIR_RMINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_VERT_FULL_NOT_HALF ++// Description : Disable half-line pulses during VBI ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_RESET 0x0 ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_BITS 0x00020000 ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_MSB 17 ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_LSB 17 ++#define VEC_DAC_EC_VERT_FULL_NOT_HALF_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_SEQ_EN ++// Description : Enable NCO reset ++#define VEC_DAC_EC_SEQ_EN_RESET 0x0 ++#define VEC_DAC_EC_SEQ_EN_BITS 0x00010000 ++#define VEC_DAC_EC_SEQ_EN_MSB 16 ++#define VEC_DAC_EC_SEQ_EN_LSB 16 ++#define VEC_DAC_EC_SEQ_EN_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_U2_FLD_MASK ++// Description : Field sequence ++#define VEC_DAC_EC_U2_FLD_MASK_RESET 0x0 ++#define VEC_DAC_EC_U2_FLD_MASK_BITS 0x0000c000 ++#define VEC_DAC_EC_U2_FLD_MASK_MSB 15 ++#define VEC_DAC_EC_U2_FLD_MASK_LSB 14 ++#define VEC_DAC_EC_U2_FLD_MASK_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_U4_SEQ_MASK ++// Description : NCO reset sequence ++#define VEC_DAC_EC_U4_SEQ_MASK_RESET 0x0 ++#define VEC_DAC_EC_U4_SEQ_MASK_BITS 0x00003c00 ++#define VEC_DAC_EC_U4_SEQ_MASK_MSB 13 ++#define VEC_DAC_EC_U4_SEQ_MASK_LSB 10 ++#define VEC_DAC_EC_U4_SEQ_MASK_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_INTERP_RATE_MINUS1 ++// Description : Interpolation rate 2<=R<=16 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_RESET 0x0 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_BITS 0x000003c0 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_MSB 9 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_LSB 6 ++#define VEC_DAC_EC_INTERP_RATE_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_INTERP_SHIFT_MINUS1 ++// Description : Power-of-2 scaling after interpolation ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_RESET 0x0 ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_BITS 0x0000003c ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_MSB 5 ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_LSB 2 ++#define VEC_DAC_EC_INTERP_SHIFT_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1 ++// Description : Interlaced / progressive ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_RESET 0x0 ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_BITS 0x00000002 ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_MSB 1 ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_LSB 1 ++#define VEC_DAC_EC_FIELDS_PER_FRAME_MINUS1_ACCESS "RW" ++// ----------------------------------------------------------------------------- ++// Field : VEC_DAC_EC_PAL_EN ++// Description : Enable phase alternate line (PAL) mode ++#define VEC_DAC_EC_PAL_EN_RESET 0x0 ++#define VEC_DAC_EC_PAL_EN_BITS 0x00000001 ++#define VEC_DAC_EC_PAL_EN_MSB 0 ++#define VEC_DAC_EC_PAL_EN_LSB 0 ++#define VEC_DAC_EC_PAL_EN_ACCESS "RW" ++// ============================================================================= ++#endif // VEC_REGS_DEFINED diff --git a/target/linux/bcm27xx/patches-6.1/950-0888-v4l2-Add-pisp-compression-format-support-to-v4l2.patch b/target/linux/bcm27xx/patches-6.1/950-0888-v4l2-Add-pisp-compression-format-support-to-v4l2.patch new file mode 100644 index 0000000000..cf0b02c64b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0888-v4l2-Add-pisp-compression-format-support-to-v4l2.patch @@ -0,0 +1,75 @@ +From 3a419974ba02d32795a5ecfaf3c020f23173b6a1 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Tue, 14 Feb 2023 20:58:59 +0000 +Subject: [PATCH] v4l2: Add pisp compression format support to v4l2 + +Signed-off-by: Naushir Patuck +--- + drivers/media/v4l2-core/v4l2-ioctl.c | 12 ++++++++---- + include/uapi/linux/media-bus-format.h | 14 ++++++++++++++ + include/uapi/linux/videodev2.h | 12 ++++++++---- + 3 files changed, 30 insertions(+), 8 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1507,10 +1507,14 @@ static void v4l_fill_fmtdesc(struct v4l2 + case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit Format"; break; + case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break; + case V4L2_PIX_FMT_RPI_BE: descr = "PiSP Opaque Format"; break; +- case V4L2_PIX_FMT_PISP_COMP_RGGB: +- case V4L2_PIX_FMT_PISP_COMP_GRBG: +- case V4L2_PIX_FMT_PISP_COMP_GBRG: +- case V4L2_PIX_FMT_PISP_COMP_BGGR: descr = "PiSP Bayer Compressed Format"; break; ++ case V4L2_PIX_FMT_PISP_COMP1_RGGB: ++ case V4L2_PIX_FMT_PISP_COMP1_GRBG: ++ case V4L2_PIX_FMT_PISP_COMP1_GBRG: ++ case V4L2_PIX_FMT_PISP_COMP1_BGGR: descr = "PiSP Bayer Comp 1"; break; ++ case V4L2_PIX_FMT_PISP_COMP2_RGGB: ++ case V4L2_PIX_FMT_PISP_COMP2_GRBG: ++ case V4L2_PIX_FMT_PISP_COMP2_GBRG: ++ case V4L2_PIX_FMT_PISP_COMP2_BGGR: descr = "PiSP Bayer Comp 2"; break; + default: + if (fmt->description[0]) + return; +--- a/include/uapi/linux/media-bus-format.h ++++ b/include/uapi/linux/media-bus-format.h +@@ -175,4 +175,18 @@ + /* Sensor ancillary metadata formats - next is 0x7002 */ + #define MEDIA_BUS_FMT_SENSOR_DATA 0x7002 + ++/* PiSP Formats */ ++#define MEDIA_BUS_FMT_PISP_COMP1_RGGB 0x8001 ++#define MEDIA_BUS_FMT_PISP_COMP1_GRBG 0x8002 ++#define MEDIA_BUS_FMT_PISP_COMP1_GBRG 0x8003 ++#define MEDIA_BUS_FMT_PISP_COMP1_BGGR 0x8004 ++#define MEDIA_BUS_FMT_PISP_COMP2_RGGB 0x8005 ++#define MEDIA_BUS_FMT_PISP_COMP2_GRBG 0x8006 ++#define MEDIA_BUS_FMT_PISP_COMP2_GBRG 0x8007 ++#define MEDIA_BUS_FMT_PISP_COMP2_BGGR 0x8008 ++ ++#define MEDIA_BUS_FMT_PISP_FE_CONFIG 0x8100 ++#define MEDIA_BUS_FMT_PISP_FE_STATS 0x8101 ++#define MEDIA_BUS_FMT_PISP_BE_CONFIG 0x8200 ++ + #endif /* __LINUX_MEDIA_BUS_FORMAT_H */ +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -795,10 +795,14 @@ struct v4l2_pix_format { + + /* The pixel format for all our buffers (the precise format is found in the config buffer). */ + #define V4L2_PIX_FMT_RPI_BE v4l2_fourcc('R', 'P', 'B', 'P') +-#define V4L2_PIX_FMT_PISP_COMP_RGGB v4l2_fourcc('P', 'C', 'R', 'G') +-#define V4L2_PIX_FMT_PISP_COMP_GRBG v4l2_fourcc('P', 'C', 'G', 'R') +-#define V4L2_PIX_FMT_PISP_COMP_GBRG v4l2_fourcc('P', 'C', 'G', 'B') +-#define V4L2_PIX_FMT_PISP_COMP_BGGR v4l2_fourcc('P', 'C', 'B', 'G') ++#define V4L2_PIX_FMT_PISP_COMP1_RGGB v4l2_fourcc('P', 'C', '1', 'R') ++#define V4L2_PIX_FMT_PISP_COMP1_GRBG v4l2_fourcc('P', 'C', '1', 'G') ++#define V4L2_PIX_FMT_PISP_COMP1_GBRG v4l2_fourcc('P', 'C', '1', 'g') ++#define V4L2_PIX_FMT_PISP_COMP1_BGGR v4l2_fourcc('P', 'C', '1', 'B') ++#define V4L2_PIX_FMT_PISP_COMP2_RGGB v4l2_fourcc('P', 'C', '2', 'R') ++#define V4L2_PIX_FMT_PISP_COMP2_GRBG v4l2_fourcc('P', 'C', '2', 'G') ++#define V4L2_PIX_FMT_PISP_COMP2_GBRG v4l2_fourcc('P', 'C', '2', 'g') ++#define V4L2_PIX_FMT_PISP_COMP2_BGGR v4l2_fourcc('P', 'C', '2', 'B') + + /* SDR formats - used only for Software Defined Radio devices */ + #define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0889-media-rp1-Add-CFE-Camera-Front-End-support.patch b/target/linux/bcm27xx/patches-6.1/950-0889-media-rp1-Add-CFE-Camera-Front-End-support.patch new file mode 100644 index 0000000000..038633b74e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0889-media-rp1-Add-CFE-Camera-Front-End-support.patch @@ -0,0 +1,4527 @@ +From 8a31623de7f034f6521b348e9a510e78a6e7e493 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Tue, 14 Feb 2023 17:30:12 +0000 +Subject: [PATCH] media: rp1: Add CFE (Camera Front End) support + +Signed-off-by: Naushir Patuck +--- + drivers/media/platform/raspberrypi/Kconfig | 1 + + drivers/media/platform/raspberrypi/Makefile | 1 + + .../platform/raspberrypi/rp1_cfe/Kconfig | 14 + + .../platform/raspberrypi/rp1_cfe/Makefile | 6 + + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 2186 +++++++++++++++++ + .../media/platform/raspberrypi/rp1_cfe/cfe.h | 40 + + .../platform/raspberrypi/rp1_cfe/cfe_fmts.h | 294 +++ + .../media/platform/raspberrypi/rp1_cfe/csi2.c | 446 ++++ + .../media/platform/raspberrypi/rp1_cfe/csi2.h | 75 + + .../media/platform/raspberrypi/rp1_cfe/dphy.c | 177 ++ + .../media/platform/raspberrypi/rp1_cfe/dphy.h | 26 + + .../raspberrypi/rp1_cfe/pisp_common.h | 69 + + .../platform/raspberrypi/rp1_cfe/pisp_fe.c | 563 +++++ + .../platform/raspberrypi/rp1_cfe/pisp_fe.h | 53 + + .../raspberrypi/rp1_cfe/pisp_fe_config.h | 272 ++ + .../raspberrypi/rp1_cfe/pisp_statistics.h | 62 + + .../platform/raspberrypi/rp1_cfe/pisp_types.h | 144 ++ + 17 files changed, 4429 insertions(+) + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/Kconfig + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/Makefile + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/cfe.c + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/cfe.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/csi2.c + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/csi2.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/dphy.c + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/dphy.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_common.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe_config.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h + create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h + +--- a/drivers/media/platform/raspberrypi/Kconfig ++++ b/drivers/media/platform/raspberrypi/Kconfig +@@ -3,3 +3,4 @@ + comment "Raspberry Pi media platform drivers" + + source "drivers/media/platform/raspberrypi/pisp_be/Kconfig" ++source "drivers/media/platform/raspberrypi/rp1_cfe/Kconfig" +--- a/drivers/media/platform/raspberrypi/Makefile ++++ b/drivers/media/platform/raspberrypi/Makefile +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 + + obj-y += pisp_be/ ++obj-y += rp1_cfe/ +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/Kconfig +@@ -0,0 +1,14 @@ ++# RP1 V4L2 camera support ++ ++config VIDEO_RP1_CFE ++ tristate "RP1 Camera Frond End (CFE) video capture driver" ++ depends on VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ select MEDIA_CONTROLLER ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_FWNODE ++ help ++ Say Y here to enable support for the RP1 Camera Front End. ++ ++ To compile this driver as a module, choose M here. The module will be ++ called rp1-cfe. +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for RP1 Camera Front End driver ++# ++rp1-cfe-objs := cfe.o csi2.o pisp_fe.o dphy.o ++obj-$(CONFIG_VIDEO_RP1_CFE) += rp1-cfe.o +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -0,0 +1,2186 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * RP1 Camera Front End Driver ++ * ++ * Copyright (C) 2021-2022 - Raspberry Pi Ltd. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cfe.h" ++#include "cfe_fmts.h" ++#include "csi2.h" ++#include "pisp_fe.h" ++#include "pisp_fe_config.h" ++#include "pisp_statistics.h" ++ ++#define CFE_MODULE_NAME "rp1-cfe" ++#define CFE_VERSION "1.0" ++ ++bool cfe_debug_irq; ++ ++#define cfe_dbg_irq(fmt, arg...) \ ++ do { \ ++ if (cfe_debug_irq) \ ++ dev_dbg(&cfe->pdev->dev, fmt, ##arg); \ ++ } while (0) ++#define cfe_dbg(fmt, arg...) dev_dbg(&cfe->pdev->dev, fmt, ##arg) ++#define cfe_info(fmt, arg...) dev_info(&cfe->pdev->dev, fmt, ##arg) ++#define cfe_err(fmt, arg...) dev_err(&cfe->pdev->dev, fmt, ##arg) ++ ++/* MIPICFG registers */ ++#define MIPICFG_CFG 0x004 ++#define MIPICFG_INTR 0x028 ++#define MIPICFG_INTE 0x02c ++#define MIPICFG_INTF 0x030 ++#define MIPICFG_INTS 0x034 ++ ++#define MIPICFG_CFG_SEL_CSI BIT(0) ++ ++#define MIPICFG_INT_CSI_DMA BIT(0) ++#define MIPICFG_INT_CSI_HOST BIT(2) ++#define MIPICFG_INT_PISP_FE BIT(4) ++ ++#define BPL_ALIGNMENT 16 ++#define MAX_BYTESPERLINE 0xffffff00 ++#define MAX_BUFFER_SIZE 0xffffff00 ++/* ++ * Max width is therefore determined by the max stride divided by the number of ++ * bits per pixel. ++ * ++ * However, to avoid overflow issues let's use a 16k maximum. This lets us ++ * calculate 16k * 16k * 4 with 32bits. If we need higher maximums, a careful ++ * review and adjustment of the code is needed so that it will deal with ++ * overflows correctly. ++ */ ++#define MAX_WIDTH 16384 ++#define MAX_HEIGHT MAX_WIDTH ++/* Define a nominal minimum image size */ ++#define MIN_WIDTH 16 ++#define MIN_HEIGHT 16 ++/* Default size of the embedded buffer */ ++#define DEFAULT_EMBEDDED_SIZE 8192 ++ ++const struct v4l2_mbus_framefmt cfe_default_format = { ++ .width = 640, ++ .height = 480, ++ .code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .field = V4L2_FIELD_NONE, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ .ycbcr_enc = V4L2_YCBCR_ENC_601, ++ .quantization = V4L2_QUANTIZATION_FULL_RANGE, ++ .xfer_func = V4L2_XFER_FUNC_NONE, ++}; ++ ++const struct v4l2_mbus_framefmt cfe_default_meta_format = { ++ .width = 8192, ++ .height = 1, ++ .code = MEDIA_BUS_FMT_SENSOR_DATA, ++}; ++ ++enum node_ids { ++ /* CSI2 HW output nodes first. */ ++ CSI2_CH0, ++ CSI2_CH1_EMBEDDED, ++ CSI2_CH2, ++ CSI2_CH3, ++ /* FE only nodes from here on. */ ++ FE_OUT0, ++ FE_OUT1, ++ FE_STATS, ++ FE_CONFIG, ++ NUM_NODES ++}; ++ ++struct node_description { ++ unsigned int id; ++ const char *name; ++ enum v4l2_buf_type buf_type; ++ unsigned int cap; ++ unsigned int pad_flags; ++ unsigned int link_pad; ++}; ++ ++/* Must match the ordering of enum ids */ ++static const struct node_description node_desc[NUM_NODES] = { ++ [CSI2_CH0] = { ++ .name = "csi2_ch0", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ .cap = V4L2_CAP_VIDEO_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = CSI2_NUM_CHANNELS + 0 ++ }, ++ /* This node is assigned for the embedded data channel! */ ++ [CSI2_CH1_EMBEDDED] = { ++ .name = "embedded", ++ .buf_type = V4L2_BUF_TYPE_META_CAPTURE, ++ .cap = V4L2_CAP_META_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = CSI2_NUM_CHANNELS + 1 ++ }, ++ [CSI2_CH2] = { ++ .name = "csi2_ch2", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ .cap = V4L2_CAP_META_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = CSI2_NUM_CHANNELS + 2 ++ }, ++ [CSI2_CH3] = { ++ .name = "csi2_ch3", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ .cap = V4L2_CAP_META_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = CSI2_NUM_CHANNELS + 3 ++ }, ++ [FE_OUT0] = { ++ .name = "fe_image0", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ .cap = V4L2_CAP_VIDEO_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = FE_OUTPUT0_PAD ++ }, ++ [FE_OUT1] = { ++ .name = "fe_image1", ++ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ .cap = V4L2_CAP_VIDEO_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = FE_OUTPUT1_PAD ++ }, ++ [FE_STATS] = { ++ .name = "fe_stats", ++ .buf_type = V4L2_BUF_TYPE_META_CAPTURE, ++ .cap = V4L2_CAP_META_CAPTURE, ++ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = FE_STATS_PAD ++ }, ++ [FE_CONFIG] = { ++ .name = "fe_config", ++ .buf_type = V4L2_BUF_TYPE_META_OUTPUT, ++ .cap = V4L2_CAP_META_OUTPUT, ++ .pad_flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT, ++ .link_pad = FE_CONFIG_PAD ++ }, ++}; ++ ++#define is_fe_node(node) (((node)->id) >= FE_OUT0) ++#define is_csi2_node(node) (!is_fe_node(node)) ++#define is_image_output_node(node) \ ++ (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ++#define is_meta_output_node(node) \ ++ (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_META_CAPTURE) ++#define is_meta_input_node(node) \ ++ (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_META_OUTPUT) ++#define is_meta_node(node) (is_meta_output_node(node) || is_meta_input_node(node)) ++ ++/* To track state across all nodes. */ ++#define NUM_STATES 5 ++#define NODE_REGISTERED BIT(0) ++#define NODE_ENABLED BIT(1) ++#define NODE_STREAMING BIT(2) ++#define FS_INT BIT(3) ++#define FE_INT BIT(4) ++ ++struct cfe_buffer { ++ struct vb2_v4l2_buffer vb; ++ struct list_head list; ++}; ++ ++struct cfe_config_buffer { ++ struct cfe_buffer buf; ++ struct pisp_fe_config config; ++}; ++ ++static inline struct cfe_buffer *to_cfe_buffer(struct vb2_buffer *vb) ++{ ++ return container_of(vb, struct cfe_buffer, vb.vb2_buf); ++} ++ ++static inline ++struct cfe_config_buffer *to_cfe_config_buffer(struct cfe_buffer *buf) ++{ ++ return container_of(buf, struct cfe_config_buffer, buf); ++} ++ ++struct cfe_node { ++ unsigned int id; ++ /* Pointer pointing to current v4l2_buffer */ ++ struct cfe_buffer *cur_frm; ++ /* Pointer pointing to next v4l2_buffer */ ++ struct cfe_buffer *next_frm; ++ /* Used to store current pixel format */ ++ struct v4l2_format fmt; ++ /* Buffer queue used in video-buf */ ++ struct vb2_queue buffer_queue; ++ /* Queue of filled frames */ ++ struct list_head dma_queue; ++ /* lock used to access this structure */ ++ struct mutex lock; ++ /* Identifies video device for this channel */ ++ struct video_device video_dev; ++ /* Pointer to the parent handle */ ++ struct cfe_device *cfe; ++ struct media_pad pad; ++}; ++ ++struct cfe_device { ++ struct dentry *debugfs; ++ struct kref kref; ++ ++ /* V4l2 specific parameters */ ++ struct v4l2_async_subdev asd; ++ ++ /* peripheral base address */ ++ void __iomem *mipi_cfg_base; ++ ++ struct clk *clk; ++ ++ /* V4l2 device */ ++ struct v4l2_device v4l2_dev; ++ struct media_device mdev; ++ struct media_pipeline pipe; ++ ++ /* IRQ lock for node state and DMA queues */ ++ spinlock_t state_lock; ++ bool job_ready; ++ bool job_queued; ++ ++ /* parent device */ ++ struct platform_device *pdev; ++ /* subdevice async Notifier */ ++ struct v4l2_async_notifier notifier; ++ ++ /* ptr to sub device */ ++ struct v4l2_subdev *sensor; ++ ++ struct cfe_node node[NUM_NODES]; ++ DECLARE_BITMAP(node_flags, NUM_STATES * NUM_NODES); ++ ++ struct csi2_device csi2; ++ struct pisp_fe_device fe; ++ ++ bool sensor_embedded_data; ++ int fe_csi2_channel; ++ ++ unsigned int sequence; ++ u64 ts; ++}; ++ ++static inline bool is_fe_enabled(struct cfe_device *cfe) ++{ ++ return cfe->fe_csi2_channel != -1; ++} ++ ++static inline struct cfe_device *to_cfe_device(struct v4l2_device *v4l2_dev) ++{ ++ return container_of(v4l2_dev, struct cfe_device, v4l2_dev); ++} ++ ++static inline u32 cfg_reg_read(struct cfe_device *cfe, u32 offset) ++{ ++ return readl(cfe->mipi_cfg_base + offset); ++} ++ ++static inline void cfg_reg_write(struct cfe_device *cfe, u32 offset, u32 val) ++{ ++ writel(val, cfe->mipi_cfg_base + offset); ++} ++ ++static bool check_state(struct cfe_device *cfe, unsigned long state, ++ unsigned int node_id) ++{ ++ unsigned long bit; ++ ++ for_each_set_bit(bit, &state, sizeof(state)) { ++ if (!test_bit(bit + (node_id * NUM_STATES), cfe->node_flags)) ++ return false; ++ } ++ return true; ++} ++ ++static void set_state(struct cfe_device *cfe, unsigned long state, ++ unsigned int node_id) ++{ ++ unsigned long bit; ++ ++ for_each_set_bit(bit, &state, sizeof(state)) ++ set_bit(bit + (node_id * NUM_STATES), cfe->node_flags); ++} ++ ++static void clear_state(struct cfe_device *cfe, unsigned long state, ++ unsigned int node_id) ++{ ++ unsigned long bit; ++ ++ for_each_set_bit(bit, &state, sizeof(state)) ++ clear_bit(bit + (node_id * NUM_STATES), cfe->node_flags); ++} ++ ++static bool test_any_node(struct cfe_device *cfe, unsigned long cond) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ if (check_state(cfe, cond, i)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool test_all_nodes(struct cfe_device *cfe, unsigned long precond, ++ unsigned long cond) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ if (check_state(cfe, precond, i)) { ++ if (!check_state(cfe, cond, i)) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static void clear_all_nodes(struct cfe_device *cfe, unsigned long precond, ++ unsigned long state) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ if (check_state(cfe, precond, i)) ++ clear_state(cfe, state, i); ++ } ++} ++ ++static int mipi_cfg_regs_show(struct seq_file *s, void *data) ++{ ++ struct cfe_device *cfe = s->private; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(&cfe->pdev->dev); ++ if (ret) ++ return ret; ++ ++#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", cfg_reg_read(cfe, reg)) ++ DUMP(MIPICFG_CFG); ++ DUMP(MIPICFG_INTR); ++ DUMP(MIPICFG_INTE); ++ DUMP(MIPICFG_INTF); ++ DUMP(MIPICFG_INTS); ++#undef DUMP ++ ++ pm_runtime_put(&cfe->pdev->dev); ++ ++ return 0; ++} ++ ++static int format_show(struct seq_file *s, void *data) ++{ ++ struct cfe_device *cfe = s->private; ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->node[i]; ++ unsigned long sb, state = 0; ++ ++ for (sb = 0; sb < NUM_STATES; sb++) { ++ if (check_state(cfe, BIT(sb), i)) ++ state |= BIT(sb); ++ } ++ ++ seq_printf(s, "\nNode %u (%s) state: 0x%lx\n", i, ++ node_desc[i].name, state); ++ ++ if (is_image_output_node(node)) ++ seq_printf(s, "format: " V4L2_FOURCC_CONV " 0x%x\n" ++ "resolution: %ux%u\nbpl: %u\nsize: %u\n", ++ V4L2_FOURCC_CONV_ARGS(node->fmt.fmt.pix.pixelformat), ++ node->fmt.fmt.pix.pixelformat, ++ node->fmt.fmt.pix.width, ++ node->fmt.fmt.pix.height, ++ node->fmt.fmt.pix.bytesperline, ++ node->fmt.fmt.pix.sizeimage); ++ else ++ seq_printf(s, "format: " V4L2_FOURCC_CONV " 0x%x\nsize: %u\n", ++ V4L2_FOURCC_CONV_ARGS(node->fmt.fmt.meta.dataformat), ++ node->fmt.fmt.meta.dataformat, ++ node->fmt.fmt.meta.buffersize); ++ } ++ ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(mipi_cfg_regs); ++DEFINE_SHOW_ATTRIBUTE(format); ++ ++/* Format setup functions */ ++const struct cfe_fmt *find_format_by_code(u32 code) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(formats); i++) { ++ if (formats[i].code == code) ++ return &formats[i]; ++ } ++ ++ return NULL; ++} ++ ++static const struct cfe_fmt *find_format_by_pix(u32 pixelformat) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(formats); i++) { ++ if (formats[i].fourcc == pixelformat) ++ return &formats[i]; ++ } ++ ++ return NULL; ++} ++ ++static int cfe_calc_format_size_bpl(struct cfe_device *cfe, ++ const struct cfe_fmt *fmt, ++ struct v4l2_format *f) ++{ ++ unsigned int min_bytesperline; ++ ++ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 2, ++ &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0, 0); ++ ++ min_bytesperline = ++ ALIGN((f->fmt.pix.width * fmt->depth) >> 3, BPL_ALIGNMENT); ++ ++ if (f->fmt.pix.bytesperline > min_bytesperline && ++ f->fmt.pix.bytesperline <= MAX_BYTESPERLINE) ++ f->fmt.pix.bytesperline = ++ ALIGN(f->fmt.pix.bytesperline, BPL_ALIGNMENT); ++ else ++ f->fmt.pix.bytesperline = min_bytesperline; ++ ++ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; ++ ++ cfe_dbg("%s: " V4L2_FOURCC_CONV " size: %ux%u bpl:%u img_size:%u\n", ++ __func__, V4L2_FOURCC_CONV_ARGS(f->fmt.pix.pixelformat), ++ f->fmt.pix.width, f->fmt.pix.height, ++ f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); ++ ++ return 0; ++} ++ ++static void cfe_schedule_next_csi2_job(struct cfe_device *cfe) ++{ ++ struct cfe_buffer *buf; ++ unsigned int i; ++ dma_addr_t addr; ++ ++ for (i = 0; i < CSI2_NUM_CHANNELS; i++) { ++ struct cfe_node *node = &cfe->node[i]; ++ unsigned int stride, size; ++ ++ if (!check_state(cfe, NODE_STREAMING, i)) ++ continue; ++ ++ buf = list_first_entry(&node->dma_queue, struct cfe_buffer, ++ list); ++ node->next_frm = buf; ++ list_del(&buf->list); ++ ++ cfe_dbg("%s: [%s] buffer:%p\n", ++ __func__, node_desc[node->id].name, &buf->vb.vb2_buf); ++ ++ if (is_meta_node(node)) { ++ size = node->fmt.fmt.meta.buffersize; ++ stride = 0; ++ } else { ++ size = node->fmt.fmt.pix.sizeimage; ++ stride = node->fmt.fmt.pix.bytesperline; ++ } ++ ++ addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ csi2_set_buffer(&cfe->csi2, node->id, addr, stride, size); ++ } ++} ++ ++static void cfe_schedule_next_pisp_job(struct cfe_device *cfe) ++{ ++ struct vb2_buffer *vb2_bufs[FE_NUM_PADS] = { 0 }; ++ struct cfe_config_buffer *config_buf; ++ struct cfe_buffer *buf; ++ unsigned int i; ++ ++ for (i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->node[i]; ++ ++ if (!check_state(cfe, NODE_STREAMING, i)) ++ continue; ++ ++ buf = list_first_entry(&node->dma_queue, struct cfe_buffer, ++ list); ++ ++ cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, ++ node_desc[node->id].name, &buf->vb.vb2_buf); ++ ++ node->next_frm = buf; ++ vb2_bufs[node_desc[i].link_pad] = &buf->vb.vb2_buf; ++ list_del(&buf->list); ++ } ++ ++ config_buf = to_cfe_config_buffer(cfe->node[FE_CONFIG].next_frm); ++ pisp_fe_submit_job(&cfe->fe, vb2_bufs, &config_buf->config); ++} ++ ++static bool cfe_check_job_ready(struct cfe_device *cfe) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->node[i]; ++ ++ if (!check_state(cfe, NODE_ENABLED, i)) ++ continue; ++ ++ if (list_empty(&node->dma_queue)) { ++ cfe_dbg_irq("%s: [%s] has no buffer, unable to schedule job\n", ++ __func__, node_desc[i].name); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static void cfe_prepare_next_job(struct cfe_device *cfe) ++{ ++ cfe->job_queued = true; ++ cfe_schedule_next_csi2_job(cfe); ++ if (is_fe_enabled(cfe)) ++ cfe_schedule_next_pisp_job(cfe); ++ ++ /* Flag if another job is ready after this. */ ++ cfe->job_ready = cfe_check_job_ready(cfe); ++ ++ cfe_dbg_irq("%s: end with scheduled job\n", __func__); ++} ++ ++static void cfe_process_buffer_complete(struct cfe_node *node, ++ unsigned int sequence) ++{ ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, node_desc[node->id].name, ++ &node->cur_frm->vb.vb2_buf); ++ ++ node->cur_frm->vb.sequence = sequence; ++ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); ++} ++ ++static void cfe_queue_event_sof(struct cfe_node *node) ++{ ++ struct v4l2_event event = { ++ .type = V4L2_EVENT_FRAME_SYNC, ++ .u.frame_sync.frame_sequence = node->cfe->sequence, ++ }; ++ ++ v4l2_event_queue(&node->video_dev, &event); ++} ++ ++static void cfe_sof_isr_handler(struct cfe_node *node) ++{ ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg_irq("%s: [%s] seq %u\n", __func__, node_desc[node->id].name, ++ cfe->sequence); ++ ++ node->cur_frm = node->next_frm; ++ node->next_frm = NULL; ++ ++ /* ++ * If this is the first node to see a frame start, sample the ++ * timestamp to use for all frames across all channels. ++ */ ++ if (!test_any_node(cfe, NODE_STREAMING | FS_INT)) ++ cfe->ts = ktime_get_ns(); ++ ++ set_state(cfe, FS_INT, node->id); ++ ++ /* If all nodes have seen a frame start, we can queue another job. */ ++ if (test_all_nodes(cfe, NODE_STREAMING, FS_INT)) ++ cfe->job_queued = false; ++ ++ if (node->cur_frm) ++ node->cur_frm->vb.vb2_buf.timestamp = cfe->ts; ++ ++ if (is_image_output_node(node)) ++ cfe_queue_event_sof(node); ++} ++ ++static void cfe_eof_isr_handler(struct cfe_node *node) ++{ ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg_irq("%s: [%s] seq %u\n", __func__, node_desc[node->id].name, ++ cfe->sequence); ++ ++ if (node->cur_frm) ++ cfe_process_buffer_complete(node, cfe->sequence); ++ ++ node->cur_frm = NULL; ++ set_state(cfe, FE_INT, node->id); ++ ++ /* ++ * If all nodes have seen a frame end, we can increment ++ * the sequence counter now. ++ */ ++ if (test_all_nodes(cfe, NODE_STREAMING, FE_INT)) { ++ cfe->sequence++; ++ clear_all_nodes(cfe, NODE_STREAMING, FE_INT | FS_INT); ++ } ++} ++ ++static irqreturn_t cfe_isr(int irq, void *dev) ++{ ++ struct cfe_device *cfe = dev; ++ unsigned int i; ++ bool sof[NUM_NODES] = {0}, eof[NUM_NODES] = {0}, lci[NUM_NODES] = {0}; ++ u32 sts; ++ ++ sts = cfg_reg_read(cfe, MIPICFG_INTS); ++ ++ if (sts & MIPICFG_INT_CSI_DMA) ++ csi2_isr(&cfe->csi2, sof, eof, lci); ++ ++ if (sts & MIPICFG_INT_PISP_FE) ++ pisp_fe_isr(&cfe->fe, sof + CSI2_NUM_CHANNELS, ++ eof + CSI2_NUM_CHANNELS); ++ ++ spin_lock(&cfe->state_lock); ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->node[i]; ++ ++ /* ++ * The check_state(NODE_STREAMING) is to ensure we do not loop ++ * over the CSI2_CHx nodes when the FE is active since they ++ * generate interrupts even though the node is not streaming. ++ */ ++ if (!check_state(cfe, NODE_STREAMING, i) || ++ !(sof[i] || eof[i] || lci[i])) ++ continue; ++ ++ /* ++ * There are 3 cases where we could get FS + FE_ACK at ++ * the same time: ++ * 1) FE of the current frame, and FS of the next frame. ++ * 2) FS + FE of the same frame. ++ * 3) FE of the current frame, and FS + FE of the next ++ * frame. To handle this, see the sof handler below. ++ * ++ * (1) is handled implicitly by the ordering of the FE and FS ++ * handlers below. ++ */ ++ if (eof[i]) { ++ /* ++ * The condition below tests for (2). Run the FS handler ++ * first before the FE handler, both for the current ++ * frame. ++ */ ++ if (sof[i] && !check_state(cfe, FS_INT, i)) { ++ cfe_sof_isr_handler(node); ++ sof[i] = false; ++ } ++ ++ cfe_eof_isr_handler(node); ++ } ++ ++ if (sof[i]) { ++ /* ++ * The condition below tests for (3). In such cases, we ++ * come in here with FS flag set in the node state from ++ * the previous frame since it only gets cleared in ++ * eof_isr_handler(). Handle the FE for the previous ++ * frame first before the FS handler for the current ++ * frame. ++ */ ++ if (check_state(cfe, FS_INT, node->id)) { ++ cfe_dbg("%s: [%s] Handling missing previous FE interrupt\n", ++ __func__, node_desc[node->id].name); ++ cfe_eof_isr_handler(node); ++ } ++ ++ cfe_sof_isr_handler(node); ++ } ++ ++ if (!cfe->job_queued && cfe->job_ready) ++ cfe_prepare_next_job(cfe); ++ } ++ ++ spin_unlock(&cfe->state_lock); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Stream helpers ++ */ ++ ++static void cfe_start_channel(struct cfe_node *node) ++{ ++ struct cfe_device *cfe = node->cfe; ++ struct v4l2_subdev_state *state; ++ struct v4l2_mbus_framefmt *source_fmt; ++ const struct cfe_fmt *fmt; ++ unsigned long flags; ++ unsigned int width = 0, height = 0; ++ bool start_fe = is_fe_enabled(cfe) && ++ test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ if (start_fe || is_image_output_node(node)) { ++ width = node->fmt.fmt.pix.width; ++ height = node->fmt.fmt.pix.height; ++ } ++ ++ state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); ++ ++ if (start_fe) { ++ WARN_ON(!is_fe_enabled(cfe)); ++ cfe_dbg("%s: %s using csi2 channel %d\n", ++ __func__, node_desc[FE_OUT0].name, ++ cfe->fe_csi2_channel); ++ ++ source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, cfe->fe_csi2_channel); ++ fmt = find_format_by_code(source_fmt->code); ++ ++ /* ++ * Start the associated CSI2 Channel as well. ++ * ++ * Must write to the ADDR register to latch the ctrl values ++ * even if we are connected to the front end. Once running, ++ * this is handled by the CSI2 AUTO_ARM mode. ++ */ ++ csi2_start_channel(&cfe->csi2, cfe->fe_csi2_channel, ++ fmt->csi_dt, CSI2_MODE_FE_STREAMING, ++ true, false, width, height); ++ csi2_set_buffer(&cfe->csi2, cfe->fe_csi2_channel, 0, 0, -1); ++ pisp_fe_start(&cfe->fe); ++ } ++ ++ if (is_csi2_node(node)) { ++ u32 mode = CSI2_MODE_NORMAL; ++ ++ source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, ++ node_desc[node->id].link_pad - CSI2_NUM_CHANNELS); ++ fmt = find_format_by_code(source_fmt->code); ++ ++ if (is_image_output_node(node)) { ++ if (node->fmt.fmt.pix.pixelformat == ++ fmt->remap[CFE_REMAP_16BIT]) ++ mode = CSI2_MODE_REMAP; ++ else if (node->fmt.fmt.pix.pixelformat == ++ fmt->remap[CFE_REMAP_COMPRESSED]) { ++ mode = CSI2_MODE_COMPRESSED; ++ csi2_set_compression(&cfe->csi2, node->id, ++ CSI2_COMPRESSION_DELTA, 0, ++ 0); ++ } ++ } ++ /* Unconditionally start this CSI2 channel. */ ++ csi2_start_channel(&cfe->csi2, node->id, fmt->csi_dt, ++ mode, ++ /* Auto arm */ ++ false, ++ /* Pack bytes */ ++ node->id == CSI2_CH1_EMBEDDED ? true : false, ++ width, height); ++ } ++ ++ v4l2_subdev_unlock_state(state); ++ ++ spin_lock_irqsave(&cfe->state_lock, flags); ++ if (cfe->job_ready && test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) ++ cfe_prepare_next_job(cfe); ++ spin_unlock_irqrestore(&cfe->state_lock, flags); ++} ++ ++static void cfe_stop_channel(struct cfe_node *node, bool fe_stop) ++{ ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: [%s] fe_stop %u\n", __func__, ++ node_desc[node->id].name, fe_stop); ++ ++ if (fe_stop) { ++ csi2_stop_channel(&cfe->csi2, cfe->fe_csi2_channel); ++ pisp_fe_stop(&cfe->fe); ++ } ++ ++ if (is_csi2_node(node)) ++ csi2_stop_channel(&cfe->csi2, node->id); ++} ++ ++static void cfe_return_buffers(struct cfe_node *node, ++ enum vb2_buffer_state state) ++{ ++ struct cfe_device *cfe = node->cfe; ++ struct cfe_buffer *buf, *tmp; ++ unsigned long flags; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ spin_lock_irqsave(&cfe->state_lock, flags); ++ list_for_each_entry_safe(buf, tmp, &node->dma_queue, list) { ++ list_del(&buf->list); ++ vb2_buffer_done(&buf->vb.vb2_buf, state); ++ } ++ ++ if (node->cur_frm) ++ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); ++ if (node->next_frm && node->cur_frm != node->next_frm) ++ vb2_buffer_done(&node->next_frm->vb.vb2_buf, state); ++ ++ node->cur_frm = NULL; ++ node->next_frm = NULL; ++ spin_unlock_irqrestore(&cfe->state_lock, flags); ++} ++ ++/* ++ * vb2 ops ++ */ ++ ++static int cfe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, ++ unsigned int *nplanes, unsigned int sizes[], ++ struct device *alloc_devs[]) ++{ ++ struct cfe_node *node = vb2_get_drv_priv(vq); ++ struct cfe_device *cfe = node->cfe; ++ unsigned int size = is_image_output_node(node) ? ++ node->fmt.fmt.pix.sizeimage : ++ node->fmt.fmt.meta.buffersize; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ if (vq->num_buffers + *nbuffers < 3) ++ *nbuffers = 3 - vq->num_buffers; ++ ++ if (*nplanes) { ++ if (sizes[0] < size) { ++ cfe_err("sizes[0] %i < size %u\n", sizes[0], size); ++ return -EINVAL; ++ } ++ size = sizes[0]; ++ } ++ ++ *nplanes = 1; ++ sizes[0] = size; ++ ++ return 0; ++} ++ ++static int cfe_buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); ++ struct cfe_device *cfe = node->cfe; ++ struct cfe_buffer *buf = to_cfe_buffer(vb); ++ unsigned long size; ++ ++ cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, node_desc[node->id].name, ++ vb); ++ ++ size = is_image_output_node(node) ? node->fmt.fmt.pix.sizeimage : ++ node->fmt.fmt.meta.buffersize; ++ if (vb2_plane_size(vb, 0) < size) { ++ cfe_err("data will not fit into plane (%lu < %lu)\n", ++ vb2_plane_size(vb, 0), size); ++ return -EINVAL; ++ } ++ ++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); ++ ++ if (node->id == FE_CONFIG) { ++ struct cfe_config_buffer *b = to_cfe_config_buffer(buf); ++ void *addr = vb2_plane_vaddr(vb, 0); ++ ++ memcpy(&b->config, addr, sizeof(struct pisp_fe_config)); ++ return pisp_fe_validate_config(&cfe->fe, &b->config, ++ &cfe->node[FE_OUT0].fmt, ++ &cfe->node[FE_OUT1].fmt); ++ } ++ ++ return 0; ++} ++ ++static void cfe_buffer_queue(struct vb2_buffer *vb) ++{ ++ struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); ++ struct cfe_device *cfe = node->cfe; ++ struct cfe_buffer *buf = to_cfe_buffer(vb); ++ unsigned long flags; ++ ++ cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, node_desc[node->id].name, ++ vb); ++ ++ spin_lock_irqsave(&cfe->state_lock, flags); ++ ++ list_add_tail(&buf->list, &node->dma_queue); ++ ++ if (!cfe->job_ready) ++ cfe->job_ready = cfe_check_job_ready(cfe); ++ ++ if (!cfe->job_queued && cfe->job_ready && ++ test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) { ++ cfe_dbg("Preparing job immediately for channel %u\n", ++ node->id); ++ cfe_prepare_next_job(cfe); ++ } ++ ++ spin_unlock_irqrestore(&cfe->state_lock, flags); ++} ++ ++static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count) ++{ ++ struct v4l2_mbus_config mbus_config = { 0 }; ++ struct cfe_node *node = vb2_get_drv_priv(vq); ++ struct cfe_device *cfe = node->cfe; ++ int ret; ++ ++ cfe_dbg("%s: [%s] begin.\n", __func__, node_desc[node->id].name); ++ ++ if (!check_state(cfe, NODE_ENABLED, node->id)) { ++ cfe_err("%s node link is not enabled.\n", ++ node_desc[node->id].name); ++ return -EINVAL; ++ } ++ ++ ret = pm_runtime_resume_and_get(&cfe->pdev->dev); ++ if (ret < 0) { ++ cfe_err("pm_runtime_resume_and_get failed\n"); ++ goto err_streaming; ++ } ++ ++ ret = media_pipeline_start(&node->pad, &cfe->pipe); ++ if (ret < 0) { ++ cfe_err("Failed to start media pipeline: %d\n", ret); ++ goto err_pm_put; ++ } ++ ++ clear_state(cfe, FS_INT | FE_INT, node->id); ++ set_state(cfe, NODE_STREAMING, node->id); ++ cfe_start_channel(node); ++ ++ if (!test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) { ++ cfe_dbg("Not all nodes are set to streaming yet!\n"); ++ return 0; ++ } ++ ++ cfg_reg_write(cfe, MIPICFG_CFG, MIPICFG_CFG_SEL_CSI); ++ cfg_reg_write(cfe, MIPICFG_INTE, MIPICFG_INT_CSI_DMA | MIPICFG_INT_PISP_FE); ++ ++ cfe->csi2.active_data_lanes = cfe->csi2.dphy.num_lanes; ++ cfe_dbg("Running with %u data lanes\n", cfe->csi2.active_data_lanes); ++ ++ ret = v4l2_subdev_call(cfe->sensor, pad, get_mbus_config, 0, ++ &mbus_config); ++ if (ret < 0 && ret != -ENOIOCTLCMD) { ++ cfe_err("g_mbus_config failed\n"); ++ goto err_pm_put; ++ } ++ ++ cfe->csi2.active_data_lanes = mbus_config.bus.mipi_csi2.num_data_lanes; ++ if (!cfe->csi2.active_data_lanes) ++ cfe->csi2.active_data_lanes = cfe->csi2.dphy.num_lanes; ++ if (cfe->csi2.active_data_lanes > cfe->csi2.dphy.num_lanes) { ++ cfe_err("Device has requested %u data lanes, which is >%u configured in DT\n", ++ cfe->csi2.active_data_lanes, cfe->csi2.dphy.num_lanes); ++ ret = -EINVAL; ++ goto err_disable_cfe; ++ } ++ ++ cfe_dbg("Starting sensor streaming\n"); ++ ++ csi2_open_rx(&cfe->csi2); ++ ++ cfe->sequence = 0; ++ ret = v4l2_subdev_call(cfe->sensor, video, s_stream, 1); ++ if (ret < 0) { ++ cfe_err("stream on failed in subdev\n"); ++ goto err_disable_cfe; ++ } ++ ++ cfe_dbg("%s: [%s] end.\n", __func__, node_desc[node->id].name); ++ ++ return 0; ++ ++err_disable_cfe: ++ csi2_close_rx(&cfe->csi2); ++ cfe_stop_channel(node, true); ++ media_pipeline_stop(&node->pad); ++err_pm_put: ++ pm_runtime_put(&cfe->pdev->dev); ++err_streaming: ++ cfe_return_buffers(node, VB2_BUF_STATE_QUEUED); ++ clear_state(cfe, NODE_STREAMING, node->id); ++ ++ return ret; ++} ++ ++static void cfe_stop_streaming(struct vb2_queue *vq) ++{ ++ struct cfe_node *node = vb2_get_drv_priv(vq); ++ struct cfe_device *cfe = node->cfe; ++ unsigned long flags; ++ bool fe_stop; ++ ++ cfe_dbg("%s: [%s] begin.\n", __func__, node_desc[node->id].name); ++ ++ spin_lock_irqsave(&cfe->state_lock, flags); ++ fe_stop = is_fe_enabled(cfe) && ++ test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); ++ ++ cfe->job_ready = false; ++ clear_state(cfe, NODE_STREAMING, node->id); ++ spin_unlock_irqrestore(&cfe->state_lock, flags); ++ ++ cfe_stop_channel(node, fe_stop); ++ ++ if (!test_any_node(cfe, NODE_STREAMING)) { ++ /* Stop streaming the sensor and disable the peripheral. */ ++ if (v4l2_subdev_call(cfe->sensor, video, s_stream, 0) < 0) ++ cfe_err("stream off failed in subdev\n"); ++ ++ csi2_close_rx(&cfe->csi2); ++ ++ cfg_reg_write(cfe, MIPICFG_INTE, 0); ++ } ++ ++ media_pipeline_stop(&node->pad); ++ ++ /* Clear all queued buffers for the node */ ++ cfe_return_buffers(node, VB2_BUF_STATE_ERROR); ++ ++ pm_runtime_put(&cfe->pdev->dev); ++ ++ cfe_dbg("%s: [%s] end.\n", __func__, node_desc[node->id].name); ++} ++ ++static const struct vb2_ops cfe_video_qops = { ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++ .queue_setup = cfe_queue_setup, ++ .buf_prepare = cfe_buffer_prepare, ++ .buf_queue = cfe_buffer_queue, ++ .start_streaming = cfe_start_streaming, ++ .stop_streaming = cfe_stop_streaming, ++}; ++ ++/* ++ * v4l2 ioctl ops ++ */ ++ ++static int cfe_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ strscpy(cap->driver, CFE_MODULE_NAME, sizeof(cap->driver)); ++ strscpy(cap->card, CFE_MODULE_NAME, sizeof(cap->card)); ++ ++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", ++ dev_name(&cfe->pdev->dev)); ++ ++ cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE | ++ V4L2_CAP_META_OUTPUT; ++ ++ return 0; ++} ++ ++static int cfe_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ unsigned int i, j; ++ ++ if (!is_image_output_node(node)) ++ return -EINVAL; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) { ++ if (f->mbus_code && formats[i].code != f->mbus_code) ++ continue; ++ ++ if (formats[i].flags & CFE_FORMAT_FLAG_META_OUT || ++ formats[i].flags & CFE_FORMAT_FLAG_META_CAP) ++ continue; ++ ++ if (is_fe_node(node) && ++ !(formats[i].flags & CFE_FORMAT_FLAG_FE_OUT)) ++ continue; ++ ++ if (j == f->index) { ++ f->pixelformat = formats[i].fourcc; ++ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ return 0; ++ } ++ j++; ++ } ++ ++ return -EINVAL; ++} ++ ++static int cfe_g_fmt(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ if (f->type != node->buffer_queue.type) ++ return -EINVAL; ++ ++ *f = node->fmt; ++ ++ return 0; ++} ++ ++static int try_fmt_vid_cap(struct cfe_node *node, struct v4l2_format *f) ++{ ++ struct cfe_device *cfe = node->cfe; ++ const struct cfe_fmt *fmt; ++ ++ cfe_dbg("%s: [%s] %ux%u, V4L2 pix " V4L2_FOURCC_CONV "\n", ++ __func__, node_desc[node->id].name, ++ f->fmt.pix.width, f->fmt.pix.height, ++ V4L2_FOURCC_CONV_ARGS(f->fmt.pix.pixelformat)); ++ ++ if (!is_image_output_node(node)) ++ return -EINVAL; ++ ++ /* ++ * Default to a format that works for both CSI2 and FE. ++ */ ++ fmt = find_format_by_pix(f->fmt.pix.pixelformat); ++ if (!fmt) ++ fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10); ++ ++ f->fmt.pix.pixelformat = fmt->fourcc; ++ ++ if (is_fe_node(node) && fmt->remap[CFE_REMAP_16BIT]) { ++ f->fmt.pix.pixelformat = fmt->remap[CFE_REMAP_16BIT]; ++ fmt = find_format_by_pix(f->fmt.pix.pixelformat); ++ } ++ ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ ++ cfe_calc_format_size_bpl(cfe, fmt, f); ++ ++ return 0; ++} ++ ++static int cfe_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ struct vb2_queue *q = &node->buffer_queue; ++ int ret; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ if (vb2_is_busy(q)) ++ return -EBUSY; ++ ++ ret = try_fmt_vid_cap(node, f); ++ if (ret) ++ return ret; ++ ++ node->fmt = *f; ++ ++ cfe_dbg("%s: Set %ux%u, V4L2 pix " V4L2_FOURCC_CONV "\n", __func__, ++ node->fmt.fmt.pix.width, node->fmt.fmt.pix.height, ++ V4L2_FOURCC_CONV_ARGS(node->fmt.fmt.pix.pixelformat)); ++ ++ return 0; ++} ++ ++static int cfe_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ return try_fmt_vid_cap(node, f); ++} ++ ++static int cfe_enum_fmt_meta(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ if (!is_meta_node(node) || f->index != 0) ++ return -EINVAL; ++ ++ switch (node->id) { ++ case CSI2_CH1_EMBEDDED: ++ f->pixelformat = V4L2_META_FMT_SENSOR_DATA; ++ return 0; ++ case FE_STATS: ++ f->pixelformat = V4L2_META_FMT_RPI_FE_STATS; ++ return 0; ++ case FE_CONFIG: ++ f->pixelformat = V4L2_META_FMT_RPI_FE_CFG; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int try_fmt_meta(struct cfe_node *node, struct v4l2_format *f) ++{ ++ switch (node->id) { ++ case CSI2_CH1_EMBEDDED: ++ f->fmt.meta.dataformat = V4L2_META_FMT_SENSOR_DATA; ++ if (!f->fmt.meta.buffersize) ++ f->fmt.meta.buffersize = DEFAULT_EMBEDDED_SIZE; ++ f->fmt.meta.buffersize = ++ min_t(u32, f->fmt.meta.buffersize, MAX_BUFFER_SIZE); ++ f->fmt.meta.buffersize = ++ ALIGN(f->fmt.meta.buffersize, BPL_ALIGNMENT); ++ return 0; ++ case FE_STATS: ++ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_STATS; ++ f->fmt.meta.buffersize = sizeof(struct pisp_statistics); ++ return 0; ++ case FE_CONFIG: ++ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_CFG; ++ f->fmt.meta.buffersize = sizeof(struct pisp_fe_config); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int cfe_s_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ struct vb2_queue *q = &node->buffer_queue; ++ int ret; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ if (vb2_is_busy(q)) ++ return -EBUSY; ++ ++ if (f->type != node->buffer_queue.type) ++ return -EINVAL; ++ ++ ret = try_fmt_meta(node, f); ++ if (ret) ++ return ret; ++ ++ node->fmt = *f; ++ ++ cfe_dbg("%s: Set " V4L2_FOURCC_CONV "\n", __func__, ++ V4L2_FOURCC_CONV_ARGS(node->fmt.fmt.meta.dataformat)); ++ ++ return 0; ++} ++ ++static int cfe_try_fmt_meta(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ return try_fmt_meta(node, f); ++} ++ ++static int cfe_enum_framesizes(struct file *file, void *priv, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ const struct cfe_fmt *fmt; ++ ++ cfe_dbg("%s [%s]\n", __func__, node_desc[node->id].name); ++ ++ if (fsize->index > 0) ++ return -EINVAL; ++ ++ /* check for valid format */ ++ fmt = find_format_by_pix(fsize->pixel_format); ++ if (!fmt) { ++ cfe_dbg("Invalid pixel code: %x\n", fsize->pixel_format); ++ return -EINVAL; ++ } ++ ++ /* TODO: Do we have limits on the step_width? */ ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; ++ fsize->stepwise.min_width = MIN_WIDTH; ++ fsize->stepwise.max_width = MAX_WIDTH; ++ fsize->stepwise.step_width = 2; ++ fsize->stepwise.min_height = MIN_HEIGHT; ++ fsize->stepwise.max_height = MAX_HEIGHT; ++ fsize->stepwise.step_height = 1; ++ ++ return 0; ++} ++ ++static int cfe_subscribe_event(struct v4l2_fh *fh, ++ const struct v4l2_event_subscription *sub) ++{ ++ struct cfe_node *node = video_get_drvdata(fh->vdev); ++ ++ switch (sub->type) { ++ case V4L2_EVENT_FRAME_SYNC: ++ if (!is_image_output_node(node)) ++ break; ++ ++ return v4l2_event_subscribe(fh, sub, 2, NULL); ++ case V4L2_EVENT_SOURCE_CHANGE: ++ if (is_meta_input_node(node)) ++ break; ++ ++ return v4l2_event_subscribe(fh, sub, 4, NULL); ++ } ++ ++ return v4l2_ctrl_subscribe_event(fh, sub); ++} ++ ++static const struct v4l2_ioctl_ops cfe_ioctl_ops = { ++ .vidioc_querycap = cfe_querycap, ++ .vidioc_enum_fmt_vid_cap = cfe_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = cfe_g_fmt, ++ .vidioc_s_fmt_vid_cap = cfe_s_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = cfe_try_fmt_vid_cap, ++ ++ .vidioc_enum_fmt_meta_cap = cfe_enum_fmt_meta, ++ .vidioc_g_fmt_meta_cap = cfe_g_fmt, ++ .vidioc_s_fmt_meta_cap = cfe_s_fmt_meta, ++ .vidioc_try_fmt_meta_cap = cfe_try_fmt_meta, ++ ++ .vidioc_enum_fmt_meta_out = cfe_enum_fmt_meta, ++ .vidioc_g_fmt_meta_out = cfe_g_fmt, ++ .vidioc_s_fmt_meta_out = cfe_s_fmt_meta, ++ .vidioc_try_fmt_meta_out = cfe_try_fmt_meta, ++ ++ .vidioc_enum_framesizes = cfe_enum_framesizes, ++ ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_create_bufs = vb2_ioctl_create_bufs, ++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ ++ .vidioc_subscribe_event = cfe_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++}; ++ ++static void cfe_notify(struct v4l2_subdev *sd, unsigned int notification, ++ void *arg) ++{ ++ struct cfe_device *cfe = to_cfe_device(sd->v4l2_dev); ++ unsigned int i; ++ ++ switch (notification) { ++ case V4L2_DEVICE_NOTIFY_EVENT: ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->node[i]; ++ ++ if (check_state(cfe, NODE_REGISTERED, i)) ++ continue; ++ ++ v4l2_event_queue(&node->video_dev, arg); ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++/* cfe capture driver file operations */ ++static const struct v4l2_file_operations cfe_fops = { ++ .owner = THIS_MODULE, ++ .open = v4l2_fh_open, ++ .release = vb2_fop_release, ++ .poll = vb2_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = vb2_fop_mmap, ++}; ++ ++static int cfe_video_link_validate(struct media_link *link) ++{ ++ struct video_device *vd = container_of(link->sink->entity, ++ struct video_device, entity); ++ struct cfe_node *node = container_of(vd, struct cfe_node, video_dev); ++ struct cfe_device *cfe = node->cfe; ++ struct v4l2_mbus_framefmt *source_fmt; ++ struct v4l2_subdev_state *state; ++ struct v4l2_subdev *source_sd; ++ int ret = 0; ++ ++ cfe_dbg("%s: [%s] link \"%s\":%u -> \"%s\":%u\n", __func__, ++ node_desc[node->id].name, ++ link->source->entity->name, link->source->index, ++ link->sink->entity->name, link->sink->index); ++ ++ if (!media_entity_remote_source_pad_unique(link->sink->entity)) { ++ cfe_err("video node %s pad not connected\n", vd->name); ++ return -ENOTCONN; ++ } ++ ++ source_sd = media_entity_to_v4l2_subdev(link->source->entity); ++ ++ state = v4l2_subdev_lock_and_get_active_state(source_sd); ++ ++ source_fmt = v4l2_subdev_get_pad_format(source_sd, state, ++ link->source->index); ++ if (!source_fmt) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (is_image_output_node(node)) { ++ struct v4l2_pix_format *pix_fmt = &node->fmt.fmt.pix; ++ const struct cfe_fmt *fmt; ++ ++ if (source_fmt->width != pix_fmt->width || ++ source_fmt->height != pix_fmt->height) { ++ cfe_err("Wrong width or height %ux%u (remote pad set to %ux%u)\n", ++ pix_fmt->width, pix_fmt->height, ++ source_fmt->width, ++ source_fmt->height); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ fmt = find_format_by_code(source_fmt->code); ++ if (!fmt || fmt->fourcc != pix_fmt->pixelformat) { ++ cfe_err("Format mismatch!\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ } else if (node->id == CSI2_CH1_EMBEDDED) { ++ struct v4l2_meta_format *meta_fmt = &node->fmt.fmt.meta; ++ ++ if (source_fmt->width * source_fmt->height != ++ meta_fmt->buffersize || ++ source_fmt->code != MEDIA_BUS_FMT_SENSOR_DATA) { ++ cfe_err("WARNING: Wrong metadata width/height/code %ux%u %08x (remote pad set to %ux%u %08x)\n", ++ meta_fmt->buffersize, 1, ++ MEDIA_BUS_FMT_SENSOR_DATA, ++ source_fmt->width, ++ source_fmt->height, ++ source_fmt->code); ++ /* TODO: this should throw an error eventually */ ++ } ++ } ++ ++out: ++ v4l2_subdev_unlock_state(state); ++ ++ return ret; ++} ++ ++static const struct media_entity_operations cfe_media_entity_ops = { ++ .link_validate = cfe_video_link_validate, ++}; ++ ++static int cfe_video_link_notify(struct media_link *link, u32 flags, ++ unsigned int notification) ++{ ++ struct media_device *mdev = link->graph_obj.mdev; ++ struct cfe_device *cfe = container_of(mdev, struct cfe_device, mdev); ++ struct media_entity *fe = &cfe->fe.sd.entity; ++ struct media_entity *csi2 = &cfe->csi2.sd.entity; ++ unsigned long lock_flags; ++ unsigned int i; ++ ++ if (notification != MEDIA_DEV_NOTIFY_POST_LINK_CH) ++ return 0; ++ ++ cfe_dbg("%s: %s[%u] -> %s[%u] 0x%x", __func__, ++ link->source->entity->name, link->source->index, ++ link->sink->entity->name, link->sink->index, flags); ++ ++ spin_lock_irqsave(&cfe->state_lock, lock_flags); ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ if (link->sink->entity != &cfe->node[i].video_dev.entity && ++ link->source->entity != &cfe->node[i].video_dev.entity) ++ continue; ++ ++ if (link->flags & MEDIA_LNK_FL_ENABLED) ++ set_state(cfe, NODE_ENABLED, i); ++ else ++ clear_state(cfe, NODE_ENABLED, i); ++ ++ break; ++ } ++ ++ spin_unlock_irqrestore(&cfe->state_lock, lock_flags); ++ ++ if (link->source->entity != csi2) ++ return 0; ++ if (link->sink->index != 0) ++ return 0; ++ if (link->source->index == node_desc[CSI2_CH1_EMBEDDED].link_pad) ++ return 0; ++ ++ cfe->fe_csi2_channel = -1; ++ if (link->sink->entity == fe && (link->flags & MEDIA_LNK_FL_ENABLED)) { ++ if (link->source->index == node_desc[CSI2_CH0].link_pad) ++ cfe->fe_csi2_channel = CSI2_CH0; ++ else if (link->source->index == node_desc[CSI2_CH2].link_pad) ++ cfe->fe_csi2_channel = CSI2_CH2; ++ else if (link->source->index == node_desc[CSI2_CH3].link_pad) ++ cfe->fe_csi2_channel = CSI2_CH3; ++ } ++ ++ if (is_fe_enabled(cfe)) ++ cfe_dbg("%s: Found CSI2:%d -> FE:0 link\n", __func__, ++ cfe->fe_csi2_channel); ++ else ++ cfe_dbg("%s: Unable to find CSI2:x -> FE:0 link\n", __func__); ++ ++ return 0; ++} ++ ++static const struct media_device_ops cfe_media_device_ops = { ++ .link_notify = cfe_video_link_notify, ++}; ++ ++static void cfe_release(struct kref *kref) ++{ ++ struct cfe_device *cfe = container_of(kref, struct cfe_device, kref); ++ ++ media_device_cleanup(&cfe->mdev); ++ ++ kfree(cfe); ++} ++ ++static void cfe_put(struct cfe_device *cfe) ++{ ++ kref_put(&cfe->kref, cfe_release); ++} ++ ++static void cfe_get(struct cfe_device *cfe) ++{ ++ kref_get(&cfe->kref); ++} ++ ++static void cfe_node_release(struct video_device *vdev) ++{ ++ struct cfe_node *node = video_get_drvdata(vdev); ++ ++ cfe_put(node->cfe); ++} ++ ++static int cfe_register_node(struct cfe_device *cfe, int id) ++{ ++ struct video_device *vdev; ++ const struct cfe_fmt *fmt; ++ struct vb2_queue *q; ++ struct cfe_node *node = &cfe->node[id]; ++ int ret; ++ ++ node->cfe = cfe; ++ node->id = id; ++ ++ if (is_image_output_node(node)) { ++ fmt = find_format_by_code(cfe_default_format.code); ++ if (!fmt) { ++ cfe_err("Failed to find format code\n"); ++ return -EINVAL; ++ } ++ ++ node->fmt.fmt.pix.pixelformat = fmt->fourcc; ++ v4l2_fill_pix_format(&node->fmt.fmt.pix, &cfe_default_format); ++ ++ ret = try_fmt_vid_cap(node, &node->fmt); ++ if (ret) ++ return ret; ++ } else { ++ ret = try_fmt_meta(node, &node->fmt); ++ if (ret) ++ return ret; ++ } ++ node->fmt.type = node_desc[id].buf_type; ++ ++ mutex_init(&node->lock); ++ ++ q = &node->buffer_queue; ++ q->type = node_desc[id].buf_type; ++ q->io_modes = VB2_MMAP | VB2_DMABUF; ++ q->drv_priv = node; ++ q->ops = &cfe_video_qops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->buf_struct_size = id == FE_CONFIG ? sizeof(struct cfe_config_buffer) ++ : sizeof(struct cfe_buffer); ++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ q->lock = &node->lock; ++ q->min_buffers_needed = 1; ++ q->dev = &cfe->pdev->dev; ++ ++ ret = vb2_queue_init(q); ++ if (ret) { ++ cfe_err("vb2_queue_init() failed\n"); ++ return ret; ++ } ++ ++ INIT_LIST_HEAD(&node->dma_queue); ++ ++ vdev = &node->video_dev; ++ vdev->release = cfe_node_release; ++ vdev->fops = &cfe_fops; ++ vdev->ioctl_ops = &cfe_ioctl_ops; ++ vdev->entity.ops = &cfe_media_entity_ops; ++ vdev->v4l2_dev = &cfe->v4l2_dev; ++ vdev->vfl_dir = (is_image_output_node(node) || is_meta_output_node(node)) ++ ? VFL_DIR_RX : VFL_DIR_TX; ++ vdev->queue = q; ++ vdev->lock = &node->lock; ++ vdev->device_caps = node_desc[id].cap; ++ vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; ++ ++ /* Define the device names */ ++ snprintf(vdev->name, sizeof(vdev->name), "%s-%s", CFE_MODULE_NAME, ++ node_desc[id].name); ++ ++ video_set_drvdata(vdev, node); ++ if (node->id == FE_OUT0) ++ vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; ++ node->pad.flags = node_desc[id].pad_flags; ++ media_entity_pads_init(&vdev->entity, 1, &node->pad); ++ ++ if (is_meta_node(node)) { ++ v4l2_disable_ioctl(&node->video_dev, ++ VIDIOC_ENUM_FRAMEINTERVALS); ++ v4l2_disable_ioctl(&node->video_dev, ++ VIDIOC_ENUM_FRAMESIZES); ++ } ++ ++ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); ++ if (ret) { ++ cfe_err("Unable to register video device %s\n", vdev->name); ++ return ret; ++ } ++ ++ cfe_info("Registered [%s] node id %d successfully as /dev/video%u\n", ++ vdev->name, id, vdev->num); ++ ++ /* ++ * Acquire a reference to cfe, which will be released when the video ++ * device will be unregistered and userspace will have closed all open ++ * file handles. ++ */ ++ cfe_get(cfe); ++ set_state(cfe, NODE_REGISTERED, id); ++ ++ return 0; ++} ++ ++static void cfe_unregister_nodes(struct cfe_device *cfe) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->node[i]; ++ ++ if (check_state(cfe, NODE_REGISTERED, i)) { ++ clear_state(cfe, NODE_REGISTERED, i); ++ video_unregister_device(&node->video_dev); ++ } ++ } ++} ++ ++static int cfe_link_node_pads(struct cfe_device *cfe) ++{ ++ unsigned int i; ++ int ret; ++ ++ for (i = 0; i < CSI2_NUM_CHANNELS; i++) { ++ struct cfe_node *node = &cfe->node[i]; ++ ++ if (!check_state(cfe, NODE_REGISTERED, i)) ++ continue; ++ ++ if (i < cfe->sensor->entity.num_pads) { ++ /* Sensor -> CSI2 */ ++ ret = media_create_pad_link(&cfe->sensor->entity, i, ++ &cfe->csi2.sd.entity, i, ++ MEDIA_LNK_FL_IMMUTABLE | ++ MEDIA_LNK_FL_ENABLED); ++ if (ret) ++ return ret; ++ } ++ ++ /* CSI2 channel # -> /dev/video# */ ++ ret = media_create_pad_link(&cfe->csi2.sd.entity, ++ node_desc[i].link_pad, ++ &node->video_dev.entity, 0, 0); ++ if (ret) ++ return ret; ++ ++ if (node->id != CSI2_CH1_EMBEDDED) { ++ /* CSI2 channel # -> FE Input */ ++ ret = media_create_pad_link(&cfe->csi2.sd.entity, ++ node_desc[i].link_pad, ++ &cfe->fe.sd.entity, ++ FE_STREAM_PAD, 0); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ for (; i < NUM_NODES; i++) { ++ struct cfe_node *node = &cfe->node[i]; ++ struct media_entity *src, *dst; ++ unsigned int src_pad, dst_pad; ++ ++ if (node_desc[i].pad_flags & MEDIA_PAD_FL_SINK) { ++ /* FE -> /dev/video# */ ++ src = &cfe->fe.sd.entity; ++ src_pad = node_desc[i].link_pad; ++ dst = &node->video_dev.entity; ++ dst_pad = 0; ++ } else { ++ /* /dev/video# -> FE */ ++ dst = &cfe->fe.sd.entity; ++ dst_pad = node_desc[i].link_pad; ++ src = &node->video_dev.entity; ++ src_pad = 0; ++ } ++ ++ ret = media_create_pad_link(src, src_pad, dst, dst_pad, 0); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int cfe_probe_complete(struct cfe_device *cfe) ++{ ++ unsigned int i; ++ int ret; ++ ++ cfe->v4l2_dev.notify = cfe_notify; ++ ++ cfe->sensor_embedded_data = (cfe->sensor->entity.num_pads >= 2); ++ ++ for (i = 0; i < NUM_NODES; i++) { ++ ret = cfe_register_node(cfe, i); ++ if (ret) { ++ cfe_err("Unable to register video node %u.\n", i); ++ goto unregister; ++ } ++ } ++ ++ ret = cfe_link_node_pads(cfe); ++ if (ret) { ++ cfe_err("Unable to link node pads.\n"); ++ goto unregister; ++ } ++ ++ ret = v4l2_device_register_subdev_nodes(&cfe->v4l2_dev); ++ if (ret) { ++ cfe_err("Unable to register subdev nodes.\n"); ++ goto unregister; ++ } ++ ++ /* ++ * Release the initial reference, all references are now owned by the ++ * video devices. ++ */ ++ cfe_put(cfe); ++ return 0; ++ ++unregister: ++ cfe_unregister_nodes(cfe); ++ cfe_put(cfe); ++ ++ return ret; ++} ++ ++static int cfe_async_bound(struct v4l2_async_notifier *notifier, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); ++ ++ if (cfe->sensor) { ++ cfe_info("Rejecting subdev %s (Already set!!)", subdev->name); ++ return 0; ++ } ++ ++ cfe->sensor = subdev; ++ cfe_info("Using sensor %s for capture\n", subdev->name); ++ ++ return 0; ++} ++ ++static int cfe_async_complete(struct v4l2_async_notifier *notifier) ++{ ++ struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); ++ ++ return cfe_probe_complete(cfe); ++} ++ ++static const struct v4l2_async_notifier_operations cfe_async_ops = { ++ .bound = cfe_async_bound, ++ .complete = cfe_async_complete, ++}; ++ ++static int of_cfe_connect_subdevs(struct cfe_device *cfe) ++{ ++ struct platform_device *pdev = cfe->pdev; ++ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; ++ struct device_node *node = pdev->dev.of_node; ++ struct device_node *ep_node; ++ struct device_node *sensor_node; ++ unsigned int lane; ++ int ret = -EINVAL; ++ ++ /* Get the local endpoint and remote device. */ ++ ep_node = of_graph_get_next_endpoint(node, NULL); ++ if (!ep_node) { ++ cfe_err("can't get next endpoint\n"); ++ return -EINVAL; ++ } ++ ++ cfe_dbg("ep_node is %pOF\n", ep_node); ++ ++ sensor_node = of_graph_get_remote_port_parent(ep_node); ++ if (!sensor_node) { ++ cfe_err("can't get remote parent\n"); ++ goto cleanup_exit; ++ } ++ ++ cfe_info("found subdevice %pOF\n", sensor_node); ++ ++ /* Parse the local endpoint and validate its configuration. */ ++ v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); ++ ++ cfe->csi2.multipacket_line = ++ fwnode_property_present(of_fwnode_handle(ep_node), ++ "multipacket-line"); ++ ++ if (ep.bus_type != V4L2_MBUS_CSI2_DPHY) { ++ cfe_err("endpoint node type != CSI2\n"); ++ return -EINVAL; ++ } ++ ++ for (lane = 0; lane < ep.bus.mipi_csi2.num_data_lanes; lane++) { ++ if (ep.bus.mipi_csi2.data_lanes[lane] != lane + 1) { ++ cfe_err("subdevice %pOF: data lanes reordering not supported\n", ++ sensor_node); ++ goto cleanup_exit; ++ } ++ } ++ ++ /* TODO: Get the frequency from devicetree */ ++ cfe->csi2.dphy.dphy_freq = 999; ++ cfe->csi2.dphy.num_lanes = ep.bus.mipi_csi2.num_data_lanes; ++ cfe->csi2.bus_flags = ep.bus.mipi_csi2.flags; ++ ++ cfe_dbg("subdevice %pOF: %u data lanes, flags=0x%08x, multipacket_line=%u\n", ++ sensor_node, cfe->csi2.dphy.num_lanes, cfe->csi2.bus_flags, ++ cfe->csi2.multipacket_line); ++ ++ /* Initialize and register the async notifier. */ ++ v4l2_async_nf_init(&cfe->notifier); ++ cfe->notifier.ops = &cfe_async_ops; ++ ++ cfe->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; ++ cfe->asd.match.fwnode = of_fwnode_handle(sensor_node); ++ ret = __v4l2_async_nf_add_subdev(&cfe->notifier, &cfe->asd); ++ if (ret) { ++ cfe_err("Error adding subdevice: %d\n", ret); ++ goto cleanup_exit; ++ } ++ ++ ret = v4l2_async_nf_register(&cfe->v4l2_dev, &cfe->notifier); ++ if (ret) { ++ cfe_err("Error registering async notifier: %d\n", ret); ++ ret = -EINVAL; ++ } ++ ++cleanup_exit: ++ of_node_put(sensor_node); ++ of_node_put(ep_node); ++ ++ return ret; ++} ++ ++static int cfe_probe(struct platform_device *pdev) ++{ ++ struct cfe_device *cfe; ++ char debugfs_name[32]; ++ int ret; ++ ++ cfe = kzalloc(sizeof(*cfe), GFP_KERNEL); ++ if (!cfe) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, cfe); ++ ++ kref_init(&cfe->kref); ++ cfe->pdev = pdev; ++ cfe->fe_csi2_channel = -1; ++ spin_lock_init(&cfe->state_lock); ++ ++ cfe->csi2.base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(cfe->csi2.base)) { ++ dev_err(&pdev->dev, "Failed to get dma io block\n"); ++ ret = PTR_ERR(cfe->csi2.base); ++ goto err_cfe_put; ++ } ++ ++ cfe->csi2.dphy.base = devm_platform_ioremap_resource(pdev, 1); ++ if (IS_ERR(cfe->csi2.dphy.base)) { ++ dev_err(&pdev->dev, "Failed to get host io block\n"); ++ ret = PTR_ERR(cfe->csi2.dphy.base); ++ goto err_cfe_put; ++ } ++ ++ cfe->mipi_cfg_base = devm_platform_ioremap_resource(pdev, 2); ++ if (IS_ERR(cfe->mipi_cfg_base)) { ++ dev_err(&pdev->dev, "Failed to get mipi cfg io block\n"); ++ ret = PTR_ERR(cfe->mipi_cfg_base); ++ goto err_cfe_put; ++ } ++ ++ cfe->fe.base = devm_platform_ioremap_resource(pdev, 3); ++ if (IS_ERR(cfe->fe.base)) { ++ dev_err(&pdev->dev, "Failed to get pisp fe io block\n"); ++ ret = PTR_ERR(cfe->fe.base); ++ goto err_cfe_put; ++ } ++ ++ ret = platform_get_irq(pdev, 0); ++ if (ret <= 0) { ++ dev_err(&pdev->dev, "No IRQ resource\n"); ++ ret = -EINVAL; ++ goto err_cfe_put; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, ret, cfe_isr, 0, "rp1-cfe", cfe); ++ if (ret) { ++ dev_err(&pdev->dev, "Unable to request interrupt\n"); ++ ret = -EINVAL; ++ goto err_cfe_put; ++ } ++ ++ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); ++ if (ret) { ++ dev_err(&pdev->dev, "DMA enable failed\n"); ++ goto err_cfe_put; ++ } ++ ++ /* TODO: Enable clock only when running. */ ++ cfe->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(cfe->clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(cfe->clk), ++ "clock not found\n"); ++ ++ cfe->mdev.dev = &pdev->dev; ++ cfe->mdev.ops = &cfe_media_device_ops; ++ strscpy(cfe->mdev.model, CFE_MODULE_NAME, sizeof(cfe->mdev.model)); ++ strscpy(cfe->mdev.serial, "", sizeof(cfe->mdev.serial)); ++ snprintf(cfe->mdev.bus_info, sizeof(cfe->mdev.bus_info), "platform:%s", ++ dev_name(&pdev->dev)); ++ ++ media_device_init(&cfe->mdev); ++ ++ cfe->v4l2_dev.mdev = &cfe->mdev; ++ ++ ret = v4l2_device_register(&pdev->dev, &cfe->v4l2_dev); ++ if (ret) { ++ cfe_err("Unable to register v4l2 device.\n"); ++ goto err_cfe_put; ++ } ++ ++ snprintf(debugfs_name, sizeof(debugfs_name), "rp1-cfe:%s", ++ dev_name(&pdev->dev)); ++ cfe->debugfs = debugfs_create_dir(debugfs_name, NULL); ++ debugfs_create_file("format", 0444, cfe->debugfs, cfe, &format_fops); ++ debugfs_create_file("regs", 0444, cfe->debugfs, cfe, ++ &mipi_cfg_regs_fops); ++ ++ /* Enable the block power domain */ ++ pm_runtime_enable(&pdev->dev); ++ ++ ret = pm_runtime_resume_and_get(&cfe->pdev->dev); ++ if (ret) ++ goto err_runtime_disable; ++ ++ cfe->csi2.v4l2_dev = &cfe->v4l2_dev; ++ ret = csi2_init(&cfe->csi2, cfe->debugfs); ++ if (ret) { ++ cfe_err("Failed to init csi2 (%d)\n", ret); ++ goto err_runtime_put; ++ } ++ ++ cfe->fe.v4l2_dev = &cfe->v4l2_dev; ++ ret = pisp_fe_init(&cfe->fe, cfe->debugfs); ++ if (ret) { ++ cfe_err("Failed to init pisp fe (%d)\n", ret); ++ goto err_csi2_uninit; ++ } ++ ++ cfe->mdev.hw_revision = cfe->fe.hw_revision; ++ ret = media_device_register(&cfe->mdev); ++ if (ret < 0) { ++ cfe_err("Unable to register media-controller device.\n"); ++ goto err_pisp_fe_uninit; ++ } ++ ++ ret = of_cfe_connect_subdevs(cfe); ++ if (ret) { ++ cfe_err("Failed to connect subdevs\n"); ++ goto err_media_unregister; ++ } ++ ++ pm_runtime_put(&cfe->pdev->dev); ++ ++ return 0; ++ ++err_media_unregister: ++ media_device_unregister(&cfe->mdev); ++err_pisp_fe_uninit: ++ pisp_fe_uninit(&cfe->fe); ++err_csi2_uninit: ++ csi2_uninit(&cfe->csi2); ++err_runtime_put: ++ pm_runtime_put(&cfe->pdev->dev); ++err_runtime_disable: ++ pm_runtime_disable(&pdev->dev); ++ debugfs_remove(cfe->debugfs); ++ v4l2_device_unregister(&cfe->v4l2_dev); ++err_cfe_put: ++ cfe_put(cfe); ++ ++ return ret; ++} ++ ++static int cfe_remove(struct platform_device *pdev) ++{ ++ struct cfe_device *cfe = platform_get_drvdata(pdev); ++ ++ debugfs_remove(cfe->debugfs); ++ ++ v4l2_async_nf_unregister(&cfe->notifier); ++ media_device_unregister(&cfe->mdev); ++ cfe_unregister_nodes(cfe); ++ ++ pisp_fe_uninit(&cfe->fe); ++ csi2_uninit(&cfe->csi2); ++ ++ pm_runtime_disable(&pdev->dev); ++ ++ v4l2_device_unregister(&cfe->v4l2_dev); ++ ++ return 0; ++} ++ ++static int cfe_runtime_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct cfe_device *cfe = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(cfe->clk); ++ ++ return 0; ++} ++ ++static int cfe_runtime_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct cfe_device *cfe = platform_get_drvdata(pdev); ++ int ret; ++ ++ ret = clk_prepare_enable(cfe->clk); ++ if (ret) { ++ dev_err(dev, "Unable to enable clock\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops cfe_pm_ops = { ++ SET_RUNTIME_PM_OPS(cfe_runtime_suspend, cfe_runtime_resume, NULL) ++ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) ++}; ++ ++static const struct of_device_id cfe_of_match[] = { ++ { .compatible = "raspberrypi,rp1-cfe" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, cfe_of_match); ++ ++static struct platform_driver cfe_driver = { ++ .probe = cfe_probe, ++ .remove = cfe_remove, ++ .driver = { ++ .name = CFE_MODULE_NAME, ++ .of_match_table = cfe_of_match, ++ .pm = &cfe_pm_ops, ++ }, ++}; ++ ++module_platform_driver(cfe_driver); ++ ++MODULE_AUTHOR("Naushir Patuck "); ++MODULE_DESCRIPTION("RP1 Camera Front End driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(CFE_VERSION); +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 CFE driver. ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _RP1_CFE_ ++#define _RP1_CFE_ ++ ++#include ++#include ++#include ++ ++extern bool cfe_debug_irq; ++ ++enum cfe_remap_types { ++ CFE_REMAP_16BIT, ++ CFE_REMAP_COMPRESSED, ++ CFE_NUM_REMAP, ++}; ++ ++#define CFE_FORMAT_FLAG_META_OUT BIT(0) ++#define CFE_FORMAT_FLAG_META_CAP BIT(1) ++#define CFE_FORMAT_FLAG_FE_OUT BIT(2) ++ ++struct cfe_fmt { ++ u32 fourcc; ++ u32 code; ++ u8 depth; ++ u8 csi_dt; ++ u32 remap[CFE_NUM_REMAP]; ++ u32 flags; ++}; ++ ++extern const struct v4l2_mbus_framefmt cfe_default_format; ++extern const struct v4l2_mbus_framefmt cfe_default_meta_format; ++ ++const struct cfe_fmt *find_format_by_code(u32 code); ++ ++#endif +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h +@@ -0,0 +1,294 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 Camera Front End formats definition ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _CFE_FMTS_H_ ++#define _CFE_FMTS_H_ ++ ++#include "cfe.h" ++ ++static const struct cfe_fmt formats[] = { ++ /* YUV Formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .code = MEDIA_BUS_FMT_YUYV8_1X16, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .code = MEDIA_BUS_FMT_UYVY8_1X16, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .code = MEDIA_BUS_FMT_YVYU8_1X16, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .code = MEDIA_BUS_FMT_VYUY8_1X16, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ }, ++ { ++ /* RGB Formats */ ++ .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ ++ .code = MEDIA_BUS_FMT_RGB565_2X8_LE, ++ .depth = 16, ++ .csi_dt = 0x22, ++ }, ++ { .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ ++ .code = MEDIA_BUS_FMT_RGB565_2X8_BE, ++ .depth = 16, ++ .csi_dt = 0x22 ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ ++ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, ++ .depth = 16, ++ .csi_dt = 0x21, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ ++ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, ++ .depth = 16, ++ .csi_dt = 0x21, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ ++ .code = MEDIA_BUS_FMT_RGB888_1X24, ++ .depth = 24, ++ .csi_dt = 0x24, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ ++ .code = MEDIA_BUS_FMT_BGR888_1X24, ++ .depth = 24, ++ .csi_dt = 0x24, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ ++ .code = MEDIA_BUS_FMT_ARGB8888_1X32, ++ .depth = 32, ++ .csi_dt = 0x0, ++ }, ++ ++ /* Bayer Formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .code = MEDIA_BUS_FMT_SBGGR8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .code = MEDIA_BUS_FMT_SGBRG8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .code = MEDIA_BUS_FMT_SGRBG8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR10P, ++ .code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG10P, ++ .code = MEDIA_BUS_FMT_SGBRG10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG10P, ++ .code = MEDIA_BUS_FMT_SGRBG10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB10P, ++ .code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR12P, ++ .code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG12P, ++ .code = MEDIA_BUS_FMT_SGBRG12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG12P, ++ .code = MEDIA_BUS_FMT_SGRBG12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB12P, ++ .code = MEDIA_BUS_FMT_SRGGB12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR14P, ++ .code = MEDIA_BUS_FMT_SBGGR14_1X14, ++ .depth = 14, ++ .csi_dt = 0x2d, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG14P, ++ .code = MEDIA_BUS_FMT_SGBRG14_1X14, ++ .depth = 14, ++ .csi_dt = 0x2d, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG14P, ++ .code = MEDIA_BUS_FMT_SGRBG14_1X14, ++ .depth = 14, ++ .csi_dt = 0x2d, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB14P, ++ .code = MEDIA_BUS_FMT_SRGGB14_1X14, ++ .depth = 14, ++ .csi_dt = 0x2d, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SBGGR16, ++ .code = MEDIA_BUS_FMT_SBGGR16_1X16, ++ .depth = 16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGBRG16, ++ .code = MEDIA_BUS_FMT_SGBRG16_1X16, ++ .depth = 16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SGRBG16, ++ .code = MEDIA_BUS_FMT_SGRBG16_1X16, ++ .depth = 16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_SRGGB16, ++ .code = MEDIA_BUS_FMT_SRGGB16_1X16, ++ .depth = 16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ /* PiSP Compressed Mode 1 */ ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_RGGB, ++ .code = MEDIA_BUS_FMT_PISP_COMP1_RGGB, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_BGGR, ++ .code = MEDIA_BUS_FMT_PISP_COMP1_BGGR, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GBRG, ++ .code = MEDIA_BUS_FMT_PISP_COMP1_GBRG, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GRBG, ++ .code = MEDIA_BUS_FMT_PISP_COMP1_GRBG, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ /* Greyscale format */ ++ { ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .code = MEDIA_BUS_FMT_Y8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y10P, ++ .code = MEDIA_BUS_FMT_Y10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ .remap = { V4L2_PIX_FMT_Y16 }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y12P, ++ .code = MEDIA_BUS_FMT_Y12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ .remap = { V4L2_PIX_FMT_Y16 }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y14P, ++ .code = MEDIA_BUS_FMT_Y14_1X14, ++ .depth = 14, ++ .csi_dt = 0x2d, ++ .remap = { V4L2_PIX_FMT_Y16 }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y16, ++ .depth = 16, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, ++ ++ /* Embedded data format */ ++ { ++ .fourcc = V4L2_META_FMT_SENSOR_DATA, ++ .code = MEDIA_BUS_FMT_SENSOR_DATA, ++ .depth = 8, ++ .csi_dt = 0x12, ++ .flags = CFE_FORMAT_FLAG_META_CAP, ++ }, ++ ++ /* Frontend formats */ ++ { ++ .fourcc = V4L2_META_FMT_RPI_FE_CFG, ++ .flags = CFE_FORMAT_FLAG_META_OUT, ++ }, ++ { ++ .fourcc = V4L2_META_FMT_RPI_FE_STATS, ++ .flags = CFE_FORMAT_FLAG_META_CAP, ++ }, ++}; ++ ++#endif /* _CFE_FMTS_H_ */ +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -0,0 +1,446 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * RP1 CSI-2 Driver ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "csi2.h" ++#include "cfe.h" ++ ++#define csi2_dbg_irq(fmt, arg...) \ ++ do { \ ++ if (cfe_debug_irq) \ ++ dev_dbg(csi2->v4l2_dev->dev, fmt, ##arg); \ ++ } while (0) ++#define csi2_dbg(fmt, arg...) dev_dbg(csi2->v4l2_dev->dev, fmt, ##arg) ++#define csi2_info(fmt, arg...) dev_info(csi2->v4l2_dev->dev, fmt, ##arg) ++#define csi2_err(fmt, arg...) dev_err(csi2->v4l2_dev->dev, fmt, ##arg) ++ ++/* CSI2-DMA registers */ ++#define CSI2_STATUS 0x000 ++#define CSI2_QOS 0x004 ++#define CSI2_DISCARDS_OVERFLOW 0x008 ++#define CSI2_DISCARDS_INACTIVE 0x00c ++#define CSI2_DISCARDS_UNMATCHED 0x010 ++#define CSI2_DISCARDS_LEN_LIMIT 0x014 ++#define CSI2_LLEV_PANICS 0x018 ++#define CSI2_ULEV_PANICS 0x01c ++#define CSI2_IRQ_MASK 0x020 ++#define CSI2_CTRL 0x024 ++#define CSI2_CH_CTRL(x) ((x) * 0x40 + 0x28) ++#define CSI2_CH_ADDR0(x) ((x) * 0x40 + 0x2c) ++#define CSI2_CH_ADDR1(x) ((x) * 0x40 + 0x3c) ++#define CSI2_CH_STRIDE(x) ((x) * 0x40 + 0x30) ++#define CSI2_CH_LENGTH(x) ((x) * 0x40 + 0x34) ++#define CSI2_CH_DEBUG(x) ((x) * 0x40 + 0x38) ++#define CSI2_CH_FRAME_SIZE(x) ((x) * 0x40 + 0x40) ++#define CSI2_CH_COMP_CTRL(x) ((x) * 0x40 + 0x44) ++#define CSI2_CH_FE_FRAME_ID(x) ((x) * 0x40 + 0x48) ++ ++/* CSI2_STATUS */ ++#define IRQ_FS(x) (BIT(0) << (x)) ++#define IRQ_FE(x) (BIT(4) << (x)) ++#define IRQ_FE_ACK(x) (BIT(8) << (x)) ++#define IRQ_LE(x) (BIT(12) << (x)) ++#define IRQ_LE_ACK(x) (BIT(16) << (x)) ++#define IRQ_CH_MASK(x) (IRQ_FS(x) | IRQ_FE(x) | IRQ_FE_ACK(x) | IRQ_LE(x) | IRQ_LE_ACK(x)) ++#define IRQ_OVERFLOW BIT(20) ++#define IRQ_DISCARD_OVERFLOW BIT(21) ++#define IRQ_DISCARD_LEN_LIMIT BIT(22) ++#define IRQ_DISCARD_UNMATCHED BIT(23) ++#define IRQ_DISCARD_INACTIVE BIT(24) ++ ++/* CSI2_CTRL */ ++#define EOP_IS_EOL BIT(0) ++ ++/* CSI2_CH_CTRL */ ++#define DMA_EN BIT(0) ++#define FORCE BIT(3) ++#define AUTO_ARM BIT(4) ++#define IRQ_EN_FS BIT(13) ++#define IRQ_EN_FE BIT(14) ++#define IRQ_EN_FE_ACK BIT(15) ++#define IRQ_EN_LE BIT(16) ++#define IRQ_EN_LE_ACK BIT(17) ++#define FLUSH_FE BIT(28) ++#define PACK_LINE BIT(29) ++#define PACK_BYTES BIT(30) ++#define CH_MODE_MASK GENMASK(2, 1) ++#define VC_MASK GENMASK(6, 5) ++#define DT_MASK GENMASK(12, 7) ++#define LC_MASK GENMASK(27, 18) ++ ++/* CHx_COMPRESSION_CONTROL */ ++#define COMP_OFFSET_MASK GENMASK(15, 0) ++#define COMP_SHIFT_MASK GENMASK(19, 16) ++#define COMP_MODE_MASK GENMASK(25, 24) ++ ++static inline u32 csi2_reg_read(struct csi2_device *csi2, u32 offset) ++{ ++ return readl(csi2->base + offset); ++} ++ ++static inline void csi2_reg_write(struct csi2_device *csi2, u32 offset, u32 val) ++{ ++ writel(val, csi2->base + offset); ++} ++ ++static inline void set_field(u32 *valp, u32 field, u32 mask) ++{ ++ u32 val = *valp; ++ ++ val &= ~mask; ++ val |= (field << __ffs(mask)) & mask; ++ *valp = val; ++} ++ ++static int csi2_regs_show(struct seq_file *s, void *data) ++{ ++ struct csi2_device *csi2 = s->private; ++ unsigned int i; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(csi2->v4l2_dev->dev); ++ if (ret) ++ return ret; ++ ++#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", csi2_reg_read(csi2, reg)) ++#define DUMP_CH(idx, reg) seq_printf(s, #reg "(%u) \t0x%08x\n", idx, csi2_reg_read(csi2, reg(idx))) ++ ++ DUMP(CSI2_STATUS); ++ DUMP(CSI2_DISCARDS_OVERFLOW); ++ DUMP(CSI2_DISCARDS_INACTIVE); ++ DUMP(CSI2_DISCARDS_UNMATCHED); ++ DUMP(CSI2_DISCARDS_LEN_LIMIT); ++ DUMP(CSI2_LLEV_PANICS); ++ DUMP(CSI2_ULEV_PANICS); ++ DUMP(CSI2_IRQ_MASK); ++ DUMP(CSI2_CTRL); ++ ++ for (i = 0; i < CSI2_NUM_CHANNELS; ++i) { ++ DUMP_CH(i, CSI2_CH_CTRL); ++ DUMP_CH(i, CSI2_CH_ADDR0); ++ DUMP_CH(i, CSI2_CH_ADDR1); ++ DUMP_CH(i, CSI2_CH_STRIDE); ++ DUMP_CH(i, CSI2_CH_LENGTH); ++ DUMP_CH(i, CSI2_CH_DEBUG); ++ DUMP_CH(i, CSI2_CH_FRAME_SIZE); ++ DUMP_CH(i, CSI2_CH_COMP_CTRL); ++ DUMP_CH(i, CSI2_CH_FE_FRAME_ID); ++ } ++ ++#undef DUMP ++#undef DUMP_CH ++ ++ pm_runtime_put(csi2->v4l2_dev->dev); ++ ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(csi2_regs); ++ ++void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof, bool *lci) ++{ ++ unsigned int i; ++ u32 status; ++ ++ status = csi2_reg_read(csi2, CSI2_STATUS); ++ csi2_dbg_irq("ISR: STA: 0x%x\n", status); ++ ++ /* Write value back to clear the interrupts */ ++ csi2_reg_write(csi2, CSI2_STATUS, status); ++ ++ for (i = 0; i < CSI2_NUM_CHANNELS; i++) { ++ u32 dbg; ++ ++ if ((status & IRQ_CH_MASK(i)) == 0) ++ continue; ++ ++ dbg = csi2_reg_read(csi2, CSI2_CH_DEBUG(i)); ++ ++ csi2_dbg_irq("ISR: [%u], %s%s%s%s%s frame: %u line: %u\n", i, ++ (status & IRQ_FS(i)) ? "FS " : "", ++ (status & IRQ_FE(i)) ? "FE " : "", ++ (status & IRQ_FE_ACK(i)) ? "FE_ACK " : "", ++ (status & IRQ_LE(i)) ? "LE " : "", ++ (status & IRQ_LE_ACK(i)) ? "LE_ACK " : "", ++ dbg >> 16, ++ csi2->num_lines[i] ? ++ ((dbg & 0xffff) % csi2->num_lines[i]) : ++ 0); ++ ++ sof[i] = !!(status & IRQ_FS(i)); ++ eof[i] = !!(status & IRQ_FE_ACK(i)); ++ lci[i] = !!(status & IRQ_LE_ACK(i)); ++ } ++} ++ ++void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, ++ dma_addr_t dmaaddr, unsigned int stride, unsigned int size) ++{ ++ u64 addr = dmaaddr; ++ /* ++ * ADDRESS0 must be written last as it triggers the double buffering ++ * mechanism for all buffer registers within the hardware. ++ */ ++ addr >>= 4; ++ csi2_reg_write(csi2, CSI2_CH_LENGTH(channel), size >> 4); ++ csi2_reg_write(csi2, CSI2_CH_STRIDE(channel), stride >> 4); ++ csi2_reg_write(csi2, CSI2_CH_ADDR1(channel), addr >> 32); ++ csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), addr & 0xffffffff); ++} ++ ++void csi2_set_compression(struct csi2_device *csi2, unsigned int channel, ++ enum csi2_compression_mode mode, unsigned int shift, ++ unsigned int offset) ++{ ++ u32 compression = 0; ++ ++ set_field(&compression, COMP_OFFSET_MASK, offset); ++ set_field(&compression, COMP_SHIFT_MASK, shift); ++ set_field(&compression, COMP_MODE_MASK, mode); ++ csi2_reg_write(csi2, CSI2_CH_COMP_CTRL(channel), compression); ++} ++ ++void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, ++ u16 dt, enum csi2_mode mode, bool auto_arm, ++ bool pack_bytes, unsigned int width, ++ unsigned int height) ++{ ++ u32 ctrl; ++ ++ csi2_dbg("%s [%u]\n", __func__, channel); ++ ++ /* ++ * Disable the channel, but ensure N != 0! Otherwise we end up with a ++ * spurious LE + LE_ACK interrupt when re-enabling the channel. ++ */ ++ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), 0x100 << __ffs(LC_MASK)); ++ csi2_reg_write(csi2, CSI2_CH_DEBUG(channel), 0); ++ csi2_reg_write(csi2, CSI2_STATUS, IRQ_CH_MASK(channel)); ++ ++ /* Enable channel and FS/FE/LE interrupts. */ ++ ctrl = DMA_EN | IRQ_EN_FS | IRQ_EN_FE_ACK | IRQ_EN_LE_ACK | PACK_LINE; ++ /* PACK_BYTES ensures no striding for embedded data. */ ++ if (pack_bytes) ++ ctrl |= PACK_BYTES; ++ ++ if (auto_arm) ++ ctrl |= AUTO_ARM; ++ ++ if (width && height) { ++ int line_int_freq = height >> 2; ++ ++ line_int_freq = min(max(0x80, line_int_freq), 0x3ff); ++ set_field(&ctrl, line_int_freq, LC_MASK); ++ set_field(&ctrl, mode, CH_MODE_MASK); ++ csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), ++ (height << 16) | width); ++ } else { ++ /* ++ * Do not disable line interrupts for the embedded data channel, ++ * set it to the maximum value. This avoids spamming the ISR ++ * with spurious line interrupts. ++ */ ++ set_field(&ctrl, 0x3ff, LC_MASK); ++ set_field(&ctrl, 0x00, CH_MODE_MASK); ++ } ++ ++ set_field(&ctrl, dt, DT_MASK); ++ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), ctrl); ++ csi2->num_lines[channel] = height; ++} ++ ++void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel) ++{ ++ csi2_dbg("%s [%u]\n", __func__, channel); ++ ++ /* Channel disable. Use FORCE to allow stopping mid-frame. */ ++ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), ++ (0x100 << __ffs(LC_MASK)) | FORCE); ++ /* Latch the above change by writing to the ADDR0 register. */ ++ csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0); ++ /* Write this again, the HW needs it! */ ++ csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0); ++} ++ ++void csi2_open_rx(struct csi2_device *csi2) ++{ ++ dphy_start(&csi2->dphy); ++ ++ if (!csi2->multipacket_line) ++ csi2_reg_write(csi2, CSI2_CTRL, EOP_IS_EOL); ++} ++ ++void csi2_close_rx(struct csi2_device *csi2) ++{ ++ dphy_stop(&csi2->dphy); ++} ++ ++static struct csi2_device *to_csi2_device(struct v4l2_subdev *subdev) ++{ ++ return container_of(subdev, struct csi2_device, sd); ++} ++ ++static int csi2_init_cfg(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state) ++{ ++ struct v4l2_mbus_framefmt *fmt; ++ ++ for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; ++i) { ++ const struct v4l2_mbus_framefmt *def_fmt; ++ ++ /* CSI2_CH1_EMBEDDED */ ++ if (i == 1) ++ def_fmt = &cfe_default_meta_format; ++ else ++ def_fmt = &cfe_default_format; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, i); ++ *fmt = *def_fmt; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, i + CSI2_NUM_CHANNELS); ++ *fmt = *def_fmt; ++ } ++ ++ return 0; ++} ++ ++static int csi2_pad_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *fmt; ++ const struct cfe_fmt *cfe_fmt; ++ ++ /* TODO: format validation */ ++ ++ cfe_fmt = find_format_by_code(format->format.code); ++ if (!cfe_fmt) ++ cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10); ++ ++ format->format.code = cfe_fmt->code; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); ++ *fmt = format->format; ++ ++ if (format->pad < CSI2_NUM_CHANNELS) { ++ /* Propagate to the source pad */ ++ fmt = v4l2_subdev_get_pad_format(sd, state, ++ format->pad + CSI2_NUM_CHANNELS); ++ *fmt = format->format; ++ } ++ ++ return 0; ++} ++ ++static int csi2_link_validate(struct v4l2_subdev *sd, struct media_link *link, ++ struct v4l2_subdev_format *source_fmt, ++ struct v4l2_subdev_format *sink_fmt) ++{ ++ struct csi2_device *csi2 = to_csi2_device(sd); ++ ++ csi2_dbg("%s: link \"%s\":%u -> \"%s\":%u\n", __func__, ++ link->source->entity->name, link->source->index, ++ link->sink->entity->name, link->sink->index); ++ ++ if ((link->source->entity == &csi2->sd.entity && ++ link->source->index == 1) || ++ (link->sink->entity == &csi2->sd.entity && ++ link->sink->index == 1)) { ++ csi2_dbg("Ignore metadata pad for now\n"); ++ return 0; ++ } ++ ++ /* The width, height and code must match. */ ++ if (source_fmt->format.width != sink_fmt->format.width || ++ source_fmt->format.width != sink_fmt->format.width || ++ source_fmt->format.code != sink_fmt->format.code) { ++ csi2_err("%s: format does not match (source %ux%u 0x%x, sink %ux%u 0x%x)\n", ++ __func__, ++ source_fmt->format.width, source_fmt->format.height, ++ source_fmt->format.code, ++ sink_fmt->format.width, sink_fmt->format.height, ++ sink_fmt->format.code); ++ return -EPIPE; ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_pad_ops csi2_subdev_pad_ops = { ++ .init_cfg = csi2_init_cfg, ++ .get_fmt = v4l2_subdev_get_fmt, ++ .set_fmt = csi2_pad_set_fmt, ++ .link_validate = csi2_link_validate, ++}; ++ ++static const struct media_entity_operations csi2_entity_ops = { ++ .link_validate = v4l2_subdev_link_validate, ++}; ++ ++static const struct v4l2_subdev_ops csi2_subdev_ops = { ++ .pad = &csi2_subdev_pad_ops, ++}; ++ ++int csi2_init(struct csi2_device *csi2, struct dentry *debugfs) ++{ ++ unsigned int i, ret; ++ ++ csi2->dphy.dev = csi2->v4l2_dev->dev; ++ dphy_probe(&csi2->dphy); ++ ++ debugfs_create_file("csi2_regs", 0444, debugfs, csi2, &csi2_regs_fops); ++ ++ for (i = 0; i < CSI2_NUM_CHANNELS * 2; i++) ++ csi2->pad[i].flags = i < CSI2_NUM_CHANNELS ? ++ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&csi2->sd.entity, ARRAY_SIZE(csi2->pad), ++ csi2->pad); ++ if (ret) ++ return ret; ++ ++ /* Initialize subdev */ ++ v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops); ++ csi2->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; ++ csi2->sd.entity.ops = &csi2_entity_ops; ++ csi2->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ csi2->sd.owner = THIS_MODULE; ++ snprintf(csi2->sd.name, sizeof(csi2->sd.name), "csi2"); ++ ++ ret = v4l2_subdev_init_finalize(&csi2->sd); ++ if (ret) ++ goto err_entity_cleanup; ++ ++ ret = v4l2_device_register_subdev(csi2->v4l2_dev, &csi2->sd); ++ if (ret) { ++ csi2_err("Failed register csi2 subdev (%d)\n", ret); ++ goto err_subdev_cleanup; ++ } ++ ++ return 0; ++ ++err_subdev_cleanup: ++ v4l2_subdev_cleanup(&csi2->sd); ++err_entity_cleanup: ++ media_entity_cleanup(&csi2->sd.entity); ++ ++ return ret; ++} ++ ++void csi2_uninit(struct csi2_device *csi2) ++{ ++ v4l2_device_unregister_subdev(&csi2->sd); ++ v4l2_subdev_cleanup(&csi2->sd); ++ media_entity_cleanup(&csi2->sd.entity); ++} +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h +@@ -0,0 +1,75 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 CSI-2 driver. ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _RP1_CSI2_ ++#define _RP1_CSI2_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "dphy.h" ++ ++#define CSI2_NUM_CHANNELS 4 ++ ++enum csi2_mode { ++ CSI2_MODE_NORMAL, ++ CSI2_MODE_REMAP, ++ CSI2_MODE_COMPRESSED, ++ CSI2_MODE_FE_STREAMING ++}; ++ ++enum csi2_compression_mode { ++ CSI2_COMPRESSION_DELTA = 1, ++ CSI2_COMPRESSION_SIMPLE = 2, ++ CSI2_COMPRESSION_COMBINED = 3, ++}; ++ ++struct csi2_cfg { ++ u16 width; ++ u16 height; ++ u32 stride; ++ u32 buffer_size; ++}; ++ ++struct csi2_device { ++ /* Parent V4l2 device */ ++ struct v4l2_device *v4l2_dev; ++ ++ void __iomem *base; ++ ++ struct dphy_data dphy; ++ ++ enum v4l2_mbus_type bus_type; ++ unsigned int bus_flags; ++ u32 active_data_lanes; ++ bool multipacket_line; ++ unsigned int num_lines[CSI2_NUM_CHANNELS]; ++ ++ struct media_pad pad[CSI2_NUM_CHANNELS * 2]; ++ struct v4l2_subdev sd; ++}; ++ ++void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof, bool *lci); ++void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, ++ dma_addr_t dmaaddr, unsigned int stride, ++ unsigned int size); ++void csi2_set_compression(struct csi2_device *csi2, unsigned int channel, ++ enum csi2_compression_mode mode, unsigned int shift, ++ unsigned int offset); ++void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, ++ u16 dt, enum csi2_mode mode, bool auto_arm, ++ bool pack_bytes, unsigned int width, ++ unsigned int height); ++void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel); ++void csi2_open_rx(struct csi2_device *csi2); ++void csi2_close_rx(struct csi2_device *csi2); ++int csi2_init(struct csi2_device *csi2, struct dentry *debugfs); ++void csi2_uninit(struct csi2_device *csi2); ++ ++#endif +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/dphy.c +@@ -0,0 +1,177 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * RP1 CSI-2 Driver ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "dphy.h" ++ ++#define dphy_dbg(fmt, arg...) dev_dbg(dphy->dev, fmt, ##arg) ++#define dphy_info(fmt, arg...) dev_info(dphy->dev, fmt, ##arg) ++#define dphy_err(fmt, arg...) dev_err(dphy->dev, fmt, ##arg) ++ ++/* DW dphy Host registers */ ++#define VERSION 0x000 ++#define N_LANES 0x004 ++#define RESETN 0x008 ++#define PHY_SHUTDOWNZ 0x040 ++#define PHY_RSTZ 0x044 ++#define PHY_RX 0x048 ++#define PHY_STOPSTATE 0x04c ++#define PHY_TST_CTRL0 0x050 ++#define PHY_TST_CTRL1 0x054 ++#define PHY2_TST_CTRL0 0x058 ++#define PHY2_TST_CTRL1 0x05c ++ ++/* DW dphy Host Transactions */ ++#define DPHY_HS_RX_CTRL_LANE0_OFFSET 0x44 ++#define DPHY_PLL_INPUT_DIV_OFFSET 0x17 ++#define DPHY_PLL_LOOP_DIV_OFFSET 0x18 ++#define DPHY_PLL_DIV_CTRL_OFFSET 0x19 ++ ++static u32 dw_csi2_host_read(struct dphy_data *dphy, u32 offset) ++{ ++ return readl(dphy->base + offset); ++} ++ ++static void dw_csi2_host_write(struct dphy_data *dphy, u32 offset, u32 data) ++{ ++ writel(data, dphy->base + offset); ++} ++ ++static void set_tstclr(struct dphy_data *dphy, u32 val) ++{ ++ u32 ctrl0 = dw_csi2_host_read(dphy, PHY_TST_CTRL0); ++ ++ dw_csi2_host_write(dphy, PHY_TST_CTRL0, (ctrl0 & ~1) | val); ++} ++ ++static void set_tstclk(struct dphy_data *dphy, u32 val) ++{ ++ u32 ctrl0 = dw_csi2_host_read(dphy, PHY_TST_CTRL0); ++ ++ dw_csi2_host_write(dphy, PHY_TST_CTRL0, (ctrl0 & ~2) | (val << 1)); ++} ++ ++static uint8_t get_tstdout(struct dphy_data *dphy) ++{ ++ u32 ctrl1 = dw_csi2_host_read(dphy, PHY_TST_CTRL1); ++ ++ return ((ctrl1 >> 8) & 0xff); ++} ++ ++static void set_testen(struct dphy_data *dphy, u32 val) ++{ ++ u32 ctrl1 = dw_csi2_host_read(dphy, PHY_TST_CTRL1); ++ ++ dw_csi2_host_write(dphy, PHY_TST_CTRL1, ++ (ctrl1 & ~(1 << 16)) | (val << 16)); ++} ++ ++static void set_testdin(struct dphy_data *dphy, u32 val) ++{ ++ u32 ctrl1 = dw_csi2_host_read(dphy, PHY_TST_CTRL1); ++ ++ dw_csi2_host_write(dphy, PHY_TST_CTRL1, (ctrl1 & ~0xff) | val); ++} ++ ++static uint8_t dphy_transaction(struct dphy_data *dphy, u8 test_code, ++ uint8_t test_data) ++{ ++ /* See page 101 of the MIPI DPHY databook. */ ++ set_tstclk(dphy, 1); ++ set_testen(dphy, 0); ++ set_testdin(dphy, test_code); ++ set_testen(dphy, 1); ++ set_tstclk(dphy, 0); ++ set_testen(dphy, 0); ++ set_testdin(dphy, test_data); ++ set_tstclk(dphy, 1); ++ return get_tstdout(dphy); ++} ++ ++static void dphy_set_hsfreqrange(struct dphy_data *dphy, uint32_t freq_mhz) ++{ ++ /* See Table 5-1 on page 65 of dphy databook */ ++ static const u16 hsfreqrange_table[][2] = { ++ { 89, 0b000000 }, { 99, 0b010000 }, { 109, 0b100000 }, ++ { 129, 0b000001 }, { 139, 0b010001 }, { 149, 0b100001 }, ++ { 169, 0b000010 }, { 179, 0b010010 }, { 199, 0b100010 }, ++ { 219, 0b000011 }, { 239, 0b010011 }, { 249, 0b100011 }, ++ { 269, 0b000100 }, { 299, 0b010100 }, { 329, 0b000101 }, ++ { 359, 0b010101 }, { 399, 0b100101 }, { 449, 0b000110 }, ++ { 499, 0b010110 }, { 549, 0b000111 }, { 599, 0b010111 }, ++ { 649, 0b001000 }, { 699, 0b011000 }, { 749, 0b001001 }, ++ { 799, 0b011001 }, { 849, 0b101001 }, { 899, 0b111001 }, ++ { 949, 0b001010 }, { 999, 0b011010 }, { 1049, 0b101010 }, ++ { 1099, 0b111010 }, { 1149, 0b001011 }, { 1199, 0b011011 }, ++ { 1249, 0b101011 }, { 1299, 0b111011 }, { 1349, 0b001100 }, ++ { 1399, 0b011100 }, { 1449, 0b101100 }, { 1500, 0b111100 }, ++ }; ++ unsigned int i; ++ ++ if (freq_mhz < 80 || freq_mhz > 1500) ++ dphy_err("DPHY: Frequency %u MHz out of range\n", freq_mhz); ++ ++ for (i = 0; i < ARRAY_SIZE(hsfreqrange_table) - 1; i++) { ++ if (freq_mhz <= hsfreqrange_table[i][0]) ++ break; ++ } ++ ++ dphy_transaction(dphy, DPHY_HS_RX_CTRL_LANE0_OFFSET, ++ hsfreqrange_table[i][1] << 1); ++} ++ ++static void dphy_init(struct dphy_data *dphy) ++{ ++ dw_csi2_host_write(dphy, PHY_RSTZ, 0); ++ dw_csi2_host_write(dphy, PHY_SHUTDOWNZ, 0); ++ set_tstclk(dphy, 1); ++ set_testen(dphy, 0); ++ set_tstclr(dphy, 1); ++ usleep_range(15, 20); ++ set_tstclr(dphy, 0); ++ usleep_range(15, 20); ++ ++ dphy_set_hsfreqrange(dphy, dphy->dphy_freq); ++ ++ usleep_range(5, 10); ++ dw_csi2_host_write(dphy, PHY_SHUTDOWNZ, 1); ++ usleep_range(5, 10); ++ dw_csi2_host_write(dphy, PHY_RSTZ, 1); ++} ++ ++void dphy_start(struct dphy_data *dphy) ++{ ++ dw_csi2_host_write(dphy, N_LANES, (dphy->num_lanes - 1)); ++ dphy_init(dphy); ++ dw_csi2_host_write(dphy, RESETN, 0xffffffff); ++ usleep_range(10, 50); ++} ++ ++void dphy_stop(struct dphy_data *dphy) ++{ ++ /* Set only one lane (lane 0) as active (ON) */ ++ dw_csi2_host_write(dphy, N_LANES, 0); ++ dw_csi2_host_write(dphy, RESETN, 0); ++} ++ ++void dphy_probe(struct dphy_data *dphy) ++{ ++ u32 host_ver; ++ u8 host_ver_major, host_ver_minor; ++ ++ host_ver = dw_csi2_host_read(dphy, VERSION); ++ host_ver_major = (u8)((host_ver >> 24) - '0'); ++ host_ver_minor = (u8)((host_ver >> 16) - '0'); ++ host_ver_minor = host_ver_minor * 10; ++ host_ver_minor += (u8)((host_ver >> 8) - '0'); ++ ++ dphy_info("DW dphy Host HW v%u.%u\n", host_ver_major, host_ver_minor); ++} +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/dphy.h +@@ -0,0 +1,26 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ ++ ++#ifndef _RP1_DPHY_ ++#define _RP1_DPHY_ ++ ++#include ++#include ++ ++struct dphy_data { ++ struct device *dev; ++ ++ void __iomem *base; ++ ++ u32 dphy_freq; ++ u32 num_lanes; ++}; ++ ++void dphy_probe(struct dphy_data *dphy); ++void dphy_start(struct dphy_data *dphy); ++void dphy_stop(struct dphy_data *dphy); ++ ++#endif +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_common.h +@@ -0,0 +1,69 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 PiSP common definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _PISP_COMMON_H_ ++#define _PISP_COMMON_H_ ++ ++#include "pisp_types.h" ++ ++struct pisp_bla_config { ++ u16 black_level_r; ++ u16 black_level_gr; ++ u16 black_level_gb; ++ u16 black_level_b; ++ u16 output_black_level; ++ u8 pad[2]; ++}; ++ ++struct pisp_wbg_config { ++ u16 gain_r; ++ u16 gain_g; ++ u16 gain_b; ++ u8 pad[2]; ++}; ++ ++struct pisp_compress_config { ++ /* value subtracted from incoming data */ ++ u16 offset; ++ u8 pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ u8 mode; ++}; ++ ++struct pisp_decompress_config { ++ /* value added to reconstructed data */ ++ u16 offset; ++ u8 pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ u8 mode; ++}; ++ ++enum pisp_axi_flags { ++ /* ++ * round down bursts to end at a 32-byte boundary, to align following ++ * bursts ++ */ ++ PISP_AXI_FLAG_ALIGN = 128, ++ /* for FE writer: force WSTRB high, to pad output to 16-byte boundary */ ++ PISP_AXI_FLAG_PAD = 64, ++ /* for FE writer: Use Output FIFO level to trigger "panic" */ ++ PISP_AXI_FLAG_PANIC = 32, ++}; ++ ++struct pisp_axi_config { ++ /* ++ * burst length minus one, which must be in the range 0:15; OR'd with ++ * flags ++ */ ++ u8 maxlen_flags; ++ /* { prot[2:0], cache[3:0] } fields, echoed on AXI bus */ ++ u8 cache_prot; ++ /* QoS field(s) (4x4 bits for FE writer; 4 bits for other masters) */ ++ u16 qos; ++}; ++ ++#endif /* _PISP_COMMON_H_ */ +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +@@ -0,0 +1,563 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * PiSP Front End driver. ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "pisp_fe.h" ++#include "cfe.h" ++ ++#define FE_VERSION 0x000 ++#define FE_CONTROL 0x004 ++#define FE_STATUS 0x008 ++#define FE_FRAME_STATUS 0x00c ++#define FE_ERROR_STATUS 0x010 ++#define FE_OUTPUT_STATUS 0x014 ++#define FE_INT_EN 0x018 ++#define FE_INT_STATUS 0x01c ++ ++/* CONTROL */ ++#define FE_CONTROL_QUEUE BIT(0) ++#define FE_CONTROL_ABORT BIT(1) ++#define FE_CONTROL_RESET BIT(2) ++#define FE_CONTROL_LATCH_REGS BIT(3) ++ ++/* INT_EN / INT_STATUS */ ++#define FE_INT_EOF BIT(0) ++#define FE_INT_SOF BIT(1) ++#define FE_INT_LINES0 BIT(8) ++#define FE_INT_LINES1 BIT(9) ++#define FE_INT_STATS BIT(16) ++#define FE_INT_QREADY BIT(24) ++ ++/* STATUS */ ++#define FE_STATUS_QUEUED BIT(0) ++#define FE_STATUS_WAITING BIT(1) ++#define FE_STATUS_ACTIVE BIT(2) ++ ++#define PISP_FE_CONFIG_BASE_OFFSET 0x0040 ++ ++#define PISP_FE_ENABLE_STATS_CLUSTER \ ++ (PISP_FE_ENABLE_STATS_CROP | PISP_FE_ENABLE_DECIMATE | \ ++ PISP_FE_ENABLE_BLC | PISP_FE_ENABLE_CDAF_STATS | \ ++ PISP_FE_ENABLE_AWB_STATS | PISP_FE_ENABLE_RGBY | \ ++ PISP_FE_ENABLE_LSC | PISP_FE_ENABLE_AGC_STATS) ++ ++#define PISP_FE_ENABLE_OUTPUT_CLUSTER(i) \ ++ ((PISP_FE_ENABLE_CROP0 | PISP_FE_ENABLE_DOWNSCALE0 | \ ++ PISP_FE_ENABLE_COMPRESS0 | PISP_FE_ENABLE_OUTPUT0) << (4 * (i))) ++ ++struct pisp_fe_config_param { ++ u32 dirty_flags; ++ u32 dirty_flags_extra; ++ size_t offset; ++ size_t size; ++}; ++ ++static const struct pisp_fe_config_param pisp_fe_config_map[] = { ++ /* *_dirty_flag_extra types */ ++ { 0, PISP_FE_DIRTY_GLOBAL, offsetof(struct pisp_fe_config, global), ++ sizeof(struct pisp_fe_global_config) }, ++ { 0, PISP_FE_DIRTY_FLOATING, offsetof(struct pisp_fe_config, floating_stats), ++ sizeof(struct pisp_fe_floating_stats_config) }, ++ { 0, PISP_FE_DIRTY_OUTPUT_AXI, offsetof(struct pisp_fe_config, output_axi), ++ sizeof(struct pisp_fe_output_axi_config) }, ++ /* *_dirty_flag types */ ++ { PISP_FE_ENABLE_INPUT, 0, offsetof(struct pisp_fe_config, input), ++ sizeof(struct pisp_fe_input_config) }, ++ { PISP_FE_ENABLE_DECOMPRESS, 0, offsetof(struct pisp_fe_config, decompress), ++ sizeof(struct pisp_decompress_config) }, ++ { PISP_FE_ENABLE_DECOMPAND, 0, offsetof(struct pisp_fe_config, decompand), ++ sizeof(struct pisp_fe_decompand_config) }, ++ { PISP_FE_ENABLE_BLA, 0, offsetof(struct pisp_fe_config, bla), ++ sizeof(struct pisp_bla_config) }, ++ { PISP_FE_ENABLE_DPC, 0, offsetof(struct pisp_fe_config, dpc), ++ sizeof(struct pisp_fe_dpc_config) }, ++ { PISP_FE_ENABLE_STATS_CROP, 0, offsetof(struct pisp_fe_config, stats_crop), ++ sizeof(struct pisp_fe_crop_config) }, ++ { PISP_FE_ENABLE_BLC, 0, offsetof(struct pisp_fe_config, blc), ++ sizeof(struct pisp_bla_config) }, ++ { PISP_FE_ENABLE_CDAF_STATS, 0, offsetof(struct pisp_fe_config, cdaf_stats), ++ sizeof(struct pisp_fe_cdaf_stats_config) }, ++ { PISP_FE_ENABLE_AWB_STATS, 0, offsetof(struct pisp_fe_config, awb_stats), ++ sizeof(struct pisp_fe_awb_stats_config) }, ++ { PISP_FE_ENABLE_RGBY, 0, offsetof(struct pisp_fe_config, rgby), ++ sizeof(struct pisp_fe_rgby_config) }, ++ { PISP_FE_ENABLE_LSC, 0, offsetof(struct pisp_fe_config, lsc), ++ sizeof(struct pisp_fe_lsc_config) }, ++ { PISP_FE_ENABLE_AGC_STATS, 0, offsetof(struct pisp_fe_config, agc_stats), ++ sizeof(struct pisp_agc_statistics) }, ++ { PISP_FE_ENABLE_CROP0, 0, offsetof(struct pisp_fe_config, ch[0].crop), ++ sizeof(struct pisp_fe_crop_config) }, ++ { PISP_FE_ENABLE_DOWNSCALE0, 0, offsetof(struct pisp_fe_config, ch[0].downscale), ++ sizeof(struct pisp_fe_downscale_config) }, ++ { PISP_FE_ENABLE_COMPRESS0, 0, offsetof(struct pisp_fe_config, ch[0].compress), ++ sizeof(struct pisp_compress_config) }, ++ { PISP_FE_ENABLE_OUTPUT0, 0, offsetof(struct pisp_fe_config, ch[0].output), ++ sizeof(struct pisp_fe_output_config) }, ++ { PISP_FE_ENABLE_CROP1, 0, offsetof(struct pisp_fe_config, ch[1].crop), ++ sizeof(struct pisp_fe_crop_config) }, ++ { PISP_FE_ENABLE_DOWNSCALE1, 0, offsetof(struct pisp_fe_config, ch[1].downscale), ++ sizeof(struct pisp_fe_downscale_config) }, ++ { PISP_FE_ENABLE_COMPRESS1, 0, offsetof(struct pisp_fe_config, ch[1].compress), ++ sizeof(struct pisp_compress_config) }, ++ { PISP_FE_ENABLE_OUTPUT1, 0, offsetof(struct pisp_fe_config, ch[1].output), ++ sizeof(struct pisp_fe_output_config) }, ++}; ++ ++#define pisp_fe_dbg_irq(fmt, arg...) \ ++ do { \ ++ if (cfe_debug_irq) \ ++ dev_dbg(fe->v4l2_dev->dev, fmt, ##arg); \ ++ } while (0) ++#define pisp_fe_dbg(fmt, arg...) dev_dbg(fe->v4l2_dev->dev, fmt, ##arg) ++#define pisp_fe_info(fmt, arg...) dev_info(fe->v4l2_dev->dev, fmt, ##arg) ++#define pisp_fe_err(fmt, arg...) dev_err(fe->v4l2_dev->dev, fmt, ##arg) ++ ++static inline u32 pisp_fe_reg_read(struct pisp_fe_device *fe, u32 offset) ++{ ++ return readl(fe->base + offset); ++} ++ ++static inline void pisp_fe_reg_write(struct pisp_fe_device *fe, u32 offset, ++ u32 val) ++{ ++ writel(val, fe->base + offset); ++} ++ ++static inline void pisp_fe_reg_write_relaxed(struct pisp_fe_device *fe, u32 offset, ++ u32 val) ++{ ++ writel_relaxed(val, fe->base + offset); ++} ++ ++static int pisp_regs_show(struct seq_file *s, void *data) ++{ ++ struct pisp_fe_device *fe = s->private; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(fe->v4l2_dev->dev); ++ if (ret) ++ return ret; ++ ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS); ++ ++#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", pisp_fe_reg_read(fe, reg)) ++ DUMP(FE_VERSION); ++ DUMP(FE_CONTROL); ++ DUMP(FE_STATUS); ++ DUMP(FE_FRAME_STATUS); ++ DUMP(FE_ERROR_STATUS); ++ DUMP(FE_OUTPUT_STATUS); ++ DUMP(FE_INT_EN); ++ DUMP(FE_INT_STATUS); ++#undef DUMP ++ ++ pm_runtime_put(fe->v4l2_dev->dev); ++ ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(pisp_regs); ++ ++static void pisp_config_write(struct pisp_fe_device *fe, ++ struct pisp_fe_config *config, ++ unsigned int start_offset, ++ unsigned int size) ++{ ++ const unsigned int max_offset = ++ offsetof(struct pisp_fe_config, ch[PISP_FE_NUM_OUTPUTS]); ++ unsigned int i, end_offset; ++ u32 *cfg = (u32 *)config; ++ ++ start_offset = min(start_offset, max_offset); ++ end_offset = min(start_offset + size, max_offset); ++ ++ cfg += start_offset >> 2; ++ for (i = start_offset; i < end_offset; i += 4, cfg++) ++ pisp_fe_reg_write_relaxed(fe, PISP_FE_CONFIG_BASE_OFFSET + i, ++ *cfg); ++} ++ ++void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof) ++{ ++ u32 status, int_status, out_status, frame_status, error_status; ++ unsigned int i; ++ ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS); ++ status = pisp_fe_reg_read(fe, FE_STATUS); ++ out_status = pisp_fe_reg_read(fe, FE_OUTPUT_STATUS); ++ frame_status = pisp_fe_reg_read(fe, FE_FRAME_STATUS); ++ error_status = pisp_fe_reg_read(fe, FE_ERROR_STATUS); ++ ++ int_status = pisp_fe_reg_read(fe, FE_INT_STATUS); ++ pisp_fe_reg_write(fe, FE_INT_STATUS, int_status); ++ ++ pisp_fe_dbg_irq("%s: status 0x%x out 0x%x frame 0x%x error 0x%x int 0x%x\n", ++ __func__, status, out_status, frame_status, error_status, ++ int_status); ++ ++ /* We do not report interrupts for the input/stream pad. */ ++ for (i = 0; i < FE_NUM_PADS - 1; i++) { ++ sof[i] = !!(int_status & FE_INT_SOF); ++ eof[i] = !!(int_status & FE_INT_EOF); ++ } ++} ++ ++static bool pisp_fe_validate_output(struct pisp_fe_config const *cfg, ++ unsigned int c, struct v4l2_format const *f) ++{ ++ unsigned int wbytes; ++ ++ wbytes = cfg->ch[c].output.format.width; ++ if (cfg->ch[c].output.format.format & PISP_IMAGE_FORMAT_BPS_MASK) ++ wbytes *= 2; ++ ++ /* Check output image dimensions are nonzero and not too big */ ++ if (cfg->ch[c].output.format.width < 2 || ++ cfg->ch[c].output.format.height < 2 || ++ cfg->ch[c].output.format.height > f->fmt.pix.height || ++ cfg->ch[c].output.format.stride > f->fmt.pix.bytesperline || ++ wbytes > f->fmt.pix.bytesperline) ++ return false; ++ ++ /* Check for zero-sized crops, which could cause lockup */ ++ if ((cfg->global.enables & PISP_FE_ENABLE_CROP(c)) && ++ ((cfg->ch[c].crop.offset_x >= (cfg->input.format.width & ~1) || ++ cfg->ch[c].crop.offset_y >= cfg->input.format.height || ++ cfg->ch[c].crop.width < 2 || ++ cfg->ch[c].crop.height < 2))) ++ return false; ++ ++ if ((cfg->global.enables & PISP_FE_ENABLE_DOWNSCALE(c)) && ++ (cfg->ch[c].downscale.output_width < 2 || ++ cfg->ch[c].downscale.output_height < 2)) ++ return false; ++ ++ return true; ++} ++ ++static bool pisp_fe_validate_stats(struct pisp_fe_config const *cfg) ++{ ++ /* Check for zero-sized crop, which could cause lockup */ ++ return (!(cfg->global.enables & PISP_FE_ENABLE_STATS_CROP) || ++ (cfg->stats_crop.offset_x < (cfg->input.format.width & ~1) && ++ cfg->stats_crop.offset_y < cfg->input.format.height && ++ cfg->stats_crop.width >= 2 && ++ cfg->stats_crop.height >= 2)); ++} ++ ++int pisp_fe_validate_config(struct pisp_fe_device *fe, ++ struct pisp_fe_config *cfg, ++ struct v4l2_format const *f0, ++ struct v4l2_format const *f1) ++{ ++ unsigned int i; ++ ++ /* ++ * Check the input is enabled, streaming and has nonzero size; ++ * to avoid cases where the hardware might lock up or try to ++ * read inputs from memory (which this driver doesn't support). ++ */ ++ if (!(cfg->global.enables & PISP_FE_ENABLE_INPUT) || ++ cfg->input.streaming != 1 || cfg->input.format.width < 2 || ++ cfg->input.format.height < 2) { ++ pisp_fe_err("%s: Input config not valid", __func__); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < PISP_FE_NUM_OUTPUTS; i++) { ++ if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) { ++ if (cfg->global.enables & ++ PISP_FE_ENABLE_OUTPUT_CLUSTER(i)) { ++ pisp_fe_err("%s: Output %u not valid", ++ __func__, i); ++ return -EINVAL; ++ } ++ continue; ++ } ++ ++ if (!pisp_fe_validate_output(cfg, i, i ? f1 : f0)) ++ return -EINVAL; ++ } ++ ++ if ((cfg->global.enables & PISP_FE_ENABLE_STATS_CLUSTER) && ++ !pisp_fe_validate_stats(cfg)) { ++ pisp_fe_err("%s: Stats config not valid", __func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs, ++ struct pisp_fe_config *cfg) ++{ ++ unsigned int i; ++ u64 addr; ++ u32 status; ++ ++ /* ++ * Check output buffers exist and outputs are correctly configured. ++ * If valid, set the buffer's DMA address; otherwise disable. ++ */ ++ for (i = 0; i < PISP_FE_NUM_OUTPUTS; i++) { ++ struct vb2_buffer *buf = vb2_bufs[FE_OUTPUT0_PAD + i]; ++ ++ if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) ++ continue; ++ ++ addr = vb2_dma_contig_plane_dma_addr(buf, 0); ++ cfg->output_buffer[i].addr_lo = addr & 0xffffffff; ++ cfg->output_buffer[i].addr_hi = addr >> 32; ++ } ++ ++ if (vb2_bufs[FE_STATS_PAD]) { ++ addr = vb2_dma_contig_plane_dma_addr(vb2_bufs[FE_STATS_PAD], 0); ++ cfg->stats_buffer.addr_lo = addr & 0xffffffff; ++ cfg->stats_buffer.addr_hi = addr >> 32; ++ } ++ ++ /* Set up ILINES interrupts 3/4 of the way down each output */ ++ cfg->ch[0].output.ilines = ++ max(0x80u, (3u * cfg->ch[0].output.format.height) >> 2); ++ cfg->ch[1].output.ilines = ++ max(0x80u, (3u * cfg->ch[1].output.format.height) >> 2); ++ ++ /* ++ * The hardware must have consumed the previous config by now. ++ * This read of status also serves as a memory barrier before the ++ * sequence of relaxed writes which follow. ++ */ ++ status = pisp_fe_reg_read(fe, FE_STATUS); ++ pisp_fe_dbg_irq("%s: status = 0x%x\n", __func__, status); ++ if (WARN_ON(status & FE_STATUS_QUEUED)) ++ return; ++ ++ /* ++ * Unconditionally write buffers, global and input parameters. ++ * Write cropping and output parameters whenever they are enabled. ++ * Selectively write other parameters that have been marked as ++ * changed through the dirty flags. ++ */ ++ pisp_config_write(fe, cfg, 0, ++ offsetof(struct pisp_fe_config, decompress)); ++ cfg->dirty_flags_extra &= ~PISP_FE_DIRTY_GLOBAL; ++ cfg->dirty_flags &= ~PISP_FE_ENABLE_INPUT; ++ cfg->dirty_flags |= (cfg->global.enables & ++ (PISP_FE_ENABLE_STATS_CROP | ++ PISP_FE_ENABLE_OUTPUT_CLUSTER(0) | ++ PISP_FE_ENABLE_OUTPUT_CLUSTER(1))); ++ for (i = 0; i < ARRAY_SIZE(pisp_fe_config_map); i++) { ++ const struct pisp_fe_config_param *p = &pisp_fe_config_map[i]; ++ ++ if (cfg->dirty_flags & p->dirty_flags || ++ cfg->dirty_flags_extra & p->dirty_flags_extra) ++ pisp_config_write(fe, cfg, p->offset, p->size); ++ } ++ ++ /* This final non-relaxed write serves as a memory barrier */ ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_QUEUE); ++} ++ ++void pisp_fe_start(struct pisp_fe_device *fe) ++{ ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_RESET); ++ pisp_fe_reg_write(fe, FE_INT_STATUS, -1); ++ pisp_fe_reg_write(fe, FE_INT_EN, FE_INT_EOF | FE_INT_SOF | FE_INT_LINES0 | FE_INT_LINES1); ++ fe->inframe_count = 0; ++} ++ ++void pisp_fe_stop(struct pisp_fe_device *fe) ++{ ++ pisp_fe_reg_write(fe, FE_INT_EN, 0); ++ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_ABORT); ++ usleep_range(1000, 2000); ++ WARN_ON(pisp_fe_reg_read(fe, FE_STATUS)); ++ pisp_fe_reg_write(fe, FE_INT_STATUS, -1); ++} ++ ++static struct pisp_fe_device *to_pisp_fe_device(struct v4l2_subdev *subdev) ++{ ++ return container_of(subdev, struct pisp_fe_device, sd); ++} ++ ++static int pisp_fe_init_cfg(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state) ++{ ++ struct v4l2_mbus_framefmt *fmt; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_STREAM_PAD); ++ *fmt = cfe_default_format; ++ fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_CONFIG_PAD); ++ *fmt = cfe_default_meta_format; ++ fmt->code = MEDIA_BUS_FMT_PISP_FE_CONFIG; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_OUTPUT0_PAD); ++ *fmt = cfe_default_format; ++ fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_OUTPUT1_PAD); ++ *fmt = cfe_default_format; ++ fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_STATS_PAD); ++ *fmt = cfe_default_meta_format; ++ fmt->code = MEDIA_BUS_FMT_PISP_FE_STATS; ++ ++ return 0; ++} ++ ++static int pisp_fe_pad_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *fmt; ++ const struct cfe_fmt *cfe_fmt; ++ ++ /* TODO: format propagation to source pads */ ++ /* TODO: format validation */ ++ ++ switch (format->pad) { ++ case FE_STREAM_PAD: ++ case FE_OUTPUT0_PAD: ++ case FE_OUTPUT1_PAD: ++ cfe_fmt = find_format_by_code(format->format.code); ++ if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT)) ++ cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10); ++ ++ format->format.code = cfe_fmt->code; ++ ++ break; ++ ++ case FE_CONFIG_PAD: ++ format->format.code = MEDIA_BUS_FMT_PISP_FE_CONFIG; ++ break; ++ ++ case FE_STATS_PAD: ++ format->format.code = MEDIA_BUS_FMT_PISP_FE_STATS; ++ break; ++ } ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); ++ *fmt = format->format; ++ ++ return 0; ++} ++ ++static int pisp_fe_link_validate(struct v4l2_subdev *sd, ++ struct media_link *link, ++ struct v4l2_subdev_format *source_fmt, ++ struct v4l2_subdev_format *sink_fmt) ++{ ++ struct pisp_fe_device *fe = to_pisp_fe_device(sd); ++ ++ pisp_fe_dbg("%s: link \"%s\":%u -> \"%s\":%u\n", __func__, ++ link->source->entity->name, link->source->index, ++ link->sink->entity->name, link->sink->index); ++ ++ /* The width, height and code must match. */ ++ if (source_fmt->format.width != sink_fmt->format.width || ++ source_fmt->format.width != sink_fmt->format.width || ++ source_fmt->format.code != sink_fmt->format.code) { ++ pisp_fe_err("%s: format does not match (source %ux%u 0x%x, sink %ux%u 0x%x)\n", ++ __func__, ++ source_fmt->format.width, ++ source_fmt->format.height, ++ source_fmt->format.code, ++ sink_fmt->format.width, ++ sink_fmt->format.height, ++ sink_fmt->format.code); ++ return -EPIPE; ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_pad_ops pisp_fe_subdev_pad_ops = { ++ .init_cfg = pisp_fe_init_cfg, ++ .get_fmt = v4l2_subdev_get_fmt, ++ .set_fmt = pisp_fe_pad_set_fmt, ++ .link_validate = pisp_fe_link_validate, ++}; ++ ++static const struct media_entity_operations pisp_fe_entity_ops = { ++ .link_validate = v4l2_subdev_link_validate, ++}; ++ ++static const struct v4l2_subdev_ops pisp_fe_subdev_ops = { ++ .pad = &pisp_fe_subdev_pad_ops, ++}; ++ ++int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs) ++{ ++ int ret; ++ ++ debugfs_create_file("pisp_regs", 0444, debugfs, fe, &pisp_regs_fops); ++ ++ fe->hw_revision = pisp_fe_reg_read(fe, FE_VERSION); ++ pisp_fe_info("PiSP FE HW v%u.%u\n", ++ (fe->hw_revision >> 24) & 0xff, ++ (fe->hw_revision >> 20) & 0x0f); ++ ++ fe->pad[FE_STREAM_PAD].flags = ++ MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; ++ fe->pad[FE_CONFIG_PAD].flags = MEDIA_PAD_FL_SINK; ++ fe->pad[FE_OUTPUT0_PAD].flags = MEDIA_PAD_FL_SOURCE; ++ fe->pad[FE_OUTPUT1_PAD].flags = MEDIA_PAD_FL_SOURCE; ++ fe->pad[FE_STATS_PAD].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&fe->sd.entity, ARRAY_SIZE(fe->pad), ++ fe->pad); ++ if (ret) ++ return ret; ++ ++ /* Initialize subdev */ ++ v4l2_subdev_init(&fe->sd, &pisp_fe_subdev_ops); ++ fe->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; ++ fe->sd.entity.ops = &pisp_fe_entity_ops; ++ fe->sd.entity.name = "pisp-fe"; ++ fe->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ fe->sd.owner = THIS_MODULE; ++ snprintf(fe->sd.name, sizeof(fe->sd.name), "pisp-fe"); ++ ++ ret = v4l2_subdev_init_finalize(&fe->sd); ++ if (ret) ++ goto err_entity_cleanup; ++ ++ ret = v4l2_device_register_subdev(fe->v4l2_dev, &fe->sd); ++ if (ret) { ++ pisp_fe_err("Failed register pisp fe subdev (%d)\n", ret); ++ goto err_subdev_cleanup; ++ } ++ ++ /* Must be in IDLE state (STATUS == 0) here. */ ++ WARN_ON(pisp_fe_reg_read(fe, FE_STATUS)); ++ ++ return 0; ++ ++err_subdev_cleanup: ++ v4l2_subdev_cleanup(&fe->sd); ++err_entity_cleanup: ++ media_entity_cleanup(&fe->sd.entity); ++ ++ return ret; ++} ++ ++void pisp_fe_uninit(struct pisp_fe_device *fe) ++{ ++ v4l2_device_unregister_subdev(&fe->sd); ++ v4l2_subdev_cleanup(&fe->sd); ++ media_entity_cleanup(&fe->sd.entity); ++} +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * PiSP Front End driver. ++ * Copyright (c) 2021 Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _PISP_FE_H_ ++#define _PISP_FE_H_ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "pisp_fe_config.h" ++ ++enum pisp_fe_pads { ++ FE_STREAM_PAD, ++ FE_CONFIG_PAD, ++ FE_OUTPUT0_PAD, ++ FE_OUTPUT1_PAD, ++ FE_STATS_PAD, ++ FE_NUM_PADS ++}; ++ ++struct pisp_fe_device { ++ /* Parent V4l2 device */ ++ struct v4l2_device *v4l2_dev; ++ void __iomem *base; ++ u32 hw_revision; ++ ++ u16 inframe_count; ++ struct media_pad pad[FE_NUM_PADS]; ++ struct v4l2_subdev sd; ++}; ++ ++void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof); ++int pisp_fe_validate_config(struct pisp_fe_device *fe, ++ struct pisp_fe_config *cfg, ++ struct v4l2_format const *f0, ++ struct v4l2_format const *f1); ++void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs, ++ struct pisp_fe_config *cfg); ++void pisp_fe_start(struct pisp_fe_device *fe); ++void pisp_fe_stop(struct pisp_fe_device *fe); ++int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs); ++void pisp_fe_uninit(struct pisp_fe_device *fe); ++ ++#endif +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe_config.h +@@ -0,0 +1,272 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 PiSP Front End Driver Configuration structures ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _PISP_FE_CONFIG_ ++#define _PISP_FE_CONFIG_ ++ ++#include ++ ++#include "pisp_statistics.h" ++ ++#define PISP_FE_NUM_OUTPUTS 2 ++ ++enum pisp_fe_enable { ++ PISP_FE_ENABLE_INPUT = 0x000001, ++ PISP_FE_ENABLE_DECOMPRESS = 0x000002, ++ PISP_FE_ENABLE_DECOMPAND = 0x000004, ++ PISP_FE_ENABLE_BLA = 0x000008, ++ PISP_FE_ENABLE_DPC = 0x000010, ++ PISP_FE_ENABLE_STATS_CROP = 0x000020, ++ PISP_FE_ENABLE_DECIMATE = 0x000040, ++ PISP_FE_ENABLE_BLC = 0x000080, ++ PISP_FE_ENABLE_CDAF_STATS = 0x000100, ++ PISP_FE_ENABLE_AWB_STATS = 0x000200, ++ PISP_FE_ENABLE_RGBY = 0x000400, ++ PISP_FE_ENABLE_LSC = 0x000800, ++ PISP_FE_ENABLE_AGC_STATS = 0x001000, ++ PISP_FE_ENABLE_CROP0 = 0x010000, ++ PISP_FE_ENABLE_DOWNSCALE0 = 0x020000, ++ PISP_FE_ENABLE_COMPRESS0 = 0x040000, ++ PISP_FE_ENABLE_OUTPUT0 = 0x080000, ++ PISP_FE_ENABLE_CROP1 = 0x100000, ++ PISP_FE_ENABLE_DOWNSCALE1 = 0x200000, ++ PISP_FE_ENABLE_COMPRESS1 = 0x400000, ++ PISP_FE_ENABLE_OUTPUT1 = 0x800000 ++}; ++ ++#define PISP_FE_ENABLE_CROP(i) (PISP_FE_ENABLE_CROP0 << (4 * (i))) ++#define PISP_FE_ENABLE_DOWNSCALE(i) (PISP_FE_ENABLE_DOWNSCALE0 << (4 * (i))) ++#define PISP_FE_ENABLE_COMPRESS(i) (PISP_FE_ENABLE_COMPRESS0 << (4 * (i))) ++#define PISP_FE_ENABLE_OUTPUT(i) (PISP_FE_ENABLE_OUTPUT0 << (4 * (i))) ++ ++/* ++ * We use the enable flags to show when blocks are "dirty", but we need some ++ * extra ones too. ++ */ ++enum pisp_fe_dirty { ++ PISP_FE_DIRTY_GLOBAL = 0x0001, ++ PISP_FE_DIRTY_FLOATING = 0x0002, ++ PISP_FE_DIRTY_OUTPUT_AXI = 0x0004 ++}; ++ ++struct pisp_fe_global_config { ++ u32 enables; ++ u8 bayer_order; ++ u8 pad[3]; ++}; ++ ++struct pisp_fe_input_axi_config { ++ /* burst length minus one, in the range 0..15; OR'd with flags */ ++ u8 maxlen_flags; ++ /* { prot[2:0], cache[3:0] } fields */ ++ u8 cache_prot; ++ /* QoS (only 4 LS bits are used) */ ++ u16 qos; ++}; ++ ++struct pisp_fe_output_axi_config { ++ /* burst length minus one, in the range 0..15; OR'd with flags */ ++ u8 maxlen_flags; ++ /* { prot[2:0], cache[3:0] } fields */ ++ u8 cache_prot; ++ /* QoS (4 bitfields of 4 bits each for different panic levels) */ ++ u16 qos; ++ /* For Panic mode: Output FIFO panic threshold */ ++ u16 thresh; ++ /* For Panic mode: Output FIFO statistics throttle threshold */ ++ u16 throttle; ++}; ++ ++struct pisp_fe_input_config { ++ u8 streaming; ++ u8 pad[3]; ++ struct pisp_image_format_config format; ++ struct pisp_fe_input_axi_config axi; ++ /* Extra cycles delay before issuing each burst request */ ++ u8 holdoff; ++ u8 pad2[3]; ++}; ++ ++struct pisp_fe_output_config { ++ struct pisp_image_format_config format; ++ u16 ilines; ++ u8 pad[2]; ++}; ++ ++struct pisp_fe_input_buffer_config { ++ u32 addr_lo; ++ u32 addr_hi; ++ u16 frame_id; ++ u16 pad; ++}; ++ ++#define PISP_FE_DECOMPAND_LUT_SIZE 65 ++ ++struct pisp_fe_decompand_config { ++ u16 lut[PISP_FE_DECOMPAND_LUT_SIZE]; ++ u16 pad; ++}; ++ ++struct pisp_fe_dpc_config { ++ u8 coeff_level; ++ u8 coeff_range; ++ u8 coeff_range2; ++#define PISP_FE_DPC_FLAG_FOLDBACK 1 ++#define PISP_FE_DPC_FLAG_VFLAG 2 ++ u8 flags; ++}; ++ ++#define PISP_FE_LSC_LUT_SIZE 16 ++ ++struct pisp_fe_lsc_config { ++ u8 shift; ++ u8 pad0; ++ u16 scale; ++ u16 centre_x; ++ u16 centre_y; ++ u16 lut[PISP_FE_LSC_LUT_SIZE]; ++}; ++ ++struct pisp_fe_rgby_config { ++ u16 gain_r; ++ u16 gain_g; ++ u16 gain_b; ++ u8 maxflag; ++ u8 pad; ++}; ++ ++struct pisp_fe_agc_stats_config { ++ u16 offset_x; ++ u16 offset_y; ++ u16 size_x; ++ u16 size_y; ++ /* each weight only 4 bits */ ++ u8 weights[PISP_AGC_STATS_NUM_ZONES / 2]; ++ u16 row_offset_x; ++ u16 row_offset_y; ++ u16 row_size_x; ++ u16 row_size_y; ++ u8 row_shift; ++ u8 float_shift; ++ u8 pad1[2]; ++}; ++ ++struct pisp_fe_awb_stats_config { ++ u16 offset_x; ++ u16 offset_y; ++ u16 size_x; ++ u16 size_y; ++ u8 shift; ++ u8 pad[3]; ++ u16 r_lo; ++ u16 r_hi; ++ u16 g_lo; ++ u16 g_hi; ++ u16 b_lo; ++ u16 b_hi; ++}; ++ ++struct pisp_fe_floating_stats_region { ++ u16 offset_x; ++ u16 offset_y; ++ u16 size_x; ++ u16 size_y; ++}; ++ ++struct pisp_fe_floating_stats_config { ++ struct pisp_fe_floating_stats_region ++ regions[PISP_FLOATING_STATS_NUM_ZONES]; ++}; ++ ++#define PISP_FE_CDAF_NUM_WEIGHTS 8 ++ ++struct pisp_fe_cdaf_stats_config { ++ u16 noise_constant; ++ u16 noise_slope; ++ u16 offset_x; ++ u16 offset_y; ++ u16 size_x; ++ u16 size_y; ++ u16 skip_x; ++ u16 skip_y; ++ u32 mode; ++}; ++ ++struct pisp_fe_stats_buffer_config { ++ u32 addr_lo; ++ u32 addr_hi; ++}; ++ ++struct pisp_fe_crop_config { ++ u16 offset_x; ++ u16 offset_y; ++ u16 width; ++ u16 height; ++}; ++ ++enum pisp_fe_downscale_flags { ++ DOWNSCALE_BAYER = ++ 1, /* downscale the four Bayer components independently... */ ++ DOWNSCALE_BIN = ++ 2 /* ...without trying to preserve their spatial relationship */ ++}; ++ ++struct pisp_fe_downscale_config { ++ u8 xin; ++ u8 xout; ++ u8 yin; ++ u8 yout; ++ u8 flags; /* enum pisp_fe_downscale_flags */ ++ u8 pad[3]; ++ u16 output_width; ++ u16 output_height; ++}; ++ ++struct pisp_fe_output_buffer_config { ++ u32 addr_lo; ++ u32 addr_hi; ++}; ++ ++/* Each of the two output channels/branches: */ ++struct pisp_fe_output_branch_config { ++ struct pisp_fe_crop_config crop; ++ struct pisp_fe_downscale_config downscale; ++ struct pisp_compress_config compress; ++ struct pisp_fe_output_config output; ++ u32 pad; ++}; ++ ++/* And finally one to rule them all: */ ++struct pisp_fe_config { ++ /* I/O configuration: */ ++ struct pisp_fe_stats_buffer_config stats_buffer; ++ struct pisp_fe_output_buffer_config output_buffer[PISP_FE_NUM_OUTPUTS]; ++ struct pisp_fe_input_buffer_config input_buffer; ++ /* processing configuration: */ ++ struct pisp_fe_global_config global; ++ struct pisp_fe_input_config input; ++ struct pisp_decompress_config decompress; ++ struct pisp_fe_decompand_config decompand; ++ struct pisp_bla_config bla; ++ struct pisp_fe_dpc_config dpc; ++ struct pisp_fe_crop_config stats_crop; ++ u32 spare1; /* placeholder for future decimate configuration */ ++ struct pisp_bla_config blc; ++ struct pisp_fe_rgby_config rgby; ++ struct pisp_fe_lsc_config lsc; ++ struct pisp_fe_agc_stats_config agc_stats; ++ struct pisp_fe_awb_stats_config awb_stats; ++ struct pisp_fe_cdaf_stats_config cdaf_stats; ++ struct pisp_fe_floating_stats_config floating_stats; ++ struct pisp_fe_output_axi_config output_axi; ++ struct pisp_fe_output_branch_config ch[PISP_FE_NUM_OUTPUTS]; ++ /* non-register fields: */ ++ u32 dirty_flags; /* these use pisp_fe_enable */ ++ u32 dirty_flags_extra; /* these use pisp_fe_dirty */ ++}; ++ ++#endif /* _PISP_FE_CONFIG_ */ +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 PiSP Front End statistics definitions ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _PISP_FE_STATISTICS_H_ ++#define _PISP_FE_STATISTICS_H_ ++ ++#define PISP_FLOATING_STATS_NUM_ZONES 4 ++#define PISP_AGC_STATS_NUM_BINS 1024 ++#define PISP_AGC_STATS_SIZE 16 ++#define PISP_AGC_STATS_NUM_ZONES (PISP_AGC_STATS_SIZE * PISP_AGC_STATS_SIZE) ++#define PISP_AGC_STATS_NUM_ROW_SUMS 512 ++ ++struct pisp_agc_statistics_zone { ++ u64 Y_sum; ++ u32 counted; ++ u32 pad; ++}; ++ ++struct pisp_agc_statistics { ++ u32 row_sums[PISP_AGC_STATS_NUM_ROW_SUMS]; ++ /* ++ * 32-bits per bin means an image (just less than) 16384x16384 pixels ++ * in size can weight every pixel from 0 to 15. ++ */ ++ u32 histogram[PISP_AGC_STATS_NUM_BINS]; ++ struct pisp_agc_statistics_zone floating[PISP_FLOATING_STATS_NUM_ZONES]; ++}; ++ ++#define PISP_AWB_STATS_SIZE 32 ++#define PISP_AWB_STATS_NUM_ZONES (PISP_AWB_STATS_SIZE * PISP_AWB_STATS_SIZE) ++ ++struct pisp_awb_statistics_zone { ++ u32 R_sum; ++ u32 G_sum; ++ u32 B_sum; ++ u32 counted; ++}; ++ ++struct pisp_awb_statistics { ++ struct pisp_awb_statistics_zone zones[PISP_AWB_STATS_NUM_ZONES]; ++ struct pisp_awb_statistics_zone floating[PISP_FLOATING_STATS_NUM_ZONES]; ++}; ++ ++#define PISP_CDAF_STATS_SIZE 8 ++#define PISP_CDAF_STATS_NUM_FOMS (PISP_CDAF_STATS_SIZE * PISP_CDAF_STATS_SIZE) ++ ++struct pisp_cdaf_statistics { ++ u64 foms[PISP_CDAF_STATS_NUM_FOMS]; ++ u64 floating[PISP_FLOATING_STATS_NUM_ZONES]; ++}; ++ ++struct pisp_statistics { ++ struct pisp_awb_statistics awb; ++ struct pisp_agc_statistics agc; ++ struct pisp_cdaf_statistics cdaf; ++}; ++ ++#endif /* _PISP_FE_STATISTICS_H_ */ +--- /dev/null ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h +@@ -0,0 +1,144 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * RP1 PiSP Front End image definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _PISP_FE_TYPES_H_ ++#define _PISP_FE_TYPES_H_ ++ ++/* This definition must match the format description in the hardware exactly! */ ++struct pisp_image_format_config { ++ /* size in pixels */ ++ u16 width, height; ++ /* must match struct pisp_image_format below */ ++ u32 format; ++ s32 stride; ++ /* some planar image formats will need a second stride */ ++ s32 stride2; ++}; ++ ++static_assert(sizeof(struct pisp_image_format_config) == 16); ++ ++enum pisp_bayer_order { ++ /* ++ * Note how bayer_order&1 tells you if G is on the even pixels of the ++ * checkerboard or not, and bayer_order&2 tells you if R is on the even ++ * rows or is swapped with B. Note that if the top (of the 8) bits is ++ * set, this denotes a monochrome or greyscale image, and the lower bits ++ * should all be ignored. ++ */ ++ PISP_BAYER_ORDER_RGGB = 0, ++ PISP_BAYER_ORDER_GBRG = 1, ++ PISP_BAYER_ORDER_BGGR = 2, ++ PISP_BAYER_ORDER_GRBG = 3, ++ PISP_BAYER_ORDER_GREYSCALE = 128 ++}; ++ ++enum pisp_image_format { ++ /* ++ * Precise values are mostly tbd. Generally these will be portmanteau ++ * values comprising bit fields and flags. This format must be shared ++ * throughout the PiSP. ++ */ ++ PISP_IMAGE_FORMAT_BPS_8 = 0x00000000, ++ PISP_IMAGE_FORMAT_BPS_10 = 0x00000001, ++ PISP_IMAGE_FORMAT_BPS_12 = 0x00000002, ++ PISP_IMAGE_FORMAT_BPS_16 = 0x00000003, ++ PISP_IMAGE_FORMAT_BPS_MASK = 0x00000003, ++ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED = 0x00000000, ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR = 0x00000010, ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR = 0x00000020, ++ PISP_IMAGE_FORMAT_PLANARITY_MASK = 0x00000030, ++ ++ PISP_IMAGE_FORMAT_SAMPLING_444 = 0x00000000, ++ PISP_IMAGE_FORMAT_SAMPLING_422 = 0x00000100, ++ PISP_IMAGE_FORMAT_SAMPLING_420 = 0x00000200, ++ PISP_IMAGE_FORMAT_SAMPLING_MASK = 0x00000300, ++ ++ PISP_IMAGE_FORMAT_ORDER_NORMAL = 0x00000000, ++ PISP_IMAGE_FORMAT_ORDER_SWAPPED = 0x00001000, ++ ++ PISP_IMAGE_FORMAT_SHIFT_0 = 0x00000000, ++ PISP_IMAGE_FORMAT_SHIFT_1 = 0x00010000, ++ PISP_IMAGE_FORMAT_SHIFT_2 = 0x00020000, ++ PISP_IMAGE_FORMAT_SHIFT_3 = 0x00030000, ++ PISP_IMAGE_FORMAT_SHIFT_4 = 0x00040000, ++ PISP_IMAGE_FORMAT_SHIFT_5 = 0x00050000, ++ PISP_IMAGE_FORMAT_SHIFT_6 = 0x00060000, ++ PISP_IMAGE_FORMAT_SHIFT_7 = 0x00070000, ++ PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000, ++ PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000, ++ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_3 = 0x03000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MASK = 0x03000000, ++ ++ PISP_IMAGE_FORMAT_HOG_SIGNED = 0x04000000, ++ PISP_IMAGE_FORMAT_HOG_UNSIGNED = 0x08000000, ++ PISP_IMAGE_FORMAT_INTEGRAL_IMAGE = 0x10000000, ++ PISP_IMAGE_FORMAT_WALLPAPER_ROLL = 0x20000000, ++ PISP_IMAGE_FORMAT_THREE_CHANNEL = 0x40000000, ++ ++ /* Lastly a few specific instantiations of the above. */ ++ PISP_IMAGE_FORMAT_SINGLE_16 = PISP_IMAGE_FORMAT_BPS_16, ++ PISP_IMAGE_FORMAT_THREE_16 = ++ PISP_IMAGE_FORMAT_BPS_16 | PISP_IMAGE_FORMAT_THREE_CHANNEL ++}; ++ ++#define PISP_IMAGE_FORMAT_bps_8(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8) ++#define PISP_IMAGE_FORMAT_bps_10(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10) ++#define PISP_IMAGE_FORMAT_bps_12(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12) ++#define PISP_IMAGE_FORMAT_bps_16(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16) ++#define PISP_IMAGE_FORMAT_bps(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) ? \ ++ 8 + (2 << (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : \ ++ 8) ++#define PISP_IMAGE_FORMAT_shift(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1) ++#define PISP_IMAGE_FORMAT_three_channel(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL) ++#define PISP_IMAGE_FORMAT_single_channel(fmt) \ ++ (!((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL)) ++#define PISP_IMAGE_FORMAT_compressed(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED) ++#define PISP_IMAGE_FORMAT_sampling_444(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_444) ++#define PISP_IMAGE_FORMAT_sampling_422(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_422) ++#define PISP_IMAGE_FORMAT_sampling_420(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_420) ++#define PISP_IMAGE_FORMAT_order_normal(fmt) \ ++ (!((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED)) ++#define PISP_IMAGE_FORMAT_order_swapped(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED) ++#define PISP_IMAGE_FORMAT_interleaved(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED) ++#define PISP_IMAGE_FORMAT_semiplanar(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR) ++#define PISP_IMAGE_FORMAT_planar(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR) ++#define PISP_IMAGE_FORMAT_wallpaper(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL) ++#define PISP_IMAGE_FORMAT_HOG(fmt) \ ++ ((fmt) & \ ++ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED)) ++ ++#define PISP_WALLPAPER_WIDTH 128 // in bytes ++ ++#endif /* _PISP_FE_TYPES_H_ */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0890-dt-bindings-net-cdns-macb-AXI-tuning-properties.patch b/target/linux/bcm27xx/patches-6.1/950-0890-dt-bindings-net-cdns-macb-AXI-tuning-properties.patch new file mode 100644 index 0000000000..7d81e03429 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0890-dt-bindings-net-cdns-macb-AXI-tuning-properties.patch @@ -0,0 +1,38 @@ +From 2be65d1fd1f7d3cf6f59b58b53e285400f04a160 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 15 Feb 2023 09:46:35 +0000 +Subject: [PATCH] dt-bindings: net: cdns,macb: AXI tuning properties + +Add optional properties to tune the AXI interface - +cdns,aw2w-max-pipe, cdns,ar2r-max-pipe and cdns,use-aw2b-fill. + +Signed-off-by: Phil Elwell +--- + .../devicetree/bindings/net/cdns,macb.yaml | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/Documentation/devicetree/bindings/net/cdns,macb.yaml ++++ b/Documentation/devicetree/bindings/net/cdns,macb.yaml +@@ -121,6 +121,22 @@ properties: + Node containing PHY children. If this node is not present, then PHYs will + be direct children. + ++ cdns,aw2w-max-pipe: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ Maximum number of outstanding AXI write requests ++ ++ cdns,ar2r-max-pipe: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ Maximum number of outstanding AXI read requests ++ ++ cdns,use-aw2b-fill: ++ type: boolean ++ description: ++ If set, the maximum number of outstanding write transactions operates ++ between the AW to B AXI channel, instead of the AW to W AXI channel. ++ + patternProperties: + "^ethernet-phy@[0-9a-f]$": + type: object diff --git a/target/linux/bcm27xx/patches-6.1/950-0891-ASoC-dwc-list-all-supported-sample-sizes.patch b/target/linux/bcm27xx/patches-6.1/950-0891-ASoC-dwc-list-all-supported-sample-sizes.patch new file mode 100644 index 0000000000..06d69c7c4c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0891-ASoC-dwc-list-all-supported-sample-sizes.patch @@ -0,0 +1,29 @@ +From 9ef0615a5c5f93cb72af8df3a2dae6d23b106eb5 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 21 Feb 2023 21:26:16 +0000 +Subject: [PATCH] ASoC: dwc: list all supported sample sizes + +The hardware configuration determines the maximum-supported sample size +for each channel, but TCRx allows smaller sizes to be specified at run +time. Include the smaller supported sizes in the formats array. + +Signed-off-by: Phil Elwell +--- + sound/soc/dwc/dwc-i2s.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -448,9 +448,9 @@ static const u32 bus_widths[COMP_MAX_DAT + static const u32 formats[COMP_MAX_WORDSIZE] = { + SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_FMTBIT_S16_LE, +- SNDRV_PCM_FMTBIT_S24_LE, +- SNDRV_PCM_FMTBIT_S24_LE, +- SNDRV_PCM_FMTBIT_S32_LE, ++ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, ++ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, ++ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, + 0, + 0, + 0 diff --git a/target/linux/bcm27xx/patches-6.1/950-0892-ASoC-dwc-Support-set_bclk_ratio.patch b/target/linux/bcm27xx/patches-6.1/950-0892-ASoC-dwc-Support-set_bclk_ratio.patch new file mode 100644 index 0000000000..b18e5f888f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0892-ASoC-dwc-Support-set_bclk_ratio.patch @@ -0,0 +1,59 @@ +From 06f794e8cb227249e03893e4b4923ff58556eb60 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 4 Mar 2021 14:49:23 +0000 +Subject: [PATCH] ASoC: dwc: Support set_bclk_ratio + +Signed-off-by: Phil Elwell +--- + sound/soc/dwc/dwc-i2s.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -351,11 +351,46 @@ static int dw_i2s_set_fmt(struct snd_soc + return ret; + } + ++static int dw_i2s_set_bclk_ratio(struct snd_soc_dai *cpu_dai, ++ unsigned int ratio) ++{ ++ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); ++ struct i2s_clk_config_data *config = &dev->config; ++ ++ dev_err(dev->dev, "%s(%d)\n", __func__, ratio); ++ switch (ratio) { ++ case 32: ++ config->data_width = 16; ++ dev->ccr = 0x00; ++ dev->xfer_resolution = 0x02; ++ break; ++ ++ case 48: ++ config->data_width = 24; ++ dev->ccr = 0x08; ++ dev->xfer_resolution = 0x04; ++ break; ++ ++ case 64: ++ config->data_width = 32; ++ dev->ccr = 0x10; ++ dev->xfer_resolution = 0x05; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ i2s_write_reg(dev->i2s_base, CCR, dev->ccr); ++ ++ return 0; ++} ++ + static const struct snd_soc_dai_ops dw_i2s_dai_ops = { + .hw_params = dw_i2s_hw_params, + .prepare = dw_i2s_prepare, + .trigger = dw_i2s_trigger, + .set_fmt = dw_i2s_set_fmt, ++ .set_bclk_ratio = dw_i2s_set_bclk_ratio, + }; + + #ifdef CONFIG_PM diff --git a/target/linux/bcm27xx/patches-6.1/950-0893-ASoC-dwc-Add-DMACR-handling.patch b/target/linux/bcm27xx/patches-6.1/950-0893-ASoC-dwc-Add-DMACR-handling.patch new file mode 100644 index 0000000000..474903c327 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0893-ASoC-dwc-Add-DMACR-handling.patch @@ -0,0 +1,81 @@ +From b3b1177092d4d2ba6df74042d39aa42c5055f687 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 3 Jul 2023 09:08:16 +0100 +Subject: [PATCH] ASoC: dwc: Add DMACR handling + +Add control of the DMACR register, which is required for paced DMA +(i.e. DREQ) support. + +Signed-off-by: Phil Elwell +--- + sound/soc/dwc/dwc-i2s.c | 13 ++++++++++--- + sound/soc/dwc/local.h | 13 +++++++++++++ + 2 files changed, 23 insertions(+), 3 deletions(-) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -185,9 +185,9 @@ static void i2s_stop(struct dw_i2s_dev * + + static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) + { +- u32 ch_reg; + struct i2s_clk_config_data *config = &dev->config; +- ++ u32 ch_reg; ++ u32 dmacr = 0; + + i2s_disable_channels(dev, stream); + +@@ -198,15 +198,22 @@ static void dw_i2s_config(struct dw_i2s_ + i2s_write_reg(dev->i2s_base, TFCR(ch_reg), + dev->fifo_th - 1); + i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); ++ dmacr |= (DMACR_DMAEN_TXCH0 << ch_reg); + } else { + i2s_write_reg(dev->i2s_base, RCR(ch_reg), + dev->xfer_resolution); + i2s_write_reg(dev->i2s_base, RFCR(ch_reg), + dev->fifo_th - 1); + i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); ++ dmacr |= (DMACR_DMAEN_RXCH0 << ch_reg); + } +- + } ++ if (stream == SNDRV_PCM_STREAM_PLAYBACK) ++ dmacr |= DMACR_DMAEN_TX; ++ else if (stream == SNDRV_PCM_STREAM_CAPTURE) ++ dmacr |= DMACR_DMAEN_RX; ++ ++ i2s_write_reg(dev->i2s_base, DMACR, dmacr); + } + + static int dw_i2s_hw_params(struct snd_pcm_substream *substream, +--- a/sound/soc/dwc/local.h ++++ b/sound/soc/dwc/local.h +@@ -25,6 +25,8 @@ + #define RXFFR 0x014 + #define TXFFR 0x018 + ++#define DMACR 0x200 ++ + /* Interrupt status register fields */ + #define ISR_TXFO BIT(5) + #define ISR_TXFE BIT(4) +@@ -47,6 +49,17 @@ + #define RFF(x) (0x40 * x + 0x050) + #define TFF(x) (0x40 * x + 0x054) + ++#define DMACR_DMAEN_TX BIT(17) ++#define DMACR_DMAEN_RX BIT(16) ++#define DMACR_DMAEN_TXCH3 BIT(11) ++#define DMACR_DMAEN_TXCH2 BIT(10) ++#define DMACR_DMAEN_TXCH1 BIT(9) ++#define DMACR_DMAEN_TXCH0 BIT(8) ++#define DMACR_DMAEN_RXCH3 BIT(3) ++#define DMACR_DMAEN_RXCH2 BIT(2) ++#define DMACR_DMAEN_RXCH1 BIT(1) ++#define DMACR_DMAEN_RXCH0 BIT(0) ++ + /* I2SCOMPRegisters */ + #define I2S_COMP_PARAM_2 0x01F0 + #define I2S_COMP_PARAM_1 0x01F4 diff --git a/target/linux/bcm27xx/patches-6.1/950-0894-ASOC-dwc-Improve-DMA-shutdown.patch b/target/linux/bcm27xx/patches-6.1/950-0894-ASOC-dwc-Improve-DMA-shutdown.patch new file mode 100644 index 0000000000..73704a8be3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0894-ASOC-dwc-Improve-DMA-shutdown.patch @@ -0,0 +1,128 @@ +From e6baee4502c0228c79408b047096a1259a84353f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 3 Jul 2023 10:14:43 +0100 +Subject: [PATCH] ASOC: dwc: Improve DMA shutdown + +Disabling the I2S interface with outstanding transfers prevents the +DMAC from shutting down, so keep it partially active after a stop. + +Signed-off-by: Phil Elwell +--- + sound/soc/dwc/dwc-i2s.c | 72 ++++++++++++++++++++++++++++++++++++----- + 1 file changed, 64 insertions(+), 8 deletions(-) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -165,24 +165,26 @@ static void i2s_start(struct dw_i2s_dev + i2s_write_reg(dev->i2s_base, CER, 1); + } + +-static void i2s_stop(struct dw_i2s_dev *dev, +- struct snd_pcm_substream *substream) ++static void i2s_pause(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream) + { + + i2s_clear_irqs(dev, substream->stream); +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +- i2s_write_reg(dev->i2s_base, ITER, 0); +- else +- i2s_write_reg(dev->i2s_base, IRER, 0); + + i2s_disable_irqs(dev, substream->stream, 8); + + if (!dev->active) { + i2s_write_reg(dev->i2s_base, CER, 0); +- i2s_write_reg(dev->i2s_base, IER, 0); ++ /* Keep the device enabled until the shutdown - do not clear IER */ + } + } + ++static void i2s_stop(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream) ++{ ++ i2s_clear_irqs(dev, substream->stream); ++ ++ i2s_disable_irqs(dev, substream->stream, 8); ++} ++ + static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) + { + struct i2s_clk_config_data *config = &dev->config; +@@ -288,6 +290,55 @@ static int dw_i2s_hw_params(struct snd_p + return 0; + } + ++static int dw_i2s_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *cpu_dai) ++{ ++ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); ++ union dw_i2s_snd_dma_data *dma_data = NULL; ++ u32 dmacr; ++ ++ dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name); ++ if (!(dev->capability & DWC_I2S_RECORD) && ++ substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ return -EINVAL; ++ ++ if (!(dev->capability & DWC_I2S_PLAY) && ++ substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ return -EINVAL; ++ ++ dw_i2s_config(dev, substream->stream); ++ dmacr = i2s_read_reg(dev->i2s_base, DMACR); ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ dma_data = &dev->play_dma_data; ++ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ dma_data = &dev->capture_dma_data; ++ ++ snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data); ++ i2s_write_reg(dev->i2s_base, DMACR, dmacr); ++ ++ return 0; ++} ++ ++static void dw_i2s_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name); ++ i2s_disable_channels(dev, substream->stream); ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ i2s_write_reg(dev->i2s_base, ITER, 0); ++ else ++ i2s_write_reg(dev->i2s_base, IRER, 0); ++ ++ i2s_disable_irqs(dev, substream->stream, 8); ++ ++ if (!dev->active) { ++ i2s_write_reg(dev->i2s_base, CER, 0); ++ i2s_write_reg(dev->i2s_base, IER, 0); ++ } ++} ++ + static int dw_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { +@@ -315,9 +366,12 @@ static int dw_i2s_trigger(struct snd_pcm + i2s_start(dev, substream); + break; + ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ dev->active--; ++ i2s_pause(dev, substream); ++ break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: +- case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dev->active--; + i2s_stop(dev, substream); + break; +@@ -394,6 +448,8 @@ static int dw_i2s_set_bclk_ratio(struct + + static const struct snd_soc_dai_ops dw_i2s_dai_ops = { + .hw_params = dw_i2s_hw_params, ++ .startup = dw_i2s_startup, ++ .shutdown = dw_i2s_shutdown, + .prepare = dw_i2s_prepare, + .trigger = dw_i2s_trigger, + .set_fmt = dw_i2s_set_fmt, diff --git a/target/linux/bcm27xx/patches-6.1/950-0895-ASOC-dwc-Fix-16-bit-audio-handling.patch b/target/linux/bcm27xx/patches-6.1/950-0895-ASOC-dwc-Fix-16-bit-audio-handling.patch new file mode 100644 index 0000000000..fa5eb61044 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0895-ASOC-dwc-Fix-16-bit-audio-handling.patch @@ -0,0 +1,88 @@ +From 9c6694c24f26ea435165431d41c72451fadbd753 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 21 Jul 2023 12:07:16 +0100 +Subject: [PATCH] ASOC: dwc: Fix 16-bit audio handling + +IMO the Synopsys datasheet could be clearer in this area, but it seems +that the DMA data ports (DMATX and DMARX) expect left and right samples +in alternate writes; if a stereo pair is pushed in a single 32-bit +write, the upper half is ignored, leading to double speed audio with a +confused stereo image. Make sure the necessary changes happen by +updating the DMA configuration data in the hw_params method. + +The set_bclk_ratio change was made at a time when it looked like it +could be causing an error, but I think the division of responsibilities +is clearer this way (and the kernel log clearer without the info-level +message). + +Signed-off-by: Phil Elwell +--- + sound/soc/dwc/dwc-i2s.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -223,23 +223,34 @@ static int dw_i2s_hw_params(struct snd_p + { + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + struct i2s_clk_config_data *config = &dev->config; ++ union dw_i2s_snd_dma_data *dma_data = NULL; + int ret; + ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ dma_data = &dev->play_dma_data; ++ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ dma_data = &dev->capture_dma_data; ++ else ++ return -1; ++ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + config->data_width = 16; ++ dma_data->dt.addr_width = 2; + dev->ccr = 0x00; + dev->xfer_resolution = 0x02; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + config->data_width = 24; ++ dma_data->dt.addr_width = 4; + dev->ccr = 0x08; + dev->xfer_resolution = 0x04; + break; + + case SNDRV_PCM_FORMAT_S32_LE: + config->data_width = 32; ++ dma_data->dt.addr_width = 4; + dev->ccr = 0x10; + dev->xfer_resolution = 0x05; + break; +@@ -418,24 +429,21 @@ static int dw_i2s_set_bclk_ratio(struct + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); + struct i2s_clk_config_data *config = &dev->config; + +- dev_err(dev->dev, "%s(%d)\n", __func__, ratio); ++ dev_dbg(dev->dev, "%s(%d)\n", __func__, ratio); ++ if (ratio < config->data_width * 2) ++ return -EINVAL; ++ + switch (ratio) { + case 32: +- config->data_width = 16; + dev->ccr = 0x00; +- dev->xfer_resolution = 0x02; + break; + + case 48: +- config->data_width = 24; + dev->ccr = 0x08; +- dev->xfer_resolution = 0x04; + break; + + case 64: +- config->data_width = 32; + dev->ccr = 0x10; +- dev->xfer_resolution = 0x05; + break; + default: + return -EINVAL; diff --git a/target/linux/bcm27xx/patches-6.1/950-0896-ASoC-bcm-Remove-dependency-on-BCM2835-I2S.patch b/target/linux/bcm27xx/patches-6.1/950-0896-ASoC-bcm-Remove-dependency-on-BCM2835-I2S.patch new file mode 100644 index 0000000000..9f4f7a0c9a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0896-ASoC-bcm-Remove-dependency-on-BCM2835-I2S.patch @@ -0,0 +1,304 @@ +From f476db1b71e8b82e5299168f963a2fefb7a395e2 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 1 Sep 2023 14:07:48 +0100 +Subject: [PATCH] ASoC: bcm: Remove dependency on BCM2835 I2S + +These soundcard drivers don't rely on a specific I2S interface, so +remove the dependency declarations. + +See: https://github.com/raspberrypi/linux-2712/issues/111 + +Signed-off-by: Phil Elwell +--- + sound/soc/bcm/Kconfig | 40 +--------------------------------------- + 1 file changed, 1 insertion(+), 39 deletions(-) + +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -29,13 +29,11 @@ config SND_BCM63XX_I2S_WHISTLER + + config SND_BCM2708_SOC_CHIPDIP_DAC + tristate "Support for the ChipDip DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + help + Say Y or M if you want to add support for the ChipDip DAC soundcard + + config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD + tristate "Support for Google voiceHAT soundcard" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_VOICEHAT + select SND_RPI_SIMPLE_SOUNDCARD + help +@@ -43,7 +41,6 @@ config SND_BCM2708_SOC_GOOGLEVOICEHAT_SO + + config SND_BCM2708_SOC_HIFIBERRY_DAC + tristate "Support for HifiBerry DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM5102A + select SND_RPI_SIMPLE_SOUNDCARD + help +@@ -51,7 +48,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC + + config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + tristate "Support for HifiBerry DAC+" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x + select SND_SOC_TPA6130A2 + select COMMON_CLK_HIFIBERRY_DACPRO +@@ -60,7 +56,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + + config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD + tristate "Support for HifiBerry DAC+ HD" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM179X_I2C + select COMMON_CLK_HIFIBERRY_DACPLUSHD + help +@@ -68,7 +63,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + + config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC + tristate "Support for HifiBerry DAC+ADC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + select SND_SOC_DMIC + select COMMON_CLK_HIFIBERRY_DACPRO +@@ -77,7 +71,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + + config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO + tristate "Support for HifiBerry DAC+ADC PRO" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + select SND_SOC_PCM186X_I2C + select SND_SOC_TPA6130A2 +@@ -87,29 +80,25 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + + config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP + tristate "Support for HifiBerry DAC+DSP" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_RPI_SIMPLE_SOUNDCARD + help + Say Y or M if you want to add support for HifiBerry DSP-DAC. + + config SND_BCM2708_SOC_HIFIBERRY_DIGI + tristate "Support for HifiBerry Digi" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + help + Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board. + + config SND_BCM2708_SOC_HIFIBERRY_AMP + tristate "Support for the HifiBerry Amp" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_TAS5713 + select SND_RPI_SIMPLE_SOUNDCARD + help + Say Y or M if you want to add support for the HifiBerry Amp amplifier board. + +- config SND_BCM2708_SOC_PIFI_40 ++config SND_BCM2708_SOC_PIFI_40 + tristate "Support for the PiFi-40 amp" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_TAS571X + select SND_PIFI_40 + help +@@ -117,7 +106,6 @@ config SND_BCM2708_SOC_HIFIBERRY_AMP + + config SND_BCM2708_SOC_RPI_CIRRUS + tristate "Support for Cirrus Logic Audio Card" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM5102 + select SND_SOC_WM8804 + help +@@ -126,7 +114,6 @@ config SND_BCM2708_SOC_RPI_CIRRUS + + config SND_BCM2708_SOC_RPI_DAC + tristate "Support for RPi-DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM1794A + select SND_RPI_SIMPLE_SOUNDCARD + help +@@ -134,14 +121,12 @@ config SND_BCM2708_SOC_RPI_DAC + + config SND_BCM2708_SOC_RPI_PROTO + tristate "Support for Rpi-PROTO" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8731_I2C + help + Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731). + + config SND_BCM2708_SOC_JUSTBOOM_BOTH + tristate "Support for simultaneous JustBoom Digi and JustBoom DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_SOC_PCM512x + help +@@ -153,14 +138,12 @@ config SND_BCM2708_SOC_JUSTBOOM_BOTH + + config SND_BCM2708_SOC_JUSTBOOM_DAC + tristate "Support for JustBoom DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x + help + Say Y or M if you want to add support for JustBoom DAC. + + config SND_BCM2708_SOC_JUSTBOOM_DIGI + tristate "Support for JustBoom Digi" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_RPI_WM8804_SOUNDCARD + help +@@ -168,21 +151,18 @@ config SND_BCM2708_SOC_JUSTBOOM_DIGI + + config SND_BCM2708_SOC_IQAUDIO_CODEC + tristate "Support for IQaudIO-CODEC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_DA7213 + help + Say Y or M if you want to add support for IQaudIO-CODEC. + + config SND_BCM2708_SOC_IQAUDIO_DAC + tristate "Support for IQaudIO-DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + help + Say Y or M if you want to add support for IQaudIO-DAC. + + config SND_BCM2708_SOC_IQAUDIO_DIGI + tristate "Support for IQAudIO Digi" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_RPI_WM8804_SOUNDCARD + help +@@ -190,14 +170,12 @@ config SND_BCM2708_SOC_IQAUDIO_DIGI + + config SND_BCM2708_SOC_I_SABRE_Q2M + tristate "Support for Audiophonics I-Sabre Q2M DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_I_SABRE_CODEC + help + Say Y or M if you want to add support for Audiophonics I-SABRE Q2M DAC + + config SND_BCM2708_SOC_ADAU1977_ADC + tristate "Support for ADAU1977 ADC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_ADAU1977_I2C + select SND_RPI_SIMPLE_SOUNDCARD + help +@@ -205,35 +183,30 @@ config SND_BCM2708_SOC_ADAU1977_ADC + + config SND_AUDIOINJECTOR_PI_SOUNDCARD + tristate "Support for audioinjector.net Pi add on soundcard" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8731_I2C + help + Say Y or M if you want to add support for audioinjector.net Pi Hat + + config SND_AUDIOINJECTOR_OCTO_SOUNDCARD + tristate "Support for audioinjector.net Octo channel (Hat) soundcard" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_CS42XX8_I2C + help + Say Y or M if you want to add support for audioinjector.net octo add on + + config SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD + tristate "Support for audioinjector.net isolated DAC and ADC soundcard" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_CS4271_I2C + help + Say Y or M if you want to add support for audioinjector.net isolated soundcard + + config SND_AUDIOSENSE_PI + tristate "Support for AudioSense Add-On Soundcard" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_TLV320AIC32X4_I2C + help + Say Y or M if you want to add support for tlv320aic32x4 add-on + + config SND_DIGIDAC1_SOUNDCARD + tristate "Support for Red Rocks Audio DigiDAC1" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_SOC_WM8741 + help +@@ -241,35 +214,30 @@ config SND_DIGIDAC1_SOUNDCARD + + config SND_BCM2708_SOC_DIONAUDIO_LOCO + tristate "Support for Dion Audio LOCO DAC-AMP" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM5102a + help + Say Y or M if you want to add support for Dion Audio LOCO. + + config SND_BCM2708_SOC_DIONAUDIO_LOCO_V2 + tristate "Support for Dion Audio LOCO-V2 DAC-AMP" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM5122 + help + Say Y or M if you want to add support for Dion Audio LOCO-V2. + + config SND_BCM2708_SOC_ALLO_PIANO_DAC + tristate "Support for Allo Piano DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + help + Say Y or M if you want to add support for Allo Piano DAC. + + config SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS + tristate "Support for Allo Piano DAC Plus" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + help + Say Y or M if you want to add support for Allo Piano DAC Plus. + + config SND_BCM2708_SOC_ALLO_BOSS_DAC + tristate "Support for Allo Boss DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + select COMMON_CLK_HIFIBERRY_DACPRO + help +@@ -277,7 +245,6 @@ config SND_BCM2708_SOC_ALLO_BOSS_DAC + + config SND_BCM2708_SOC_ALLO_BOSS2_DAC + tristate "Support for Allo Boss2 DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + depends on I2C + select REGMAP_I2C + select SND_AUDIO_GRAPH_CARD +@@ -286,7 +253,6 @@ config SND_BCM2708_SOC_ALLO_BOSS2_DAC + + config SND_BCM2708_SOC_ALLO_DIGIONE + tristate "Support for Allo DigiOne" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_WM8804 + select SND_RPI_WM8804_SOUNDCARD + help +@@ -294,7 +260,6 @@ config SND_BCM2708_SOC_ALLO_DIGIONE + + config SND_BCM2708_SOC_ALLO_KATANA_DAC + tristate "Support for Allo Katana DAC" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + depends on I2C + select REGMAP_I2C + select SND_AUDIO_GRAPH_CARD +@@ -303,14 +268,12 @@ config SND_BCM2708_SOC_ALLO_KATANA_DAC + + config SND_BCM2708_SOC_FE_PI_AUDIO + tristate "Support for Fe-Pi-Audio" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_SGTL5000 + help + Say Y or M if you want to add support for Fe-Pi-Audio. + + config SND_PISOUND + tristate "Support for Blokas Labs pisound" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_RAWMIDI + help + Say Y or M if you want to add support for Blokas Labs pisound. +@@ -328,7 +291,6 @@ config SND_RPI_WM8804_SOUNDCARD + + config SND_DACBERRY400 + tristate "Support for DACBERRY400 Soundcard" +- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_TLV320AIC3X_I2C + help + Say Y or M if you want to add support for tlv320aic3x add-on diff --git a/target/linux/bcm27xx/patches-6.1/950-0897-hwmon-Add-RP1-ADC-and-temperature-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0897-hwmon-Add-RP1-ADC-and-temperature-driver.patch new file mode 100644 index 0000000000..c3cf21455b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0897-hwmon-Add-RP1-ADC-and-temperature-driver.patch @@ -0,0 +1,343 @@ +From cad3c92ff0c1a5fa539d08b695b0f6b326924890 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 2 Mar 2023 18:04:42 +0000 +Subject: [PATCH] hwmon: Add RP1 ADC and temperature driver + +Signed-off-by: Phil Elwell +--- + drivers/hwmon/Kconfig | 7 + + drivers/hwmon/Makefile | 1 + + drivers/hwmon/rp1-adc.c | 301 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 309 insertions(+) + create mode 100644 drivers/hwmon/rp1-adc.c + +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -2331,6 +2331,13 @@ config SENSORS_INTEL_M10_BMC_HWMON + sensors monitor various telemetry data of different components on the + card, e.g. board temperature, FPGA core temperature/voltage/current. + ++config SENSORS_RP1_ADC ++ tristate "RP1 ADC and temperature sensor driver" ++ depends on MFD_RP1 ++ help ++ Say yes here to enable support for the voltage and temperature ++ sensors of the Raspberry Pi RP1 peripheral chip. ++ + if ACPI + + comment "ACPI drivers" +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -173,6 +173,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591 + obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o + obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o + obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o ++obj-$(CONFIG_SENSORS_RP1_ADC) += rp1-adc.o + obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o + obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o + obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o +--- /dev/null ++++ b/drivers/hwmon/rp1-adc.c +@@ -0,0 +1,301 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Driver for the RP1 ADC and temperature sensor ++ * Copyright (C) 2023 Raspberry Pi Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MODULE_NAME "rp1-adc" ++ ++#define RP1_ADC_CS 0x00 ++#define RP1_ADC_RESULT 0x04 ++#define RP1_ADC_FCS 0x08 ++#define RP1_ADC_FIFO 0x0c ++#define RP1_ADC_DIV 0x10 ++ ++#define RP1_ADC_INTR 0x14 ++#define RP1_ADC_INTE 0x18 ++#define RP1_ADC_INTF 0x1c ++#define RP1_ADC_INTS 0x20 ++ ++#define RP1_ADC_RWTYPE_SET 0x2000 ++#define RP1_ADC_RWTYPE_CLR 0x3000 ++ ++#define RP1_ADC_CS_RROBIN_MASK 0x1f ++#define RP1_ADC_CS_RROBIN_SHIFT 16 ++#define RP1_ADC_CS_AINSEL_MASK 0x7 ++#define RP1_ADC_CS_AINSEL_SHIFT 12 ++#define RP1_ADC_CS_ERR_STICKY 0x400 ++#define RP1_ADC_CS_ERR 0x200 ++#define RP1_ADC_CS_READY 0x100 ++#define RP1_ADC_CS_START_MANY 0x8 ++#define RP1_ADC_CS_START_ONCE 0x4 ++#define RP1_ADC_CS_TS_EN 0x2 ++#define RP1_ADC_CS_EN 0x1 ++ ++#define RP1_ADC_FCS_THRESH_MASK 0xf ++#define RP1_ADC_FCS_THRESH_SHIFT 24 ++#define RP1_ADC_FCS_LEVEL_MASK 0xf ++#define RP1_ADC_FCS_LEVEL_SHIFT 16 ++#define RP1_ADC_FCS_OVER 0x800 ++#define RP1_ADC_FCS_UNDER 0x400 ++#define RP1_ADC_FCS_FULL 0x200 ++#define RP1_ADC_FCS_EMPTY 0x100 ++#define RP1_ADC_FCS_DREQ_EN 0x8 ++#define RP1_ADC_FCS_ERR 0x4 ++#define RP1_ADC_FCS_SHIFR 0x2 ++#define RP1_ADC_FCS_EN 0x1 ++ ++#define RP1_ADC_FIFO_ERR 0x8000 ++#define RP1_ADC_FIFO_VAL_MASK 0xfff ++ ++#define RP1_ADC_DIV_INT_MASK 0xffff ++#define RP1_ADC_DIV_INT_SHIFT 8 ++#define RP1_ADC_DIV_FRAC_MASK 0xff ++#define RP1_ADC_DIV_FRAC_SHIFT 0 ++ ++struct rp1_adc_data { ++ void __iomem *base; ++ spinlock_t lock; ++ struct device *hwmon_dev; ++ int vref_mv; ++}; ++ ++static int rp1_adc_ready_wait(struct rp1_adc_data *data) ++{ ++ int retries = 10; ++ ++ while (retries && !(readl(data->base + RP1_ADC_CS) & RP1_ADC_CS_READY)) ++ retries--; ++ ++ return retries ? 0 : -EIO; ++} ++ ++static int rp1_adc_read(struct rp1_adc_data *data, ++ struct device_attribute *devattr, unsigned int *val) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ int channel = attr->index; ++ int ret; ++ ++ spin_lock(&data->lock); ++ ++ writel(RP1_ADC_CS_AINSEL_MASK << RP1_ADC_CS_AINSEL_SHIFT, ++ data->base + RP1_ADC_RWTYPE_CLR + RP1_ADC_CS); ++ writel(channel << RP1_ADC_CS_AINSEL_SHIFT, ++ data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS); ++ writel(RP1_ADC_CS_START_ONCE, ++ data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS); ++ ++ ret = rp1_adc_ready_wait(data); ++ if (!ret) ++ *val = readl(data->base + RP1_ADC_RESULT); ++ ++ spin_unlock(&data->lock); ++ ++ return ret; ++} ++ ++static int rp1_adc_to_mv(struct rp1_adc_data *data, unsigned int val) ++{ ++ return ((u64)data->vref_mv * val) / 0xfff; ++} ++ ++static ssize_t rp1_adc_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ struct rp1_adc_data *data = dev_get_drvdata(dev); ++ unsigned int val; ++ int ret; ++ ++ ret = rp1_adc_read(data, devattr, &val); ++ if (ret) ++ return ret; ++ ++ return sprintf(buf, "%d\n", rp1_adc_to_mv(data, val)); ++} ++ ++static ssize_t rp1_adc_temp_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ struct rp1_adc_data *data = dev_get_drvdata(dev); ++ unsigned int val; ++ int ret, mv, mc; ++ ++ writel(RP1_ADC_CS_TS_EN, ++ data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS); ++ ret = rp1_adc_read(data, devattr, &val); ++ if (ret) ++ return ret; ++ ++ mv = rp1_adc_to_mv(data, val); ++ ++ /* T = 27 - (ADC_voltage - 0.706)/0.001721 */ ++ ++ mc = 27000 - DIV_ROUND_CLOSEST((mv - 706) * (s64)1000000, 1721); ++ ++ return sprintf(buf, "%d\n", mc); ++} ++ ++static ssize_t rp1_adc_raw_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ struct rp1_adc_data *data = dev_get_drvdata(dev); ++ unsigned int val; ++ int ret = rp1_adc_read(data, devattr, &val); ++ ++ if (ret) ++ return ret; ++ ++ return sprintf(buf, "%u\n", val); ++} ++ ++static ssize_t rp1_adc_temp_raw_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ struct rp1_adc_data *data = dev_get_drvdata(dev); ++ unsigned int val; ++ int ret = rp1_adc_read(data, devattr, &val); ++ ++ if (ret) ++ return ret; ++ ++ return sprintf(buf, "%u\n", val); ++} ++ ++static SENSOR_DEVICE_ATTR_RO(in1_input, rp1_adc, 0); ++static SENSOR_DEVICE_ATTR_RO(in2_input, rp1_adc, 1); ++static SENSOR_DEVICE_ATTR_RO(in3_input, rp1_adc, 2); ++static SENSOR_DEVICE_ATTR_RO(in4_input, rp1_adc, 3); ++static SENSOR_DEVICE_ATTR_RO(temp1_input, rp1_adc_temp, 4); ++static SENSOR_DEVICE_ATTR_RO(in1_raw, rp1_adc_raw, 0); ++static SENSOR_DEVICE_ATTR_RO(in2_raw, rp1_adc_raw, 1); ++static SENSOR_DEVICE_ATTR_RO(in3_raw, rp1_adc_raw, 2); ++static SENSOR_DEVICE_ATTR_RO(in4_raw, rp1_adc_raw, 3); ++static SENSOR_DEVICE_ATTR_RO(temp1_raw, rp1_adc_temp_raw, 4); ++ ++static struct attribute *rp1_adc_attrs[] = { ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_in2_input.dev_attr.attr, ++ &sensor_dev_attr_in3_input.dev_attr.attr, ++ &sensor_dev_attr_in4_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_in1_raw.dev_attr.attr, ++ &sensor_dev_attr_in2_raw.dev_attr.attr, ++ &sensor_dev_attr_in3_raw.dev_attr.attr, ++ &sensor_dev_attr_in4_raw.dev_attr.attr, ++ &sensor_dev_attr_temp1_raw.dev_attr.attr, ++ NULL ++}; ++ ++static umode_t rp1_adc_is_visible(struct kobject *kobj, ++ struct attribute *attr, int index) ++{ ++ return 0444; ++} ++ ++static const struct attribute_group rp1_adc_group = { ++ .attrs = rp1_adc_attrs, ++ .is_visible = rp1_adc_is_visible, ++}; ++__ATTRIBUTE_GROUPS(rp1_adc); ++ ++static int __init rp1_adc_probe(struct platform_device *pdev) ++{ ++ struct rp1_adc_data *data; ++ struct regulator *reg; ++ struct clk *clk; ++ int vref_uv, ret; ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ spin_lock_init(&data->lock); ++ ++ data->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(data->base)) ++ return PTR_ERR(data->base); ++ ++ platform_set_drvdata(pdev, data); ++ ++ clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) ++ return -ENODEV; ++ ++ clk_set_rate(clk, 50000000); ++ clk_prepare_enable(clk); ++ ++ reg = devm_regulator_get(&pdev->dev, "vref"); ++ if (IS_ERR(reg)) ++ return PTR_ERR(reg); ++ ++ vref_uv = regulator_get_voltage(reg); ++ data->vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000); ++ ++ data->hwmon_dev = ++ devm_hwmon_device_register_with_groups(&pdev->dev, ++ "rp1_adc", ++ data, ++ rp1_adc_groups); ++ if (IS_ERR(data->hwmon_dev)) { ++ ret = PTR_ERR(data->hwmon_dev); ++ dev_err(&pdev->dev, "hwmon_device_register failed with %d.\n", ret); ++ goto err_register; ++ } ++ ++ /* Disable interrupts */ ++ writel(0, data->base + RP1_ADC_INTE); ++ ++ /* Enable the block, clearing any sticky error */ ++ writel(RP1_ADC_CS_EN | RP1_ADC_CS_ERR_STICKY, data->base + RP1_ADC_CS); ++ ++ return 0; ++ ++err_register: ++ sysfs_remove_group(&pdev->dev.kobj, &rp1_adc_group); ++ ++ return ret; ++} ++ ++static int rp1_adc_remove(struct platform_device *pdev) ++{ ++ struct rp1_adc_data *data = platform_get_drvdata(pdev); ++ ++ hwmon_device_unregister(data->hwmon_dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id rp1_adc_dt_ids[] = { ++ { .compatible = "raspberrypi,rp1-adc", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, rp1_adc_dt_ids); ++ ++static struct platform_driver rp1_adc_driver = { ++ .remove = rp1_adc_remove, ++ .driver = { ++ .name = MODULE_NAME, ++ .of_match_table = rp1_adc_dt_ids, ++ }, ++}; ++ ++module_platform_driver_probe(rp1_adc_driver, rp1_adc_probe); ++ ++MODULE_DESCRIPTION("RP1 ADC driver"); ++MODULE_AUTHOR("Phil Elwell "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/bcm27xx/patches-6.1/950-0898-mfd-bcm2835-pm-Add-support-for-BCM2712.patch b/target/linux/bcm27xx/patches-6.1/950-0898-mfd-bcm2835-pm-Add-support-for-BCM2712.patch new file mode 100644 index 0000000000..37210173db --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0898-mfd-bcm2835-pm-Add-support-for-BCM2712.patch @@ -0,0 +1,69 @@ +From 0c7aeb96fd3ab68011ba6c24239c501190890308 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 8 Mar 2023 14:27:58 +0000 +Subject: [PATCH] mfd: bcm2835-pm: Add support for BCM2712 + +BCM2712 lacks the "asb" and "rpivid_asb" register ranges, but still +requires the use of the bcm2835-power driver to reset the V3D block. + +Signed-off-by: Phil Elwell +--- + drivers/mfd/bcm2835-pm.c | 28 +++++++++++++++++++--------- + 1 file changed, 19 insertions(+), 9 deletions(-) + +--- a/drivers/mfd/bcm2835-pm.c ++++ b/drivers/mfd/bcm2835-pm.c +@@ -69,12 +69,30 @@ static int bcm2835_pm_get_pdata(struct p + return 0; + } + ++static const struct of_device_id bcm2835_pm_of_match[] = { ++ { .compatible = "brcm,bcm2835-pm-wdt", }, ++ { .compatible = "brcm,bcm2835-pm", }, ++ { .compatible = "brcm,bcm2711-pm", }, ++ { .compatible = "brcm,bcm2712-pm", .data = (const void *)1}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match); ++ + static int bcm2835_pm_probe(struct platform_device *pdev) + { ++ const struct of_device_id *of_id; + struct device *dev = &pdev->dev; + struct bcm2835_pm *pm; ++ bool is_2712; + int ret; + ++ of_id = of_match_node(bcm2835_pm_of_match, pdev->dev.of_node); ++ if (!of_id) { ++ dev_err(&pdev->dev, "Failed to match compatible string\n"); ++ return -EINVAL; ++ } ++ is_2712 = !!of_id->data; ++ + pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL); + if (!pm) + return -ENOMEM; +@@ -97,21 +115,13 @@ static int bcm2835_pm_probe(struct platf + * bcm2835-pm binding as the key for whether we can reference + * the full PM register range and support power domains. + */ +- if (pm->asb) ++ if (pm->asb || is_2712) + return devm_mfd_add_devices(dev, -1, bcm2835_power_devs, + ARRAY_SIZE(bcm2835_power_devs), + NULL, 0, NULL); + return 0; + } + +-static const struct of_device_id bcm2835_pm_of_match[] = { +- { .compatible = "brcm,bcm2835-pm-wdt", }, +- { .compatible = "brcm,bcm2835-pm", }, +- { .compatible = "brcm,bcm2711-pm", }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match); +- + static struct platform_driver bcm2835_pm_driver = { + .probe = bcm2835_pm_probe, + .driver = { diff --git a/target/linux/bcm27xx/patches-6.1/950-0899-soc-bcm-bcm2835-power-Add-support-for-BCM2712.patch b/target/linux/bcm27xx/patches-6.1/950-0899-soc-bcm-bcm2835-power-Add-support-for-BCM2712.patch new file mode 100644 index 0000000000..e7e3652d91 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0899-soc-bcm-bcm2835-power-Add-support-for-BCM2712.patch @@ -0,0 +1,76 @@ +From 9cf85a95eeb239a079a3485bd1d0447431bdc7f1 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 8 Mar 2023 14:42:48 +0000 +Subject: [PATCH] soc: bcm: bcm2835-power: Add support for BCM2712 + +BCM2712 has a PM block but neither ASB nor RPIVID_ASB. Use the absence +of the "asb" register range to indicate BCM2712 and its different PM +register range. + +Signed-off-by: Phil Elwell +--- + drivers/soc/bcm/bcm2835-power.c | 29 +++++++++++++++++++---------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +--- a/drivers/soc/bcm/bcm2835-power.c ++++ b/drivers/soc/bcm/bcm2835-power.c +@@ -79,6 +79,7 @@ + #define PM_IMAGE 0x108 + #define PM_GRAFX 0x10c + #define PM_PROC 0x110 ++#define PM_GRAFX_2712 0x304 + #define PM_ENAB BIT(12) + #define PM_ISPRSTN BIT(8) + #define PM_H264RSTN BIT(7) +@@ -381,6 +382,9 @@ static int bcm2835_power_pd_power_on(str + return bcm2835_power_power_on(pd, PM_GRAFX); + + case BCM2835_POWER_DOMAIN_GRAFX_V3D: ++ if (!power->asb) ++ return bcm2835_asb_power_on(pd, PM_GRAFX_2712, ++ 0, 0, PM_V3DRSTN); + return bcm2835_asb_power_on(pd, PM_GRAFX, + ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, + PM_V3DRSTN); +@@ -447,6 +451,9 @@ static int bcm2835_power_pd_power_off(st + return bcm2835_power_power_off(pd, PM_GRAFX); + + case BCM2835_POWER_DOMAIN_GRAFX_V3D: ++ if (!power->asb) ++ return bcm2835_asb_power_off(pd, PM_GRAFX_2712, ++ 0, 0, PM_V3DRSTN); + return bcm2835_asb_power_off(pd, PM_GRAFX, + ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, + PM_V3DRSTN); +@@ -642,19 +649,21 @@ static int bcm2835_power_probe(struct pl + power->asb = pm->asb; + power->rpivid_asb = pm->rpivid_asb; + +- id = readl(power->asb + ASB_AXI_BRDG_ID); +- if (id != BCM2835_BRDG_ID /* "BRDG" */) { +- dev_err(dev, "ASB register ID returned 0x%08x\n", id); +- return -ENODEV; +- } +- +- if (power->rpivid_asb) { +- id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID); ++ if (power->asb) { ++ id = readl(power->asb + ASB_AXI_BRDG_ID); + if (id != BCM2835_BRDG_ID /* "BRDG" */) { +- dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n", +- id); ++ dev_err(dev, "ASB register ID returned 0x%08x\n", id); + return -ENODEV; + } ++ ++ if (power->rpivid_asb) { ++ id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID); ++ if (id != BCM2835_BRDG_ID /* "BRDG" */) { ++ dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n", ++ id); ++ return -ENODEV; ++ } ++ } + } + + power->pd_xlate.domains = devm_kcalloc(dev, diff --git a/target/linux/bcm27xx/patches-6.1/950-0900-drivers-spi-Fix-spi-gpio-to-correctly-implement-sck-.patch b/target/linux/bcm27xx/patches-6.1/950-0900-drivers-spi-Fix-spi-gpio-to-correctly-implement-sck-.patch new file mode 100644 index 0000000000..ff8471411f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0900-drivers-spi-Fix-spi-gpio-to-correctly-implement-sck-.patch @@ -0,0 +1,150 @@ +From 380c336af070edf85826abbb0057bf92a03ec466 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Wed, 1 Mar 2023 17:57:11 +0000 +Subject: [PATCH] drivers: spi: Fix spi-gpio to correctly implement + sck-idle-input + +Formerly, if configured using DT, CS GPIOs were driven from spi.c +and it was possible for CS to be asserted (low) *before* starting +to drive SCK. CS GPIOs have been brought under control of this +driver in both ACPI and DT cases, with a fixup for GPIO polarity. + +Signed-off-by: Nick Hollinghurst +--- + drivers/spi/spi-gpio.c | 74 +++++++++++++++++++++++++++++------------- + 1 file changed, 51 insertions(+), 23 deletions(-) + +--- a/drivers/spi/spi-gpio.c ++++ b/drivers/spi/spi-gpio.c +@@ -37,6 +37,7 @@ struct spi_gpio { + struct gpio_desc *mosi; + bool sck_idle_input; + struct gpio_desc **cs_gpios; ++ bool cs_dont_invert; + }; + + /*----------------------------------------------------------------------*/ +@@ -233,12 +234,18 @@ static void spi_gpio_chipselect(struct s + gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL); + } + +- /* Drive chip select line, if we have one */ ++ /* ++ * Drive chip select line, if we have one. ++ * SPI chip selects are normally active-low, but when ++ * cs_dont_invert is set, we assume their polarity is ++ * controlled by the GPIO, and write '1' to assert. ++ */ + if (spi_gpio->cs_gpios) { + struct gpio_desc *cs = spi_gpio->cs_gpios[spi->chip_select]; ++ int val = ((spi->mode & SPI_CS_HIGH) || spi_gpio->cs_dont_invert) ? ++ is_active : !is_active; + +- /* SPI chip selects are normally active-low */ +- gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); ++ gpiod_set_value_cansleep(cs, val); + } + + if (spi_gpio->sck_idle_input && !is_active) +@@ -254,12 +261,14 @@ static int spi_gpio_setup(struct spi_dev + /* + * The CS GPIOs have already been + * initialized from the descriptor lookup. ++ * Here we set them to the non-asserted state. + */ + if (spi_gpio->cs_gpios) { + cs = spi_gpio->cs_gpios[spi->chip_select]; + if (!spi->controller_state && cs) + status = gpiod_direction_output(cs, +- !(spi->mode & SPI_CS_HIGH)); ++ !((spi->mode & SPI_CS_HIGH) || ++ spi_gpio->cs_dont_invert)); + } + + if (!status) +@@ -336,6 +345,38 @@ static int spi_gpio_request(struct devic + return PTR_ERR_OR_ZERO(spi_gpio->sck); + } + ++/* ++ * In order to implement "sck-idle-input" (which requires SCK ++ * direction and CS level to be switched in a particular order), ++ * we need to control GPIO chip selects from within this driver. ++ */ ++ ++static int spi_gpio_probe_get_cs_gpios(struct device *dev, ++ struct spi_master *master, ++ bool gpio_defines_polarity) ++{ ++ int i; ++ struct spi_gpio *spi_gpio = spi_master_get_devdata(master); ++ ++ spi_gpio->cs_dont_invert = gpio_defines_polarity; ++ spi_gpio->cs_gpios = devm_kcalloc(dev, master->num_chipselect, ++ sizeof(*spi_gpio->cs_gpios), ++ GFP_KERNEL); ++ if (!spi_gpio->cs_gpios) ++ return -ENOMEM; ++ ++ for (i = 0; i < master->num_chipselect; i++) { ++ spi_gpio->cs_gpios[i] = ++ devm_gpiod_get_index(dev, "cs", i, ++ gpio_defines_polarity ? ++ GPIOD_OUT_LOW : GPIOD_OUT_HIGH); ++ if (IS_ERR(spi_gpio->cs_gpios[i])) ++ return PTR_ERR(spi_gpio->cs_gpios[i]); ++ } ++ ++ return 0; ++} ++ + #ifdef CONFIG_OF + static const struct of_device_id spi_gpio_dt_ids[] = { + { .compatible = "spi-gpio" }, +@@ -346,10 +387,12 @@ MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids) + static int spi_gpio_probe_dt(struct platform_device *pdev, + struct spi_master *master) + { +- master->dev.of_node = pdev->dev.of_node; +- master->use_gpio_descriptors = true; ++ struct device *dev = &pdev->dev; + +- return 0; ++ master->dev.of_node = dev->of_node; ++ master->num_chipselect = gpiod_count(dev, "cs"); ++ ++ return spi_gpio_probe_get_cs_gpios(dev, master, true); + } + #else + static inline int spi_gpio_probe_dt(struct platform_device *pdev, +@@ -364,8 +407,6 @@ static int spi_gpio_probe_pdata(struct p + { + struct device *dev = &pdev->dev; + struct spi_gpio_platform_data *pdata = dev_get_platdata(dev); +- struct spi_gpio *spi_gpio = spi_master_get_devdata(master); +- int i; + + #ifdef GENERIC_BITBANG + if (!pdata || !pdata->num_chipselect) +@@ -377,20 +418,7 @@ static int spi_gpio_probe_pdata(struct p + */ + master->num_chipselect = pdata->num_chipselect ?: 1; + +- spi_gpio->cs_gpios = devm_kcalloc(dev, master->num_chipselect, +- sizeof(*spi_gpio->cs_gpios), +- GFP_KERNEL); +- if (!spi_gpio->cs_gpios) +- return -ENOMEM; +- +- for (i = 0; i < master->num_chipselect; i++) { +- spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs", i, +- GPIOD_OUT_HIGH); +- if (IS_ERR(spi_gpio->cs_gpios[i])) +- return PTR_ERR(spi_gpio->cs_gpios[i]); +- } +- +- return 0; ++ return spi_gpio_probe_get_cs_gpios(dev, master, false); + } + + static int spi_gpio_probe(struct platform_device *pdev) diff --git a/target/linux/bcm27xx/patches-6.1/950-0901-spi-spi-gpio-Implement-spidelay-when-requested-bit-r.patch b/target/linux/bcm27xx/patches-6.1/950-0901-spi-spi-gpio-Implement-spidelay-when-requested-bit-r.patch new file mode 100644 index 0000000000..1b7952ab18 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0901-spi-spi-gpio-Implement-spidelay-when-requested-bit-r.patch @@ -0,0 +1,55 @@ +From 586f87307e75552292cfc6c76b81cd38d5ec31e2 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Mon, 4 Sep 2023 10:57:47 +0100 +Subject: [PATCH] spi: spi-gpio: Implement spidelay when requested bit rate <= + 1 Mbps + +Formerly the delay was omitted as bit-banged SPI seldom achieved +even one Mbit/s; but some modern platforms can run faster, and +some SPI devices may need to be clocked slower. + +Signed-off-by: Nick Hollinghurst +--- + drivers/spi/spi-gpio.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/spi/spi-gpio.c ++++ b/drivers/spi/spi-gpio.c +@@ -11,12 +11,12 @@ + #include + #include + #include ++#include + + #include + #include + #include + +- + /* + * This bitbanging SPI master driver should help make systems usable + * when a native hardware SPI engine is not available, perhaps because +@@ -111,12 +111,18 @@ static inline int getmiso(const struct s + } + + /* +- * NOTE: this clocks "as fast as we can". It "should" be a function of the +- * requested device clock. Software overhead means we usually have trouble +- * reaching even one Mbit/sec (except when we can inline bitops), so for now +- * we'll just assume we never need additional per-bit slowdowns. ++ * Generic bit-banged GPIO SPI might free-run at something in the range ++ * 1Mbps ~ 10Mbps (depending on the platform), and some SPI devices may ++ * need to be clocked at a lower rate. ndelay() is often implemented by ++ * udelay() with rounding up, so do the delay only for nsecs >= 500 ++ * (<= 1Mbps). The conditional test adds a small overhead. + */ +-#define spidelay(nsecs) do {} while (0) ++ ++static inline void spidelay(unsigned long nsecs) ++{ ++ if (nsecs >= 500) ++ ndelay(nsecs); ++} + + #include "spi-bitbang-txrx.h" + diff --git a/target/linux/bcm27xx/patches-6.1/950-0902-drm-v3d-fix-up-register-addresses-for-V3D-7.x.patch b/target/linux/bcm27xx/patches-6.1/950-0902-drm-v3d-fix-up-register-addresses-for-V3D-7.x.patch new file mode 100644 index 0000000000..1a51a85660 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0902-drm-v3d-fix-up-register-addresses-for-V3D-7.x.patch @@ -0,0 +1,672 @@ +From 3f949caeef21269afc67dd62ae9826204f215934 Mon Sep 17 00:00:00 2001 +From: Iago Toral Quiroga +Date: Thu, 2 Mar 2023 11:49:46 +0100 +Subject: [PATCH] drm/v3d: fix up register addresses for V3D 7.x + +v2: fix kernel panic with debug-fs interface to list registers +--- + drivers/gpu/drm/v3d/v3d_debugfs.c | 177 +++++++++++++++++------------- + drivers/gpu/drm/v3d/v3d_gem.c | 3 + + drivers/gpu/drm/v3d/v3d_irq.c | 47 ++++---- + drivers/gpu/drm/v3d/v3d_regs.h | 51 ++++++++- + drivers/gpu/drm/v3d/v3d_sched.c | 41 ++++--- + 5 files changed, 204 insertions(+), 115 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_debugfs.c ++++ b/drivers/gpu/drm/v3d/v3d_debugfs.c +@@ -13,69 +13,83 @@ + #include "v3d_drv.h" + #include "v3d_regs.h" + +-#define REGDEF(reg) { reg, #reg } ++#define REGDEF(min_ver, max_ver, reg) { min_ver, max_ver, reg, #reg } + struct v3d_reg_def { ++ u32 min_ver; ++ u32 max_ver; + u32 reg; + const char *name; + }; + + static const struct v3d_reg_def v3d_hub_reg_defs[] = { +- REGDEF(V3D_HUB_AXICFG), +- REGDEF(V3D_HUB_UIFCFG), +- REGDEF(V3D_HUB_IDENT0), +- REGDEF(V3D_HUB_IDENT1), +- REGDEF(V3D_HUB_IDENT2), +- REGDEF(V3D_HUB_IDENT3), +- REGDEF(V3D_HUB_INT_STS), +- REGDEF(V3D_HUB_INT_MSK_STS), +- +- REGDEF(V3D_MMU_CTL), +- REGDEF(V3D_MMU_VIO_ADDR), +- REGDEF(V3D_MMU_VIO_ID), +- REGDEF(V3D_MMU_DEBUG_INFO), ++ REGDEF(33, 42, V3D_HUB_AXICFG), ++ REGDEF(33, 71, V3D_HUB_UIFCFG), ++ REGDEF(33, 71, V3D_HUB_IDENT0), ++ REGDEF(33, 71, V3D_HUB_IDENT1), ++ REGDEF(33, 71, V3D_HUB_IDENT2), ++ REGDEF(33, 71, V3D_HUB_IDENT3), ++ REGDEF(33, 71, V3D_HUB_INT_STS), ++ REGDEF(33, 71, V3D_HUB_INT_MSK_STS), ++ ++ REGDEF(33, 71, V3D_MMU_CTL), ++ REGDEF(33, 71, V3D_MMU_VIO_ADDR), ++ REGDEF(33, 71, V3D_MMU_VIO_ID), ++ REGDEF(33, 71, V3D_MMU_DEBUG_INFO), ++ ++ REGDEF(71, 71, V3D_V7_GMP_STATUS), ++ REGDEF(71, 71, V3D_V7_GMP_CFG), ++ REGDEF(71, 71, V3D_V7_GMP_VIO_ADDR), + }; + + static const struct v3d_reg_def v3d_gca_reg_defs[] = { +- REGDEF(V3D_GCA_SAFE_SHUTDOWN), +- REGDEF(V3D_GCA_SAFE_SHUTDOWN_ACK), ++ REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN), ++ REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN_ACK), + }; + + static const struct v3d_reg_def v3d_core_reg_defs[] = { +- REGDEF(V3D_CTL_IDENT0), +- REGDEF(V3D_CTL_IDENT1), +- REGDEF(V3D_CTL_IDENT2), +- REGDEF(V3D_CTL_MISCCFG), +- REGDEF(V3D_CTL_INT_STS), +- REGDEF(V3D_CTL_INT_MSK_STS), +- REGDEF(V3D_CLE_CT0CS), +- REGDEF(V3D_CLE_CT0CA), +- REGDEF(V3D_CLE_CT0EA), +- REGDEF(V3D_CLE_CT1CS), +- REGDEF(V3D_CLE_CT1CA), +- REGDEF(V3D_CLE_CT1EA), +- +- REGDEF(V3D_PTB_BPCA), +- REGDEF(V3D_PTB_BPCS), +- +- REGDEF(V3D_GMP_STATUS), +- REGDEF(V3D_GMP_CFG), +- REGDEF(V3D_GMP_VIO_ADDR), +- +- REGDEF(V3D_ERR_FDBGO), +- REGDEF(V3D_ERR_FDBGB), +- REGDEF(V3D_ERR_FDBGS), +- REGDEF(V3D_ERR_STAT), ++ REGDEF(33, 71, V3D_CTL_IDENT0), ++ REGDEF(33, 71, V3D_CTL_IDENT1), ++ REGDEF(33, 71, V3D_CTL_IDENT2), ++ REGDEF(33, 71, V3D_CTL_MISCCFG), ++ REGDEF(33, 71, V3D_CTL_INT_STS), ++ REGDEF(33, 71, V3D_CTL_INT_MSK_STS), ++ REGDEF(33, 71, V3D_CLE_CT0CS), ++ REGDEF(33, 71, V3D_CLE_CT0CA), ++ REGDEF(33, 71, V3D_CLE_CT0EA), ++ REGDEF(33, 71, V3D_CLE_CT1CS), ++ REGDEF(33, 71, V3D_CLE_CT1CA), ++ REGDEF(33, 71, V3D_CLE_CT1EA), ++ ++ REGDEF(33, 71, V3D_PTB_BPCA), ++ REGDEF(33, 71, V3D_PTB_BPCS), ++ ++ REGDEF(33, 41, V3D_GMP_STATUS), ++ REGDEF(33, 41, V3D_GMP_CFG), ++ REGDEF(33, 41, V3D_GMP_VIO_ADDR), ++ ++ REGDEF(33, 71, V3D_ERR_FDBGO), ++ REGDEF(33, 71, V3D_ERR_FDBGB), ++ REGDEF(33, 71, V3D_ERR_FDBGS), ++ REGDEF(33, 71, V3D_ERR_STAT), + }; + + static const struct v3d_reg_def v3d_csd_reg_defs[] = { +- REGDEF(V3D_CSD_STATUS), +- REGDEF(V3D_CSD_CURRENT_CFG0), +- REGDEF(V3D_CSD_CURRENT_CFG1), +- REGDEF(V3D_CSD_CURRENT_CFG2), +- REGDEF(V3D_CSD_CURRENT_CFG3), +- REGDEF(V3D_CSD_CURRENT_CFG4), +- REGDEF(V3D_CSD_CURRENT_CFG5), +- REGDEF(V3D_CSD_CURRENT_CFG6), ++ REGDEF(41, 71, V3D_CSD_STATUS), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG0), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG1), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG2), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG3), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG4), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG5), ++ REGDEF(41, 41, V3D_CSD_CURRENT_CFG6), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG0), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG1), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG2), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG3), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG4), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG5), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG6), ++ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG7), + }; + + static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) +@@ -86,38 +100,41 @@ static int v3d_v3d_debugfs_regs(struct s + int i, core; + + for (i = 0; i < ARRAY_SIZE(v3d_hub_reg_defs); i++) { +- seq_printf(m, "%s (0x%04x): 0x%08x\n", +- v3d_hub_reg_defs[i].name, v3d_hub_reg_defs[i].reg, +- V3D_READ(v3d_hub_reg_defs[i].reg)); ++ const struct v3d_reg_def *def = &v3d_hub_reg_defs[i]; ++ ++ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { ++ seq_printf(m, "%s (0x%04x): 0x%08x\n", ++ def->name, def->reg, V3D_READ(def->reg)); ++ } + } + +- if (v3d->ver < 41) { +- for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) { ++ for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) { ++ const struct v3d_reg_def *def = &v3d_gca_reg_defs[i]; ++ ++ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { + seq_printf(m, "%s (0x%04x): 0x%08x\n", +- v3d_gca_reg_defs[i].name, +- v3d_gca_reg_defs[i].reg, +- V3D_GCA_READ(v3d_gca_reg_defs[i].reg)); ++ def->name, def->reg, V3D_GCA_READ(def->reg)); + } + } + + for (core = 0; core < v3d->cores; core++) { + for (i = 0; i < ARRAY_SIZE(v3d_core_reg_defs); i++) { +- seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", +- core, +- v3d_core_reg_defs[i].name, +- v3d_core_reg_defs[i].reg, +- V3D_CORE_READ(core, +- v3d_core_reg_defs[i].reg)); ++ const struct v3d_reg_def *def = &v3d_core_reg_defs[i]; ++ ++ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { ++ seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", ++ core, def->name, def->reg, ++ V3D_CORE_READ(core, def->reg)); ++ } + } + +- if (v3d_has_csd(v3d)) { +- for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) { ++ for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) { ++ const struct v3d_reg_def *def = &v3d_csd_reg_defs[i]; ++ ++ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { + seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", +- core, +- v3d_csd_reg_defs[i].name, +- v3d_csd_reg_defs[i].reg, +- V3D_CORE_READ(core, +- v3d_csd_reg_defs[i].reg)); ++ core, def->name, def->reg, ++ V3D_CORE_READ(core, def->reg)); + } + } + } +@@ -148,8 +165,10 @@ static int v3d_v3d_debugfs_ident(struct + str_yes_no(ident2 & V3D_HUB_IDENT2_WITH_MMU)); + seq_printf(m, "TFU: %s\n", + str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TFU)); +- seq_printf(m, "TSY: %s\n", +- str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY)); ++ if (v3d->ver <= 42) { ++ seq_printf(m, "TSY: %s\n", ++ str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY)); ++ } + seq_printf(m, "MSO: %s\n", + str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_MSO)); + seq_printf(m, "L3C: %s (%dkb)\n", +@@ -178,10 +197,14 @@ static int v3d_v3d_debugfs_ident(struct + seq_printf(m, " QPUs: %d\n", nslc * qups); + seq_printf(m, " Semaphores: %d\n", + V3D_GET_FIELD(ident1, V3D_IDENT1_NSEM)); +- seq_printf(m, " BCG int: %d\n", +- (ident2 & V3D_IDENT2_BCG_INT) != 0); +- seq_printf(m, " Override TMU: %d\n", +- (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); ++ if (v3d->ver <= 42) { ++ seq_printf(m, " BCG int: %d\n", ++ (ident2 & V3D_IDENT2_BCG_INT) != 0); ++ } ++ if (v3d->ver < 40) { ++ seq_printf(m, " Override TMU: %d\n", ++ (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); ++ } + } + + return 0; +@@ -289,8 +312,10 @@ static int v3d_measure_clock(struct seq_ + int measure_ms = 1000; + + if (v3d->ver >= 40) { ++ int cycle_count_reg = v3d->ver < 71 ? ++ V3D_PCTR_CYCLE_COUNT : V3D_V7_PCTR_CYCLE_COUNT; + V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3, +- V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT, ++ V3D_SET_FIELD(cycle_count_reg, + V3D_PCTR_S0)); + V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1); + V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1); +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -88,6 +88,9 @@ v3d_init_hw_state(struct v3d_dev *v3d) + static void + v3d_idle_axi(struct v3d_dev *v3d, int core) + { ++ if (v3d->ver >= 71) ++ return; ++ + V3D_CORE_WRITE(core, V3D_GMP_CFG, V3D_GMP_CFG_STOP_REQ); + + if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS) & +--- a/drivers/gpu/drm/v3d/v3d_irq.c ++++ b/drivers/gpu/drm/v3d/v3d_irq.c +@@ -20,16 +20,17 @@ + #include "v3d_regs.h" + #include "v3d_trace.h" + +-#define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \ +- V3D_INT_FLDONE | \ +- V3D_INT_FRDONE | \ +- V3D_INT_CSDDONE | \ +- V3D_INT_GMPV)) +- +-#define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \ +- V3D_HUB_INT_MMU_PTI | \ +- V3D_HUB_INT_MMU_CAP | \ +- V3D_HUB_INT_TFUC)) ++#define V3D_CORE_IRQS(ver) ((u32)(V3D_INT_OUTOMEM | \ ++ V3D_INT_FLDONE | \ ++ V3D_INT_FRDONE | \ ++ (ver < 71 ? V3D_INT_CSDDONE : V3D_V7_INT_CSDDONE) | \ ++ (ver < 71 ? V3D_INT_GMPV : 0))) ++ ++#define V3D_HUB_IRQS(ver) ((u32)(V3D_HUB_INT_MMU_WRV | \ ++ V3D_HUB_INT_MMU_PTI | \ ++ V3D_HUB_INT_MMU_CAP | \ ++ V3D_HUB_INT_TFUC | \ ++ (ver >= 71 ? V3D_V7_HUB_INT_GMPV : 0))) + + static irqreturn_t + v3d_hub_irq(int irq, void *arg); +@@ -118,7 +119,8 @@ v3d_irq(int irq, void *arg) + status = IRQ_HANDLED; + } + +- if (intsts & V3D_INT_CSDDONE) { ++ if ((v3d->ver < 71 && (intsts & V3D_INT_CSDDONE)) || ++ (v3d->ver >= 71 && (intsts & V3D_V7_INT_CSDDONE))) { + struct v3d_fence *fence = + to_v3d_fence(v3d->csd_job->base.irq_fence); + v3d->gpu_queue_stats[V3D_CSD].last_exec_end = local_clock(); +@@ -131,7 +133,7 @@ v3d_irq(int irq, void *arg) + /* We shouldn't be triggering these if we have GMP in + * always-allowed mode. + */ +- if (intsts & V3D_INT_GMPV) ++ if (v3d->ver < 71 && (intsts & V3D_INT_GMPV)) + dev_err(v3d->drm.dev, "GMP violation\n"); + + /* V3D 4.2 wires the hub and core IRQs together, so if we & +@@ -205,6 +207,11 @@ v3d_hub_irq(int irq, void *arg) + status = IRQ_HANDLED; + } + ++ if (v3d->ver >= 71 && intsts & V3D_V7_HUB_INT_GMPV) { ++ dev_err(v3d->drm.dev, "GMP Violation\n"); ++ status = IRQ_HANDLED; ++ } ++ + return status; + } + +@@ -219,8 +226,8 @@ v3d_irq_init(struct v3d_dev *v3d) + * for us. + */ + for (core = 0; core < v3d->cores; core++) +- V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS); +- V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS); ++ V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver)); ++ V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver)); + + irq1 = platform_get_irq_optional(v3d_to_pdev(v3d), 1); + if (irq1 == -EPROBE_DEFER) +@@ -264,12 +271,12 @@ v3d_irq_enable(struct v3d_dev *v3d) + + /* Enable our set of interrupts, masking out any others. */ + for (core = 0; core < v3d->cores; core++) { +- V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~V3D_CORE_IRQS); +- V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_CLR, V3D_CORE_IRQS); ++ V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~V3D_CORE_IRQS(v3d->ver)); ++ V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_CLR, V3D_CORE_IRQS(v3d->ver)); + } + +- V3D_WRITE(V3D_HUB_INT_MSK_SET, ~V3D_HUB_IRQS); +- V3D_WRITE(V3D_HUB_INT_MSK_CLR, V3D_HUB_IRQS); ++ V3D_WRITE(V3D_HUB_INT_MSK_SET, ~V3D_HUB_IRQS(v3d->ver)); ++ V3D_WRITE(V3D_HUB_INT_MSK_CLR, V3D_HUB_IRQS(v3d->ver)); + } + + void +@@ -284,8 +291,8 @@ v3d_irq_disable(struct v3d_dev *v3d) + + /* Clear any pending interrupts we might have left. */ + for (core = 0; core < v3d->cores; core++) +- V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS); +- V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS); ++ V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver)); ++ V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver)); + + cancel_work_sync(&v3d->overflow_mem_work); + } +--- a/drivers/gpu/drm/v3d/v3d_regs.h ++++ b/drivers/gpu/drm/v3d/v3d_regs.h +@@ -57,6 +57,7 @@ + #define V3D_HUB_INT_MSK_STS 0x0005c + #define V3D_HUB_INT_MSK_SET 0x00060 + #define V3D_HUB_INT_MSK_CLR 0x00064 ++# define V3D_V7_HUB_INT_GMPV BIT(6) + # define V3D_HUB_INT_MMU_WRV BIT(5) + # define V3D_HUB_INT_MMU_PTI BIT(4) + # define V3D_HUB_INT_MMU_CAP BIT(3) +@@ -64,6 +65,7 @@ + # define V3D_HUB_INT_TFUC BIT(1) + # define V3D_HUB_INT_TFUF BIT(0) + ++/* GCA registers only exist in V3D < 41 */ + #define V3D_GCA_CACHE_CTRL 0x0000c + # define V3D_GCA_CACHE_CTRL_FLUSH BIT(0) + +@@ -87,6 +89,7 @@ + # define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0) + + #define V3D_TFU_CS 0x00400 ++#define V3D_V7_TFU_CS 0x00700 + /* Stops current job, empties input fifo. */ + # define V3D_TFU_CS_TFURST BIT(31) + # define V3D_TFU_CS_CVTCT_MASK V3D_MASK(23, 16) +@@ -96,6 +99,7 @@ + # define V3D_TFU_CS_BUSY BIT(0) + + #define V3D_TFU_SU 0x00404 ++#define V3D_V7_TFU_SU 0x00704 + /* Interrupt when FINTTHR input slots are free (0 = disabled) */ + # define V3D_TFU_SU_FINTTHR_MASK V3D_MASK(13, 8) + # define V3D_TFU_SU_FINTTHR_SHIFT 8 +@@ -107,38 +111,53 @@ + # define V3D_TFU_SU_THROTTLE_SHIFT 0 + + #define V3D_TFU_ICFG 0x00408 ++#define V3D_V7_TFU_ICFG 0x00708 + /* Interrupt when the conversion is complete. */ + # define V3D_TFU_ICFG_IOC BIT(0) + + /* Input Image Address */ + #define V3D_TFU_IIA 0x0040c ++#define V3D_V7_TFU_IIA 0x0070c + /* Input Chroma Address */ + #define V3D_TFU_ICA 0x00410 ++#define V3D_V7_TFU_ICA 0x00710 + /* Input Image Stride */ + #define V3D_TFU_IIS 0x00414 ++#define V3D_V7_TFU_IIS 0x00714 + /* Input Image U-Plane Address */ + #define V3D_TFU_IUA 0x00418 ++#define V3D_V7_TFU_IUA 0x00718 ++/* Image output config (VD 7.x only) */ ++#define V3D_V7_TFU_IOC 0x0071c + /* Output Image Address */ + #define V3D_TFU_IOA 0x0041c ++#define V3D_V7_TFU_IOA 0x00720 + /* Image Output Size */ + #define V3D_TFU_IOS 0x00420 ++#define V3D_V7_TFU_IOS 0x00724 + /* TFU YUV Coefficient 0 */ + #define V3D_TFU_COEF0 0x00424 +-/* Use these regs instead of the defaults. */ ++#define V3D_V7_TFU_COEF0 0x00728 ++/* Use these regs instead of the defaults (V3D 4.x only) */ + # define V3D_TFU_COEF0_USECOEF BIT(31) + /* TFU YUV Coefficient 1 */ + #define V3D_TFU_COEF1 0x00428 ++#define V3D_V7_TFU_COEF1 0x0072c + /* TFU YUV Coefficient 2 */ + #define V3D_TFU_COEF2 0x0042c ++#define V3D_V7_TFU_COEF2 0x00730 + /* TFU YUV Coefficient 3 */ + #define V3D_TFU_COEF3 0x00430 ++#define V3D_V7_TFU_COEF3 0x00734 + ++/* V3D 4.x only */ + #define V3D_TFU_CRC 0x00434 + + /* Per-MMU registers. */ + + #define V3D_MMUC_CONTROL 0x01000 + # define V3D_MMUC_CONTROL_CLEAR BIT(3) ++# define V3D_V7_MMUC_CONTROL_CLEAR BIT(11) + # define V3D_MMUC_CONTROL_FLUSHING BIT(2) + # define V3D_MMUC_CONTROL_FLUSH BIT(1) + # define V3D_MMUC_CONTROL_ENABLE BIT(0) +@@ -246,7 +265,6 @@ + + #define V3D_CTL_L2TCACTL 0x00030 + # define V3D_L2TCACTL_TMUWCF BIT(8) +-# define V3D_L2TCACTL_L2T_NO_WM BIT(4) + /* Invalidates cache lines. */ + # define V3D_L2TCACTL_FLM_FLUSH 0 + /* Removes cachelines without writing dirty lines back. */ +@@ -268,7 +286,9 @@ + # define V3D_INT_QPU_MASK V3D_MASK(27, 16) + # define V3D_INT_QPU_SHIFT 16 + # define V3D_INT_CSDDONE BIT(7) ++# define V3D_V7_INT_CSDDONE BIT(6) + # define V3D_INT_PCTR BIT(6) ++# define V3D_V7_INT_PCTR BIT(5) + # define V3D_INT_GMPV BIT(5) + # define V3D_INT_TRFB BIT(4) + # define V3D_INT_SPILLUSE BIT(3) +@@ -350,14 +370,19 @@ + #define V3D_V4_PCTR_0_SRC_X(x) (V3D_V4_PCTR_0_SRC_0_3 + \ + 4 * (x)) + # define V3D_PCTR_S0_MASK V3D_MASK(6, 0) ++# define V3D_V7_PCTR_S0_MASK V3D_MASK(7, 0) + # define V3D_PCTR_S0_SHIFT 0 + # define V3D_PCTR_S1_MASK V3D_MASK(14, 8) ++# define V3D_V7_PCTR_S1_MASK V3D_MASK(15, 8) + # define V3D_PCTR_S1_SHIFT 8 + # define V3D_PCTR_S2_MASK V3D_MASK(22, 16) ++# define V3D_V7_PCTR_S2_MASK V3D_MASK(23, 16) + # define V3D_PCTR_S2_SHIFT 16 + # define V3D_PCTR_S3_MASK V3D_MASK(30, 24) ++# define V3D_V7_PCTR_S3_MASK V3D_MASK(31, 24) + # define V3D_PCTR_S3_SHIFT 24 + # define V3D_PCTR_CYCLE_COUNT 32 ++# define V3D_V7_PCTR_CYCLE_COUNT 0 + + /* Output values of the counters. */ + #define V3D_PCTR_0_PCTR0 0x00680 +@@ -365,6 +390,7 @@ + #define V3D_PCTR_0_PCTRX(x) (V3D_PCTR_0_PCTR0 + \ + 4 * (x)) + #define V3D_GMP_STATUS 0x00800 ++#define V3D_V7_GMP_STATUS 0x00600 + # define V3D_GMP_STATUS_GMPRST BIT(31) + # define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24) + # define V3D_GMP_STATUS_WR_COUNT_SHIFT 24 +@@ -378,12 +404,14 @@ + # define V3D_GMP_STATUS_VIO BIT(0) + + #define V3D_GMP_CFG 0x00804 ++#define V3D_V7_GMP_CFG 0x00604 + # define V3D_GMP_CFG_LBURSTEN BIT(3) + # define V3D_GMP_CFG_PGCRSEN BIT() + # define V3D_GMP_CFG_STOP_REQ BIT(1) + # define V3D_GMP_CFG_PROT_ENABLE BIT(0) + + #define V3D_GMP_VIO_ADDR 0x00808 ++#define V3D_V7_GMP_VIO_ADDR 0x00608 + #define V3D_GMP_VIO_TYPE 0x0080c + #define V3D_GMP_TABLE_ADDR 0x00810 + #define V3D_GMP_CLEAR_LOAD 0x00814 +@@ -399,24 +427,28 @@ + # define V3D_CSD_STATUS_HAVE_QUEUED_DISPATCH BIT(0) + + #define V3D_CSD_QUEUED_CFG0 0x00904 ++#define V3D_V7_CSD_QUEUED_CFG0 0x00930 + # define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_MASK V3D_MASK(31, 16) + # define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_SHIFT 16 + # define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_MASK V3D_MASK(15, 0) + # define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_SHIFT 0 + + #define V3D_CSD_QUEUED_CFG1 0x00908 ++#define V3D_V7_CSD_QUEUED_CFG1 0x00934 + # define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_MASK V3D_MASK(31, 16) + # define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_SHIFT 16 + # define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_MASK V3D_MASK(15, 0) + # define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_SHIFT 0 + + #define V3D_CSD_QUEUED_CFG2 0x0090c ++#define V3D_V7_CSD_QUEUED_CFG2 0x00938 + # define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_MASK V3D_MASK(31, 16) + # define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_SHIFT 16 + # define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_MASK V3D_MASK(15, 0) + # define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_SHIFT 0 + + #define V3D_CSD_QUEUED_CFG3 0x00910 ++#define V3D_V7_CSD_QUEUED_CFG3 0x0093c + # define V3D_CSD_QUEUED_CFG3_OVERLAP_WITH_PREV BIT(26) + # define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_MASK V3D_MASK(25, 20) + # define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_SHIFT 20 +@@ -429,22 +461,36 @@ + + /* Number of batches, minus 1 */ + #define V3D_CSD_QUEUED_CFG4 0x00914 ++#define V3D_V7_CSD_QUEUED_CFG4 0x00940 + + /* Shader address, pnan, singleseg, threading, like a shader record. */ + #define V3D_CSD_QUEUED_CFG5 0x00918 ++#define V3D_V7_CSD_QUEUED_CFG5 0x00944 + + /* Uniforms address (4 byte aligned) */ + #define V3D_CSD_QUEUED_CFG6 0x0091c ++#define V3D_V7_CSD_QUEUED_CFG6 0x00948 ++ ++#define V3D_V7_CSD_QUEUED_CFG7 0x0094c + + #define V3D_CSD_CURRENT_CFG0 0x00920 ++#define V3D_V7_CSD_CURRENT_CFG0 0x00958 + #define V3D_CSD_CURRENT_CFG1 0x00924 ++#define V3D_V7_CSD_CURRENT_CFG1 0x0095c + #define V3D_CSD_CURRENT_CFG2 0x00928 ++#define V3D_V7_CSD_CURRENT_CFG2 0x00960 + #define V3D_CSD_CURRENT_CFG3 0x0092c ++#define V3D_V7_CSD_CURRENT_CFG3 0x00964 + #define V3D_CSD_CURRENT_CFG4 0x00930 ++#define V3D_V7_CSD_CURRENT_CFG4 0x00968 + #define V3D_CSD_CURRENT_CFG5 0x00934 ++#define V3D_V7_CSD_CURRENT_CFG5 0x0096c + #define V3D_CSD_CURRENT_CFG6 0x00938 ++#define V3D_V7_CSD_CURRENT_CFG6 0x00970 ++#define V3D_V7_CSD_CURRENT_CFG7 0x00974 + + #define V3D_CSD_CURRENT_ID0 0x0093c ++#define V3D_V7_CSD_CURRENT_ID0 0x00978 + # define V3D_CSD_CURRENT_ID0_WG_X_MASK V3D_MASK(31, 16) + # define V3D_CSD_CURRENT_ID0_WG_X_SHIFT 16 + # define V3D_CSD_CURRENT_ID0_WG_IN_SG_MASK V3D_MASK(11, 8) +@@ -453,6 +499,7 @@ + # define V3D_CSD_CURRENT_ID0_L_IDX_SHIFT 0 + + #define V3D_CSD_CURRENT_ID1 0x00940 ++#define V3D_V7_CSD_CURRENT_ID1 0x0097c + # define V3D_CSD_CURRENT_ID0_WG_Z_MASK V3D_MASK(31, 16) + # define V3D_CSD_CURRENT_ID0_WG_Z_SHIFT 16 + # define V3D_CSD_CURRENT_ID0_WG_Y_MASK V3D_MASK(15, 0) +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -282,6 +282,8 @@ static struct dma_fence *v3d_render_job_ + return fence; + } + ++#define V3D_TFU_REG(name) ((v3d->ver < 71) ? V3D_TFU_ ## name : V3D_V7_TFU_ ## name) ++ + static struct dma_fence * + v3d_tfu_job_run(struct drm_sched_job *sched_job) + { +@@ -302,20 +304,22 @@ v3d_tfu_job_run(struct drm_sched_job *sc + trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); + + v3d_sched_stats_add_job(&v3d->gpu_queue_stats[V3D_TFU], sched_job); +- V3D_WRITE(V3D_TFU_IIA, job->args.iia); +- V3D_WRITE(V3D_TFU_IIS, job->args.iis); +- V3D_WRITE(V3D_TFU_ICA, job->args.ica); +- V3D_WRITE(V3D_TFU_IUA, job->args.iua); +- V3D_WRITE(V3D_TFU_IOA, job->args.ioa); +- V3D_WRITE(V3D_TFU_IOS, job->args.ios); +- V3D_WRITE(V3D_TFU_COEF0, job->args.coef[0]); +- if (job->args.coef[0] & V3D_TFU_COEF0_USECOEF) { +- V3D_WRITE(V3D_TFU_COEF1, job->args.coef[1]); +- V3D_WRITE(V3D_TFU_COEF2, job->args.coef[2]); +- V3D_WRITE(V3D_TFU_COEF3, job->args.coef[3]); ++ V3D_WRITE(V3D_TFU_REG(IIA), job->args.iia); ++ V3D_WRITE(V3D_TFU_REG(IIS), job->args.iis); ++ V3D_WRITE(V3D_TFU_REG(ICA), job->args.ica); ++ V3D_WRITE(V3D_TFU_REG(IUA), job->args.iua); ++ V3D_WRITE(V3D_TFU_REG(IOA), job->args.ioa); ++ if (v3d->ver >= 71) ++ V3D_WRITE(V3D_V7_TFU_IOC, job->args.v71.ioc); ++ V3D_WRITE(V3D_TFU_REG(IOS), job->args.ios); ++ V3D_WRITE(V3D_TFU_REG(COEF0), job->args.coef[0]); ++ if (v3d->ver >= 71 || (job->args.coef[0] & V3D_TFU_COEF0_USECOEF)) { ++ V3D_WRITE(V3D_TFU_REG(COEF1), job->args.coef[1]); ++ V3D_WRITE(V3D_TFU_REG(COEF2), job->args.coef[2]); ++ V3D_WRITE(V3D_TFU_REG(COEF3), job->args.coef[3]); + } + /* ICFG kicks off the job. */ +- V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC); ++ V3D_WRITE(V3D_TFU_REG(ICFG), job->args.icfg | V3D_TFU_ICFG_IOC); + + return fence; + } +@@ -327,7 +331,7 @@ v3d_csd_job_run(struct drm_sched_job *sc + struct v3d_dev *v3d = job->base.v3d; + struct drm_device *dev = &v3d->drm; + struct dma_fence *fence; +- int i; ++ int i, csd_cfg0_reg, csd_cfg_reg_count; + + v3d->csd_job = job; + +@@ -346,10 +350,12 @@ v3d_csd_job_run(struct drm_sched_job *sc + v3d_sched_stats_add_job(&v3d->gpu_queue_stats[V3D_CSD], sched_job); + v3d_switch_perfmon(v3d, &job->base); + +- for (i = 1; i <= 6; i++) +- V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0 + 4 * i, job->args.cfg[i]); ++ csd_cfg0_reg = v3d->ver < 71 ? V3D_CSD_QUEUED_CFG0 : V3D_V7_CSD_QUEUED_CFG0; ++ csd_cfg_reg_count = v3d->ver < 71 ? 6 : 7; ++ for (i = 1; i <= csd_cfg_reg_count; i++) ++ V3D_CORE_WRITE(0, csd_cfg0_reg + 4 * i, job->args.cfg[i]); + /* CFG0 write kicks off the job. */ +- V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0, job->args.cfg[0]); ++ V3D_CORE_WRITE(0, csd_cfg0_reg, job->args.cfg[0]); + + return fence; + } +@@ -452,7 +458,8 @@ v3d_csd_job_timedout(struct drm_sched_jo + { + struct v3d_csd_job *job = to_csd_job(sched_job); + struct v3d_dev *v3d = job->base.v3d; +- u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4); ++ u32 batches = V3D_CORE_READ(0, (v3d->ver < 71 ? V3D_CSD_CURRENT_CFG4 : ++ V3D_V7_CSD_CURRENT_CFG4)); + + /* If we've made progress, skip reset and let the timer get + * rearmed. diff --git a/target/linux/bcm27xx/patches-6.1/950-0903-drm-v3d-update-UAPI-to-match-user-space-for-V3D-7.x.patch b/target/linux/bcm27xx/patches-6.1/950-0903-drm-v3d-update-UAPI-to-match-user-space-for-V3D-7.x.patch new file mode 100644 index 0000000000..ed1d5f05df --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0903-drm-v3d-update-UAPI-to-match-user-space-for-V3D-7.x.patch @@ -0,0 +1,24 @@ +From 22fb30936524ae96151789741885edbc45efb53d Mon Sep 17 00:00:00 2001 +From: Iago Toral Quiroga +Date: Thu, 2 Mar 2023 11:52:08 +0100 +Subject: [PATCH] drm/v3d: update UAPI to match user-space for V3D 7.x + +V3D t.x takes a new parameter to configure TFU jobs that needs +to be provided by user space. +--- + include/uapi/drm/v3d_drm.h | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/include/uapi/drm/v3d_drm.h ++++ b/include/uapi/drm/v3d_drm.h +@@ -319,6 +319,10 @@ struct drm_v3d_submit_tfu { + + /* Pointer to an array of ioctl extensions*/ + __u64 extensions; ++ ++ struct { ++ __u32 ioc; ++ } v71; + }; + + /* Submits a compute shader for dispatch. This job will block on any diff --git a/target/linux/bcm27xx/patches-6.1/950-0904-drm-v3d-add-brcm-2712-v3d-as-a-compatible-V3D-device.patch b/target/linux/bcm27xx/patches-6.1/950-0904-drm-v3d-add-brcm-2712-v3d-as-a-compatible-V3D-device.patch new file mode 100644 index 0000000000..64189338e6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0904-drm-v3d-add-brcm-2712-v3d-as-a-compatible-V3D-device.patch @@ -0,0 +1,19 @@ +From 18bc419d38eda06ded78c7b702c0e21e5af8f24c Mon Sep 17 00:00:00 2001 +From: Iago Toral Quiroga +Date: Thu, 2 Mar 2023 11:54:45 +0100 +Subject: [PATCH] drm/v3d: add brcm,2712-v3d as a compatible V3D device + +--- + drivers/gpu/drm/v3d/v3d_drv.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -193,6 +193,7 @@ static const struct drm_driver v3d_drm_d + }; + + static const struct of_device_id v3d_of_match[] = { ++ { .compatible = "brcm,2712-v3d" }, + { .compatible = "brcm,2711-v3d" }, + { .compatible = "brcm,7268-v3d" }, + { .compatible = "brcm,7278-v3d" }, diff --git a/target/linux/bcm27xx/patches-6.1/950-0905-drm-v3d-Improve-MMU-support-for-larger-pages.patch b/target/linux/bcm27xx/patches-6.1/950-0905-drm-v3d-Improve-MMU-support-for-larger-pages.patch new file mode 100644 index 0000000000..3c53996ff0 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0905-drm-v3d-Improve-MMU-support-for-larger-pages.patch @@ -0,0 +1,64 @@ +From 12c7ea43b930976f35ce75d11fd3f55438868e13 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 4 Aug 2023 11:26:10 +0100 +Subject: [PATCH] drm/v3d: Improve MMU support for larger pages + +The built-in MMU driver went most of the way towards supporting larger +kernel pages, but dropped the ball when it comes to calculating indexes +into the page table. Fix it. + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/v3d/v3d_mmu.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_mmu.c ++++ b/drivers/gpu/drm/v3d/v3d_mmu.c +@@ -22,6 +22,7 @@ + #include "v3d_regs.h" + + #define V3D_MMU_PAGE_SHIFT 12 ++#define V3D_PAGE_FACTOR (PAGE_SIZE >> V3D_MMU_PAGE_SHIFT) + + /* Note: All PTEs for the 1MB superpage must be filled with the + * superpage bit set. +@@ -88,7 +89,7 @@ void v3d_mmu_insert_ptes(struct v3d_bo * + { + struct drm_gem_shmem_object *shmem_obj = &bo->base; + struct v3d_dev *v3d = to_v3d_dev(shmem_obj->base.dev); +- u32 page = bo->node.start; ++ u32 page = bo->node.start * V3D_PAGE_FACTOR; + u32 page_prot = V3D_PTE_WRITEABLE | V3D_PTE_VALID; + struct sg_dma_page_iter dma_iter; + +@@ -98,13 +99,13 @@ void v3d_mmu_insert_ptes(struct v3d_bo * + u32 pte = page_prot | page_address; + u32 i; + +- BUG_ON(page_address + (PAGE_SIZE >> V3D_MMU_PAGE_SHIFT) >= ++ BUG_ON(page_address + V3D_PAGE_FACTOR >= + BIT(24)); +- for (i = 0; i < PAGE_SIZE >> V3D_MMU_PAGE_SHIFT; i++) ++ for (i = 0; i < V3D_PAGE_FACTOR; i++) + v3d->pt[page++] = pte + i; + } + +- WARN_ON_ONCE(page - bo->node.start != ++ WARN_ON_ONCE(page - (bo->node.start * V3D_PAGE_FACTOR) != + shmem_obj->base.size >> V3D_MMU_PAGE_SHIFT); + + if (v3d_mmu_flush_all(v3d)) +@@ -115,10 +116,10 @@ void v3d_mmu_remove_ptes(struct v3d_bo * + { + struct v3d_dev *v3d = to_v3d_dev(bo->base.base.dev); + u32 npages = bo->base.base.size >> V3D_MMU_PAGE_SHIFT; +- u32 page; ++ u32 page = bo->node.start * V3D_PAGE_FACTOR; + +- for (page = bo->node.start; page < bo->node.start + npages; page++) +- v3d->pt[page] = 0; ++ while (npages--) ++ v3d->pt[page++] = 0; + + if (v3d_mmu_flush_all(v3d)) + dev_err(v3d->drm.dev, "MMU flush timeout\n"); diff --git a/target/linux/bcm27xx/patches-6.1/950-0906-dt-bindings-gpu-v3d-Add-BCM2712-to-compatibility-lis.patch b/target/linux/bcm27xx/patches-6.1/950-0906-dt-bindings-gpu-v3d-Add-BCM2712-to-compatibility-lis.patch new file mode 100644 index 0000000000..43c5c395c9 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0906-dt-bindings-gpu-v3d-Add-BCM2712-to-compatibility-lis.patch @@ -0,0 +1,19 @@ +From 5970fa51663511d7f773db7109ff6fa2504f186a Mon Sep 17 00:00:00 2001 +From: Iago Toral Quiroga +Date: Thu, 2 Mar 2023 11:56:52 +0100 +Subject: [PATCH] dt-bindings: gpu: v3d: Add BCM2712 to compatibility list + +--- + Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml ++++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml +@@ -16,6 +16,7 @@ properties: + + compatible: + enum: ++ - brcm,2712-v3d + - brcm,2711-v3d + - brcm,7268-v3d + - brcm,7278-v3d diff --git a/target/linux/bcm27xx/patches-6.1/950-0907-drivers-char-add-generic-gpiomem-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0907-drivers-char-add-generic-gpiomem-driver.patch new file mode 100644 index 0000000000..14e6b0a9e4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0907-drivers-char-add-generic-gpiomem-driver.patch @@ -0,0 +1,328 @@ +From fdf9cab5eaa849e90b12e17718bc47130a91433c Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 25 Apr 2023 15:52:13 +0100 +Subject: [PATCH] drivers: char: add generic gpiomem driver + +Based on bcm2835-gpiomem. + +We allow export of the "GPIO registers" to userspace via a chardev as +this allows for finer access control (e.g. users must be group gpio, root +not required). + +This driver allows access to either rp1-gpiomem or gpiomem, depending on +which nodes are populated in devicetree. + +RP1 has a different look-and-feel to BCM283x SoCs as it has split ranges +for IO controls and the parallel registered OE/IN/OUT access. To handle +this, the driver concatenates the ranges for an IO bank and the +corresponding RIO instance into a contiguous buffer. + +Signed-off-by: Jonathan Bell +--- + drivers/char/Kconfig | 8 + + drivers/char/Makefile | 1 + + drivers/char/raspberrypi-gpiomem.c | 276 +++++++++++++++++++++++++++++ + 3 files changed, 285 insertions(+) + create mode 100644 drivers/char/raspberrypi-gpiomem.c + +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -461,4 +461,12 @@ config RANDOM_TRUST_BOOTLOADER + believe its RNG facilities may be faulty. This may also be configured + at boot time with "random.trust_bootloader=on/off". + ++config RASPBERRYPI_GPIOMEM ++ tristate "Rootless GPIO access via mmap() on Raspberry Pi boards" ++ default n ++ help ++ Provides users with root-free access to the GPIO registers ++ on the board. Calling mmap(/dev/gpiomem) will map the GPIO ++ register page to the user's pointer. ++ + endmenu +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -46,3 +46,4 @@ obj-$(CONFIG_XILLYBUS_CLASS) += xillybus + obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o + obj-$(CONFIG_ADI) += adi.o + obj-$(CONFIG_BRCM_CHAR_DRIVERS) += broadcom/ ++obj-$(CONFIG_RASPBERRYPI_GPIOMEM) += raspberrypi-gpiomem.o +--- /dev/null ++++ b/drivers/char/raspberrypi-gpiomem.c +@@ -0,0 +1,276 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/** ++ * raspberrypi-gpiomem.c ++ * ++ * Provides MMIO access to discontiguous section of Device memory as a linear ++ * user mapping. Successor to bcm2835-gpiomem.c. ++ * ++ * Copyright (c) 2023, Raspberry Pi Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_NAME "rpi-gpiomem" ++#define DEVICE_MINOR 0 ++ ++/* ++ * Sensible max for a hypothetical "gpio" controller that splits pads, ++ * IO controls, GPIO in/out/enable, and function selection into different ++ * ranges. Most use only one or two. ++ */ ++#define MAX_RANGES 4 ++ ++struct io_windows { ++ unsigned long phys_base; ++ unsigned long len; ++}; ++ ++struct rpi_gpiomem_priv { ++ dev_t devid; ++ struct class *class; ++ struct cdev rpi_gpiomem_cdev; ++ struct device *dev; ++ const char *name; ++ unsigned int nr_wins; ++ struct io_windows iowins[4]; ++}; ++ ++static int rpi_gpiomem_open(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ struct rpi_gpiomem_priv *priv; ++ ++ if (dev != DEVICE_MINOR) ++ ret = -ENXIO; ++ ++ priv = container_of(inode->i_cdev, struct rpi_gpiomem_priv, ++ rpi_gpiomem_cdev); ++ if (!priv) ++ return -EINVAL; ++ file->private_data = priv; ++ return ret; ++} ++ ++static int rpi_gpiomem_release(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ ++ if (dev != DEVICE_MINOR) ++ ret = -ENXIO; ++ ++ return ret; ++} ++ ++static const struct vm_operations_struct rpi_gpiomem_vm_ops = { ++#ifdef CONFIG_HAVE_IOREMAP_PROT ++ .access = generic_access_phys ++#endif ++}; ++ ++static int rpi_gpiomem_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int i; ++ struct rpi_gpiomem_priv *priv; ++ unsigned long base; ++ unsigned long len = 0; ++ unsigned long offset; ++ ++ priv = file->private_data; ++ /* ++ * Userspace must provide a virtual address space at least ++ * the size of the concatenated ranges. ++ */ ++ for (i = 0; i < priv->nr_wins; i++) ++ len += priv->iowins[i].len; ++ if (len > vma->vm_end - vma->vm_start + 1) ++ return -EINVAL; ++ ++ vma->vm_ops = &rpi_gpiomem_vm_ops; ++ offset = vma->vm_start; ++ for (i = 0; i < priv->nr_wins; i++) { ++ base = priv->iowins[i].phys_base >> PAGE_SHIFT; ++ len = priv->iowins[i].len; ++ vma->vm_page_prot = phys_mem_access_prot(file, base, len, ++ vma->vm_page_prot); ++ if (remap_pfn_range(vma, offset, ++ base, len, ++ vma->vm_page_prot)) ++ break; ++ offset += len; ++ } ++ ++ if (i < priv->nr_wins) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static const struct file_operations rpi_gpiomem_fops = { ++ .owner = THIS_MODULE, ++ .open = rpi_gpiomem_open, ++ .release = rpi_gpiomem_release, ++ .mmap = rpi_gpiomem_mmap, ++}; ++ ++static const struct of_device_id rpi_gpiomem_of_match[]; ++ ++static int rpi_gpiomem_probe(struct platform_device *pdev) ++{ ++ int err, i; ++ const struct of_device_id *id; ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct resource *ioresource; ++ struct rpi_gpiomem_priv *priv; ++ ++ /* Allocate buffers and instance data */ ++ ++ priv = kzalloc(sizeof(struct rpi_gpiomem_priv), GFP_KERNEL); ++ ++ if (!priv) { ++ err = -ENOMEM; ++ goto failed_inst_alloc; ++ } ++ platform_set_drvdata(pdev, priv); ++ ++ priv->dev = dev; ++ id = of_match_device(rpi_gpiomem_of_match, dev); ++ if (!id) ++ return -EINVAL; ++ ++ /* ++ * Device node naming - for legacy (bcm2835) DT bindings, the driver ++ * created the node based on a hardcoded name - for new bindings, ++ * take the node name from DT. ++ */ ++ if (id == &rpi_gpiomem_of_match[0]) { ++ priv->name = "gpiomem"; ++ } else { ++ err = of_property_read_string(node, "chardev-name", &priv->name); ++ if (err) ++ return -EINVAL; ++ } ++ ++ /* ++ * Go find the register ranges associated with this instance ++ */ ++ for (i = 0; i < MAX_RANGES; i++) { ++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ if (!ioresource && i == 0) { ++ dev_err(priv->dev, "failed to get IO resource - no ranges available\n"); ++ err = -ENOENT; ++ goto failed_get_resource; ++ } ++ if (!ioresource) ++ break; ++ ++ priv->iowins[i].phys_base = ioresource->start; ++ priv->iowins[i].len = (ioresource->end + 1) - ioresource->start; ++ dev_info(&pdev->dev, "window base 0x%08lx size 0x%08lx\n", ++ priv->iowins[i].phys_base, priv->iowins[i].len); ++ priv->nr_wins++; ++ } ++ ++ /* Create character device entries */ ++ ++ err = alloc_chrdev_region(&priv->devid, ++ DEVICE_MINOR, 1, priv->name); ++ if (err != 0) { ++ dev_err(priv->dev, "unable to allocate device number"); ++ goto failed_alloc_chrdev; ++ } ++ cdev_init(&priv->rpi_gpiomem_cdev, &rpi_gpiomem_fops); ++ priv->rpi_gpiomem_cdev.owner = THIS_MODULE; ++ err = cdev_add(&priv->rpi_gpiomem_cdev, priv->devid, 1); ++ if (err != 0) { ++ dev_err(priv->dev, "unable to register device"); ++ goto failed_cdev_add; ++ } ++ ++ /* Create sysfs entries */ ++ ++ priv->class = class_create(THIS_MODULE, priv->name); ++ if (IS_ERR(priv->class)) { ++ err = PTR_ERR(priv->class); ++ goto failed_class_create; ++ } ++ ++ dev = device_create(priv->class, NULL, priv->devid, NULL, priv->name); ++ if (IS_ERR(dev)) { ++ err = PTR_ERR(dev); ++ goto failed_device_create; ++ } ++ ++ dev_info(priv->dev, "initialised %u regions as /dev/%s\n", ++ priv->nr_wins, priv->name); ++ ++ return 0; ++ ++failed_device_create: ++ class_destroy(priv->class); ++failed_class_create: ++ cdev_del(&priv->rpi_gpiomem_cdev); ++failed_cdev_add: ++ unregister_chrdev_region(priv->devid, 1); ++failed_alloc_chrdev: ++failed_get_resource: ++ kfree(priv); ++failed_inst_alloc: ++ dev_err(&pdev->dev, "could not load rpi_gpiomem"); ++ return err; ++} ++ ++static int rpi_gpiomem_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rpi_gpiomem_priv *priv = platform_get_drvdata(pdev); ++ ++ device_destroy(priv->class, priv->devid); ++ class_destroy(priv->class); ++ cdev_del(&priv->rpi_gpiomem_cdev); ++ unregister_chrdev_region(priv->devid, 1); ++ kfree(priv); ++ ++ dev_info(dev, "%s driver removed - OK", priv->name); ++ return 0; ++} ++ ++static const struct of_device_id rpi_gpiomem_of_match[] = { ++ { ++ .compatible = "brcm,bcm2835-gpiomem", ++ }, ++ { ++ .compatible = "raspberrypi,gpiomem", ++ }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rpi_gpiomem_of_match); ++ ++static struct platform_driver rpi_gpiomem_driver = { ++ .probe = rpi_gpiomem_probe, ++ .remove = rpi_gpiomem_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rpi_gpiomem_of_match, ++ }, ++}; ++ ++module_platform_driver(rpi_gpiomem_driver); ++ ++MODULE_ALIAS("platform:rpi-gpiomem"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("Driver for accessing GPIOs from userspace"); ++MODULE_AUTHOR("Jonathan Bell "); diff --git a/target/linux/bcm27xx/patches-6.1/950-0909-drivers-char-delete-bcm2835-gpiomem.patch b/target/linux/bcm27xx/patches-6.1/950-0909-drivers-char-delete-bcm2835-gpiomem.patch new file mode 100644 index 0000000000..5d6eb16fb2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0909-drivers-char-delete-bcm2835-gpiomem.patch @@ -0,0 +1,301 @@ +From 27bda80061b46e18fe83be11228df5365363b377 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 26 Apr 2023 13:44:15 +0100 +Subject: [PATCH] drivers: char: delete bcm2835-gpiomem + +This functionality is now provided by raspberrypi-gpiomem. + +Signed-off-by: Jonathan Bell +--- + drivers/char/broadcom/Kconfig | 8 - + drivers/char/broadcom/Makefile | 1 - + drivers/char/broadcom/bcm2835-gpiomem.c | 258 ------------------------ + 3 files changed, 267 deletions(-) + delete mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c + +--- a/drivers/char/broadcom/Kconfig ++++ b/drivers/char/broadcom/Kconfig +@@ -23,14 +23,6 @@ config BCM_VCIO + + endif + +-config BCM2835_DEVGPIOMEM +- tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835" +- default m +- help +- Provides users with root-free access to the GPIO registers +- on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO +- register page to the user's pointer. +- + config BCM2835_SMI_DEV + tristate "Character device driver for BCM2835 Secondary Memory Interface" + depends on BCM2835_SMI +--- a/drivers/char/broadcom/Makefile ++++ b/drivers/char/broadcom/Makefile +@@ -1,5 +1,4 @@ + obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o + obj-$(CONFIG_BCM_VCIO) += vcio.o +-obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o + obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o + obj-$(CONFIG_RPIVID_MEM) += rpivid-mem.o +--- a/drivers/char/broadcom/bcm2835-gpiomem.c ++++ /dev/null +@@ -1,258 +0,0 @@ +-/** +- * GPIO memory device driver +- * +- * Creates a chardev /dev/gpiomem which will provide user access to +- * the BCM2835's GPIO registers when it is mmap()'d. +- * No longer need root for user GPIO access, but without relaxing permissions +- * on /dev/mem. +- * +- * Written by Luke Wren +- * Copyright (c) 2015, Raspberry Pi (Trading) Ltd. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions, and the following disclaimer, +- * without modification. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 3. The names of the above-listed copyright holders may not be used +- * to endorse or promote products derived from this software without +- * specific prior written permission. +- * +- * ALTERNATIVELY, this software may be distributed under the terms of the +- * GNU General Public License ("GPL") version 2, as published by the Free +- * Software Foundation. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define DEVICE_NAME "bcm2835-gpiomem" +-#define DRIVER_NAME "gpiomem-bcm2835" +-#define DEVICE_MINOR 0 +- +-struct bcm2835_gpiomem_instance { +- unsigned long gpio_regs_phys; +- struct device *dev; +-}; +- +-static struct cdev bcm2835_gpiomem_cdev; +-static dev_t bcm2835_gpiomem_devid; +-static struct class *bcm2835_gpiomem_class; +-static struct device *bcm2835_gpiomem_dev; +-static struct bcm2835_gpiomem_instance *inst; +- +- +-/**************************************************************************** +-* +-* GPIO mem chardev file ops +-* +-***************************************************************************/ +- +-static int bcm2835_gpiomem_open(struct inode *inode, struct file *file) +-{ +- int dev = iminor(inode); +- int ret = 0; +- +- if (dev != DEVICE_MINOR) { +- dev_err(inst->dev, "Unknown minor device: %d", dev); +- ret = -ENXIO; +- } +- return ret; +-} +- +-static int bcm2835_gpiomem_release(struct inode *inode, struct file *file) +-{ +- int dev = iminor(inode); +- int ret = 0; +- +- if (dev != DEVICE_MINOR) { +- dev_err(inst->dev, "Unknown minor device %d", dev); +- ret = -ENXIO; +- } +- return ret; +-} +- +-static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = { +-#ifdef CONFIG_HAVE_IOREMAP_PROT +- .access = generic_access_phys +-#endif +-}; +- +-static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma) +-{ +- /* Ignore what the user says - they're getting the GPIO regs +- whether they like it or not! */ +- unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT; +- +- vma->vm_page_prot = phys_mem_access_prot(file, gpio_page, +- PAGE_SIZE, +- vma->vm_page_prot); +- vma->vm_ops = &bcm2835_gpiomem_vm_ops; +- if (remap_pfn_range(vma, vma->vm_start, +- gpio_page, +- PAGE_SIZE, +- vma->vm_page_prot)) { +- return -EAGAIN; +- } +- return 0; +-} +- +-static const struct file_operations +-bcm2835_gpiomem_fops = { +- .owner = THIS_MODULE, +- .open = bcm2835_gpiomem_open, +- .release = bcm2835_gpiomem_release, +- .mmap = bcm2835_gpiomem_mmap, +-}; +- +- +- /**************************************************************************** +-* +-* Probe and remove functions +-* +-***************************************************************************/ +- +- +-static int bcm2835_gpiomem_probe(struct platform_device *pdev) +-{ +- int err; +- void *ptr_err; +- struct device *dev = &pdev->dev; +- struct resource *ioresource; +- +- /* Allocate buffers and instance data */ +- +- inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL); +- +- if (!inst) { +- err = -ENOMEM; +- goto failed_inst_alloc; +- } +- +- inst->dev = dev; +- +- ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (ioresource) { +- inst->gpio_regs_phys = ioresource->start; +- } else { +- dev_err(inst->dev, "failed to get IO resource"); +- err = -ENOENT; +- goto failed_get_resource; +- } +- +- /* Create character device entries */ +- +- err = alloc_chrdev_region(&bcm2835_gpiomem_devid, +- DEVICE_MINOR, 1, DEVICE_NAME); +- if (err != 0) { +- dev_err(inst->dev, "unable to allocate device number"); +- goto failed_alloc_chrdev; +- } +- cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops); +- bcm2835_gpiomem_cdev.owner = THIS_MODULE; +- err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1); +- if (err != 0) { +- dev_err(inst->dev, "unable to register device"); +- goto failed_cdev_add; +- } +- +- /* Create sysfs entries */ +- +- bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME); +- ptr_err = bcm2835_gpiomem_class; +- if (IS_ERR(ptr_err)) +- goto failed_class_create; +- +- bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL, +- bcm2835_gpiomem_devid, NULL, +- "gpiomem"); +- ptr_err = bcm2835_gpiomem_dev; +- if (IS_ERR(ptr_err)) +- goto failed_device_create; +- +- dev_info(inst->dev, "Initialised: Registers at 0x%08lx", +- inst->gpio_regs_phys); +- +- return 0; +- +-failed_device_create: +- class_destroy(bcm2835_gpiomem_class); +-failed_class_create: +- cdev_del(&bcm2835_gpiomem_cdev); +- err = PTR_ERR(ptr_err); +-failed_cdev_add: +- unregister_chrdev_region(bcm2835_gpiomem_devid, 1); +-failed_alloc_chrdev: +-failed_get_resource: +- kfree(inst); +-failed_inst_alloc: +- dev_err(inst->dev, "could not load bcm2835_gpiomem"); +- return err; +-} +- +-static int bcm2835_gpiomem_remove(struct platform_device *pdev) +-{ +- struct device *dev = inst->dev; +- +- kfree(inst); +- device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid); +- class_destroy(bcm2835_gpiomem_class); +- cdev_del(&bcm2835_gpiomem_cdev); +- unregister_chrdev_region(bcm2835_gpiomem_devid, 1); +- +- dev_info(dev, "GPIO mem driver removed - OK"); +- return 0; +-} +- +- /**************************************************************************** +-* +-* Register the driver with device tree +-* +-***************************************************************************/ +- +-static const struct of_device_id bcm2835_gpiomem_of_match[] = { +- {.compatible = "brcm,bcm2835-gpiomem",}, +- { /* sentinel */ }, +-}; +- +-MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match); +- +-static struct platform_driver bcm2835_gpiomem_driver = { +- .probe = bcm2835_gpiomem_probe, +- .remove = bcm2835_gpiomem_remove, +- .driver = { +- .name = DRIVER_NAME, +- .owner = THIS_MODULE, +- .of_match_table = bcm2835_gpiomem_of_match, +- }, +-}; +- +-module_platform_driver(bcm2835_gpiomem_driver); +- +-MODULE_ALIAS("platform:gpiomem-bcm2835"); +-MODULE_LICENSE("GPL"); +-MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); +-MODULE_AUTHOR("Luke Wren "); diff --git a/target/linux/bcm27xx/patches-6.1/950-0910-drivers-hwmon-rp1-adc-check-conversion-validity-befo.patch b/target/linux/bcm27xx/patches-6.1/950-0910-drivers-hwmon-rp1-adc-check-conversion-validity-befo.patch new file mode 100644 index 0000000000..557b7ac406 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0910-drivers-hwmon-rp1-adc-check-conversion-validity-befo.patch @@ -0,0 +1,34 @@ +From 3cafcfbab9b5f3f1357b415b6ca09911eeb405d6 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Thu, 4 May 2023 15:48:53 +0100 +Subject: [PATCH] drivers: hwmon: rp1-adc: check conversion validity before + supplying value + +The SAR ADC architecture may complete a conversion but instability in the +comparator can corrupt the result. Such corruption is signalled in the CS +ERR bit, asserted alongside each conversion result. + +Signed-off-by: Jonathan Bell +--- + drivers/hwmon/rp1-adc.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/hwmon/rp1-adc.c ++++ b/drivers/hwmon/rp1-adc.c +@@ -97,8 +97,14 @@ static int rp1_adc_read(struct rp1_adc_d + data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS); + + ret = rp1_adc_ready_wait(data); +- if (!ret) +- *val = readl(data->base + RP1_ADC_RESULT); ++ if (ret) ++ return ret; ++ ++ /* Asserted if the completed conversion had a convergence error */ ++ if (readl(data->base + RP1_ADC_CS) & RP1_ADC_CS_ERR) ++ return -EIO; ++ ++ *val = readl(data->base + RP1_ADC_RESULT); + + spin_unlock(&data->lock); + diff --git a/target/linux/bcm27xx/patches-6.1/950-0911-dmaengine-bcm2835-Add-BCM2712-support.patch b/target/linux/bcm27xx/patches-6.1/950-0911-dmaengine-bcm2835-Add-BCM2712-support.patch new file mode 100644 index 0000000000..58095cf8fd --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0911-dmaengine-bcm2835-Add-BCM2712-support.patch @@ -0,0 +1,36 @@ +From 87c5545f9a66984894384da5f8c2eeb60983732a Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 8 Mar 2023 16:53:38 +0000 +Subject: [PATCH] dmaengine: bcm2835: Add BCM2712 support + +BCM2712 has 6 40-bit channels - DMA6 to DMA11. Add a new compatible +string to indicate that the current platform is BCM2712. + +Signed-off-by: Phil Elwell +--- + drivers/dma/bcm2835-dma.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/dma/bcm2835-dma.c ++++ b/drivers/dma/bcm2835-dma.c +@@ -331,6 +331,12 @@ static const struct bcm2835_dma_cfg_data + .dma_mask = DMA_BIT_MASK(36), + }; + ++static const struct bcm2835_dma_cfg_data bcm2712_dma_cfg = { ++ .chan_40bit_mask = BIT(6) | BIT(7) | BIT(8) | BIT(9) | ++ BIT(10) | BIT(11), ++ .dma_mask = DMA_BIT_MASK(40), ++}; ++ + static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c) + { + /* lite and normal channels have different max frame length */ +@@ -1260,6 +1266,7 @@ EXPORT_SYMBOL(bcm2711_dma40_memcpy); + static const struct of_device_id bcm2835_dma_of_match[] = { + { .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg }, + { .compatible = "brcm,bcm2711-dma", .data = &bcm2711_dma_cfg }, ++ { .compatible = "brcm,bcm2712-dma", .data = &bcm2712_dma_cfg }, + {}, + }; + MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match); diff --git a/target/linux/bcm27xx/patches-6.1/950-0912-dmaengine-bcm2835-HACK-Support-DMA-Lite-channels.patch b/target/linux/bcm27xx/patches-6.1/950-0912-dmaengine-bcm2835-HACK-Support-DMA-Lite-channels.patch new file mode 100644 index 0000000000..6f651a65f6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0912-dmaengine-bcm2835-HACK-Support-DMA-Lite-channels.patch @@ -0,0 +1,57 @@ +From a671a2774cb3bcfb144622149757f6821aa0604c Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Apr 2023 16:52:19 +0200 +Subject: [PATCH] dmaengine: bcm2835: HACK: Support DMA-Lite channels + +The BCM2712 has a DMA-Lite controller that is basically a BCM2835-style +DMA controller that supports 40 bits DMA addresses. + +We need it for HDMI audio to work, but this breaks BCM2835-38 so we +should rework this later. + +Signed-off-by: Maxime Ripard +--- + drivers/dma/bcm2835-dma.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/dma/bcm2835-dma.c ++++ b/drivers/dma/bcm2835-dma.c +@@ -550,7 +550,7 @@ static struct bcm2835_desc *bcm2835_dma_ + control_block->info = info; + control_block->src = src; + control_block->dst = dst; +- control_block->stride = 0; ++ control_block->stride = (upper_32_bits(dst) << 8) | upper_32_bits(src); + control_block->next = 0; + } + +@@ -575,7 +575,7 @@ static struct bcm2835_desc *bcm2835_dma_ + d->cb_list[frame - 1].cb)->next_cb = + to_bcm2711_cbaddr(cb_entry->paddr); + if (frame && !c->is_40bit_channel) +- d->cb_list[frame - 1].cb->next = cb_entry->paddr; ++ d->cb_list[frame - 1].cb->next = to_bcm2711_cbaddr(cb_entry->paddr); + + /* update src and dst and length */ + if (src && (info & BCM2835_DMA_S_INC)) { +@@ -760,7 +760,10 @@ static void bcm2835_dma_start_desc(struc + writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT | BCM2711_DMA40_CS_FLAGS(c->dreq), + c->chan_base + BCM2711_DMA40_CS); + } else { +- writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR); ++ writel(BIT(31), c->chan_base + BCM2835_DMA_CS); ++ ++ writel(to_bcm2711_cbaddr(d->cb_list[0].paddr), ++ c->chan_base + BCM2835_DMA_ADDR); + writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq), + c->chan_base + BCM2835_DMA_CS); + } +@@ -1129,7 +1132,7 @@ static struct dma_async_tx_descriptor *b + d->cb_list[frames - 1].cb)->next_cb = + to_bcm2711_cbaddr(d->cb_list[0].paddr); + else +- d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr; ++ d->cb_list[d->frames - 1].cb->next = to_bcm2711_cbaddr(d->cb_list[0].paddr); + + return vchan_tx_prep(&c->vc, &d->vd, flags); + } diff --git a/target/linux/bcm27xx/patches-6.1/950-0913-clk-bcm-rpi-Add-disp-clock.patch b/target/linux/bcm27xx/patches-6.1/950-0913-clk-bcm-rpi-Add-disp-clock.patch new file mode 100644 index 0000000000..6f5e55d956 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0913-clk-bcm-rpi-Add-disp-clock.patch @@ -0,0 +1,46 @@ +From c8fd69c6f567bd43ba084b95a987532940465ef5 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 24 Feb 2023 14:12:50 +0100 +Subject: [PATCH] clk: bcm: rpi: Add disp clock + +BCM2712 has an extra clock exposed by the firmware called DISP, and used +by (at least) the HVS. Let's add it to the list of clocks to register in +Linux. + +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 5 +++++ + include/soc/bcm2835/raspberrypi-firmware.h | 1 + + 2 files changed, 6 insertions(+) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -34,6 +34,7 @@ static char *rpi_firmware_clk_names[] = + [RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc", + [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb", + [RPI_FIRMWARE_VEC_CLK_ID] = "vec", ++ [RPI_FIRMWARE_DISP_CLK_ID] = "disp", + }; + + #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) +@@ -139,6 +140,10 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NU + .export = true, + .minimize = true, + }, ++ [RPI_FIRMWARE_DISP_CLK_ID] = { ++ .export = true, ++ .minimize = true, ++ }, + }; + + /* +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -176,6 +176,7 @@ enum rpi_firmware_clk_id { + RPI_FIRMWARE_M2MC_CLK_ID, + RPI_FIRMWARE_PIXEL_BVB_CLK_ID, + RPI_FIRMWARE_VEC_CLK_ID, ++ RPI_FIRMWARE_DISP_CLK_ID, + RPI_FIRMWARE_NUM_CLK_ID, + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-0914-net-phy-broadcom-optionally-enable-link-down-powersa.patch b/target/linux/bcm27xx/patches-6.1/950-0914-net-phy-broadcom-optionally-enable-link-down-powersa.patch new file mode 100644 index 0000000000..2df48297b5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0914-net-phy-broadcom-optionally-enable-link-down-powersa.patch @@ -0,0 +1,26 @@ +From 6370a6cd16a5aa9726bf209c0f0a3179f4011cb1 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Mon, 22 May 2023 15:31:17 +0100 +Subject: [PATCH] net: phy: broadcom: optionally enable link-down powersave + based on DT + +It's really a function of the board whether or not to use this feature +as it may require MAC compatibility as well as interop testing. + +Signed-off-by: Jonathan Bell +--- + drivers/net/phy/broadcom.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/phy/broadcom.c ++++ b/drivers/net/phy/broadcom.c +@@ -370,6 +370,9 @@ static int bcm54xx_config_init(struct ph + (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) + bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0); + ++ if (of_property_read_bool(np, "brcm,powerdown-enable")) ++ phydev->dev_flags |= PHY_BRCM_AUTO_PWRDWN_ENABLE; ++ + bcm54xx_adjust_rxrefclk(phydev); + + switch (BRCM_PHY_MODEL(phydev)) { diff --git a/target/linux/bcm27xx/patches-6.1/950-0915-dmaengine-bcm2835-Rename-to_bcm2711_cbaddr-to-to_40b.patch b/target/linux/bcm27xx/patches-6.1/950-0915-dmaengine-bcm2835-Rename-to_bcm2711_cbaddr-to-to_40b.patch new file mode 100644 index 0000000000..ce59f6072b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0915-dmaengine-bcm2835-Rename-to_bcm2711_cbaddr-to-to_40b.patch @@ -0,0 +1,75 @@ +From cfad3f71fc450639fc259d576d0903e9132fe34a Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Thu, 25 May 2023 14:48:28 +0100 +Subject: [PATCH] dmaengine: bcm2835: Rename to_bcm2711_cbaddr to + to_40bit_cbaddr + +As the shifted address also applies to bcm2712, +give the function a more specific name. + +Signed-off-by: Dom Cobley +--- + drivers/dma/bcm2835-dma.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/dma/bcm2835-dma.c ++++ b/drivers/dma/bcm2835-dma.c +@@ -390,7 +390,7 @@ static inline uint32_t to_bcm2711_dsti(u + BCM2711_DMA40_BURST_LEN(BCM2835_DMA_GET_BURST_LENGTH(info)); + } + +-static inline uint32_t to_bcm2711_cbaddr(dma_addr_t addr) ++static inline uint32_t to_40bit_cbaddr(dma_addr_t addr) + { + BUG_ON(addr & 0x1f); + return (addr >> 5); +@@ -573,9 +573,9 @@ static struct bcm2835_desc *bcm2835_dma_ + if (frame && c->is_40bit_channel) + ((struct bcm2711_dma40_scb *) + d->cb_list[frame - 1].cb)->next_cb = +- to_bcm2711_cbaddr(cb_entry->paddr); ++ to_40bit_cbaddr(cb_entry->paddr); + if (frame && !c->is_40bit_channel) +- d->cb_list[frame - 1].cb->next = to_bcm2711_cbaddr(cb_entry->paddr); ++ d->cb_list[frame - 1].cb->next = to_40bit_cbaddr(cb_entry->paddr); + + /* update src and dst and length */ + if (src && (info & BCM2835_DMA_S_INC)) { +@@ -755,14 +755,14 @@ static void bcm2835_dma_start_desc(struc + c->desc = d = to_bcm2835_dma_desc(&vd->tx); + + if (c->is_40bit_channel) { +- writel(to_bcm2711_cbaddr(d->cb_list[0].paddr), ++ writel(to_40bit_cbaddr(d->cb_list[0].paddr), + c->chan_base + BCM2711_DMA40_CB); + writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT | BCM2711_DMA40_CS_FLAGS(c->dreq), + c->chan_base + BCM2711_DMA40_CS); + } else { + writel(BIT(31), c->chan_base + BCM2835_DMA_CS); + +- writel(to_bcm2711_cbaddr(d->cb_list[0].paddr), ++ writel(to_40bit_cbaddr(d->cb_list[0].paddr), + c->chan_base + BCM2835_DMA_ADDR); + writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq), + c->chan_base + BCM2835_DMA_CS); +@@ -1130,9 +1130,9 @@ static struct dma_async_tx_descriptor *b + if (c->is_40bit_channel) + ((struct bcm2711_dma40_scb *) + d->cb_list[frames - 1].cb)->next_cb = +- to_bcm2711_cbaddr(d->cb_list[0].paddr); ++ to_40bit_cbaddr(d->cb_list[0].paddr); + else +- d->cb_list[d->frames - 1].cb->next = to_bcm2711_cbaddr(d->cb_list[0].paddr); ++ d->cb_list[d->frames - 1].cb->next = to_40bit_cbaddr(d->cb_list[0].paddr); + + return vchan_tx_prep(&c->vc, &d->vd, flags); + } +@@ -1252,7 +1252,7 @@ void bcm2711_dma40_memcpy(dma_addr_t dst + scb->len = size; + scb->next_cb = 0; + +- writel(to_bcm2711_cbaddr(memcpy_scb_dma), memcpy_chan + BCM2711_DMA40_CB); ++ writel(to_40bit_cbaddr(memcpy_scb_dma), memcpy_chan + BCM2711_DMA40_CB); + writel(BCM2711_DMA40_MEMCPY_FLAGS | BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT, + memcpy_chan + BCM2711_DMA40_CS); + diff --git a/target/linux/bcm27xx/patches-6.1/950-0916-dmaengine-bcm2835-Fix-dma-driver-for-BCM2835-38.patch b/target/linux/bcm27xx/patches-6.1/950-0916-dmaengine-bcm2835-Fix-dma-driver-for-BCM2835-38.patch new file mode 100644 index 0000000000..a2ff2a6bb0 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0916-dmaengine-bcm2835-Fix-dma-driver-for-BCM2835-38.patch @@ -0,0 +1,77 @@ +From 75f44d1416c5de17865247d6d012c37f7650437c Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Wed, 24 May 2023 19:32:16 +0100 +Subject: [PATCH] dmaengine: bcm2835: Fix dma driver for BCM2835-38 + +The previous commit broke support on older devices. +Make the breaking parts of patch conditional on +the device being used. + +Fixes: 6e1856ac7c39 ("dmaengine: bcm2835: HACK: Support DMA-Lite channels") + +Signed-off-by: Dom Cobley +--- + drivers/dma/bcm2835-dma.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +--- a/drivers/dma/bcm2835-dma.c ++++ b/drivers/dma/bcm2835-dma.c +@@ -102,6 +102,7 @@ struct bcm2835_chan { + + bool is_lite_channel; + bool is_40bit_channel; ++ bool is_2712; + }; + + struct bcm2835_desc { +@@ -550,7 +551,11 @@ static struct bcm2835_desc *bcm2835_dma_ + control_block->info = info; + control_block->src = src; + control_block->dst = dst; +- control_block->stride = (upper_32_bits(dst) << 8) | upper_32_bits(src); ++ if (c->is_2712) ++ control_block->stride = (upper_32_bits(dst) << 8) | ++ upper_32_bits(src); ++ else ++ control_block->stride = 0; + control_block->next = 0; + } + +@@ -575,7 +580,8 @@ static struct bcm2835_desc *bcm2835_dma_ + d->cb_list[frame - 1].cb)->next_cb = + to_40bit_cbaddr(cb_entry->paddr); + if (frame && !c->is_40bit_channel) +- d->cb_list[frame - 1].cb->next = to_40bit_cbaddr(cb_entry->paddr); ++ d->cb_list[frame - 1].cb->next = c->is_2712 ? ++ to_40bit_cbaddr(cb_entry->paddr) : cb_entry->paddr; + + /* update src and dst and length */ + if (src && (info & BCM2835_DMA_S_INC)) { +@@ -762,7 +768,7 @@ static void bcm2835_dma_start_desc(struc + } else { + writel(BIT(31), c->chan_base + BCM2835_DMA_CS); + +- writel(to_40bit_cbaddr(d->cb_list[0].paddr), ++ writel(c->is_2712 ? to_40bit_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr, + c->chan_base + BCM2835_DMA_ADDR); + writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq), + c->chan_base + BCM2835_DMA_CS); +@@ -1132,7 +1138,8 @@ static struct dma_async_tx_descriptor *b + d->cb_list[frames - 1].cb)->next_cb = + to_40bit_cbaddr(d->cb_list[0].paddr); + else +- d->cb_list[d->frames - 1].cb->next = to_40bit_cbaddr(d->cb_list[0].paddr); ++ d->cb_list[d->frames - 1].cb->next = c->is_2712 ? ++ to_40bit_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr; + + return vchan_tx_prep(&c->vc, &d->vd, flags); + } +@@ -1199,6 +1206,8 @@ static int bcm2835_dma_chan_init(struct + else if (readl(c->chan_base + BCM2835_DMA_DEBUG) & + BCM2835_DMA_DEBUG_LITE) + c->is_lite_channel = true; ++ if (d->cfg_data->dma_mask == DMA_BIT_MASK(40)) ++ c->is_2712 = true; + + return 0; + } diff --git a/target/linux/bcm27xx/patches-6.1/950-0917-drivers-iommu-Add-BCM2712-IOMMU.patch b/target/linux/bcm27xx/patches-6.1/950-0917-drivers-iommu-Add-BCM2712-IOMMU.patch new file mode 100644 index 0000000000..92f43fa71b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0917-drivers-iommu-Add-BCM2712-IOMMU.patch @@ -0,0 +1,855 @@ +From 5fd6ee7fd084838e09d4e463ae53cd9aaa7fce70 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Thu, 11 May 2023 16:37:34 +0100 +Subject: [PATCH] drivers: iommu: Add BCM2712 IOMMU + +Add a driver for BCM2712 IOMMUs. +There is a small driver for the Shared IOMMU TLB Cache. +Each IOMMU instance is a separate device. + +IOMMUs are set up with a "pass-through" range covering +the lowest 40BGytes (which should cover all of SDRAM) +for the benefit of non-IOMMU-aware devices that share +a physical IOMMU; and translation for addresses in the +range 40GB to 42GB. + +An optional parameter adds a DMA offset (which otherwise +would be lost?) to virtual addresses for DMA masters on a +bus such as PCIe. + +Signed-off-by: Nick Hollinghurst +--- + drivers/iommu/Kconfig | 7 + + drivers/iommu/Makefile | 1 + + drivers/iommu/bcm2712-iommu-cache.c | 77 ++++ + drivers/iommu/bcm2712-iommu.c | 672 ++++++++++++++++++++++++++++ + drivers/iommu/bcm2712-iommu.h | 45 ++ + 5 files changed, 802 insertions(+) + create mode 100644 drivers/iommu/bcm2712-iommu-cache.c + create mode 100644 drivers/iommu/bcm2712-iommu.c + create mode 100644 drivers/iommu/bcm2712-iommu.h + +--- a/drivers/iommu/Kconfig ++++ b/drivers/iommu/Kconfig +@@ -506,4 +506,11 @@ config SPRD_IOMMU + + Say Y here if you want to use the multimedia devices listed above. + ++config BCM2712_IOMMU ++ tristate "BCM2712 IOMMU driver" ++ depends on ARM64 && ARCH_BCM ++ select IOMMU_API ++ help ++ IOMMU driver for BCM2712 ++ + endif # IOMMU_SUPPORT +--- a/drivers/iommu/Makefile ++++ b/drivers/iommu/Makefile +@@ -31,3 +31,4 @@ obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iom + obj-$(CONFIG_IOMMU_SVA) += iommu-sva-lib.o io-pgfault.o + obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o + obj-$(CONFIG_APPLE_DART) += apple-dart.o ++obj-$(CONFIG_BCM2712_IOMMU) += bcm2712-iommu.o bcm2712-iommu-cache.o +--- /dev/null ++++ b/drivers/iommu/bcm2712-iommu-cache.c +@@ -0,0 +1,77 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * IOMMU driver for BCM2712 ++ * ++ * Copyright (c) 2023 Raspberry Pi Ltd. ++ */ ++ ++#include "bcm2712-iommu.h" ++ ++#include ++#include ++#include ++#include ++ ++#define MMUC_CONTROL_ENABLE 1 ++#define MMUC_CONTROL_FLUSH 2 ++#define MMUC_CONTROL_FLUSHING 4 ++ ++void bcm2712_iommu_cache_flush(struct bcm2712_iommu_cache *cache) ++{ ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&cache->hw_lock, flags); ++ if (cache->reg_base) { ++ /* Enable and flush the TLB cache */ ++ writel(MMUC_CONTROL_ENABLE | MMUC_CONTROL_FLUSH, ++ cache->reg_base); ++ ++ /* Wait for flush to complete: it should be very quick */ ++ for (i = 0; i < 1024; i++) { ++ if (!(MMUC_CONTROL_FLUSHING & readl(cache->reg_base))) ++ break; ++ cpu_relax(); ++ } ++ } ++ spin_unlock_irqrestore(&cache->hw_lock, flags); ++} ++ ++static int bcm2712_iommu_cache_probe(struct platform_device *pdev) ++{ ++ struct bcm2712_iommu_cache *cache; ++ ++ dev_info(&pdev->dev, __func__); ++ cache = devm_kzalloc(&pdev->dev, sizeof(*cache), GFP_KERNEL); ++ if (!cache) ++ return -ENOMEM; ++ ++ cache->dev = &pdev->dev; ++ platform_set_drvdata(pdev, cache); ++ spin_lock_init(&cache->hw_lock); ++ ++ /* Get IOMMUC registers; we only use the first register (IOMMUC_CTRL) */ ++ cache->reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(cache->reg_base)) { ++ dev_err(&pdev->dev, "Failed to get IOMMU Cache registers address\n"); ++ cache->reg_base = NULL; ++ } ++ return 0; ++} ++ ++static const struct of_device_id bcm2712_iommu_cache_of_match[] = { ++ { ++ . compatible = "brcm,bcm2712-iommuc" ++ }, ++ { /* sentinel */ }, ++}; ++ ++static struct platform_driver bcm2712_iommu_cache_driver = { ++ .probe = bcm2712_iommu_cache_probe, ++ .driver = { ++ .name = "bcm2712-iommu-cache", ++ .of_match_table = bcm2712_iommu_cache_of_match ++ }, ++}; ++ ++builtin_platform_driver(bcm2712_iommu_cache_driver); +--- /dev/null ++++ b/drivers/iommu/bcm2712-iommu.c +@@ -0,0 +1,672 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * IOMMU driver for BCM2712 ++ * ++ * Copyright (c) 2023 Raspberry Pi Ltd. ++ */ ++ ++#include "bcm2712-iommu.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MMU_WR(off, val) writel(val, mmu->reg_base + (off)) ++#define MMU_RD(off) readl(mmu->reg_base + (off)) ++ ++#define domain_to_mmu(d) (container_of(d, struct bcm2712_iommu_domain, base)->mmu) ++ ++#define MMMU_CTRL_OFFSET 0x00 ++#define MMMU_CTRL_CAP_EXCEEDED BIT(27) ++#define MMMU_CTRL_CAP_EXCEEDED_ABORT_EN BIT(26) ++#define MMMU_CTRL_CAP_EXCEEDED_INT_EN BIT(25) ++#define MMMU_CTRL_CAP_EXCEEDED_EXCEPTION_EN BIT(24) ++#define MMMU_CTRL_PT_INVALID BIT(20) ++#define MMMU_CTRL_PT_INVALID_ABORT_EN BIT(19) ++#define MMMU_CTRL_PT_INVALID_EXCEPTION_EN BIT(18) ++#define MMMU_CTRL_PT_INVALID_EN BIT(17) ++#define MMMU_CTRL_WRITE_VIOLATION BIT(12) ++#define MMMU_CTRL_WRITE_VIOLATION_ABORT_EN BIT(11) ++#define MMMU_CTRL_WRITE_VIOLATION_INT_EN BIT(10) ++#define MMMU_CTRL_WRITE_VIOLATION_EXCEPTION_EN BIT(9) ++#define MMMU_CTRL_BYPASS BIT(8) ++#define MMMU_CTRL_TLB_CLEARING BIT(7) ++#define MMMU_CTRL_STATS_CLEAR BIT(3) ++#define MMMU_CTRL_TLB_CLEAR BIT(2) ++#define MMMU_CTRL_STATS_ENABLE BIT(1) ++#define MMMU_CTRL_ENABLE BIT(0) ++ ++#define MMMU_PT_PA_BASE_OFFSET 0x04 ++ ++#define MMMU_HIT_OFFSET 0x08 ++#define MMMU_MISS_OFFSET 0x0C ++#define MMMU_STALL_OFFSET 0x10 ++ ++#define MMMU_ADDR_CAP_OFFSET 0x14 ++#define MMMU_ADDR_CAP_ENABLE BIT(31) ++#define ADDR_CAP_SHIFT 28 /* ADDR_CAP is defined to be in 256 MByte units */ ++ ++#define MMMU_SHOOT_DOWN_OFFSET 0x18 ++#define MMMU_SHOOT_DOWN_SHOOTING BIT(31) ++#define MMMU_SHOOT_DOWN_SHOOT BIT(30) ++ ++#define MMMU_BYPASS_START_OFFSET 0x1C ++#define MMMU_BYPASS_START_ENABLE BIT(31) ++#define MMMU_BYPASS_START_INVERT BIT(30) ++ ++#define MMMU_BYPASS_END_OFFSET 0x20 ++#define MMMU_BYPASS_END_ENABLE BIT(31) ++ ++#define MMMU_MISC_OFFSET 0x24 ++#define MMMU_MISC_SINGLE_TABLE BIT(31) ++ ++#define MMMU_ILLEGAL_ADR_OFFSET 0x30 ++#define MMMU_ILLEGAL_ADR_ENABLE BIT(31) ++ ++#define MMMU_DEBUG_INFO_OFFSET 0x38 ++#define MMMU_DEBUG_INFO_VERSION_MASK 0x0000000Fu ++#define MMMU_DEBUG_INFO_VA_WIDTH_MASK 0x000000F0u ++#define MMMU_DEBUG_INFO_PA_WIDTH_MASK 0x00000F00u ++#define MMMU_DEBUG_INFO_BIGPAGE_WIDTH_MASK 0x000FF000u ++#define MMMU_DEBUG_INFO_SUPERPAGE_WIDTH_MASK 0x0FF00000u ++#define MMMU_DEBUG_INFO_BYPASS_4M BIT(28) ++#define MMMU_DEBUG_INFO_BYPASS BIT(29) ++ ++#define MMMU_PTE_PAGESIZE_MASK 0xC0000000u ++#define MMMU_PTE_WRITEABLE BIT(29) ++#define MMMU_PTE_VALID BIT(28) ++ ++/* ++ * BCM2712 IOMMU is organized around 4Kbyte pages (MMU_PAGE_SIZE). ++ * Linux PAGE_SIZE must not be smaller but may be larger (e.g. 4K, 16K). ++ * ++ * Unlike many larger MMUs, this one uses a 4-byte word size, allowing ++ * 1024 entries within each 4K table page, and two-level translation. ++ * ++ * Let's allocate enough table space for 2GB of translated memory (IOVA). ++ * This requires 512 4K pages (2MB) of level-2 tables, one page of ++ * top-level table (only half-filled in this particular configuration), ++ * plus one "default" page to catch illegal requests. ++ * ++ * The translated virtual address region is between 40GB and 42GB; ++ * addresses below this range pass straight through to the SDRAM. ++ * ++ * Currently we assume a 1:1:1 correspondence of IOMMU, group and domain. ++ */ ++ ++#define MMU_PAGE_SHIFT 12 ++#define MMU_PAGE_SIZE BIT(MMU_PAGE_SHIFT) ++ ++#define PAGEWORDS_SHIFT (MMU_PAGE_SHIFT - 2) ++#define HUGEPAGE_SHIFT (MMU_PAGE_SHIFT + PAGEWORDS_SHIFT) ++#define L1_CHUNK_SHIFT (MMU_PAGE_SHIFT + 2 * PAGEWORDS_SHIFT) ++ ++#define APERTURE_BASE (40ul << 30) ++#define APERTURE_SIZE (2ul << 30) ++#define APERTURE_TOP (APERTURE_BASE + APERTURE_SIZE) ++#define TRANSLATED_PAGES (APERTURE_SIZE >> MMU_PAGE_SHIFT) ++#define L2_PAGES (TRANSLATED_PAGES >> PAGEWORDS_SHIFT) ++#define TABLES_ALLOC_SIZE (L2_PAGES * MMU_PAGE_SIZE + 2 * PAGE_SIZE) ++ ++static void bcm2712_iommu_init(struct bcm2712_iommu *mmu) ++{ ++ unsigned int i, bypass_shift; ++ struct sg_dma_page_iter it; ++ u32 u = MMU_RD(MMMU_DEBUG_INFO_OFFSET); ++ ++ /* ++ * Check IOMMU version and hardware configuration. ++ * This driver is for VC IOMMU version >= 4 (with 2-level tables) ++ * and assumes at least 36 bits of virtual and physical address space. ++ * Bigpage and superpage sizes are typically 64K and 1M, but may vary ++ * (hugepage size is fixed at 4M, the range covered by an L2 page). ++ */ ++ dev_info(mmu->dev, "%s: DEBUG_INFO = 0x%08x\n", __func__, u); ++ WARN_ON(FIELD_GET(MMMU_DEBUG_INFO_VERSION_MASK, u) < 4 || ++ FIELD_GET(MMMU_DEBUG_INFO_VA_WIDTH_MASK, u) < 6 || ++ FIELD_GET(MMMU_DEBUG_INFO_PA_WIDTH_MASK, u) < 6 || ++ !(u & MMMU_DEBUG_INFO_BYPASS)); ++ ++ mmu->bigpage_mask = ++ ((1u << FIELD_GET(MMMU_DEBUG_INFO_BIGPAGE_WIDTH_MASK, u)) - 1u) << MMU_PAGE_SHIFT; ++ mmu->superpage_mask = ++ ((1u << FIELD_GET(MMMU_DEBUG_INFO_SUPERPAGE_WIDTH_MASK, u)) - 1u) << MMU_PAGE_SHIFT; ++ bypass_shift = (u & MMMU_DEBUG_INFO_BYPASS_4M) ? ++ HUGEPAGE_SHIFT : ADDR_CAP_SHIFT; ++ ++ /* Disable MMU and clear sticky flags; meanwhile flush the TLB */ ++ MMU_WR(MMMU_CTRL_OFFSET, ++ MMMU_CTRL_CAP_EXCEEDED | ++ MMMU_CTRL_PT_INVALID | ++ MMMU_CTRL_WRITE_VIOLATION | ++ MMMU_CTRL_STATS_CLEAR | ++ MMMU_CTRL_TLB_CLEAR); ++ ++ /* ++ * Put MMU into 2-level mode; set address cap and "bypass" range ++ * (note that some of these registers have unintuitive off-by-ones). ++ * Addresses below APERTURE_BASE are passed unchanged: this is ++ * useful for blocks which share an IOMMU with other blocks ++ * whose drivers are not IOMMU-aware. ++ */ ++ MMU_WR(MMMU_MISC_OFFSET, ++ MMU_RD(MMMU_MISC_OFFSET) & ~MMMU_MISC_SINGLE_TABLE); ++ MMU_WR(MMMU_ADDR_CAP_OFFSET, ++ MMMU_ADDR_CAP_ENABLE + ++ (APERTURE_TOP >> ADDR_CAP_SHIFT) - 1); ++ if (APERTURE_BASE > 0) { ++ MMU_WR(MMMU_BYPASS_START_OFFSET, ++ MMMU_BYPASS_START_ENABLE + MMMU_BYPASS_START_INVERT + ++ (APERTURE_BASE >> bypass_shift) - 1); ++ MMU_WR(MMMU_BYPASS_END_OFFSET, ++ MMMU_BYPASS_END_ENABLE + ++ (APERTURE_TOP >> bypass_shift)); ++ } else { ++ MMU_WR(MMMU_BYPASS_START_OFFSET, 0); ++ MMU_WR(MMMU_BYPASS_END_OFFSET, 0); ++ } ++ ++ /* Ensure tables are zeroed (which marks all pages as invalid) */ ++ dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ memset(mmu->tables, 0, TABLES_ALLOC_SIZE); ++ mmu->nmapped_pages = 0; ++ ++ /* Initialize the high-level table to point to the low-level pages */ ++ __sg_page_iter_start(&it.base, mmu->sgt->sgl, mmu->sgt->nents, 0); ++ for (i = 0; i < L2_PAGES; i++) { ++ if (!(i % (PAGE_SIZE / MMU_PAGE_SIZE))) { ++ __sg_page_iter_dma_next(&it); ++ u = (sg_page_iter_dma_address(&it) >> MMU_PAGE_SHIFT); ++ } else { ++ u++; ++ } ++ mmu->tables[TRANSLATED_PAGES + i] = MMMU_PTE_VALID + u; ++ } ++ ++ /* ++ * Configure the addresses of the top-level table (offset because ++ * the aperture does not start from zero), and of the default page. ++ * For simplicity, both these regions are whole Linux pages. ++ */ ++ __sg_page_iter_dma_next(&it); ++ u = (sg_page_iter_dma_address(&it) >> MMU_PAGE_SHIFT); ++ MMU_WR(MMMU_PT_PA_BASE_OFFSET, u - (APERTURE_BASE >> L1_CHUNK_SHIFT)); ++ __sg_page_iter_dma_next(&it); ++ u = (sg_page_iter_dma_address(&it) >> MMU_PAGE_SHIFT); ++ MMU_WR(MMMU_ILLEGAL_ADR_OFFSET, MMMU_ILLEGAL_ADR_ENABLE + u); ++ dma_sync_sgtable_for_device(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ mmu->dirty = false; ++ ++ /* Flush (and enable) the shared TLB cache; enable this MMU. */ ++ if (mmu->cache) ++ bcm2712_iommu_cache_flush(mmu->cache); ++ MMU_WR(MMMU_CTRL_OFFSET, ++ MMMU_CTRL_CAP_EXCEEDED_ABORT_EN | ++ MMMU_CTRL_PT_INVALID_ABORT_EN | ++ MMMU_CTRL_WRITE_VIOLATION_ABORT_EN | ++ MMMU_CTRL_STATS_ENABLE | ++ MMMU_CTRL_ENABLE); ++} ++ ++static int bcm2712_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) ++{ ++ struct bcm2712_iommu *mmu = dev ? dev_iommu_priv_get(dev) : 0; ++ struct bcm2712_iommu_domain *mydomain = ++ container_of(domain, struct bcm2712_iommu_domain, base); ++ ++ dev_info(dev, "%s: MMU %s\n", ++ __func__, mmu ? dev_name(mmu->dev) : ""); ++ ++ if (mmu) { ++ mydomain->mmu = mmu; ++ mmu->domain = mydomain; ++ ++ if (mmu->dma_iova_offset) { ++ domain->geometry.aperture_start = ++ mmu->dma_iova_offset + APERTURE_BASE; ++ domain->geometry.aperture_end = ++ mmu->dma_iova_offset + APERTURE_TOP - 1ul; ++ } ++ ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static void bcm2712_iommu_detach_dev(struct iommu_domain *domain, struct device *dev) ++{ ++ (void)domain; ++ (void)dev; ++} ++ ++static int bcm2712_iommu_map(struct iommu_domain *domain, unsigned long iova, ++ phys_addr_t pa, size_t bytes, int prot, gfp_t gfp) ++{ ++ struct bcm2712_iommu *mmu = domain_to_mmu(domain); ++ ++ (void)gfp; ++ iova -= mmu->dma_iova_offset; ++ if (iova >= APERTURE_BASE && iova + bytes <= APERTURE_TOP) { ++ unsigned int p; ++ u32 entry = MMMU_PTE_VALID | (pa >> MMU_PAGE_SHIFT); ++ u32 align = (u32)(iova | pa | bytes); ++ ++ /* large page and write enable flags */ ++ if (!(align & ((1 << HUGEPAGE_SHIFT) - 1))) ++ entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 3); ++ else if (!(align & mmu->superpage_mask) && mmu->superpage_mask) ++ entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 2); ++ else if (!(align & mmu->bigpage_mask) && mmu->bigpage_mask) ++ entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 1); ++ if (prot & IOMMU_WRITE) ++ entry |= MMMU_PTE_WRITEABLE; ++ ++ /* Ensure tables are cache-coherent with CPU */ ++ if (!mmu->dirty) { ++ dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ mmu->dirty = true; ++ } ++ ++ iova -= APERTURE_BASE; ++ for (p = iova >> MMU_PAGE_SHIFT; ++ p < (iova + bytes) >> MMU_PAGE_SHIFT; p++) { ++ mmu->nmapped_pages += !(mmu->tables[p]); ++ mmu->tables[p] = entry++; ++ } ++ } else if (iova + bytes > APERTURE_BASE || iova != pa) { ++ dev_warn(mmu->dev, "%s: iova=0x%lx pa=0x%llx size=0x%llx OUT OF RANGE!\n", ++ __func__, iova, ++ (unsigned long long)pa, (unsigned long long)bytes); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static size_t bcm2712_iommu_unmap(struct iommu_domain *domain, unsigned long iova, ++ size_t bytes, struct iommu_iotlb_gather *gather) ++{ ++ struct bcm2712_iommu *mmu = domain_to_mmu(domain); ++ ++ if (iova >= mmu->dma_iova_offset + APERTURE_BASE && ++ iova + bytes <= mmu->dma_iova_offset + APERTURE_TOP) { ++ unsigned int p; ++ ++ /* Record just the lower and upper bounds in "gather" */ ++ if (gather) { ++ bool empty = (gather->end <= gather->start); ++ ++ if (empty || gather->start < iova) ++ gather->start = iova; ++ if (empty || gather->end < iova + bytes) ++ gather->end = iova + bytes; ++ } ++ ++ /* Ensure tables are cache-coherent with CPU */ ++ if (!mmu->dirty) { ++ dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ mmu->dirty = true; ++ } ++ ++ /* Clear table entries, this marks the addresses as illegal */ ++ iova -= (mmu->dma_iova_offset + APERTURE_BASE); ++ for (p = iova >> MMU_PAGE_SHIFT; ++ p < (iova + bytes) >> MMU_PAGE_SHIFT; ++ p++) { ++ mmu->nmapped_pages -= !!(mmu->tables[p]); ++ mmu->tables[p] = 0; ++ } ++ } ++ ++ return bytes; ++} ++ ++static void bcm2712_iommu_sync_range(struct iommu_domain *domain, ++ unsigned long iova, size_t size) ++{ ++ struct bcm2712_iommu *mmu = domain_to_mmu(domain); ++ unsigned long iova_end; ++ unsigned int i, p4; ++ ++ if (!mmu || !mmu->dirty) ++ return; ++ ++ /* Ensure tables are cleaned from CPU cache or write-buffer */ ++ dma_sync_sgtable_for_device(mmu->dev, mmu->sgt, DMA_TO_DEVICE); ++ mmu->dirty = false; ++ ++ /* Flush the shared TLB cache */ ++ if (mmu->cache) ++ bcm2712_iommu_cache_flush(mmu->cache); ++ ++ /* ++ * When flushing a large range or when nothing needs to be kept, ++ * it's quicker to use the"TLB_CLEAR" flag. Otherwise, invalidate ++ * TLB entries in lines of 4 words each. Each flush/clear operation ++ * should complete almost instantaneously. ++ */ ++ iova -= mmu->dma_iova_offset; ++ iova_end = min(APERTURE_TOP, iova + size); ++ iova = max(APERTURE_BASE, iova); ++ if (mmu->nmapped_pages == 0 || iova_end - iova >= APERTURE_SIZE / 8) { ++ MMU_WR(MMMU_CTRL_OFFSET, ++ MMMU_CTRL_CAP_EXCEEDED_ABORT_EN | ++ MMMU_CTRL_PT_INVALID_ABORT_EN | ++ MMMU_CTRL_WRITE_VIOLATION_ABORT_EN | ++ MMMU_CTRL_TLB_CLEAR | ++ MMMU_CTRL_STATS_ENABLE | ++ MMMU_CTRL_ENABLE); ++ for (i = 0; i < 1024; i++) { ++ if (!(MMMU_CTRL_TLB_CLEARING & MMU_RD(MMMU_CTRL_OFFSET))) ++ break; ++ cpu_relax(); ++ } ++ } else { ++ for (p4 = iova >> (MMU_PAGE_SHIFT + 2); ++ p4 < (iova_end + 3 * MMU_PAGE_SIZE) >> (MMU_PAGE_SHIFT + 2); ++ p4++) { ++ MMU_WR(MMMU_SHOOT_DOWN_OFFSET, ++ MMMU_SHOOT_DOWN_SHOOT + (p4 << 2)); ++ for (i = 0; i < 1024; i++) { ++ if (!(MMMU_SHOOT_DOWN_SHOOTING & MMU_RD(MMMU_SHOOT_DOWN_OFFSET))) ++ break; ++ cpu_relax(); ++ } ++ } ++ } ++} ++ ++static void bcm2712_iommu_sync(struct iommu_domain *domain, ++ struct iommu_iotlb_gather *gather) ++{ ++ bcm2712_iommu_sync_range(domain, gather->start, ++ gather->end - gather->start); ++} ++ ++static void bcm2712_iommu_sync_all(struct iommu_domain *domain) ++{ ++ bcm2712_iommu_sync_range(domain, APERTURE_BASE, APERTURE_SIZE); ++} ++ ++static phys_addr_t bcm2712_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) ++{ ++ struct bcm2712_iommu *mmu = domain_to_mmu(domain); ++ u32 p; ++ ++ iova -= mmu->dma_iova_offset; ++ if (iova >= APERTURE_BASE && iova < APERTURE_TOP) { ++ p = (iova - APERTURE_BASE) >> MMU_PAGE_SHIFT; ++ p = mmu->tables[p] & 0x0FFFFFFFu; ++ return (((phys_addr_t)p) << MMU_PAGE_SHIFT) + (iova & (MMU_PAGE_SIZE - 1u)); ++ } else if (iova < APERTURE_BASE) { ++ return (phys_addr_t)iova; ++ } else { ++ return (phys_addr_t)-EINVAL; ++ } ++} ++ ++static void bcm2712_iommu_domain_free(struct iommu_domain *domain) ++{ ++ struct bcm2712_iommu_domain *mydomain = ++ container_of(domain, struct bcm2712_iommu_domain, base); ++ ++ kfree(mydomain); ++} ++ ++static const struct iommu_domain_ops bcm2712_iommu_domain_ops = { ++ .attach_dev = bcm2712_iommu_attach_dev, ++ .detach_dev = bcm2712_iommu_detach_dev, ++ .map = bcm2712_iommu_map, ++ .unmap = bcm2712_iommu_unmap, ++ .iotlb_sync = bcm2712_iommu_sync, ++ .iotlb_sync_map = bcm2712_iommu_sync_range, ++ .flush_iotlb_all = bcm2712_iommu_sync_all, ++ .iova_to_phys = bcm2712_iommu_iova_to_phys, ++ .free = bcm2712_iommu_domain_free, ++}; ++ ++static struct iommu_domain *bcm2712_iommu_domain_alloc(unsigned int type) ++{ ++ struct bcm2712_iommu_domain *domain; ++ ++ if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) ++ return NULL; ++ ++ domain = kzalloc(sizeof(*domain), GFP_KERNEL); ++ if (!domain) ++ return NULL; ++ ++ domain->base.type = type; ++ domain->base.ops = &bcm2712_iommu_domain_ops; ++ domain->base.geometry.aperture_start = APERTURE_BASE; ++ domain->base.geometry.aperture_end = APERTURE_TOP - 1ul; ++ domain->base.geometry.force_aperture = true; ++ return &domain->base; ++} ++ ++static struct iommu_device *bcm2712_iommu_probe_device(struct device *dev) ++{ ++ struct bcm2712_iommu *mmu; ++ ++ /* ++ * For reasons I don't fully understand, we need to try both ++ * cases (dev_iommu_priv_get() and platform_get_drvdata()) ++ * in order to get both GPU and ISP-BE to probe successfully. ++ */ ++ mmu = dev_iommu_priv_get(dev); ++ if (!mmu) { ++ struct device_node *np; ++ struct platform_device *pdev; ++ ++ /* Ignore devices that don't have an "iommus" property with exactly one phandle */ ++ if (!dev->of_node || ++ of_property_count_elems_of_size(dev->of_node, "iommus", sizeof(phandle)) != 1) ++ return ERR_PTR(-ENODEV); ++ ++ np = of_parse_phandle(dev->of_node, "iommus", 0); ++ if (!np) ++ return ERR_PTR(-EINVAL); ++ ++ pdev = of_find_device_by_node(np); ++ of_node_put(np); ++ if (pdev) ++ mmu = platform_get_drvdata(pdev); ++ ++ if (!mmu) ++ return ERR_PTR(-ENODEV); ++ } ++ ++ dev_info(dev, "%s: MMU %s\n", __func__, dev_name(mmu->dev)); ++ dev_iommu_priv_set(dev, mmu); ++ return &mmu->iommu; ++} ++ ++static void bcm2712_iommu_release_device(struct device *dev) ++{ ++ dev_iommu_priv_set(dev, NULL); ++} ++ ++static struct iommu_group *bcm2712_iommu_device_group(struct device *dev) ++{ ++ struct bcm2712_iommu *mmu = dev_iommu_priv_get(dev); ++ ++ if (!mmu || !mmu->group) ++ return ERR_PTR(-EINVAL); ++ ++ dev_info(dev, "%s: MMU %s\n", __func__, dev_name(mmu->dev)); ++ return iommu_group_ref_get(mmu->group); ++} ++ ++static int bcm2712_iommu_of_xlate(struct device *dev, ++ struct of_phandle_args *args) ++{ ++ struct platform_device *iommu_dev; ++ struct bcm2712_iommu *mmu; ++ ++ iommu_dev = of_find_device_by_node(args->np); ++ mmu = platform_get_drvdata(iommu_dev); ++ dev_iommu_priv_set(dev, mmu); ++ dev_info(dev, "%s: MMU %s\n", __func__, dev_name(mmu->dev)); ++ ++ return 0; ++} ++ ++static bool bcm2712_iommu_capable(struct device *dev, enum iommu_cap cap) ++{ ++ return false; ++} ++ ++static const struct iommu_ops bcm2712_iommu_ops = { ++ .capable = bcm2712_iommu_capable, ++ .domain_alloc = bcm2712_iommu_domain_alloc, ++ .probe_device = bcm2712_iommu_probe_device, ++ .release_device = bcm2712_iommu_release_device, ++ .device_group = bcm2712_iommu_device_group, ++ /* Advertise native page sizes as well as 2M, 16K which Linux may prefer */ ++ .pgsize_bitmap = (SZ_4M | SZ_2M | SZ_1M | SZ_64K | SZ_16K | SZ_4K), ++ .default_domain_ops = &bcm2712_iommu_domain_ops, ++ .of_xlate = bcm2712_iommu_of_xlate, ++}; ++ ++static int bcm2712_iommu_probe(struct platform_device *pdev) ++{ ++ struct bcm2712_iommu *mmu; ++ struct bcm2712_iommu_cache *cache = NULL; ++ int ret; ++ ++ /* First of all, check for an IOMMU shared cache */ ++ if (pdev->dev.of_node) { ++ struct device_node *cache_np; ++ struct platform_device *cache_pdev; ++ ++ cache_np = of_parse_phandle(pdev->dev.of_node, "cache", 0); ++ if (cache_np) { ++ cache_pdev = of_find_device_by_node(cache_np); ++ of_node_put(cache_np); ++ if (cache_pdev && !IS_ERR(cache_pdev)) ++ cache = platform_get_drvdata(cache_pdev); ++ if (!cache) ++ return -EPROBE_DEFER; ++ } ++ } ++ ++ /* Allocate private data */ ++ mmu = devm_kzalloc(&pdev->dev, sizeof(*mmu), GFP_KERNEL); ++ if (!mmu) ++ return -ENOMEM; ++ ++ mmu->name = dev_name(&pdev->dev); ++ mmu->dev = &pdev->dev; ++ mmu->cache = cache; ++ platform_set_drvdata(pdev, mmu); ++ spin_lock_init(&mmu->hw_lock); ++ ++ /* ++ * XXX When an IOMMU is downstream of a PCIe RC or some other chip/bus ++ * and serves some of the masters thereon (others using pass-through), ++ * we seem to fumble and lose the "dma-ranges" address offset for ++ * masters using IOMMU. This property restores it, where needed. ++ */ ++ if (!pdev->dev.of_node || ++ of_property_read_u64(pdev->dev.of_node, "dma-iova-offset", ++ &mmu->dma_iova_offset)) ++ mmu->dma_iova_offset = 0; ++ ++ /* ++ * The IOMMU is itself a device that allocates DMA-able memory ++ * to hold its translation tables. Provided the IOVA aperture ++ * is no larger than 4 GBytes (so that the L1 table fits within ++ * a single 4K page), we don't need the tables to be contiguous. ++ * Assume we can address at least 36 bits (64 GB). ++ */ ++ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36)); ++ WARN_ON(ret); ++ mmu->sgt = dma_alloc_noncontiguous(&pdev->dev, TABLES_ALLOC_SIZE, ++ DMA_TO_DEVICE, GFP_KERNEL, ++ DMA_ATTR_ALLOC_SINGLE_PAGES); ++ if (!mmu->sgt) { ++ ret = -ENOMEM; ++ goto done_err; ++ } ++ mmu->tables = dma_vmap_noncontiguous(&pdev->dev, TABLES_ALLOC_SIZE, ++ mmu->sgt); ++ if (!mmu->tables) { ++ ret = -ENOMEM; ++ goto done_err; ++ } ++ ++ /* Get IOMMU registers */ ++ mmu->reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(mmu->reg_base)) { ++ dev_err(&pdev->dev, "Failed to get IOMMU registers address\n"); ++ ret = PTR_ERR(mmu->reg_base); ++ goto done_err; ++ } ++ ++ /* Stuff */ ++ mmu->group = iommu_group_alloc(); ++ if (IS_ERR(mmu->group)) { ++ ret = PTR_ERR(mmu->group); ++ mmu->group = NULL; ++ goto done_err; ++ } ++ ret = iommu_device_sysfs_add(&mmu->iommu, mmu->dev, NULL, mmu->name); ++ if (ret) ++ goto done_err; ++ ++ /* Initialize table and hardware */ ++ bcm2712_iommu_init(mmu); ++ ret = iommu_device_register(&mmu->iommu, &bcm2712_iommu_ops, &pdev->dev); ++ ++ dev_info(&pdev->dev, "%s: Success\n", __func__); ++ return 0; ++ ++done_err: ++ dev_info(&pdev->dev, "%s: Failure %d\n", __func__, ret); ++ if (mmu->group) ++ iommu_group_put(mmu->group); ++ if (mmu->tables) ++ dma_vunmap_noncontiguous(&pdev->dev, ++ (void *)(mmu->tables)); ++ mmu->tables = NULL; ++ if (mmu->sgt) ++ dma_free_noncontiguous(&pdev->dev, TABLES_ALLOC_SIZE, ++ mmu->sgt, DMA_TO_DEVICE); ++ mmu->sgt = NULL; ++ kfree(mmu); ++ return ret; ++} ++ ++static int bcm2712_iommu_remove(struct platform_device *pdev) ++{ ++ struct bcm2712_iommu *mmu = platform_get_drvdata(pdev); ++ ++ if (mmu->reg_base) ++ MMU_WR(MMMU_CTRL_OFFSET, 0); /* disable the MMU */ ++ if (mmu->sgt) ++ dma_free_noncontiguous(&pdev->dev, TABLES_ALLOC_SIZE, ++ mmu->sgt, DMA_TO_DEVICE); ++ ++ return 0; ++} ++ ++static const struct of_device_id bcm2712_iommu_of_match[] = { ++ { ++ . compatible = "brcm,bcm2712-iommu" ++ }, ++ { /* sentinel */ }, ++}; ++ ++static struct platform_driver bcm2712_iommu_driver = { ++ .probe = bcm2712_iommu_probe, ++ .remove = bcm2712_iommu_remove, ++ .driver = { ++ .name = "bcm2712-iommu", ++ .of_match_table = bcm2712_iommu_of_match ++ }, ++}; ++ ++builtin_platform_driver(bcm2712_iommu_driver); +--- /dev/null ++++ b/drivers/iommu/bcm2712-iommu.h +@@ -0,0 +1,45 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * IOMMU driver for BCM2712 ++ * ++ * Copyright (c) 2023 Raspberry Pi Ltd. ++ */ ++ ++#ifndef _BCM2712_IOMMU_H ++#define _BCM2712_IOMMU_H ++ ++#include ++#include ++ ++struct bcm2712_iommu_cache { ++ struct device *dev; ++ spinlock_t hw_lock; /* to protect HW registers */ ++ void __iomem *reg_base; ++}; ++ ++void bcm2712_iommu_cache_flush(struct bcm2712_iommu_cache *cache); ++ ++struct bcm2712_iommu { ++ struct device *dev; ++ struct iommu_device iommu; ++ struct iommu_group *group; ++ struct bcm2712_iommu_domain *domain; ++ char const *name; ++ struct sg_table *sgt; /* allocated memory for page tables */ ++ u32 *tables; /* kernel mapping for page tables */ ++ struct bcm2712_iommu_cache *cache; ++ spinlock_t hw_lock; /* to protect HW registers */ ++ void __iomem *reg_base; ++ u64 dma_iova_offset; /* Hack for IOMMU attached to PCIe RC */ ++ u32 bigpage_mask; ++ u32 superpage_mask; ++ unsigned int nmapped_pages; ++ bool dirty; /* true when tables are oriented towards CPU */ ++}; ++ ++struct bcm2712_iommu_domain { ++ struct iommu_domain base; ++ struct bcm2712_iommu *mmu; ++}; ++ ++#endif diff --git a/target/linux/bcm27xx/patches-6.1/950-0918-irqchip-irq-brcmstb-l2-Add-config-for-2711-controlle.patch b/target/linux/bcm27xx/patches-6.1/950-0918-irqchip-irq-brcmstb-l2-Add-config-for-2711-controlle.patch new file mode 100644 index 0000000000..5ea212d4a7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0918-irqchip-irq-brcmstb-l2-Add-config-for-2711-controlle.patch @@ -0,0 +1,73 @@ +From fa4d4ed28c92cf4470e518f1a7362dc7941632d7 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Wed, 28 Jun 2023 16:24:29 +0100 +Subject: [PATCH] irqchip/irq-brcmstb-l2: Add config for 2711 controller + +We currently see these regularly: +[ 25.157560] irq 31, desc: 00000000c15e6d2c, depth: 0, count: 0, unhandled: 0 +[ 25.164658] ->handle_irq(): 00000000b1775675, brcmstb_l2_intc_irq_handle+0x0/0x1a8 +[ 25.172352] ->irq_data.chip(): 00000000fea59f1c, gic_chip_mode1+0x0/0x108 +[ 25.179166] ->action(): 000000003eda6d6f +[ 25.183096] ->action->handler(): 000000002c09e646, bad_chained_irq+0x0/0x58 +[ 25.190084] IRQ_LEVEL set +[ 25.193142] IRQ_NOPROBE set +[ 25.196198] IRQ_NOREQUEST set +[ 25.199255] IRQ_NOTHREAD set + +with: +$ cat /proc/interrupts | grep 31: + 31: 1 0 0 0 GICv2 129 Level (null) + +The interrupt is described in DT with IRQ_TYPE_LEVEL_HIGH + +But the current compatible string uses the controller in edge triggered mode +(as that config matches our register layout). + +Add a new compatible structure for level driven interrupt with our register layout. + +We had already been using this compatible string in device tree, so no change needed +there. + +Signed-off-by: Dom Cobley +--- + drivers/irqchip/irq-brcmstb-l2.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/drivers/irqchip/irq-brcmstb-l2.c ++++ b/drivers/irqchip/irq-brcmstb-l2.c +@@ -52,6 +52,16 @@ static const struct brcmstb_intc_init_pa + .cpu_mask_clear = 0x0C + }; + ++/* Register offsets in the 2711 L2 level interrupt controller */ ++static const struct brcmstb_intc_init_params l2_2711_lvl_intc_init = { ++ .handler = handle_level_irq, ++ .cpu_status = 0x00, ++ .cpu_clear = 0x08, ++ .cpu_mask_status = 0x0c, ++ .cpu_mask_set = 0x10, ++ .cpu_mask_clear = 0x14 ++}; ++ + /* L2 intc private data structure */ + struct brcmstb_l2_intc_data { + struct irq_domain *domain; +@@ -286,11 +296,18 @@ static int __init brcmstb_l2_lvl_intc_of + return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init); + } + ++static int __init brcmstb_l2_2711_lvl_intc_of_init(struct device_node *np, ++ struct device_node *parent) ++{ ++ return brcmstb_l2_intc_of_init(np, parent, &l2_2711_lvl_intc_init); ++} ++ + IRQCHIP_PLATFORM_DRIVER_BEGIN(brcmstb_l2) + IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_of_init) + IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_of_init) + IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_of_init) + IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_of_init) ++IRQCHIP_MATCH("brcm,bcm2711-l2-intc", brcmstb_l2_2711_lvl_intc_of_init) + IRQCHIP_PLATFORM_DRIVER_END(brcmstb_l2) + MODULE_DESCRIPTION("Broadcom STB generic L2 interrupt controller"); + MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-6.1/950-0919-rtc-rtc-rpi-Add-simple-RTC-driver-for-Raspberry-Pi.patch b/target/linux/bcm27xx/patches-6.1/950-0919-rtc-rtc-rpi-Add-simple-RTC-driver-for-Raspberry-Pi.patch new file mode 100644 index 0000000000..e2b8c6c6a1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0919-rtc-rtc-rpi-Add-simple-RTC-driver-for-Raspberry-Pi.patch @@ -0,0 +1,237 @@ +From 222dedcdc09247126d39364a614ff2019789f52a Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Fri, 7 Jul 2023 20:00:45 +0100 +Subject: [PATCH] rtc: rtc-rpi: Add simple RTC driver for Raspberry Pi + +This supports setting and reading the real time clock +and supports wakeup alarms. + +To support wake up alarms you want this bootloader config: + POWER_OFF_ON_HALT=1 + WAKE_ON_GPIO=0 + +You can test with: + echo +600 | sudo tee /sys/class/rtc/rtc0/wakealarm + sudo halt + +That will halt (in an almost no power state), +then wake and restart after 10 minutes. + +Signed-off-by: Dom Cobley +--- + drivers/rtc/Kconfig | 11 +++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-rpi.c | 177 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 189 insertions(+) + create mode 100644 drivers/rtc/rtc-rpi.c + +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -223,6 +223,17 @@ config RTC_DRV_AC100 + This driver can also be built as a module. If so, the module + will be called rtc-ac100. + ++config RTC_DRV_RPI ++ tristate "Raspberry Pi RTC" ++ depends on ARCH_BRCMSTB || COMPILE_TEST ++ default ARCH_BRCMSTB ++ help ++ If you say yes here you get support for the RTC found on ++ Raspberry Pi devices. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-rpi. ++ + config RTC_DRV_BRCMSTB + tristate "Broadcom STB wake-timer" + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -140,6 +140,7 @@ obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5 + obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-rc5t619.o + obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o + obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o ++obj-$(CONFIG_RTC_DRV_RPI) += rtc-rpi.o + obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o + obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o + obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o +--- /dev/null ++++ b/drivers/rtc/rtc-rpi.c +@@ -0,0 +1,177 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/** ++ * rtc-rpi.c ++ * ++ * RTC driver using firmware mailbox ++ * Supports battery backed RTC and wake alarms ++ * ++ * Based on rtc-meson-vrtc by Neil Armstrong ++ * ++ * Copyright (c) 2023, Raspberry Pi Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct rpi_rtc_data { ++ struct rtc_device *rtc; ++ struct rpi_firmware *fw; ++}; ++ ++#define RPI_FIRMWARE_GET_RTC_REG 0x00030087 ++#define RPI_FIRMWARE_SET_RTC_REG 0x00038087 ++enum {RTC_TIME, RTC_ALARM, RTC_ALARM_PENDING, RTC_ALARM_ENABLE}; ++ ++static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data[2] = {RTC_TIME}; ++ int err; ++ ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, ++ &data, sizeof(data)); ++ rtc_time64_to_tm(data[1], tm); ++ return err; ++} ++ ++static int rpi_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data[2] = {RTC_TIME, rtc_tm_to_time64(tm)}; ++ ++ return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++} ++ ++static int rpi_rtc_alarm_irq_is_enabled(struct device *dev, unsigned char *enabled) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data[2] = {RTC_ALARM_ENABLE}; ++ s32 err = 0; ++ ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, ++ &data, sizeof(data)); ++ *enabled = data[1] & 0x1; ++ return err; ++} ++ ++static int rpi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data[2] = {RTC_ALARM_ENABLE, enabled}; ++ ++ return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++} ++ ++static int rpi_rtc_alarm_clear_pending(struct device *dev) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data[2] = {RTC_ALARM_PENDING, 1}; ++ ++ return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++} ++ ++static int rpi_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data[2] = {RTC_ALARM}; ++ s32 err = 0; ++ ++ err = rpi_rtc_alarm_irq_is_enabled(dev, &alarm->enabled); ++ if (!err) ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, ++ &data, sizeof(data)); ++ rtc_time64_to_tm(data[1], &alarm->time); ++ ++ return err; ++} ++ ++static int rpi_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data[2] = {RTC_ALARM, rtc_tm_to_time64(&alarm->time)}; ++ int err; ++ ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++ ++ if (err == 0) ++ err = rpi_rtc_alarm_irq_enable(dev, alarm->enabled); ++ ++ return err; ++} ++ ++static const struct rtc_class_ops rpi_rtc_ops = { ++ .read_time = rpi_rtc_read_time, ++ .set_time = rpi_rtc_set_time, ++ .read_alarm = rpi_rtc_read_alarm, ++ .set_alarm = rpi_rtc_set_alarm, ++ .alarm_irq_enable = rpi_rtc_alarm_irq_enable, ++}; ++ ++static int rpi_rtc_probe(struct platform_device *pdev) ++{ ++ struct rpi_rtc_data *vrtc; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct device_node *fw_node; ++ struct rpi_firmware *fw; ++ int ret; ++ ++ fw_node = of_parse_phandle(np, "firmware", 0); ++ if (!fw_node) { ++ dev_err(dev, "Missing firmware node\n"); ++ return -ENOENT; ++ } ++ ++ fw = rpi_firmware_get(fw_node); ++ if (!fw) ++ return -EPROBE_DEFER; ++ ++ vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL); ++ if (!vrtc) ++ return -ENOMEM; ++ ++ vrtc->fw = fw; ++ ++ device_init_wakeup(&pdev->dev, 1); ++ ++ platform_set_drvdata(pdev, vrtc); ++ ++ vrtc->rtc = devm_rtc_allocate_device(&pdev->dev); ++ if (IS_ERR(vrtc->rtc)) ++ return PTR_ERR(vrtc->rtc); ++ ++ set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, vrtc->rtc->features); ++ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, vrtc->rtc->features); ++ ++ vrtc->rtc->ops = &rpi_rtc_ops; ++ ret = devm_rtc_register_device(vrtc->rtc); ++ ++ rpi_rtc_alarm_clear_pending(dev); ++ return ret; ++} ++ ++static const struct of_device_id rpi_rtc_dt_match[] = { ++ { .compatible = "raspberrypi,rpi-rtc"}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rpi_rtc_dt_match); ++ ++static struct platform_driver rpi_rtc_driver = { ++ .probe = rpi_rtc_probe, ++ .driver = { ++ .name = "rpi-rtc", ++ .of_match_table = rpi_rtc_dt_match, ++ }, ++}; ++ ++module_platform_driver(rpi_rtc_driver); ++ ++MODULE_DESCRIPTION("Raspberry Pi RTC driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/bcm27xx/patches-6.1/950-0920-dt-bindings-rtc-new-binding-for-Raspberry-Pi-RTC-dri.patch b/target/linux/bcm27xx/patches-6.1/950-0920-dt-bindings-rtc-new-binding-for-Raspberry-Pi-RTC-dri.patch new file mode 100644 index 0000000000..f4c630cf09 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0920-dt-bindings-rtc-new-binding-for-Raspberry-Pi-RTC-dri.patch @@ -0,0 +1,35 @@ +From ff2c2f67689e10ad66c1e33ae6a7552d82ac983c Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Fri, 7 Jul 2023 20:16:06 +0100 +Subject: [PATCH] dt-bindings: rtc: new binding for Raspberry Pi RTC driver + +Add binding for the new RTC driver for Raspberry Pi. +This platform has an RTC managed by firmware, and this RTC +driver provides the simple mailbox interface to access it. + +Signed-off-by: Dom Cobley +--- + .../devicetree/bindings/rtc/rtc-rpi.txt | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + create mode 100644 Documentation/devicetree/bindings/rtc/rtc-rpi.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/rtc/rtc-rpi.txt +@@ -0,0 +1,17 @@ ++* Raspberry Pi RTC ++ ++This is a Linux interface to an RTC managed by firmware, hence it's ++virtual from a Linux perspective. ++ ++The interface uses the firmware mailbox api to access the RTC registers. ++ ++Required properties: ++compatible: should be "raspberrypi,rpi-rtc" ++firmware: Reference to the RPi firmware device node. ++ ++Example: ++ ++ rpi_rtc: rpi_rtc { ++ compatible = "raspberrypi,rpi-rtc"; ++ firmware = <&firmware>; ++ }; diff --git a/target/linux/bcm27xx/patches-6.1/950-0921-hwmon-pwm-fan-Add-fan-speed-register-support.patch b/target/linux/bcm27xx/patches-6.1/950-0921-hwmon-pwm-fan-Add-fan-speed-register-support.patch new file mode 100644 index 0000000000..205806cdfd --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0921-hwmon-pwm-fan-Add-fan-speed-register-support.patch @@ -0,0 +1,164 @@ +From 96a8a4776cb142f5d2bb7f6379df9af40e727c0b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 11 Jul 2023 10:17:29 +0100 +Subject: [PATCH] hwmon: (pwm-fan) Add fan speed register support + +Some platforms include a fan-speed register that reports RPM directly +as an alternative to counting interrupts from the fan tachometer input. +Add support for reading a register at a given offset (rpm-offset) within +a block declared in another node (rpm-regmap). This indirection allows +the usual address mapping to be performed, and for address sharing with +another driver. + +Signed-off-by: Phil Elwell +--- + drivers/hwmon/pwm-fan.c | 59 ++++++++++++++++++++++++++++++++++++----- + 1 file changed, 52 insertions(+), 7 deletions(-) + +--- a/drivers/hwmon/pwm-fan.c ++++ b/drivers/hwmon/pwm-fan.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -51,6 +52,9 @@ struct pwm_fan_ctx { + ktime_t sample_start; + struct timer_list rpm_timer; + ++ void __iomem *rpm_regbase; ++ unsigned int rpm_offset; ++ + unsigned int pwm_value; + unsigned int pwm_fan_state; + unsigned int pwm_fan_max_state; +@@ -61,6 +65,10 @@ struct pwm_fan_ctx { + struct hwmon_channel_info fan_channel; + }; + ++static const u32 rpm_reg_channel_config[] = { ++ HWMON_F_INPUT, 0 ++}; ++ + /* This handler assumes self resetting edge triggered interrupt. */ + static irqreturn_t pulse_handler(int irq, void *dev_id) + { +@@ -335,7 +343,10 @@ static int pwm_fan_read(struct device *d + } + return -EOPNOTSUPP; + case hwmon_fan: +- *val = ctx->tachs[channel].rpm; ++ if (ctx->rpm_regbase) ++ *val = (long)readl(ctx->rpm_regbase + ctx->rpm_offset); ++ else ++ *val = ctx->tachs[channel].rpm; + return 0; + + default: +@@ -470,6 +481,7 @@ static void pwm_fan_cleanup(void *__ctx) + /* Switch off everything */ + ctx->enable_mode = pwm_disable_reg_disable; + pwm_fan_power_off(ctx); ++ iounmap(ctx->rpm_regbase); + } + + static int pwm_fan_probe(struct platform_device *pdev) +@@ -534,10 +546,23 @@ static int pwm_fan_probe(struct platform + return ret; + + ctx->tach_count = platform_irq_count(pdev); ++ if (ctx->tach_count == 0) { ++ struct device_node *rpm_node; ++ ++ rpm_node = of_parse_phandle(dev->of_node, "rpm-regmap", 0); ++ if (rpm_node) ++ ctx->rpm_regbase = of_iomap(rpm_node, 0); ++ } ++ + if (ctx->tach_count < 0) + return dev_err_probe(dev, ctx->tach_count, + "Could not get number of fan tachometer inputs\n"); +- dev_dbg(dev, "%d fan tachometer inputs\n", ctx->tach_count); ++ if (IS_ERR(ctx->rpm_regbase)) ++ return dev_err_probe(dev, PTR_ERR(ctx->rpm_regbase), ++ "Could not get rpm reg\n"); ++ ++ dev_dbg(dev, "%d fan tachometer inputs, %d rpm regmap\n", ctx->tach_count, ++ !!ctx->rpm_regbase); + + if (ctx->tach_count) { + channel_count++; /* We also have a FAN channel. */ +@@ -554,12 +579,24 @@ static int pwm_fan_probe(struct platform + if (!fan_channel_config) + return -ENOMEM; + ctx->fan_channel.config = fan_channel_config; ++ } else if (ctx->rpm_regbase) { ++ channel_count++; /* We also have a FAN channel. */ ++ ctx->fan_channel.type = hwmon_fan; ++ ctx->fan_channel.config = rpm_reg_channel_config; ++ ++ if (of_property_read_u32(pdev->dev.of_node, "rpm-offset", &ctx->rpm_offset)) { ++ dev_err(&pdev->dev, "unable to read 'rpm-offset'"); ++ ret = -EINVAL; ++ goto error; ++ } + } + + channels = devm_kcalloc(dev, channel_count + 1, + sizeof(struct hwmon_channel_info *), GFP_KERNEL); +- if (!channels) +- return -ENOMEM; ++ if (!channels) { ++ ret = -ENOMEM; ++ goto error; ++ } + + channels[0] = HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE); + +@@ -602,6 +639,8 @@ static int pwm_fan_probe(struct platform + mod_timer(&ctx->rpm_timer, jiffies + HZ); + + channels[1] = &ctx->fan_channel; ++ } else if (ctx->rpm_regbase) { ++ channels[1] = &ctx->fan_channel; + } + + ctx->info.ops = &pwm_fan_hwmon_ops; +@@ -611,12 +650,13 @@ static int pwm_fan_probe(struct platform + ctx, &ctx->info, NULL); + if (IS_ERR(hwmon)) { + dev_err(dev, "Failed to register hwmon device\n"); +- return PTR_ERR(hwmon); ++ ret = PTR_ERR(hwmon); ++ goto error; + } + + ret = pwm_fan_of_get_cooling_data(dev, ctx); + if (ret) +- return ret; ++ goto error; + + ctx->pwm_fan_state = ctx->pwm_fan_max_state; + if (IS_ENABLED(CONFIG_THERMAL)) { +@@ -627,12 +667,17 @@ static int pwm_fan_probe(struct platform + dev_err(dev, + "Failed to register pwm-fan as cooling device: %d\n", + ret); +- return ret; ++ goto error; + } + ctx->cdev = cdev; + } + + return 0; ++ ++error: ++ if (ctx->rpm_regbase) ++ iounmap(ctx->rpm_regbase); ++ return ret; + } + + static void pwm_fan_shutdown(struct platform_device *pdev) diff --git a/target/linux/bcm27xx/patches-6.1/950-0923-dt-bindings-input-Add-bindings-for-raspberrypi-butto.patch b/target/linux/bcm27xx/patches-6.1/950-0923-dt-bindings-input-Add-bindings-for-raspberrypi-butto.patch new file mode 100644 index 0000000000..2972c57fd7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0923-dt-bindings-input-Add-bindings-for-raspberrypi-butto.patch @@ -0,0 +1,63 @@ +From 07419175fdb507be2c9d3aaf4b7d18306a336348 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 2 Aug 2023 11:38:03 +0100 +Subject: [PATCH] dt-bindings: input: Add bindings for raspberrypi-button + +Add bindings for the firmware-based button driver. + +Signed-off-by: Phil Elwell +--- + .../input/raspberrypi,firmware-button.yaml | 47 +++++++++++++++++++ + 1 file changed, 47 insertions(+) + create mode 100644 Documentation/devicetree/bindings/input/raspberrypi,firmware-button.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/input/raspberrypi,firmware-button.yaml +@@ -0,0 +1,47 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/input/raspberrypi,firmware-button.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Raspberry Pi firmware buttons ++ ++maintainers: ++ - Phil Elwell ++ ++description: > ++ The Raspberry Pi 5 firmware exposes the state of the power button. The ++ raspberrypi-button driver generates a keycode when it is pressed. ++ ++properties: ++ compatible: ++ enum: ++ - raspberrypi,firmware-button ++ ++ id: ++ description: A numeric identifier of the button ++ ++ label: ++ description: Descriptive name of the button. ++ ++ linux,code: ++ description: Key code to emit. ++ ++required: ++ - compatible ++ - linux,code ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ ++ pwr_button: pwr_button { ++ compatible = "raspberrypi,firmware-button"; ++ id = ; ++ label = "pwr_button"; ++ linux,code = <116>; // KEY_POWER ++ }; ++ ++... diff --git a/target/linux/bcm27xx/patches-6.1/950-0924-dt-bindings-input-Add-bindings-for-raspberrypi-butto.patch b/target/linux/bcm27xx/patches-6.1/950-0924-dt-bindings-input-Add-bindings-for-raspberrypi-butto.patch new file mode 100644 index 0000000000..e8fea23ce8 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0924-dt-bindings-input-Add-bindings-for-raspberrypi-butto.patch @@ -0,0 +1,27 @@ +From 93c8947bc7813b49fe27a5251eef97c6df1e14c6 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 2 Aug 2023 15:01:29 +0100 +Subject: [PATCH] dt-bindings: input: Add bindings for raspberrypi-button + +Add bindings for the firmware-based button driver. + +Signed-off-by: Phil Elwell +--- + include/dt-bindings/input/raspberrypi-button.h | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 include/dt-bindings/input/raspberrypi-button.h + +--- /dev/null ++++ b/include/dt-bindings/input/raspberrypi-button.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ ++/* ++ * This header provides constants the raspberrypi-button driver. ++ */ ++ ++#ifndef _DT_BINDINGS_RASPBERRYPI_BUTTON_H ++#define _DT_BINDINGS_RASPBERRYPI_BUTTON_H ++ ++#define RASPBERRYPI_BUTTON_POWER 0 ++ ++#endif diff --git a/target/linux/bcm27xx/patches-6.1/950-0925-Input-Add-raspberrypi-button-firmware-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0925-Input-Add-raspberrypi-button-firmware-driver.patch new file mode 100644 index 0000000000..76a9261a68 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0925-Input-Add-raspberrypi-button-firmware-driver.patch @@ -0,0 +1,197 @@ +From 7c0d40384b0648030d5202114d90239b8db7d4e0 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 2 Aug 2023 11:30:48 +0100 +Subject: [PATCH] Input: Add raspberrypi-button firmware driver + +Raspberry Pi 5s have a power/suspend button that is only accessible to +the firmware. Add a driver to read it and generate key events. + +Signed-off-by: Phil Elwell +--- + drivers/input/misc/Kconfig | 10 ++ + drivers/input/misc/Makefile | 1 + + drivers/input/misc/raspberrypi-button.c | 138 +++++++++++++++++++++ + include/soc/bcm2835/raspberrypi-firmware.h | 1 + + 4 files changed, 150 insertions(+) + create mode 100644 drivers/input/misc/raspberrypi-button.c + +--- a/drivers/input/misc/Kconfig ++++ b/drivers/input/misc/Kconfig +@@ -918,6 +918,16 @@ config INPUT_RT5120_PWRKEY + To compile this driver as a module, choose M here. the module will + be called rt5120-pwrkey. + ++config INPUT_RASPBERRYPI_BUTTON ++ tristate "Raspberry Pi button support" ++ depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) ++ help ++ This enables support for firmware-controlled buttons on Raspberry ++ Pi devices. ++ ++ To compile this driver as a module, choose M here. the module will ++ be called raspberrypi-button. ++ + config INPUT_STPMIC1_ONKEY + tristate "STPMIC1 PMIC Onkey support" + depends on MFD_STPMIC1 +--- a/drivers/input/misc/Makefile ++++ b/drivers/input/misc/Makefile +@@ -70,6 +70,7 @@ obj-$(CONFIG_INPUT_RAVE_SP_PWRBUTTON) += + obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o + obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o + obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o ++obj-$(CONFIG_INPUT_RASPBERRYPI_BUTTON) += raspberrypi-button.o + obj-$(CONFIG_INPUT_RT5120_PWRKEY) += rt5120-pwrkey.o + obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o + obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o +--- /dev/null ++++ b/drivers/input/misc/raspberrypi-button.c +@@ -0,0 +1,138 @@ ++// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 ++/* ++ * Driver for Raspberry Pi power button ++ * ++ * Copyright (C) 2023 Raspberry Pi Ltd. ++ * ++ * This driver is based on drivers/hwmon/raspberrypi-hwmon.c and ++ * input/misc/pm8941-pwrkey.c/ - see original files for copyright information ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct rpi_button { ++ struct device *dev; ++ struct rpi_firmware *fw; ++ struct input_dev *input; ++ struct delayed_work poll_work; ++ unsigned long poll_rate; ++ const char *name; ++ u32 id; ++ u32 code; ++}; ++ ++static void button_poll(struct work_struct *work) ++{ ++ struct rpi_button *button; ++ u32 value; ++ int err; ++ ++ button = container_of(work, struct rpi_button, ++ poll_work.work); ++ ++ value = BIT(button->id); ++ err = rpi_firmware_property(button->fw, RPI_FIRMWARE_GET_BUTTONS_PRESSED, ++ &value, sizeof(value)); ++ if (err) { ++ dev_err_once(button->dev, "GET_BUTTON_PRESSED not implemented?\n"); ++ return; ++ } ++ ++ if (value & BIT(button->id)) { ++ input_event(button->input, EV_KEY, button->code, 1); ++ input_sync(button->input); ++ input_event(button->input, EV_KEY, button->code, 0); ++ input_sync(button->input); ++ } ++ ++ schedule_delayed_work(&button->poll_work, button->poll_rate); ++} ++ ++static int rpi_button_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rpi_button *button; ++ int err; ++ ++ button = devm_kzalloc(dev, sizeof(*button), GFP_KERNEL); ++ if (!button) ++ return -ENOMEM; ++ ++ button->dev = dev; ++ ++ /* Get the firmware pointer from our parent */ ++ button->fw = dev_get_drvdata(dev->parent); ++ ++ if (device_property_read_u32(dev, "id", &button->id)) ++ button->id = RASPBERRYPI_BUTTON_POWER; ++ ++ if (device_property_read_string(dev, "label", &button->name)) ++ button->name = "raspberrypi-button"; ++ ++ if (device_property_read_u32(dev, "linux,code", &button->code)) { ++ dev_err(&pdev->dev, "no linux,code property\n"); ++ return -EINVAL; ++ } ++ ++ button->input = devm_input_allocate_device(dev); ++ if (!button->input) { ++ dev_dbg(&pdev->dev, "unable to allocate input device\n"); ++ return -ENOMEM; ++ } ++ ++ input_set_capability(button->input, EV_KEY, button->code); ++ ++ button->input->name = button->name; ++ button->input->phys = "raspberrypi-button/input0"; ++ button->input->dev.parent = dev; ++ button->poll_rate = HZ; ++ ++ err = input_register_device(button->input); ++ if (err) { ++ dev_err(&pdev->dev, "failed to register input device: %d\n", ++ err); ++ return err; ++ } ++ ++ err = devm_delayed_work_autocancel(dev, &button->poll_work, ++ button_poll); ++ if (err) ++ return err; ++ ++ platform_set_drvdata(pdev, button); ++ schedule_delayed_work(&button->poll_work, button->poll_rate); ++ ++ return 0; ++} ++ ++static const struct of_device_id rpi_button_match[] = { ++ { .compatible = "raspberrypi,firmware-button", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, rpi_button_match); ++ ++static struct platform_driver rpi_button_driver = { ++ .probe = rpi_button_probe, ++ .driver = { ++ .name = "raspberrypi-button", ++ .of_match_table = of_match_ptr(rpi_button_match), ++ }, ++}; ++module_platform_driver(rpi_button_driver); ++ ++MODULE_AUTHOR("Phil Elwell "); ++MODULE_DESCRIPTION("Raspberry Pi button driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -98,6 +98,7 @@ enum rpi_firmware_property_tag { + RPI_FIRMWARE_GET_REBOOT_FLAGS = 0x00030064, + RPI_FIRMWARE_SET_REBOOT_FLAGS = 0x00038064, + RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066, ++ RPI_FIRMWARE_GET_BUTTONS_PRESSED = 0x00030088, + + /* Dispmanx TAGS */ + RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, diff --git a/target/linux/bcm27xx/patches-6.1/950-0926-dt-bindings-update-rpi-rtc-binding.patch b/target/linux/bcm27xx/patches-6.1/950-0926-dt-bindings-update-rpi-rtc-binding.patch new file mode 100644 index 0000000000..ffc5cc1a9d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0926-dt-bindings-update-rpi-rtc-binding.patch @@ -0,0 +1,29 @@ +From a7a3679a148e40879f1ce77580d9edf64cb5b51c Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Mon, 18 Sep 2023 16:33:06 +0100 +Subject: [PATCH] dt: bindings: update rpi-rtc binding + +Add property for bcm2712 firmware RTC driver charger control + +Signed-off-by: Jonathan Bell +--- + Documentation/devicetree/bindings/rtc/rtc-rpi.txt | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/Documentation/devicetree/bindings/rtc/rtc-rpi.txt ++++ b/Documentation/devicetree/bindings/rtc/rtc-rpi.txt +@@ -9,9 +9,14 @@ Required properties: + compatible: should be "raspberrypi,rpi-rtc" + firmware: Reference to the RPi firmware device node. + ++Optional property: ++trickle-charge-microvolt: specify a trickle charge voltage for the backup ++ battery in microvolts. ++ + Example: + + rpi_rtc: rpi_rtc { + compatible = "raspberrypi,rpi-rtc"; + firmware = <&firmware>; ++ trickle-charge-microvolt = <3000000>; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-0927-drivers-rtc-rpi-add-battery-charge-circuit-control-a.patch b/target/linux/bcm27xx/patches-6.1/950-0927-drivers-rtc-rpi-add-battery-charge-circuit-control-a.patch new file mode 100644 index 0000000000..dae0a1cbff --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0927-drivers-rtc-rpi-add-battery-charge-circuit-control-a.patch @@ -0,0 +1,153 @@ +From 33b514cb16dbf13395a0becf7442d19676ae4224 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Fri, 15 Sep 2023 17:33:03 +0100 +Subject: [PATCH] drivers: rtc-rpi: add battery charge circuit control and + readback + +Parse devicetree for a charger voltage and apply it. If nonzero and a +valid voltage, the firmware will enable charging, otherwise the charger +circuit is disabled. + +Add sysfs attributes to read back the supported charge voltage range, +the measured battery voltage, and the charger setpoint. + +Signed-off-by: Jonathan Bell +--- + drivers/rtc/rtc-rpi.c | 106 ++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 103 insertions(+), 3 deletions(-) + +--- a/drivers/rtc/rtc-rpi.c ++++ b/drivers/rtc/rtc-rpi.c +@@ -19,11 +19,22 @@ + struct rpi_rtc_data { + struct rtc_device *rtc; + struct rpi_firmware *fw; ++ u32 bbat_vchg_microvolts; + }; + + #define RPI_FIRMWARE_GET_RTC_REG 0x00030087 + #define RPI_FIRMWARE_SET_RTC_REG 0x00038087 +-enum {RTC_TIME, RTC_ALARM, RTC_ALARM_PENDING, RTC_ALARM_ENABLE}; ++ ++enum { ++ RTC_TIME, ++ RTC_ALARM, ++ RTC_ALARM_PENDING, ++ RTC_ALARM_ENABLE, ++ RTC_BBAT_CHG_VOLTS, ++ RTC_BBAT_CHG_VOLTS_MIN, ++ RTC_BBAT_CHG_VOLTS_MAX, ++ RTC_BBAT_VOLTS ++}; + + static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm) + { +@@ -114,6 +125,83 @@ static const struct rtc_class_ops rpi_rt + .alarm_irq_enable = rpi_rtc_alarm_irq_enable, + }; + ++static int rpi_rtc_set_charge_voltage(struct device *dev) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); ++ u32 data[2] = {RTC_BBAT_CHG_VOLTS, vrtc->bbat_vchg_microvolts}; ++ int err; ++ ++ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, ++ &data, sizeof(data)); ++ ++ if (err) ++ dev_err(dev, "failed to set trickle charge voltage to %uuV: %d\n", ++ vrtc->bbat_vchg_microvolts, err); ++ else if (vrtc->bbat_vchg_microvolts) ++ dev_info(dev, "trickle charging enabled at %uuV\n", ++ vrtc->bbat_vchg_microvolts); ++ ++ return err; ++} ++ ++static ssize_t rpi_rtc_print_uint_reg(struct device *dev, char *buf, u32 reg) ++{ ++ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev->parent); ++ u32 data[2] = {reg, 0}; ++ int ret = 0; ++ ++ ret = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, ++ &data, sizeof(data)); ++ if (ret < 0) ++ return ret; ++ ++ return sprintf(buf, "%u\n", data[1]); ++} ++ ++static ssize_t charging_voltage_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS); ++} ++static DEVICE_ATTR_RO(charging_voltage); ++ ++static ssize_t charging_voltage_min_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MIN); ++} ++static DEVICE_ATTR_RO(charging_voltage_min); ++ ++static ssize_t charging_voltage_max_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MAX); ++} ++static DEVICE_ATTR_RO(charging_voltage_max); ++ ++static ssize_t battery_voltage_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_VOLTS); ++} ++static DEVICE_ATTR_RO(battery_voltage); ++ ++static struct attribute *rpi_rtc_attrs[] = { ++ &dev_attr_charging_voltage.attr, ++ &dev_attr_charging_voltage_min.attr, ++ &dev_attr_charging_voltage_max.attr, ++ &dev_attr_battery_voltage.attr, ++ NULL ++}; ++ ++static const struct attribute_group rpi_rtc_sysfs_files = { ++ .attrs = rpi_rtc_attrs, ++}; ++ + static int rpi_rtc_probe(struct platform_device *pdev) + { + struct rpi_rtc_data *vrtc; +@@ -151,10 +239,22 @@ static int rpi_rtc_probe(struct platform + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, vrtc->rtc->features); + + vrtc->rtc->ops = &rpi_rtc_ops; +- ret = devm_rtc_register_device(vrtc->rtc); ++ ret = rtc_add_group(vrtc->rtc, &rpi_rtc_sysfs_files); ++ if (ret) ++ return ret; + + rpi_rtc_alarm_clear_pending(dev); +- return ret; ++ ++ /* ++ * Optionally enable trickle charging - if the property isn't ++ * present (or set to zero), trickle charging is disabled. ++ */ ++ of_property_read_u32(np, "trickle-charge-microvolt", ++ &vrtc->bbat_vchg_microvolts); ++ ++ rpi_rtc_set_charge_voltage(dev); ++ ++ return devm_rtc_register_device(vrtc->rtc); + } + + static const struct of_device_id rpi_rtc_dt_match[] = { diff --git a/target/linux/bcm27xx/patches-6.1/950-0928-vc4_drv-Avoid-panic-when-booted-with-no-kms.patch b/target/linux/bcm27xx/patches-6.1/950-0928-vc4_drv-Avoid-panic-when-booted-with-no-kms.patch new file mode 100644 index 0000000000..8aae09c81a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0928-vc4_drv-Avoid-panic-when-booted-with-no-kms.patch @@ -0,0 +1,29 @@ +From 0f5fd4538774aa6c936bb8fc78611c3113bf19d7 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Mon, 17 Apr 2023 15:21:41 +0100 +Subject: [PATCH] vc4_drv: Avoid panic when booted with no kms + +If kms/fkms overlay is not present we have no matching drivers +and so match is NULL. + +It is not safe to call component_master_add_with_match with a null match argument. + +So don't do that + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_drv.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -456,6 +456,9 @@ static int vc4_platform_drm_probe(struct + vc4_match_add_drivers(dev, &match, + component_drivers, ARRAY_SIZE(component_drivers)); + ++ if (!match) ++ return -ENODEV; ++ + return component_master_add_with_match(dev, &vc4_drm_ops, match); + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-0929-drm-vc4-Treat-zero-sized-destination-as-full-screen.patch b/target/linux/bcm27xx/patches-6.1/950-0929-drm-vc4-Treat-zero-sized-destination-as-full-screen.patch new file mode 100644 index 0000000000..70a11df293 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0929-drm-vc4-Treat-zero-sized-destination-as-full-screen.patch @@ -0,0 +1,28 @@ +From 2c987545a88507acdd8a572a3bd23a4ca0124d14 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Thu, 13 Apr 2023 17:41:11 +0100 +Subject: [PATCH] drm/vc4: Treat zero sized destination as full screen + +Kodi video planes come through with all zeros for fullscreen +Without this check, we WARN when writing width-1, height-1 +to destination dlist + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_plane.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -484,6 +484,11 @@ static int vc4_plane_setup_clipping_and_ + vc4_state->crtc_w = state->dst.x2 - state->dst.x1; + vc4_state->crtc_h = state->dst.y2 - state->dst.y1; + ++ if (!vc4_state->crtc_w) ++ vc4_state->crtc_w = state->crtc->mode.hdisplay; ++ if (!vc4_state->crtc_h) ++ vc4_state->crtc_h = state->crtc->mode.vdisplay; ++ + ret = vc4_plane_margins_adj(state); + if (ret) + return ret; diff --git a/target/linux/bcm27xx/patches-6.1/950-0930-drm-vc4-Fix-FKMS-for-when-the-YUV-chroma-planes-are-.patch b/target/linux/bcm27xx/patches-6.1/950-0930-drm-vc4-Fix-FKMS-for-when-the-YUV-chroma-planes-are-.patch new file mode 100644 index 0000000000..9182194403 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0930-drm-vc4-Fix-FKMS-for-when-the-YUV-chroma-planes-are-.patch @@ -0,0 +1,50 @@ +From bb1ee75de382c7a5218750476aa2a5792309cc70 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 30 Mar 2023 17:18:36 +0100 +Subject: [PATCH] drm/vc4: Fix FKMS for when the YUV chroma planes are + different buffers + +The code was assuming that it was a single buffer with offsets, +when kmstest uses separate buffers and 0 offsets for each plane. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -528,7 +528,7 @@ static int vc4_plane_to_mb(struct drm_pl + struct drm_plane_state *state) + { + struct drm_framebuffer *fb = state->fb; +- struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0); ++ struct drm_gem_dma_object *bo; + const struct drm_format_info *drm_fmt = fb->format; + const struct vc_image_format *vc_fmt = + vc4_get_vc_image_fmt(drm_fmt->format); +@@ -552,6 +552,7 @@ static int vc4_plane_to_mb(struct drm_pl + state->normalized_zpos : -127; + mb->plane.num_planes = num_planes; + mb->plane.is_vu = vc_fmt->is_vu; ++ bo = drm_fb_dma_get_gem_obj(fb, 0); + mb->plane.planes[0] = bo->dma_addr + fb->offsets[0]; + + rotation = drm_rotation_simplify(state->rotation, +@@ -572,11 +573,14 @@ static int vc4_plane_to_mb(struct drm_pl + /* Makes assumptions on the stride for the chroma planes as we + * can't easily plumb in non-standard pitches. + */ ++ bo = drm_fb_dma_get_gem_obj(fb, 1); + mb->plane.planes[1] = bo->dma_addr + fb->offsets[1]; +- if (num_planes > 2) ++ if (num_planes > 2) { ++ bo = drm_fb_dma_get_gem_obj(fb, 2); + mb->plane.planes[2] = bo->dma_addr + fb->offsets[2]; +- else ++ } else { + mb->plane.planes[2] = 0; ++ } + + /* Special case the YUV420 with U and V as line interleaved + * planes as we have special handling for that case. diff --git a/target/linux/bcm27xx/patches-6.1/950-0931-drm-vc4-hdmi-Enable-the-audio-clock.patch b/target/linux/bcm27xx/patches-6.1/950-0931-drm-vc4-hdmi-Enable-the-audio-clock.patch new file mode 100644 index 0000000000..f228dca9d5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0931-drm-vc4-hdmi-Enable-the-audio-clock.patch @@ -0,0 +1,39 @@ +From 0da58dfbd2cc2cfa14a629787b9ba6fa10b5f666 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 29 Mar 2023 15:26:52 +0100 +Subject: [PATCH] drm/vc4: hdmi: Enable the audio clock + +The audio clock is used by the HDMI controller driver and we were using +it to get its audio rate and compute the dividers needed to reach a +given audio sample rate. + +However, we were never enabling it, which was resulting in lockups on +the BCM2712. + +Fixes: 632ee3aa8786 ("drm/vc4: hdmi: Add audio-related callbacks") +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -3625,6 +3625,7 @@ static int vc4_hdmi_runtime_suspend(stru + { + struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + ++ clk_disable_unprepare(vc4_hdmi->audio_clock); + clk_disable_unprepare(vc4_hdmi->hsm_rpm_clock); + + return 0; +@@ -3666,6 +3667,10 @@ static int vc4_hdmi_runtime_resume(struc + goto err_disable_clk; + } + ++ ret = clk_prepare_enable(vc4_hdmi->audio_clock); ++ if (ret) ++ goto err_disable_clk; ++ + if (vc4_hdmi->variant->reset) + vc4_hdmi->variant->reset(vc4_hdmi); + diff --git a/target/linux/bcm27xx/patches-6.1/950-0932-drm-vc4-hdmi-Warn-if-writing-to-an-unknown-HDMI-regi.patch b/target/linux/bcm27xx/patches-6.1/950-0932-drm-vc4-hdmi-Warn-if-writing-to-an-unknown-HDMI-regi.patch new file mode 100644 index 0000000000..fa6a399dae --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0932-drm-vc4-hdmi-Warn-if-writing-to-an-unknown-HDMI-regi.patch @@ -0,0 +1,31 @@ +From cdbebb3a92aca7327c88c6dc6ef5d4cd470d49fc Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 23 Feb 2023 19:44:32 +0100 +Subject: [PATCH] drm/vc4: hdmi: Warn if writing to an unknown HDMI register + +The VC4 HDMI driver has a bunch of accessors to read from a register. +The read accessor was warning when accessing an unknown register, but +the write one was just returning silently. + +Let's make sure we warn also when writing to an unknown register. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +@@ -498,8 +498,11 @@ static inline void vc4_hdmi_write(struct + + field = &variant->registers[reg]; + base = __vc4_hdmi_get_field_base(hdmi, field->reg); +- if (!base) ++ if (!base) { ++ dev_warn(&hdmi->pdev->dev, ++ "Unknown register ID %u\n", reg); + return; ++ } + + writel(value, base + field->offset); + } diff --git a/target/linux/bcm27xx/patches-6.1/950-0933-drm-vc4-hvs-More-logging-for-dlist-generation.patch b/target/linux/bcm27xx/patches-6.1/950-0933-drm-vc4-hvs-More-logging-for-dlist-generation.patch new file mode 100644 index 0000000000..dee2fc0d66 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0933-drm-vc4-hvs-More-logging-for-dlist-generation.patch @@ -0,0 +1,41 @@ +From 4ebd8283403daf5507e5aafb42fe3e4c7612eb14 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 22 Mar 2023 09:51:51 +0100 +Subject: [PATCH] drm/vc4: hvs: More logging for dlist generation + +DLIST generation can get pretty tricky and there's not a lot of debug in +the driver to help. Let's add a few more to track the generated DLIST +size. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -826,11 +826,22 @@ int vc4_hvs_atomic_check(struct drm_crtc + if (hweight32(crtc_state->connector_mask) > 1) + return -EINVAL; + +- drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) +- dlist_count += vc4_plane_dlist_size(plane_state); ++ drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) { ++ u32 plane_dlist_count = vc4_plane_dlist_size(plane_state); ++ ++ drm_dbg_driver(dev, "[CRTC:%d:%s] Found [PLANE:%d:%s] with DLIST size: %u\n", ++ crtc->base.id, crtc->name, ++ plane->base.id, plane->name, ++ plane_dlist_count); ++ ++ dlist_count += plane_dlist_count; ++ } + + dlist_count++; /* Account for SCALER_CTL0_END. */ + ++ drm_dbg_driver(dev, "[CRTC:%d:%s] Allocating DLIST block with size: %u\n", ++ crtc->base.id, crtc->name, dlist_count); ++ + alloc = vc4_hvs_alloc_dlist_entry(vc4->hvs, vc4_state->assigned_channel, dlist_count); + if (IS_ERR(alloc)) + return PTR_ERR(alloc); diff --git a/target/linux/bcm27xx/patches-6.1/950-0934-drm-vc4-hvs-Print-error-if-we-fail-an-allocation.patch b/target/linux/bcm27xx/patches-6.1/950-0934-drm-vc4-hvs-Print-error-if-we-fail-an-allocation.patch new file mode 100644 index 0000000000..7c7bbb4822 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0934-drm-vc4-hvs-Print-error-if-we-fail-an-allocation.patch @@ -0,0 +1,66 @@ +From c0af63193bd307f281211e7fb32a02a52c2869b2 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 22 Mar 2023 09:53:17 +0100 +Subject: [PATCH] drm/vc4: hvs: Print error if we fail an allocation + +We need to allocate a few additional structures when checking our +atomic_state, especially related to hardware SRAM that will hold the +plane descriptors (DLIST) and the current line context (LBM) during +composition. + +Since those allocation can fail, let's add some error message in that +case to help debug what goes wrong. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 6 +++++- + drivers/gpu/drm/vc4/vc4_plane.c | 7 +++++-- + 2 files changed, 10 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -441,6 +441,8 @@ vc4_hvs_alloc_dlist_entry(struct vc4_hvs + unsigned int channel, + size_t dlist_count) + { ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *dev = &vc4->base; + struct vc4_hvs_dlist_allocation *alloc; + unsigned long flags; + int ret; +@@ -458,8 +460,10 @@ vc4_hvs_alloc_dlist_entry(struct vc4_hvs + ret = drm_mm_insert_node(&hvs->dlist_mm, &alloc->mm_node, + dlist_count); + spin_unlock_irqrestore(&hvs->mm_lock, flags); +- if (ret) ++ if (ret) { ++ drm_err(dev, "Failed to allocate DLIST entry: %d\n", ret); + return ERR_PTR(ret); ++ } + + alloc->channel = channel; + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -733,7 +733,8 @@ static void vc4_plane_calc_load(struct d + + static int vc4_plane_allocate_lbm(struct drm_plane_state *state) + { +- struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); ++ struct drm_device *drm = state->plane->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + unsigned long irqflags; + u32 lbm_size; +@@ -759,8 +760,10 @@ static int vc4_plane_allocate_lbm(struct + 0, 0); + spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); + +- if (ret) ++ if (ret) { ++ drm_err(drm, "Failed to allocate LBM entry: %d\n", ret); + return ret; ++ } + } else { + WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); + } diff --git a/target/linux/bcm27xx/patches-6.1/950-0935-drm-vc4-plane-Add-more-debugging-for-LBM-allocation.patch b/target/linux/bcm27xx/patches-6.1/950-0935-drm-vc4-plane-Add-more-debugging-for-LBM-allocation.patch new file mode 100644 index 0000000000..d8d68e79aa --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0935-drm-vc4-plane-Add-more-debugging-for-LBM-allocation.patch @@ -0,0 +1,36 @@ +From 164f7e94da446984f275be1c082b93243beadfba Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 22 Mar 2023 16:17:57 +0100 +Subject: [PATCH] drm/vc4: plane: Add more debugging for LBM allocation + +LBM allocations need a different size depending on the line length, +format, etc. + +This can get tricky, and fail. Let's add some more prints to ease the +debugging when it does. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_plane.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -735,6 +735,7 @@ static int vc4_plane_allocate_lbm(struct + { + struct drm_device *drm = state->plane->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct drm_plane *plane = state->plane; + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + unsigned long irqflags; + u32 lbm_size; +@@ -743,6 +744,9 @@ static int vc4_plane_allocate_lbm(struct + if (!lbm_size) + return 0; + ++ drm_dbg_driver(drm, "[PLANE:%d:%s] LBM Allocation Size: %u\n", ++ plane->base.id, plane->name, lbm_size); ++ + if (WARN_ON(!vc4_state->lbm_offset)) + return -EINVAL; + diff --git a/target/linux/bcm27xx/patches-6.1/950-0936-drm-vc4-plane-Use-return-variable-in-atomic_check.patch b/target/linux/bcm27xx/patches-6.1/950-0936-drm-vc4-plane-Use-return-variable-in-atomic_check.patch new file mode 100644 index 0000000000..220245c351 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0936-drm-vc4-plane-Use-return-variable-in-atomic_check.patch @@ -0,0 +1,31 @@ +From 950394a39f659746e5933cbc203a8bedef8246b7 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 14:26:44 +0100 +Subject: [PATCH] drm/vc4: plane: Use return variable in atomic_check + +The vc4_plane_atomic_check() directly returns the result of the final +function it calls. + +Using the already defined ret variable to check its content on error, +and a separate return 0 on success, makes it easier to extend. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_plane.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1378,7 +1378,11 @@ static int vc4_plane_atomic_check(struct + if (ret) + return ret; + +- return vc4_plane_allocate_lbm(new_plane_state); ++ ret = vc4_plane_allocate_lbm(new_plane_state); ++ if (ret) ++ return ret; ++ ++ return 0; + } + + static void vc4_plane_atomic_update(struct drm_plane *plane, diff --git a/target/linux/bcm27xx/patches-6.1/950-0937-drm-vc4-crtc-Move-assigned_channel-to-a-variable.patch b/target/linux/bcm27xx/patches-6.1/950-0937-drm-vc4-crtc-Move-assigned_channel-to-a-variable.patch new file mode 100644 index 0000000000..3476f548c4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0937-drm-vc4-crtc-Move-assigned_channel-to-a-variable.patch @@ -0,0 +1,47 @@ +From f3c6acc345113c57011f2b1c8421e6cf78f0bc30 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:39:13 +0100 +Subject: [PATCH] drm/vc4: crtc: Move assigned_channel to a variable + +We access multiple times the vc4_crtc_state->assigned_channel variable +in the vc4_crtc_get_scanout_position() function, so let's store it in a +local variable. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -104,6 +104,7 @@ static bool vc4_crtc_get_scanout_positio + struct vc4_hvs *hvs = vc4->hvs; + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); ++ unsigned int channel = vc4_crtc_state->assigned_channel; + unsigned int cob_size; + u32 val; + int fifo_lines; +@@ -120,7 +121,7 @@ static bool vc4_crtc_get_scanout_positio + * Read vertical scanline which is currently composed for our + * pixelvalve by the HVS, and also the scaler status. + */ +- val = HVS_READ(SCALER_DISPSTATX(vc4_crtc_state->assigned_channel)); ++ val = HVS_READ(SCALER_DISPSTATX(channel)); + + /* Get optional system timestamp after query. */ + if (etime) +@@ -136,11 +137,11 @@ static bool vc4_crtc_get_scanout_positio + *vpos /= 2; + + /* Use hpos to correct for field offset in interlaced mode. */ +- if (vc4_hvs_get_fifo_frame_count(hvs, vc4_crtc_state->assigned_channel) % 2) ++ if (vc4_hvs_get_fifo_frame_count(hvs, channel) % 2) + *hpos += mode->crtc_htotal / 2; + } + +- cob_size = vc4_crtc_get_cob_allocation(vc4, vc4_crtc_state->assigned_channel); ++ cob_size = vc4_crtc_get_cob_allocation(vc4, channel); + /* This is the offset we need for translating hvs -> pv scanout pos. */ + fifo_lines = cob_size / mode->crtc_hdisplay; + diff --git a/target/linux/bcm27xx/patches-6.1/950-0938-drm-vc4-Introduce-generation-number-enum.patch b/target/linux/bcm27xx/patches-6.1/950-0938-drm-vc4-Introduce-generation-number-enum.patch new file mode 100644 index 0000000000..9314c797a0 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0938-drm-vc4-Introduce-generation-number-enum.patch @@ -0,0 +1,1029 @@ +From fa2571d625bb53b642cd9f29a7cfc3434e1cf576 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:07:36 +0100 +Subject: [PATCH] drm/vc4: Introduce generation number enum + +With the introduction of the BCM2712 support, we will get yet another +generation of display engine to support. + +The binary check of whether it's VC5 or not thus doesn't work anymore, +especially since some parts of the driver will have changed with BCM2711, +and some others with BCM2712. + +Let's introduce an enum to store the generation the driver is running +on, which should provide more flexibility. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.c | 12 +++--- + drivers/gpu/drm/vc4/vc4_bo.c | 28 ++++++------ + drivers/gpu/drm/vc4/vc4_crtc.c | 14 +++--- + drivers/gpu/drm/vc4/vc4_drv.c | 22 ++++++---- + drivers/gpu/drm/vc4/vc4_drv.h | 7 ++- + drivers/gpu/drm/vc4/vc4_gem.c | 24 +++++------ + drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- + drivers/gpu/drm/vc4/vc4_hvs.c | 50 ++++++++++++---------- + drivers/gpu/drm/vc4/vc4_irq.c | 10 ++--- + drivers/gpu/drm/vc4/vc4_kms.c | 14 +++--- + drivers/gpu/drm/vc4/vc4_perfmon.c | 20 ++++----- + drivers/gpu/drm/vc4/vc4_plane.c | 12 +++--- + drivers/gpu/drm/vc4/vc4_render_cl.c | 2 +- + drivers/gpu/drm/vc4/vc4_v3d.c | 10 ++--- + drivers/gpu/drm/vc4/vc4_validate.c | 8 ++-- + drivers/gpu/drm/vc4/vc4_validate_shaders.c | 2 +- + 16 files changed, 126 insertions(+), 111 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c +@@ -153,11 +153,11 @@ static int __build_mock(struct kunit *te + return 0; + } + +-static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5) ++static struct vc4_dev *__mock_device(struct kunit *test, enum vc4_gen gen) + { + struct drm_device *drm; +- const struct drm_driver *drv = is_vc5 ? &vc5_drm_driver : &vc4_drm_driver; +- const struct vc4_mock_desc *desc = is_vc5 ? &vc5_mock : &vc4_mock; ++ const struct drm_driver *drv = (gen == VC4_GEN_5) ? &vc5_drm_driver : &vc4_drm_driver; ++ const struct vc4_mock_desc *desc = (gen == VC4_GEN_5) ? &vc5_mock : &vc4_mock; + struct vc4_dev *vc4; + struct device *dev; + int ret; +@@ -171,7 +171,7 @@ static struct vc4_dev *__mock_device(str + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4); + + vc4->dev = dev; +- vc4->is_vc5 = is_vc5; ++ vc4->gen = gen; + + vc4->hvs = __vc4_hvs_alloc(vc4, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4->hvs); +@@ -191,10 +191,10 @@ static struct vc4_dev *__mock_device(str + + struct vc4_dev *vc4_mock_device(struct kunit *test) + { +- return __mock_device(test, false); ++ return __mock_device(test, VC4_GEN_4); + } + + struct vc4_dev *vc5_mock_device(struct kunit *test) + { +- return __mock_device(test, true); ++ return __mock_device(test, VC4_GEN_5); + } +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -251,7 +251,7 @@ void vc4_bo_add_to_purgeable_pool(struct + { + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + mutex_lock(&vc4->purgeable.lock); +@@ -265,7 +265,7 @@ static void vc4_bo_remove_from_purgeable + { + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + /* list_del_init() is used here because the caller might release +@@ -396,7 +396,7 @@ struct drm_gem_object *vc4_create_object + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return ERR_PTR(-ENODEV); + + bo = kzalloc(sizeof(*bo), GFP_KERNEL); +@@ -427,7 +427,7 @@ struct vc4_bo *vc4_bo_create(struct drm_ + struct drm_gem_dma_object *dma_obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return ERR_PTR(-ENODEV); + + if (size == 0) +@@ -496,7 +496,7 @@ int vc4_bo_dumb_create(struct drm_file * + struct vc4_bo *bo = NULL; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + ret = vc4_dumb_fixup_args(args); +@@ -622,7 +622,7 @@ int vc4_bo_inc_usecnt(struct vc4_bo *bo) + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + /* Fast path: if the BO is already retained by someone, no need to +@@ -661,7 +661,7 @@ void vc4_bo_dec_usecnt(struct vc4_bo *bo + { + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + /* Fast path: if the BO is still retained by someone, no need to test +@@ -783,7 +783,7 @@ int vc4_create_bo_ioctl(struct drm_devic + struct vc4_bo *bo = NULL; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + ret = vc4_grab_bin_bo(vc4, vc4file); +@@ -813,7 +813,7 @@ int vc4_mmap_bo_ioctl(struct drm_device + struct drm_vc4_mmap_bo *args = data; + struct drm_gem_object *gem_obj; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + gem_obj = drm_gem_object_lookup(file_priv, args->handle); +@@ -839,7 +839,7 @@ vc4_create_shader_bo_ioctl(struct drm_de + struct vc4_bo *bo = NULL; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (args->size == 0) +@@ -918,7 +918,7 @@ int vc4_set_tiling_ioctl(struct drm_devi + struct vc4_bo *bo; + bool t_format; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (args->flags != 0) +@@ -964,7 +964,7 @@ int vc4_get_tiling_ioctl(struct drm_devi + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (args->flags != 0 || args->modifier != 0) +@@ -1011,7 +1011,7 @@ int vc4_bo_cache_init(struct drm_device + int ret; + int i; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + /* Create the initial set of BO labels that the kernel will +@@ -1075,7 +1075,7 @@ int vc4_label_bo_ioctl(struct drm_device + struct drm_gem_object *gem_obj; + int ret = 0, label; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (!args->len) +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -263,7 +263,7 @@ static u32 vc4_get_fifo_full_level(struc + * Removing 1 from the FIFO full level however + * seems to completely remove that issue. + */ +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX - 1; + + return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX; +@@ -445,7 +445,7 @@ static void vc4_crtc_config_pv(struct dr + if (is_dsi) + CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); + +- if (vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_5) + CRTC_WRITE(PV_MUX_CFG, + VC4_SET_FIELD(PV_MUX_CFG_RGB_PIXEL_MUX_MODE_NO_SWAP, + PV_MUX_CFG_RGB_PIXEL_MUX_MODE)); +@@ -936,7 +936,7 @@ static int vc4_async_set_fence_cb(struct + struct dma_fence *fence; + int ret; + +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + struct vc4_bo *bo = to_vc4_bo(&dma_bo->base); + + return vc4_queue_seqno_cb(dev, &flip_state->cb.seqno, bo->seqno, +@@ -1023,7 +1023,7 @@ static int vc4_async_page_flip(struct dr + struct vc4_bo *bo = to_vc4_bo(&dma_bo->base); + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + /* +@@ -1066,7 +1066,7 @@ int vc4_page_flip(struct drm_crtc *crtc, + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_5) + return vc5_async_page_flip(crtc, fb, event, flags); + else + return vc4_async_page_flip(crtc, fb, event, flags); +@@ -1358,13 +1358,13 @@ int __vc4_crtc_init(struct drm_device *d + + drm_crtc_helper_add(crtc, crtc_helper_funcs); + +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); + drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); + } + + +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + /* We support CTM, but only for one CRTC at a time. It's therefore + * implemented as private driver state in vc4_kms, not here. + */ +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -98,7 +98,7 @@ static int vc4_get_param_ioctl(struct dr + if (args->pad != 0) + return -EINVAL; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (!vc4->v3d) +@@ -147,7 +147,7 @@ static int vc4_open(struct drm_device *d + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_file *vc4file; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + vc4file = kzalloc(sizeof(*vc4file), GFP_KERNEL); +@@ -165,7 +165,7 @@ static void vc4_close(struct drm_device + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_file *vc4file = file->driver_priv; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + if (vc4file->bin_bo_used) +@@ -305,13 +305,17 @@ static int vc4_drm_bind(struct device *d + struct vc4_dev *vc4; + struct device_node *node; + struct drm_crtc *crtc; +- bool is_vc5; ++ enum vc4_gen gen; + int ret = 0; + + dev->coherent_dma_mask = DMA_BIT_MASK(32); + +- is_vc5 = of_device_is_compatible(dev->of_node, "brcm,bcm2711-vc5"); +- if (is_vc5) ++ if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-vc5")) ++ gen = VC4_GEN_5; ++ else ++ gen = VC4_GEN_4; ++ ++ if (gen == VC4_GEN_5) + driver = &vc5_drm_driver; + else + driver = &vc4_drm_driver; +@@ -329,14 +333,14 @@ static int vc4_drm_bind(struct device *d + vc4 = devm_drm_dev_alloc(dev, driver, struct vc4_dev, base); + if (IS_ERR(vc4)) + return PTR_ERR(vc4); +- vc4->is_vc5 = is_vc5; ++ vc4->gen = gen; + vc4->dev = dev; + + drm = &vc4->base; + platform_set_drvdata(pdev, drm); + INIT_LIST_HEAD(&vc4->debugfs_list); + +- if (!is_vc5) { ++ if (gen == VC4_GEN_4) { + ret = drmm_mutex_init(drm, &vc4->bin_bo_lock); + if (ret) + return ret; +@@ -350,7 +354,7 @@ static int vc4_drm_bind(struct device *d + if (ret) + return ret; + +- if (!is_vc5) { ++ if (gen == VC4_GEN_4) { + ret = vc4_gem_init(drm); + if (ret) + return ret; +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -80,11 +80,16 @@ struct vc4_perfmon { + u64 counters[]; + }; + ++enum vc4_gen { ++ VC4_GEN_4, ++ VC4_GEN_5, ++}; ++ + struct vc4_dev { + struct drm_device base; + struct device *dev; + +- bool is_vc5; ++ enum vc4_gen gen; + + unsigned int irq; + +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -76,7 +76,7 @@ vc4_get_hang_state_ioctl(struct drm_devi + u32 i; + int ret = 0; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -389,7 +389,7 @@ vc4_wait_for_seqno(struct drm_device *de + unsigned long timeout_expire; + DEFINE_WAIT(wait); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (vc4->finished_seqno >= seqno) +@@ -474,7 +474,7 @@ vc4_submit_next_bin_job(struct drm_devic + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_exec_info *exec; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + again: +@@ -522,7 +522,7 @@ vc4_submit_next_render_job(struct drm_de + if (!exec) + return; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + /* A previous RCL may have written to one of our textures, and +@@ -543,7 +543,7 @@ vc4_move_job_to_render(struct drm_device + struct vc4_dev *vc4 = to_vc4_dev(dev); + bool was_empty = list_empty(&vc4->render_job_list); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + list_move_tail(&exec->head, &vc4->render_job_list); +@@ -1012,7 +1012,7 @@ vc4_job_handle_completed(struct vc4_dev + unsigned long irqflags; + struct vc4_seqno_cb *cb, *cb_temp; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + spin_lock_irqsave(&vc4->job_lock, irqflags); +@@ -1051,7 +1051,7 @@ int vc4_queue_seqno_cb(struct drm_device + struct vc4_dev *vc4 = to_vc4_dev(dev); + unsigned long irqflags; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + cb->func = func; +@@ -1107,7 +1107,7 @@ vc4_wait_seqno_ioctl(struct drm_device * + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_vc4_wait_seqno *args = data; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + return vc4_wait_for_seqno_ioctl_helper(dev, args->seqno, +@@ -1124,7 +1124,7 @@ vc4_wait_bo_ioctl(struct drm_device *dev + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (args->pad != 0) +@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *d + args->shader_rec_size, + args->bo_handle_count); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -1310,7 +1310,7 @@ int vc4_gem_init(struct drm_device *dev) + struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + vc4->dma_fence_context = dma_fence_context_alloc(1); +@@ -1369,7 +1369,7 @@ int vc4_gem_madvise_ioctl(struct drm_dev + struct vc4_bo *bo; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + switch (args->madv) { +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -2614,7 +2614,7 @@ static int vc4_hdmi_audio_prepare(struct + VC4_HDMI_AUDIO_PACKET_CEA_MASK); + + /* Set the MAI threshold */ +- if (vc4->is_vc5) ++ if (vc4->gen >= VC4_GEN_5) + HDMI_WRITE(HDMI_MAI_THR, + VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) | + VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) | +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -416,7 +416,7 @@ static void vc4_hvs_irq_enable_eof(const + unsigned int channel) + { + struct vc4_dev *vc4 = hvs->vc4; +- u32 irq_mask = vc4->is_vc5 ? ++ u32 irq_mask = vc4->gen == VC4_GEN_5 ? + SCALER5_DISPCTRL_DSPEIEOF(channel) : + SCALER_DISPCTRL_DSPEIEOF(channel); + +@@ -428,7 +428,7 @@ static void vc4_hvs_irq_clear_eof(const + unsigned int channel) + { + struct vc4_dev *vc4 = hvs->vc4; +- u32 irq_mask = vc4->is_vc5 ? ++ u32 irq_mask = vc4->gen == VC4_GEN_5 ? + SCALER5_DISPCTRL_DSPEIEOF(channel) : + SCALER_DISPCTRL_DSPEIEOF(channel); + +@@ -620,7 +620,7 @@ int vc4_hvs_get_fifo_from_output(struct + u32 reg; + int ret; + +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + return output; + + /* +@@ -701,7 +701,7 @@ static int vc4_hvs_init_channel(struct v + dispctrl = SCALER_DISPCTRLX_ENABLE; + dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan)); + +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + dispctrl |= VC4_SET_FIELD(mode->hdisplay, + SCALER_DISPCTRLX_WIDTH) | + VC4_SET_FIELD(mode->vdisplay, +@@ -732,7 +732,7 @@ static int vc4_hvs_init_channel(struct v + /* Reload the LUT, since the SRAMs would have been disabled if + * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once. + */ +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + vc4_hvs_lut_load(hvs, vc4_crtc); + else + vc5_hvs_lut_load(hvs, vc4_crtc); +@@ -782,7 +782,7 @@ static int vc4_hvs_gamma_check(struct dr + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + return 0; + + if (!crtc_state->color_mgmt_changed) +@@ -1036,7 +1036,7 @@ void vc4_hvs_atomic_flush(struct drm_crt + u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(channel)); + + if (crtc->state->gamma_lut) { +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + vc4_hvs_update_gamma_lut(hvs, vc4_crtc); + dispbkgndx |= SCALER_DISPBKGND_GAMMA; + } else { +@@ -1053,7 +1053,7 @@ void vc4_hvs_atomic_flush(struct drm_crt + * should already be disabling/enabling the pipeline + * when gamma changes. + */ +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; + } + HVS_WRITE(SCALER_DISPBKGNDX(channel), dispbkgndx); +@@ -1069,7 +1069,8 @@ void vc4_hvs_atomic_flush(struct drm_crt + + void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel) + { +- struct drm_device *drm = &hvs->vc4->base; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; + u32 dispctrl; + int idx; + +@@ -1077,8 +1078,9 @@ void vc4_hvs_mask_underrun(struct vc4_hv + return; + + dispctrl = HVS_READ(SCALER_DISPCTRL); +- dispctrl &= ~(hvs->vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) : +- SCALER_DISPCTRL_DSPEISLUR(channel)); ++ dispctrl &= ~((vc4->gen == VC4_GEN_5) ? ++ SCALER5_DISPCTRL_DSPEISLUR(channel) : ++ SCALER_DISPCTRL_DSPEISLUR(channel)); + + HVS_WRITE(SCALER_DISPCTRL, dispctrl); + +@@ -1087,7 +1089,8 @@ void vc4_hvs_mask_underrun(struct vc4_hv + + void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel) + { +- struct drm_device *drm = &hvs->vc4->base; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; + u32 dispctrl; + int idx; + +@@ -1095,8 +1098,9 @@ void vc4_hvs_unmask_underrun(struct vc4_ + return; + + dispctrl = HVS_READ(SCALER_DISPCTRL); +- dispctrl |= (hvs->vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) : +- SCALER_DISPCTRL_DSPEISLUR(channel)); ++ dispctrl |= ((vc4->gen == VC4_GEN_5) ? ++ SCALER5_DISPCTRL_DSPEISLUR(channel) : ++ SCALER_DISPCTRL_DSPEISLUR(channel)); + + HVS_WRITE(SCALER_DISPSTAT, + SCALER_DISPSTAT_EUFLOW(channel)); +@@ -1139,8 +1143,10 @@ static irqreturn_t vc4_hvs_irq_handler(i + control = HVS_READ(SCALER_DISPCTRL); + + for (channel = 0; channel < SCALER_CHANNELS_COUNT; channel++) { +- dspeislur = vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) : +- SCALER_DISPCTRL_DSPEISLUR(channel); ++ dspeislur = (vc4->gen == VC4_GEN_5) ? ++ SCALER5_DISPCTRL_DSPEISLUR(channel) : ++ SCALER_DISPCTRL_DSPEISLUR(channel); ++ + /* Interrupt masking is not always honored, so check it here. */ + if (status & SCALER_DISPSTAT_EUFLOW(channel) && + control & dspeislur) { +@@ -1177,7 +1183,7 @@ int vc4_hvs_debugfs_init(struct drm_mino + if (!vc4->hvs) + return -ENODEV; + +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR, + minor->debugfs_root, + &vc4->load_tracker_enabled); +@@ -1235,7 +1241,7 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v + * between planes when they don't overlap on the screen, but + * for now we just allocate globally. + */ +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + /* 48k words of 2x12-bit pixels */ + drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024); + else +@@ -1269,7 +1275,7 @@ static int vc4_hvs_bind(struct device *d + hvs->regset.regs = hvs_regs; + hvs->regset.nregs = ARRAY_SIZE(hvs_regs); + +- if (vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_5) { + struct rpi_firmware *firmware; + struct device_node *node; + unsigned int max_rate; +@@ -1307,7 +1313,7 @@ static int vc4_hvs_bind(struct device *d + } + } + +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + hvs->dlist = hvs->regs + SCALER_DLIST_START; + else + hvs->dlist = hvs->regs + SCALER5_DLIST_START; +@@ -1348,7 +1354,7 @@ static int vc4_hvs_bind(struct device *d + SCALER_DISPCTRL_DISPEIRQ(1) | + SCALER_DISPCTRL_DISPEIRQ(2); + +- if (!vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_4) + dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ | + SCALER_DISPCTRL_SLVWREIRQ | + SCALER_DISPCTRL_SLVRDEIRQ | +@@ -1403,7 +1409,7 @@ static int vc4_hvs_bind(struct device *d + + /* Recompute Composite Output Buffer (COB) allocations for the displays + */ +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + /* The COB is 20736 pixels, or just over 10 lines at 2048 wide. + * The bottom 2048 pixels are full 32bpp RGBA (intended for the + * TXP composing RGBA to memory), whilst the remainder are only +--- a/drivers/gpu/drm/vc4/vc4_irq.c ++++ b/drivers/gpu/drm/vc4/vc4_irq.c +@@ -265,7 +265,7 @@ vc4_irq_enable(struct drm_device *dev) + { + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + if (!vc4->v3d) +@@ -282,7 +282,7 @@ vc4_irq_disable(struct drm_device *dev) + { + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + if (!vc4->v3d) +@@ -305,7 +305,7 @@ int vc4_irq_install(struct drm_device *d + struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (irq == IRQ_NOTCONNECTED) +@@ -326,7 +326,7 @@ void vc4_irq_uninstall(struct drm_device + { + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + vc4_irq_disable(dev); +@@ -339,7 +339,7 @@ void vc4_irq_reset(struct drm_device *de + struct vc4_dev *vc4 = to_vc4_dev(dev); + unsigned long irqflags; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + /* Acknowledge any stale IRQs. */ +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -378,7 +378,7 @@ static void vc4_atomic_commit_tail(struc + old_hvs_state->fifo_state[channel].pending_commit = NULL; + } + +- if (vc4->is_vc5 && !vc4->firmware_kms) { ++ if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) { + unsigned long state_rate = max(old_hvs_state->core_clock_rate, + new_hvs_state->core_clock_rate); + unsigned long core_rate = clamp_t(unsigned long, state_rate, +@@ -398,7 +398,7 @@ static void vc4_atomic_commit_tail(struc + vc4_ctm_commit(vc4, state); + + if (!vc4->firmware_kms) { +- if (vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_5) + vc5_hvs_pv_muxing_commit(vc4, state); + else + vc4_hvs_pv_muxing_commit(vc4, state); +@@ -417,7 +417,7 @@ static void vc4_atomic_commit_tail(struc + + drm_atomic_helper_cleanup_planes(dev, state); + +- if (vc4->is_vc5 && !vc4->firmware_kms) { ++ if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) { + unsigned long core_rate = min_t(unsigned long, + hvs->max_core_rate, + new_hvs_state->core_clock_rate); +@@ -482,7 +482,7 @@ static struct drm_framebuffer *vc4_fb_cr + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_mode_fb_cmd2 mode_cmd_local; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return ERR_PTR(-ENODEV); + + /* If the user didn't specify a modifier, use the +@@ -1065,7 +1065,7 @@ int vc4_kms_load(struct drm_device *dev) + * the BCM2711, but the load tracker computations are used for + * the core clock rate calculation. + */ +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + /* Start with the load tracker enabled. Can be + * disabled through the debugfs load_tracker file. + */ +@@ -1081,7 +1081,7 @@ int vc4_kms_load(struct drm_device *dev) + return ret; + } + +- if (vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_5) { + dev->mode_config.max_width = 7680; + dev->mode_config.max_height = 7680; + } else { +@@ -1089,7 +1089,7 @@ int vc4_kms_load(struct drm_device *dev) + dev->mode_config.max_height = 2048; + } + +- dev->mode_config.funcs = vc4->is_vc5 ? &vc5_mode_funcs : &vc4_mode_funcs; ++ dev->mode_config.funcs = (vc4->gen > VC4_GEN_4) ? &vc5_mode_funcs : &vc4_mode_funcs; + dev->mode_config.helper_private = &vc4_mode_config_helpers; + dev->mode_config.preferred_depth = 24; + dev->mode_config.async_page_flip = true; +--- a/drivers/gpu/drm/vc4/vc4_perfmon.c ++++ b/drivers/gpu/drm/vc4/vc4_perfmon.c +@@ -23,7 +23,7 @@ void vc4_perfmon_get(struct vc4_perfmon + return; + + vc4 = perfmon->dev; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + refcount_inc(&perfmon->refcnt); +@@ -37,7 +37,7 @@ void vc4_perfmon_put(struct vc4_perfmon + return; + + vc4 = perfmon->dev; +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + if (refcount_dec_and_test(&perfmon->refcnt)) +@@ -49,7 +49,7 @@ void vc4_perfmon_start(struct vc4_dev *v + unsigned int i; + u32 mask; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + if (WARN_ON_ONCE(!perfmon || vc4->active_perfmon)) +@@ -69,7 +69,7 @@ void vc4_perfmon_stop(struct vc4_dev *vc + { + unsigned int i; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + if (WARN_ON_ONCE(!vc4->active_perfmon || +@@ -90,7 +90,7 @@ struct vc4_perfmon *vc4_perfmon_find(str + struct vc4_dev *vc4 = vc4file->dev; + struct vc4_perfmon *perfmon; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return NULL; + + mutex_lock(&vc4file->perfmon.lock); +@@ -105,7 +105,7 @@ void vc4_perfmon_open_file(struct vc4_fi + { + struct vc4_dev *vc4 = vc4file->dev; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + mutex_init(&vc4file->perfmon.lock); +@@ -126,7 +126,7 @@ void vc4_perfmon_close_file(struct vc4_f + { + struct vc4_dev *vc4 = vc4file->dev; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + mutex_lock(&vc4file->perfmon.lock); +@@ -146,7 +146,7 @@ int vc4_perfmon_create_ioctl(struct drm_ + unsigned int i; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -200,7 +200,7 @@ int vc4_perfmon_destroy_ioctl(struct drm + struct drm_vc4_perfmon_destroy *req = data; + struct vc4_perfmon *perfmon; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -228,7 +228,7 @@ int vc4_perfmon_get_values_ioctl(struct + struct vc4_perfmon *perfmon; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (!vc4->v3d) { +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -633,10 +633,10 @@ static u32 vc4_lbm_size(struct drm_plane + } + + /* Align it to 64 or 128 (hvs5) bytes */ +- lbm = roundup(lbm, vc4->is_vc5 ? 128 : 64); ++ lbm = roundup(lbm, vc4->gen == VC4_GEN_5 ? 128 : 64); + + /* Each "word" of the LBM memory contains 2 or 4 (hvs5) pixels */ +- lbm /= vc4->is_vc5 ? 4 : 2; ++ lbm /= vc4->gen == VC4_GEN_5 ? 4 : 2; + + return lbm; + } +@@ -760,7 +760,7 @@ static int vc4_plane_allocate_lbm(struct + ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, + &vc4_state->lbm, + lbm_size, +- vc4->is_vc5 ? 64 : 32, ++ vc4->gen == VC4_GEN_5 ? 64 : 32, + 0, 0); + spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); + +@@ -1141,7 +1141,7 @@ static int vc4_plane_mode_set(struct drm + mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE && + fb->format->has_alpha; + +- if (!vc4->is_vc5) { ++ if (vc4->gen == VC4_GEN_4) { + /* Control word */ + vc4_dlist_write(vc4_state, + SCALER_CTL0_VALID | +@@ -1717,7 +1717,7 @@ struct drm_plane *vc4_plane_init(struct + }; + + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { +- if (!hvs_formats[i].hvs5_only || vc4->is_vc5) { ++ if (!hvs_formats[i].hvs5_only || vc4->gen == VC4_GEN_5) { + formats[num_formats] = hvs_formats[i].drm; + num_formats++; + } +@@ -1732,7 +1732,7 @@ struct drm_plane *vc4_plane_init(struct + return ERR_CAST(vc4_plane); + plane = &vc4_plane->base; + +- if (vc4->is_vc5) ++ if (vc4->gen == VC4_GEN_5) + drm_plane_helper_add(plane, &vc5_plane_helper_funcs); + else + drm_plane_helper_add(plane, &vc4_plane_helper_funcs); +--- a/drivers/gpu/drm/vc4/vc4_render_cl.c ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -599,7 +599,7 @@ int vc4_get_rcl(struct drm_device *dev, + bool has_bin = args->bin_cl_size != 0; + int ret; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + if (args->min_x_tile > args->max_x_tile || +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -127,7 +127,7 @@ static int vc4_v3d_debugfs_ident(struct + int + vc4_v3d_pm_get(struct vc4_dev *vc4) + { +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + mutex_lock(&vc4->power_lock); +@@ -148,7 +148,7 @@ vc4_v3d_pm_get(struct vc4_dev *vc4) + void + vc4_v3d_pm_put(struct vc4_dev *vc4) + { +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + mutex_lock(&vc4->power_lock); +@@ -178,7 +178,7 @@ int vc4_v3d_get_bin_slot(struct vc4_dev + uint64_t seqno = 0; + struct vc4_exec_info *exec; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + try_again: +@@ -325,7 +325,7 @@ int vc4_v3d_bin_bo_get(struct vc4_dev *v + { + int ret = 0; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + mutex_lock(&vc4->bin_bo_lock); +@@ -360,7 +360,7 @@ static void bin_bo_release(struct kref * + + void vc4_v3d_bin_bo_put(struct vc4_dev *vc4) + { +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return; + + mutex_lock(&vc4->bin_bo_lock); +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -109,7 +109,7 @@ vc4_use_bo(struct vc4_exec_info *exec, u + struct drm_gem_dma_object *obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return NULL; + + if (hindex >= exec->bo_count) { +@@ -169,7 +169,7 @@ vc4_check_tex_size(struct vc4_exec_info + uint32_t utile_w = utile_width(cpp); + uint32_t utile_h = utile_height(cpp); + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return false; + + /* The shaded vertex format stores signed 12.4 fixed point +@@ -495,7 +495,7 @@ vc4_validate_bin_cl(struct drm_device *d + uint32_t dst_offset = 0; + uint32_t src_offset = 0; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + while (src_offset < len) { +@@ -942,7 +942,7 @@ vc4_validate_shader_recs(struct drm_devi + uint32_t i; + int ret = 0; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return -ENODEV; + + for (i = 0; i < exec->shader_state_count; i++) { +--- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c ++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +@@ -786,7 +786,7 @@ vc4_validate_shader(struct drm_gem_dma_o + struct vc4_validated_shader_info *validated_shader = NULL; + struct vc4_shader_validation_state validation_state; + +- if (WARN_ON_ONCE(vc4->is_vc5)) ++ if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) + return NULL; + + memset(&validation_state, 0, sizeof(validation_state)); diff --git a/target/linux/bcm27xx/patches-6.1/950-0939-drm-vc4-Make-v3d-paths-unavailable-on-any-generation.patch b/target/linux/bcm27xx/patches-6.1/950-0939-drm-vc4-Make-v3d-paths-unavailable-on-any-generation.patch new file mode 100644 index 0000000000..699db05e0c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0939-drm-vc4-Make-v3d-paths-unavailable-on-any-generation.patch @@ -0,0 +1,577 @@ +From c382ea6b0457027b6ad883ee4348e03df515a785 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:29:27 +0100 +Subject: [PATCH] drm/vc4: Make v3d paths unavailable on any generation newer + than vc4 + +The V3D IP has been separate since BCM2711, so let's make sure we issue +a WARN if we're running not only on BCM2711, but also anything newer. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_bo.c | 28 +++++++++++----------- + drivers/gpu/drm/vc4/vc4_crtc.c | 4 ++-- + drivers/gpu/drm/vc4/vc4_drv.c | 8 +++---- + drivers/gpu/drm/vc4/vc4_gem.c | 24 +++++++++---------- + drivers/gpu/drm/vc4/vc4_irq.c | 10 ++++---- + drivers/gpu/drm/vc4/vc4_kms.c | 2 +- + drivers/gpu/drm/vc4/vc4_perfmon.c | 20 ++++++++-------- + drivers/gpu/drm/vc4/vc4_render_cl.c | 2 +- + drivers/gpu/drm/vc4/vc4_v3d.c | 10 ++++---- + drivers/gpu/drm/vc4/vc4_validate.c | 8 +++---- + drivers/gpu/drm/vc4/vc4_validate_shaders.c | 2 +- + 11 files changed, 59 insertions(+), 59 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -251,7 +251,7 @@ void vc4_bo_add_to_purgeable_pool(struct + { + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + mutex_lock(&vc4->purgeable.lock); +@@ -265,7 +265,7 @@ static void vc4_bo_remove_from_purgeable + { + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + /* list_del_init() is used here because the caller might release +@@ -396,7 +396,7 @@ struct drm_gem_object *vc4_create_object + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return ERR_PTR(-ENODEV); + + bo = kzalloc(sizeof(*bo), GFP_KERNEL); +@@ -427,7 +427,7 @@ struct vc4_bo *vc4_bo_create(struct drm_ + struct drm_gem_dma_object *dma_obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return ERR_PTR(-ENODEV); + + if (size == 0) +@@ -496,7 +496,7 @@ int vc4_bo_dumb_create(struct drm_file * + struct vc4_bo *bo = NULL; + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + ret = vc4_dumb_fixup_args(args); +@@ -622,7 +622,7 @@ int vc4_bo_inc_usecnt(struct vc4_bo *bo) + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + /* Fast path: if the BO is already retained by someone, no need to +@@ -661,7 +661,7 @@ void vc4_bo_dec_usecnt(struct vc4_bo *bo + { + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + /* Fast path: if the BO is still retained by someone, no need to test +@@ -783,7 +783,7 @@ int vc4_create_bo_ioctl(struct drm_devic + struct vc4_bo *bo = NULL; + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + ret = vc4_grab_bin_bo(vc4, vc4file); +@@ -813,7 +813,7 @@ int vc4_mmap_bo_ioctl(struct drm_device + struct drm_vc4_mmap_bo *args = data; + struct drm_gem_object *gem_obj; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + gem_obj = drm_gem_object_lookup(file_priv, args->handle); +@@ -839,7 +839,7 @@ vc4_create_shader_bo_ioctl(struct drm_de + struct vc4_bo *bo = NULL; + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (args->size == 0) +@@ -918,7 +918,7 @@ int vc4_set_tiling_ioctl(struct drm_devi + struct vc4_bo *bo; + bool t_format; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (args->flags != 0) +@@ -964,7 +964,7 @@ int vc4_get_tiling_ioctl(struct drm_devi + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (args->flags != 0 || args->modifier != 0) +@@ -1011,7 +1011,7 @@ int vc4_bo_cache_init(struct drm_device + int ret; + int i; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + /* Create the initial set of BO labels that the kernel will +@@ -1075,7 +1075,7 @@ int vc4_label_bo_ioctl(struct drm_device + struct drm_gem_object *gem_obj; + int ret = 0, label; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!args->len) +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -1023,7 +1023,7 @@ static int vc4_async_page_flip(struct dr + struct vc4_bo *bo = to_vc4_bo(&dma_bo->base); + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + /* +@@ -1066,7 +1066,7 @@ int vc4_page_flip(struct drm_crtc *crtc, + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (vc4->gen == VC4_GEN_5) ++ if (vc4->gen > VC4_GEN_4) + return vc5_async_page_flip(crtc, fb, event, flags); + else + return vc4_async_page_flip(crtc, fb, event, flags); +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -98,7 +98,7 @@ static int vc4_get_param_ioctl(struct dr + if (args->pad != 0) + return -EINVAL; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!vc4->v3d) +@@ -147,7 +147,7 @@ static int vc4_open(struct drm_device *d + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_file *vc4file; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + vc4file = kzalloc(sizeof(*vc4file), GFP_KERNEL); +@@ -165,7 +165,7 @@ static void vc4_close(struct drm_device + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_file *vc4file = file->driver_priv; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + if (vc4file->bin_bo_used) +@@ -315,7 +315,7 @@ static int vc4_drm_bind(struct device *d + else + gen = VC4_GEN_4; + +- if (gen == VC4_GEN_5) ++ if (gen > VC4_GEN_4) + driver = &vc5_drm_driver; + else + driver = &vc4_drm_driver; +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -76,7 +76,7 @@ vc4_get_hang_state_ioctl(struct drm_devi + u32 i; + int ret = 0; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -389,7 +389,7 @@ vc4_wait_for_seqno(struct drm_device *de + unsigned long timeout_expire; + DEFINE_WAIT(wait); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (vc4->finished_seqno >= seqno) +@@ -474,7 +474,7 @@ vc4_submit_next_bin_job(struct drm_devic + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_exec_info *exec; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + again: +@@ -522,7 +522,7 @@ vc4_submit_next_render_job(struct drm_de + if (!exec) + return; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + /* A previous RCL may have written to one of our textures, and +@@ -543,7 +543,7 @@ vc4_move_job_to_render(struct drm_device + struct vc4_dev *vc4 = to_vc4_dev(dev); + bool was_empty = list_empty(&vc4->render_job_list); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + list_move_tail(&exec->head, &vc4->render_job_list); +@@ -1012,7 +1012,7 @@ vc4_job_handle_completed(struct vc4_dev + unsigned long irqflags; + struct vc4_seqno_cb *cb, *cb_temp; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + spin_lock_irqsave(&vc4->job_lock, irqflags); +@@ -1051,7 +1051,7 @@ int vc4_queue_seqno_cb(struct drm_device + struct vc4_dev *vc4 = to_vc4_dev(dev); + unsigned long irqflags; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + cb->func = func; +@@ -1107,7 +1107,7 @@ vc4_wait_seqno_ioctl(struct drm_device * + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_vc4_wait_seqno *args = data; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + return vc4_wait_for_seqno_ioctl_helper(dev, args->seqno, +@@ -1124,7 +1124,7 @@ vc4_wait_bo_ioctl(struct drm_device *dev + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (args->pad != 0) +@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *d + args->shader_rec_size, + args->bo_handle_count); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -1310,7 +1310,7 @@ int vc4_gem_init(struct drm_device *dev) + struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + vc4->dma_fence_context = dma_fence_context_alloc(1); +@@ -1369,7 +1369,7 @@ int vc4_gem_madvise_ioctl(struct drm_dev + struct vc4_bo *bo; + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + switch (args->madv) { +--- a/drivers/gpu/drm/vc4/vc4_irq.c ++++ b/drivers/gpu/drm/vc4/vc4_irq.c +@@ -265,7 +265,7 @@ vc4_irq_enable(struct drm_device *dev) + { + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + if (!vc4->v3d) +@@ -282,7 +282,7 @@ vc4_irq_disable(struct drm_device *dev) + { + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + if (!vc4->v3d) +@@ -305,7 +305,7 @@ int vc4_irq_install(struct drm_device *d + struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (irq == IRQ_NOTCONNECTED) +@@ -326,7 +326,7 @@ void vc4_irq_uninstall(struct drm_device + { + struct vc4_dev *vc4 = to_vc4_dev(dev); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + vc4_irq_disable(dev); +@@ -339,7 +339,7 @@ void vc4_irq_reset(struct drm_device *de + struct vc4_dev *vc4 = to_vc4_dev(dev); + unsigned long irqflags; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + /* Acknowledge any stale IRQs. */ +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -482,7 +482,7 @@ static struct drm_framebuffer *vc4_fb_cr + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_mode_fb_cmd2 mode_cmd_local; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return ERR_PTR(-ENODEV); + + /* If the user didn't specify a modifier, use the +--- a/drivers/gpu/drm/vc4/vc4_perfmon.c ++++ b/drivers/gpu/drm/vc4/vc4_perfmon.c +@@ -23,7 +23,7 @@ void vc4_perfmon_get(struct vc4_perfmon + return; + + vc4 = perfmon->dev; +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + refcount_inc(&perfmon->refcnt); +@@ -37,7 +37,7 @@ void vc4_perfmon_put(struct vc4_perfmon + return; + + vc4 = perfmon->dev; +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + if (refcount_dec_and_test(&perfmon->refcnt)) +@@ -49,7 +49,7 @@ void vc4_perfmon_start(struct vc4_dev *v + unsigned int i; + u32 mask; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + if (WARN_ON_ONCE(!perfmon || vc4->active_perfmon)) +@@ -69,7 +69,7 @@ void vc4_perfmon_stop(struct vc4_dev *vc + { + unsigned int i; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + if (WARN_ON_ONCE(!vc4->active_perfmon || +@@ -90,7 +90,7 @@ struct vc4_perfmon *vc4_perfmon_find(str + struct vc4_dev *vc4 = vc4file->dev; + struct vc4_perfmon *perfmon; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return NULL; + + mutex_lock(&vc4file->perfmon.lock); +@@ -105,7 +105,7 @@ void vc4_perfmon_open_file(struct vc4_fi + { + struct vc4_dev *vc4 = vc4file->dev; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + mutex_init(&vc4file->perfmon.lock); +@@ -126,7 +126,7 @@ void vc4_perfmon_close_file(struct vc4_f + { + struct vc4_dev *vc4 = vc4file->dev; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + mutex_lock(&vc4file->perfmon.lock); +@@ -146,7 +146,7 @@ int vc4_perfmon_create_ioctl(struct drm_ + unsigned int i; + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -200,7 +200,7 @@ int vc4_perfmon_destroy_ioctl(struct drm + struct drm_vc4_perfmon_destroy *req = data; + struct vc4_perfmon *perfmon; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!vc4->v3d) { +@@ -228,7 +228,7 @@ int vc4_perfmon_get_values_ioctl(struct + struct vc4_perfmon *perfmon; + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (!vc4->v3d) { +--- a/drivers/gpu/drm/vc4/vc4_render_cl.c ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -599,7 +599,7 @@ int vc4_get_rcl(struct drm_device *dev, + bool has_bin = args->bin_cl_size != 0; + int ret; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + if (args->min_x_tile > args->max_x_tile || +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -127,7 +127,7 @@ static int vc4_v3d_debugfs_ident(struct + int + vc4_v3d_pm_get(struct vc4_dev *vc4) + { +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + mutex_lock(&vc4->power_lock); +@@ -148,7 +148,7 @@ vc4_v3d_pm_get(struct vc4_dev *vc4) + void + vc4_v3d_pm_put(struct vc4_dev *vc4) + { +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + mutex_lock(&vc4->power_lock); +@@ -178,7 +178,7 @@ int vc4_v3d_get_bin_slot(struct vc4_dev + uint64_t seqno = 0; + struct vc4_exec_info *exec; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + try_again: +@@ -325,7 +325,7 @@ int vc4_v3d_bin_bo_get(struct vc4_dev *v + { + int ret = 0; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + mutex_lock(&vc4->bin_bo_lock); +@@ -360,7 +360,7 @@ static void bin_bo_release(struct kref * + + void vc4_v3d_bin_bo_put(struct vc4_dev *vc4) + { +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + + mutex_lock(&vc4->bin_bo_lock); +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -109,7 +109,7 @@ vc4_use_bo(struct vc4_exec_info *exec, u + struct drm_gem_dma_object *obj; + struct vc4_bo *bo; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return NULL; + + if (hindex >= exec->bo_count) { +@@ -169,7 +169,7 @@ vc4_check_tex_size(struct vc4_exec_info + uint32_t utile_w = utile_width(cpp); + uint32_t utile_h = utile_height(cpp); + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return false; + + /* The shaded vertex format stores signed 12.4 fixed point +@@ -495,7 +495,7 @@ vc4_validate_bin_cl(struct drm_device *d + uint32_t dst_offset = 0; + uint32_t src_offset = 0; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + while (src_offset < len) { +@@ -942,7 +942,7 @@ vc4_validate_shader_recs(struct drm_devi + uint32_t i; + int ret = 0; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + + for (i = 0; i < exec->shader_state_count; i++) { +--- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c ++++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c +@@ -786,7 +786,7 @@ vc4_validate_shader(struct drm_gem_dma_o + struct vc4_validated_shader_info *validated_shader = NULL; + struct vc4_shader_validation_state validation_state; + +- if (WARN_ON_ONCE(vc4->gen == VC4_GEN_5)) ++ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return NULL; + + memset(&validation_state, 0, sizeof(validation_state)); diff --git a/target/linux/bcm27xx/patches-6.1/950-0940-drm-vc4-hvs-Use-switch-statement-to-simplify-vc4_hvs.patch b/target/linux/bcm27xx/patches-6.1/950-0940-drm-vc4-hvs-Use-switch-statement-to-simplify-vc4_hvs.patch new file mode 100644 index 0000000000..048b5d3222 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0940-drm-vc4-hvs-Use-switch-statement-to-simplify-vc4_hvs.patch @@ -0,0 +1,125 @@ +From 72e5eb3d9511af2f056911d70c4d033d4fc674b2 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 15:07:29 +0100 +Subject: [PATCH] drm/vc4: hvs: Use switch statement to simplify + vc4_hvs_get_fifo_from_output + +Since we'll support BCM2712 soon, let's move the logic behind +vc4_hvs_get_fifo_from_output() to a switch to extend it more easily. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 80 +++++++++++++++++++---------------- + 1 file changed, 43 insertions(+), 37 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -620,57 +620,63 @@ int vc4_hvs_get_fifo_from_output(struct + u32 reg; + int ret; + +- if (vc4->gen == VC4_GEN_4) ++ switch (vc4->gen) { ++ case VC4_GEN_4: + return output; + +- /* +- * NOTE: We should probably use drm_dev_enter()/drm_dev_exit() +- * here, but this function is only used during the DRM device +- * initialization, so we should be fine. +- */ +- +- switch (output) { +- case 0: +- return 0; +- +- case 1: +- return 1; +- +- case 2: +- reg = HVS_READ(SCALER_DISPECTRL); +- ret = FIELD_GET(SCALER_DISPECTRL_DSP2_MUX_MASK, reg); +- if (ret == 0) +- return 2; +- +- return 0; +- +- case 3: +- reg = HVS_READ(SCALER_DISPCTRL); +- ret = FIELD_GET(SCALER_DISPCTRL_DSP3_MUX_MASK, reg); +- if (ret == 3) +- return -EPIPE; +- +- return ret; +- +- case 4: +- reg = HVS_READ(SCALER_DISPEOLN); +- ret = FIELD_GET(SCALER_DISPEOLN_DSP4_MUX_MASK, reg); +- if (ret == 3) +- return -EPIPE; ++ case VC4_GEN_5: ++ /* ++ * NOTE: We should probably use ++ * drm_dev_enter()/drm_dev_exit() here, but this ++ * function is only used during the DRM device ++ * initialization, so we should be fine. ++ */ ++ ++ switch (output) { ++ case 0: ++ return 0; ++ ++ case 1: ++ return 1; ++ ++ case 2: ++ reg = HVS_READ(SCALER_DISPECTRL); ++ ret = FIELD_GET(SCALER_DISPECTRL_DSP2_MUX_MASK, reg); ++ if (ret == 0) ++ return 2; ++ ++ return 0; ++ ++ case 3: ++ reg = HVS_READ(SCALER_DISPCTRL); ++ ret = FIELD_GET(SCALER_DISPCTRL_DSP3_MUX_MASK, reg); ++ if (ret == 3) ++ return -EPIPE; ++ ++ return ret; ++ ++ case 4: ++ reg = HVS_READ(SCALER_DISPEOLN); ++ ret = FIELD_GET(SCALER_DISPEOLN_DSP4_MUX_MASK, reg); ++ if (ret == 3) ++ return -EPIPE; ++ ++ return ret; ++ ++ case 5: ++ reg = HVS_READ(SCALER_DISPDITHER); ++ ret = FIELD_GET(SCALER_DISPDITHER_DSP5_MUX_MASK, reg); ++ if (ret == 3) ++ return -EPIPE; + +- return ret; ++ return ret; + +- case 5: +- reg = HVS_READ(SCALER_DISPDITHER); +- ret = FIELD_GET(SCALER_DISPDITHER_DSP5_MUX_MASK, reg); +- if (ret == 3) ++ default: + return -EPIPE; +- +- return ret; +- +- default: +- return -EPIPE; ++ } + } ++ ++ return -EPIPE; + } + + static int vc4_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc, diff --git a/target/linux/bcm27xx/patches-6.1/950-0941-drm-vc4-hvs-Use-switch-statement-to-simplify-enablin.patch b/target/linux/bcm27xx/patches-6.1/950-0941-drm-vc4-hvs-Use-switch-statement-to-simplify-enablin.patch new file mode 100644 index 0000000000..984b329fb4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0941-drm-vc4-hvs-Use-switch-statement-to-simplify-enablin.patch @@ -0,0 +1,74 @@ +From 72bfb10c9393688d00e4e0b00d416e23c2753318 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 15:07:29 +0100 +Subject: [PATCH] drm/vc4: hvs: Use switch statement to simplify + enabling/disabling irq + +Since we'll support BCM2712 soon, let's move the logic to enable and +disable the end-of-frame interrupts to a switch to extend it more +easily. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 42 ++++++++++++++++++++++++++--------- + 1 file changed, 32 insertions(+), 10 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -416,24 +416,46 @@ static void vc4_hvs_irq_enable_eof(const + unsigned int channel) + { + struct vc4_dev *vc4 = hvs->vc4; +- u32 irq_mask = vc4->gen == VC4_GEN_5 ? +- SCALER5_DISPCTRL_DSPEIEOF(channel) : +- SCALER_DISPCTRL_DSPEIEOF(channel); + +- HVS_WRITE(SCALER_DISPCTRL, +- HVS_READ(SCALER_DISPCTRL) | irq_mask); ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ HVS_WRITE(SCALER_DISPCTRL, ++ HVS_READ(SCALER_DISPCTRL) | ++ SCALER_DISPCTRL_DSPEIEOF(channel)); ++ break; ++ ++ case VC4_GEN_5: ++ HVS_WRITE(SCALER_DISPCTRL, ++ HVS_READ(SCALER_DISPCTRL) | ++ SCALER5_DISPCTRL_DSPEIEOF(channel)); ++ break; ++ ++ default: ++ break; ++ } + } + + static void vc4_hvs_irq_clear_eof(const struct vc4_hvs *hvs, + unsigned int channel) + { + struct vc4_dev *vc4 = hvs->vc4; +- u32 irq_mask = vc4->gen == VC4_GEN_5 ? +- SCALER5_DISPCTRL_DSPEIEOF(channel) : +- SCALER_DISPCTRL_DSPEIEOF(channel); + +- HVS_WRITE(SCALER_DISPCTRL, +- HVS_READ(SCALER_DISPCTRL) & ~irq_mask); ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ HVS_WRITE(SCALER_DISPCTRL, ++ HVS_READ(SCALER_DISPCTRL) & ++ ~SCALER_DISPCTRL_DSPEIEOF(channel)); ++ break; ++ ++ case VC4_GEN_5: ++ HVS_WRITE(SCALER_DISPCTRL, ++ HVS_READ(SCALER_DISPCTRL) & ++ ~SCALER5_DISPCTRL_DSPEIEOF(channel)); ++ break; ++ ++ default: ++ break; ++ } + } + + static struct vc4_hvs_dlist_allocation * diff --git a/target/linux/bcm27xx/patches-6.1/950-0942-drm-vc4-hvs-Test-if-the-EOF-interrupts-are-enabled.patch b/target/linux/bcm27xx/patches-6.1/950-0942-drm-vc4-hvs-Test-if-the-EOF-interrupts-are-enabled.patch new file mode 100644 index 0000000000..704468b90e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0942-drm-vc4-hvs-Test-if-the-EOF-interrupts-are-enabled.patch @@ -0,0 +1,100 @@ +From bcf02f6ac0d429a425e8409f140bd875a1feed2e Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 27 Apr 2023 13:46:53 +0200 +Subject: [PATCH] drm/vc4: hvs: Test if the EOF interrupts are enabled + +We currently enable the EOF interrupts through the CRTC destroy_state +implementation. + +However, nothing guarantees that we can't call destroy_state multiple +times in a row, and therefore before the EOF interrupt even happens. + +This means we would enable the interrupt multiple times but disable it +only once. It wasn't an issue so far since the interrupts were only +enabled by setting a bit in a register, but with BCM2712 we will use an +external interrupt controller, with a refcounted interrupt. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.h | 8 ++++++-- + drivers/gpu/drm/vc4/vc4_hvs.c | 14 ++++++++++++-- + 2 files changed, 18 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -333,6 +333,8 @@ struct vc4_v3d { + struct debugfs_regset32 regset; + }; + ++#define HVS_NUM_CHANNELS 3 ++ + struct vc4_hvs { + struct vc4_dev *vc4; + struct platform_device *pdev; +@@ -341,6 +343,10 @@ struct vc4_hvs { + + struct clk *core_clk; + ++ struct { ++ unsigned int enabled: 1; ++ } eof_irq[HVS_NUM_CHANNELS]; ++ + unsigned long max_core_rate; + + /* Memory manager for CRTCs to allocate space in the display +@@ -373,8 +379,6 @@ struct vc4_hvs { + bool vc5_hdmi_enable_4096by2160; + }; + +-#define HVS_NUM_CHANNELS 3 +- + struct vc4_hvs_state { + struct drm_private_state base; + unsigned long core_clock_rate; +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -412,11 +412,14 @@ static void vc5_hvs_update_gamma_lut(str + vc5_hvs_lut_load(hvs, vc4_crtc); + } + +-static void vc4_hvs_irq_enable_eof(const struct vc4_hvs *hvs, ++static void vc4_hvs_irq_enable_eof(struct vc4_hvs *hvs, + unsigned int channel) + { + struct vc4_dev *vc4 = hvs->vc4; + ++ if (hvs->eof_irq[channel].enabled) ++ return; ++ + switch (vc4->gen) { + case VC4_GEN_4: + HVS_WRITE(SCALER_DISPCTRL, +@@ -433,13 +436,18 @@ static void vc4_hvs_irq_enable_eof(const + default: + break; + } ++ ++ hvs->eof_irq[channel].enabled = true; + } + +-static void vc4_hvs_irq_clear_eof(const struct vc4_hvs *hvs, ++static void vc4_hvs_irq_clear_eof(struct vc4_hvs *hvs, + unsigned int channel) + { + struct vc4_dev *vc4 = hvs->vc4; + ++ if (!hvs->eof_irq[channel].enabled) ++ return; ++ + switch (vc4->gen) { + case VC4_GEN_4: + HVS_WRITE(SCALER_DISPCTRL, +@@ -456,6 +464,8 @@ static void vc4_hvs_irq_clear_eof(const + default: + break; + } ++ ++ hvs->eof_irq[channel].enabled = false; + } + + static struct vc4_hvs_dlist_allocation * diff --git a/target/linux/bcm27xx/patches-6.1/950-0943-drm-vc4-hvs-Create-hw_init-function.patch b/target/linux/bcm27xx/patches-6.1/950-0943-drm-vc4-hvs-Create-hw_init-function.patch new file mode 100644 index 0000000000..5b748b5e94 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0943-drm-vc4-hvs-Create-hw_init-function.patch @@ -0,0 +1,188 @@ +From f3c84bb53107cef0009347d071c1a188ce24b8a3 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 14:36:28 +0100 +Subject: [PATCH] drm/vc4: hvs: Create hw_init function + +Since the BCM2712 will feature a significantly different HVS, let's move +the hardware initialisation part of our bind function into a separate +function. + +That way, it will be easier to extend in the future. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 155 ++++++++++++++++++---------------- + 1 file changed, 83 insertions(+), 72 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -1291,79 +1291,10 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v + return hvs; + } + +-static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) ++static int vc4_hvs_hw_init(struct vc4_hvs *hvs) + { +- struct platform_device *pdev = to_platform_device(dev); +- struct drm_device *drm = dev_get_drvdata(master); +- struct vc4_dev *vc4 = to_vc4_dev(drm); +- struct vc4_hvs *hvs = NULL; +- int ret; +- u32 dispctrl; +- u32 reg, top; +- +- hvs = __vc4_hvs_alloc(vc4, NULL); +- if (IS_ERR(hvs)) +- return PTR_ERR(hvs); +- +- hvs->regs = vc4_ioremap_regs(pdev, 0); +- if (IS_ERR(hvs->regs)) +- return PTR_ERR(hvs->regs); +- +- hvs->regset.base = hvs->regs; +- hvs->regset.regs = hvs_regs; +- hvs->regset.nregs = ARRAY_SIZE(hvs_regs); +- +- if (vc4->gen == VC4_GEN_5) { +- struct rpi_firmware *firmware; +- struct device_node *node; +- unsigned int max_rate; +- +- node = rpi_firmware_find_node(); +- if (!node) +- return -EINVAL; +- +- firmware = rpi_firmware_get(node); +- of_node_put(node); +- if (!firmware) +- return -EPROBE_DEFER; +- +- hvs->core_clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(hvs->core_clk)) { +- dev_err(&pdev->dev, "Couldn't get core clock\n"); +- return PTR_ERR(hvs->core_clk); +- } +- +- max_rate = rpi_firmware_clk_get_max_rate(firmware, +- RPI_FIRMWARE_CORE_CLK_ID); +- rpi_firmware_put(firmware); +- if (max_rate >= 550000000) +- hvs->vc5_hdmi_enable_hdmi_20 = true; +- +- if (max_rate >= 600000000) +- hvs->vc5_hdmi_enable_4096by2160 = true; +- +- hvs->max_core_rate = max_rate; +- +- ret = clk_prepare_enable(hvs->core_clk); +- if (ret) { +- dev_err(&pdev->dev, "Couldn't enable the core clock\n"); +- return ret; +- } +- } +- +- if (vc4->gen == VC4_GEN_4) +- hvs->dlist = hvs->regs + SCALER_DLIST_START; +- else +- hvs->dlist = hvs->regs + SCALER5_DLIST_START; +- +- /* Upload filter kernels. We only have the one for now, so we +- * keep it around for the lifetime of the driver. +- */ +- ret = vc4_hvs_upload_linear_kernel(hvs, +- &hvs->mitchell_netravali_filter, +- mitchell_netravali_1_3_1_3_kernel); +- if (ret) +- return ret; ++ struct vc4_dev *vc4 = hvs->vc4; ++ u32 dispctrl, reg; + + reg = HVS_READ(SCALER_DISPECTRL); + reg &= ~SCALER_DISPECTRL_DSP2_MUX_MASK; +@@ -1445,6 +1376,86 @@ static int vc4_hvs_bind(struct device *d + + HVS_WRITE(SCALER_DISPCTRL, dispctrl); + ++ return 0; ++} ++ ++static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_hvs *hvs = NULL; ++ int ret; ++ u32 reg, top; ++ ++ hvs = __vc4_hvs_alloc(vc4, NULL); ++ if (IS_ERR(hvs)) ++ return PTR_ERR(hvs); ++ ++ hvs->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(hvs->regs)) ++ return PTR_ERR(hvs->regs); ++ ++ hvs->regset.base = hvs->regs; ++ hvs->regset.regs = hvs_regs; ++ hvs->regset.nregs = ARRAY_SIZE(hvs_regs); ++ ++ if (vc4->gen == VC4_GEN_5) { ++ struct rpi_firmware *firmware; ++ struct device_node *node; ++ unsigned int max_rate; ++ ++ node = rpi_firmware_find_node(); ++ if (!node) ++ return -EINVAL; ++ ++ firmware = rpi_firmware_get(node); ++ of_node_put(node); ++ if (!firmware) ++ return -EPROBE_DEFER; ++ ++ hvs->core_clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(hvs->core_clk)) { ++ dev_err(&pdev->dev, "Couldn't get core clock\n"); ++ return PTR_ERR(hvs->core_clk); ++ } ++ ++ max_rate = rpi_firmware_clk_get_max_rate(firmware, ++ RPI_FIRMWARE_CORE_CLK_ID); ++ rpi_firmware_put(firmware); ++ if (max_rate >= 550000000) ++ hvs->vc5_hdmi_enable_hdmi_20 = true; ++ ++ if (max_rate >= 600000000) ++ hvs->vc5_hdmi_enable_4096by2160 = true; ++ ++ hvs->max_core_rate = max_rate; ++ ++ ret = clk_prepare_enable(hvs->core_clk); ++ if (ret) { ++ dev_err(&pdev->dev, "Couldn't enable the core clock\n"); ++ return ret; ++ } ++ } ++ ++ if (vc4->gen == VC4_GEN_4) ++ hvs->dlist = hvs->regs + SCALER_DLIST_START; ++ else ++ hvs->dlist = hvs->regs + SCALER5_DLIST_START; ++ ++ /* Upload filter kernels. We only have the one for now, so we ++ * keep it around for the lifetime of the driver. ++ */ ++ ret = vc4_hvs_upload_linear_kernel(hvs, ++ &hvs->mitchell_netravali_filter, ++ mitchell_netravali_1_3_1_3_kernel); ++ if (ret) ++ return ret; ++ ++ ret = vc4_hvs_hw_init(hvs); ++ if (ret) ++ return ret; ++ + /* Recompute Composite Output Buffer (COB) allocations for the displays + */ + if (vc4->gen == VC4_GEN_4) { diff --git a/target/linux/bcm27xx/patches-6.1/950-0944-drm-vc4-hvs-Create-cob_init-function.patch b/target/linux/bcm27xx/patches-6.1/950-0944-drm-vc4-hvs-Create-cob_init-function.patch new file mode 100644 index 0000000000..5b2e9745e9 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0944-drm-vc4-hvs-Create-cob_init-function.patch @@ -0,0 +1,167 @@ +From 99a13ce3a12303dfb54815637972627a7d207086 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 15:14:55 +0100 +Subject: [PATCH] drm/vc4: hvs: Create cob_init function + +Just like the HVS itself, the COB parameters will be fairly different in +the BCM2712. + +Let's move the COB parameters computation and its initialisation to a +separate function that will be easier to extend in the future. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 128 ++++++++++++++++++++-------------- + 1 file changed, 74 insertions(+), 54 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -1379,6 +1379,77 @@ static int vc4_hvs_hw_init(struct vc4_hv + return 0; + } + ++static int vc4_hvs_cob_init(struct vc4_hvs *hvs) ++{ ++ struct vc4_dev *vc4 = hvs->vc4; ++ u32 reg, top; ++ ++ /* ++ * Recompute Composite Output Buffer (COB) allocations for the ++ * displays ++ */ ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ /* The COB is 20736 pixels, or just over 10 lines at 2048 wide. ++ * The bottom 2048 pixels are full 32bpp RGBA (intended for the ++ * TXP composing RGBA to memory), whilst the remainder are only ++ * 24bpp RGB. ++ * ++ * Assign 3 lines to channels 1 & 2, and just over 4 lines to ++ * channel 0. ++ */ ++ #define VC4_COB_SIZE 20736 ++ #define VC4_COB_LINE_WIDTH 2048 ++ #define VC4_COB_NUM_LINES 3 ++ reg = 0; ++ top = VC4_COB_LINE_WIDTH * VC4_COB_NUM_LINES; ++ reg |= (top - 1) << 16; ++ HVS_WRITE(SCALER_DISPBASE2, reg); ++ reg = top; ++ top += VC4_COB_LINE_WIDTH * VC4_COB_NUM_LINES; ++ reg |= (top - 1) << 16; ++ HVS_WRITE(SCALER_DISPBASE1, reg); ++ reg = top; ++ top = VC4_COB_SIZE; ++ reg |= (top - 1) << 16; ++ HVS_WRITE(SCALER_DISPBASE0, reg); ++ break; ++ ++ case VC4_GEN_5: ++ /* The COB is 44416 pixels, or 10.8 lines at 4096 wide. ++ * The bottom 4096 pixels are full RGBA (intended for the TXP ++ * composing RGBA to memory), whilst the remainder are only ++ * RGB. Addressing is always pixel wide. ++ * ++ * Assign 3 lines of 4096 to channels 1 & 2, and just over 4 ++ * lines. to channel 0. ++ */ ++ #define VC5_COB_SIZE 44416 ++ #define VC5_COB_LINE_WIDTH 4096 ++ #define VC5_COB_NUM_LINES 3 ++ reg = 0; ++ top = VC5_COB_LINE_WIDTH * VC5_COB_NUM_LINES; ++ reg |= top << 16; ++ HVS_WRITE(SCALER_DISPBASE2, reg); ++ top += 16; ++ reg = top; ++ top += VC5_COB_LINE_WIDTH * VC5_COB_NUM_LINES; ++ reg |= top << 16; ++ HVS_WRITE(SCALER_DISPBASE1, reg); ++ top += 16; ++ reg = top; ++ top = VC5_COB_SIZE; ++ reg |= top << 16; ++ HVS_WRITE(SCALER_DISPBASE0, reg); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) + { + struct platform_device *pdev = to_platform_device(dev); +@@ -1386,7 +1457,6 @@ static int vc4_hvs_bind(struct device *d + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_hvs *hvs = NULL; + int ret; +- u32 reg, top; + + hvs = __vc4_hvs_alloc(vc4, NULL); + if (IS_ERR(hvs)) +@@ -1456,59 +1526,9 @@ static int vc4_hvs_bind(struct device *d + if (ret) + return ret; + +- /* Recompute Composite Output Buffer (COB) allocations for the displays +- */ +- if (vc4->gen == VC4_GEN_4) { +- /* The COB is 20736 pixels, or just over 10 lines at 2048 wide. +- * The bottom 2048 pixels are full 32bpp RGBA (intended for the +- * TXP composing RGBA to memory), whilst the remainder are only +- * 24bpp RGB. +- * +- * Assign 3 lines to channels 1 & 2, and just over 4 lines to +- * channel 0. +- */ +- #define VC4_COB_SIZE 20736 +- #define VC4_COB_LINE_WIDTH 2048 +- #define VC4_COB_NUM_LINES 3 +- reg = 0; +- top = VC4_COB_LINE_WIDTH * VC4_COB_NUM_LINES; +- reg |= (top - 1) << 16; +- HVS_WRITE(SCALER_DISPBASE2, reg); +- reg = top; +- top += VC4_COB_LINE_WIDTH * VC4_COB_NUM_LINES; +- reg |= (top - 1) << 16; +- HVS_WRITE(SCALER_DISPBASE1, reg); +- reg = top; +- top = VC4_COB_SIZE; +- reg |= (top - 1) << 16; +- HVS_WRITE(SCALER_DISPBASE0, reg); +- } else { +- /* The COB is 44416 pixels, or 10.8 lines at 4096 wide. +- * The bottom 4096 pixels are full RGBA (intended for the TXP +- * composing RGBA to memory), whilst the remainder are only +- * RGB. Addressing is always pixel wide. +- * +- * Assign 3 lines of 4096 to channels 1 & 2, and just over 4 +- * lines. to channel 0. +- */ +- #define VC5_COB_SIZE 44416 +- #define VC5_COB_LINE_WIDTH 4096 +- #define VC5_COB_NUM_LINES 3 +- reg = 0; +- top = VC5_COB_LINE_WIDTH * VC5_COB_NUM_LINES; +- reg |= top << 16; +- HVS_WRITE(SCALER_DISPBASE2, reg); +- top += 16; +- reg = top; +- top += VC5_COB_LINE_WIDTH * VC5_COB_NUM_LINES; +- reg |= top << 16; +- HVS_WRITE(SCALER_DISPBASE1, reg); +- top += 16; +- reg = top; +- top = VC5_COB_SIZE; +- reg |= top << 16; +- HVS_WRITE(SCALER_DISPBASE0, reg); +- } ++ ret = vc4_hvs_cob_init(hvs); ++ if (ret) ++ return ret; + + ret = devm_request_irq(dev, platform_get_irq(pdev, 0), + vc4_hvs_irq_handler, 0, "vc4 hvs", drm); diff --git a/target/linux/bcm27xx/patches-6.1/950-0945-drm-vc4-hvs-Rename-hvs_regs-list.patch b/target/linux/bcm27xx/patches-6.1/950-0945-drm-vc4-hvs-Rename-hvs_regs-list.patch new file mode 100644 index 0000000000..4139d79f02 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0945-drm-vc4-hvs-Rename-hvs_regs-list.patch @@ -0,0 +1,38 @@ +From 7a1c157ac856384c47df38e1de2995f55a111b85 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:41:59 +0100 +Subject: [PATCH] drm/vc4: hvs: Rename hvs_regs list + +The HVS register set has been heavily modified in the BCM2712, and we'll +thus need a separate debugfs_reg32 array for it. + +The name hvs_regs is thus a bit too generic, so let's rename it to +something more specific. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -33,7 +33,7 @@ + #include "vc4_drv.h" + #include "vc4_regs.h" + +-static const struct debugfs_reg32 hvs_regs[] = { ++static const struct debugfs_reg32 vc4_hvs_regs[] = { + VC4_REG32(SCALER_DISPCTRL), + VC4_REG32(SCALER_DISPSTAT), + VC4_REG32(SCALER_DISPID), +@@ -1467,8 +1467,8 @@ static int vc4_hvs_bind(struct device *d + return PTR_ERR(hvs->regs); + + hvs->regset.base = hvs->regs; +- hvs->regset.regs = hvs_regs; +- hvs->regset.nregs = ARRAY_SIZE(hvs_regs); ++ hvs->regset.regs = vc4_hvs_regs; ++ hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs); + + if (vc4->gen == VC4_GEN_5) { + struct rpi_firmware *firmware; diff --git a/target/linux/bcm27xx/patches-6.1/950-0946-drm-vc4-plane-Change-ptr0_offset-to-an-array.patch b/target/linux/bcm27xx/patches-6.1/950-0946-drm-vc4-plane-Change-ptr0_offset-to-an-array.patch new file mode 100644 index 0000000000..ed55f53fad --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0946-drm-vc4-plane-Change-ptr0_offset-to-an-array.patch @@ -0,0 +1,103 @@ +From 531f66804eb95323f807d240273087fbe162aeee Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 24 Mar 2023 09:56:31 +0100 +Subject: [PATCH] drm/vc4: plane: Change ptr0_offset to an array + +The BCM2712 will have a fairly different dlist, that will feature one +Pointer 0 word for each plane. + +Let's prepare by changing the ptr0_offset variable that holds the offset +in a dlist of the pointer 0 word to an array. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.h | 3 ++- + drivers/gpu/drm/vc4/vc4_plane.c | 18 +++++++++--------- + 2 files changed, 11 insertions(+), 10 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -430,7 +431,7 @@ struct vc4_plane_state { + */ + u32 pos0_offset; + u32 pos2_offset; +- u32 ptr0_offset; ++ u32 ptr0_offset[DRM_FORMAT_MAX_PLANES]; + u32 lbm_offset; + + /* Offset where the plane's dlist was last stored in the +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1242,7 +1242,7 @@ static int vc4_plane_mode_set(struct drm + * + * The pointers may be any byte address. + */ +- vc4_state->ptr0_offset = vc4_state->dlist_count; ++ vc4_state->ptr0_offset[0] = vc4_state->dlist_count; + for (i = 0; i < num_planes; i++) + vc4_dlist_write(vc4_state, vc4_state->offsets[i]); + +@@ -1447,13 +1447,13 @@ void vc4_plane_async_set_fb(struct drm_p + * scanout will start from this address as soon as the FIFO + * needs to refill with pixels. + */ +- writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]); ++ writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset[0]]); + + /* Also update the CPU-side dlist copy, so that any later + * atomic updates that don't do a new modeset on our plane + * also use our updated address. + */ +- vc4_state->dlist[vc4_state->ptr0_offset] = addr; ++ vc4_state->dlist[vc4_state->ptr0_offset[0]] = addr; + + drm_dev_exit(idx); + } +@@ -1517,8 +1517,8 @@ static void vc4_plane_atomic_async_updat + new_vc4_state->dlist[vc4_state->pos0_offset]; + vc4_state->dlist[vc4_state->pos2_offset] = + new_vc4_state->dlist[vc4_state->pos2_offset]; +- vc4_state->dlist[vc4_state->ptr0_offset] = +- new_vc4_state->dlist[vc4_state->ptr0_offset]; ++ vc4_state->dlist[vc4_state->ptr0_offset[0]] = ++ new_vc4_state->dlist[vc4_state->ptr0_offset[0]]; + + /* Note that we can't just call vc4_plane_write_dlist() + * because that would smash the context data that the HVS is +@@ -1528,8 +1528,8 @@ static void vc4_plane_atomic_async_updat + &vc4_state->hw_dlist[vc4_state->pos0_offset]); + writel(vc4_state->dlist[vc4_state->pos2_offset], + &vc4_state->hw_dlist[vc4_state->pos2_offset]); +- writel(vc4_state->dlist[vc4_state->ptr0_offset], +- &vc4_state->hw_dlist[vc4_state->ptr0_offset]); ++ writel(vc4_state->dlist[vc4_state->ptr0_offset[0]], ++ &vc4_state->hw_dlist[vc4_state->ptr0_offset[0]]); + + drm_dev_exit(idx); + } +@@ -1556,7 +1556,7 @@ static int vc4_plane_atomic_async_check( + if (old_vc4_state->dlist_count != new_vc4_state->dlist_count || + old_vc4_state->pos0_offset != new_vc4_state->pos0_offset || + old_vc4_state->pos2_offset != new_vc4_state->pos2_offset || +- old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset || ++ old_vc4_state->ptr0_offset[0] != new_vc4_state->ptr0_offset[0] || + vc4_lbm_size(plane->state) != vc4_lbm_size(new_plane_state)) + return -EINVAL; + +@@ -1566,7 +1566,7 @@ static int vc4_plane_atomic_async_check( + for (i = 0; i < new_vc4_state->dlist_count; i++) { + if (i == new_vc4_state->pos0_offset || + i == new_vc4_state->pos2_offset || +- i == new_vc4_state->ptr0_offset || ++ i == new_vc4_state->ptr0_offset[0] || + (new_vc4_state->lbm_offset && + i == new_vc4_state->lbm_offset)) + continue; diff --git a/target/linux/bcm27xx/patches-6.1/950-0947-drm-vc4-hvs-Rework-LBM-alignment.patch b/target/linux/bcm27xx/patches-6.1/950-0947-drm-vc4-hvs-Rework-LBM-alignment.patch new file mode 100644 index 0000000000..3a30b9ca85 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0947-drm-vc4-hvs-Rework-LBM-alignment.patch @@ -0,0 +1,45 @@ +From 2834b58a3b58198e551d8461a0786b75d3d76823 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Apr 2023 10:12:19 +0200 +Subject: [PATCH] drm/vc4: hvs: Rework LBM alignment + +With the introduction of the support for BCM2712, the check of whether +we're running on vc5 or not to compute the LBM alignment requirement +doesn't work anymore. + +Moreover, the LBM size will need to be computed in words for the +BCM2712, while we've had sizes in bytes so far. + +Aligning on either 64 or 32 words is thus fairly harmful on BCM2712, so +let's just explicitly align the size when needed, and then call +drm_mm_insert_node_generic() with an alignment of 1. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_plane.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -744,6 +744,11 @@ static int vc4_plane_allocate_lbm(struct + if (!lbm_size) + return 0; + ++ if (vc4->gen == VC4_GEN_5) ++ lbm_size = ALIGN(lbm_size, 64); ++ else if (vc4->gen == VC4_GEN_4) ++ lbm_size = ALIGN(lbm_size, 32); ++ + drm_dbg_driver(drm, "[PLANE:%d:%s] LBM Allocation Size: %u\n", + plane->base.id, plane->name, lbm_size); + +@@ -759,8 +764,7 @@ static int vc4_plane_allocate_lbm(struct + spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); + ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, + &vc4_state->lbm, +- lbm_size, +- vc4->gen == VC4_GEN_5 ? 64 : 32, ++ lbm_size, 1, + 0, 0); + spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); + diff --git a/target/linux/bcm27xx/patches-6.1/950-0948-drm-vc4-hvs-Change-prototype-of-__vc4_hvs_alloc-to-p.patch b/target/linux/bcm27xx/patches-6.1/950-0948-drm-vc4-hvs-Change-prototype-of-__vc4_hvs_alloc-to-p.patch new file mode 100644 index 0000000000..2927a3e04e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0948-drm-vc4-hvs-Change-prototype-of-__vc4_hvs_alloc-to-p.patch @@ -0,0 +1,93 @@ +From 23cba2abd5ffbb7337e3f381c4724eaaf01cf5a1 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 24 Mar 2023 15:45:50 +0100 +Subject: [PATCH] drm/vc4: hvs: Change prototype of __vc4_hvs_alloc to pass + registers + +The BCM2712 HVS has registers to report the size of the various SRAM the +driver uses, and their size actually differ depending on the stepping. + +The initialisation of the memory pools happen in the __vc4_hvs_alloc() +function that also allocates the main HVS structure, that will then hold +the pointer to the memory mapping of the registers. + +This creates some kind of circular dependency that we can break by +passing the mapping pointer as an argument for __vc4_hvs_alloc() to use +to query to get the SRAM sizes and initialise the memory pools +accordingly. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.c | 2 +- + drivers/gpu/drm/vc4/vc4_drv.h | 4 +++- + drivers/gpu/drm/vc4/vc4_hvs.c | 16 ++++++++++------ + 3 files changed, 14 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c +@@ -173,7 +173,7 @@ static struct vc4_dev *__mock_device(str + vc4->dev = dev; + vc4->gen = gen; + +- vc4->hvs = __vc4_hvs_alloc(vc4, NULL); ++ vc4->hvs = __vc4_hvs_alloc(vc4, NULL, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4->hvs); + + drm = &vc4->base; +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -1092,7 +1092,9 @@ void vc4_irq_reset(struct drm_device *de + + /* vc4_hvs.c */ + extern struct platform_driver vc4_hvs_driver; +-struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, struct platform_device *pdev); ++struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, ++ void __iomem *regs, ++ struct platform_device *pdev); + void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int output); + int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output); + u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo); +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -1248,7 +1248,9 @@ int vc4_hvs_debugfs_init(struct drm_mino + return 0; + } + +-struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, struct platform_device *pdev) ++struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, ++ void __iomem *regs, ++ struct platform_device *pdev) + { + struct drm_device *drm = &vc4->base; + struct vc4_hvs *hvs; +@@ -1258,6 +1260,7 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v + return ERR_PTR(-ENOMEM); + + hvs->vc4 = vc4; ++ hvs->regs = regs; + hvs->pdev = pdev; + + spin_lock_init(&hvs->mm_lock); +@@ -1456,16 +1459,17 @@ static int vc4_hvs_bind(struct device *d + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_hvs *hvs = NULL; ++ void __iomem *regs; + int ret; + +- hvs = __vc4_hvs_alloc(vc4, NULL); ++ regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ hvs = __vc4_hvs_alloc(vc4, regs, pdev); + if (IS_ERR(hvs)) + return PTR_ERR(hvs); + +- hvs->regs = vc4_ioremap_regs(pdev, 0); +- if (IS_ERR(hvs->regs)) +- return PTR_ERR(hvs->regs); +- + hvs->regset.base = hvs->regs; + hvs->regset.regs = vc4_hvs_regs; + hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs); diff --git a/target/linux/bcm27xx/patches-6.1/950-0949-drm-vc4-UV-planes-vertical-scaling-must-always-be-en.patch b/target/linux/bcm27xx/patches-6.1/950-0949-drm-vc4-UV-planes-vertical-scaling-must-always-be-en.patch new file mode 100644 index 0000000000..4a51862487 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0949-drm-vc4-UV-planes-vertical-scaling-must-always-be-en.patch @@ -0,0 +1,30 @@ +From 03e0e348df7b685439f2db61ec2d8c8da25d1217 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 23 Aug 2023 17:48:23 +0100 +Subject: [PATCH] drm/vc4: UV planes vertical scaling must always be enabled + +It has been observed that a YUV422 unity scaled plane isn't displayed. +Enabling vertical scaling on the UV planes solves this. There is +already a similar clause to always enable horizontal scaling on the +UV planes. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_plane.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -522,6 +522,12 @@ static int vc4_plane_setup_clipping_and_ + */ + if (vc4_state->x_scaling[1] == VC4_SCALING_NONE) + vc4_state->x_scaling[1] = VC4_SCALING_PPF; ++ ++ /* Similarly UV needs vertical scaling to be enabled. ++ * Without this a 1:1 scaled YUV422 plane isn't rendered. ++ */ ++ if (vc4_state->y_scaling[1] == VC4_SCALING_NONE) ++ vc4_state->y_scaling[1] = VC4_SCALING_PPF; + } else { + vc4_state->is_yuv = false; + vc4_state->x_scaling[1] = VC4_SCALING_NONE; diff --git a/target/linux/bcm27xx/patches-6.1/950-0950-drm-vc4-hdmi-Avoid-hang-with-debug-registers-when-su.patch b/target/linux/bcm27xx/patches-6.1/950-0950-drm-vc4-hdmi-Avoid-hang-with-debug-registers-when-su.patch new file mode 100644 index 0000000000..8e36b79794 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0950-drm-vc4-hdmi-Avoid-hang-with-debug-registers-when-su.patch @@ -0,0 +1,39 @@ +From e5e7679d634b10e88df340c85cd8368c9f9989eb Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Tue, 5 Sep 2023 19:38:24 +0100 +Subject: [PATCH] drm/vc4: hdmi: Avoid hang with debug registers when suspended + +Trying to read /sys/kernel/debug/dri/1/hdmi1_regs +when the hdmi is disconnected results in a fatal system hang. + +This is due to the pm suspend code disabling the dvp clock. +That is just a gate of the 108MHz clock in DVP_HT_RPI_MISC_CONFIG, +which results in accesses hanging AXI bus. + +Protect against this. + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -193,6 +193,8 @@ static int vc4_hdmi_debugfs_regs(struct + if (!drm_dev_enter(drm, &idx)) + return -ENODEV; + ++ WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); ++ + drm_print_regset32(&p, &vc4_hdmi->hdmi_regset); + drm_print_regset32(&p, &vc4_hdmi->hd_regset); + drm_print_regset32(&p, &vc4_hdmi->cec_regset); +@@ -202,6 +204,8 @@ static int vc4_hdmi_debugfs_regs(struct + drm_print_regset32(&p, &vc4_hdmi->ram_regset); + drm_print_regset32(&p, &vc4_hdmi->rm_regset); + ++ pm_runtime_put(&vc4_hdmi->pdev->dev); ++ + drm_dev_exit(idx); + + return 0; diff --git a/target/linux/bcm27xx/patches-6.1/950-0951-drm-vc4-Move-the-buffer-offset-out-of-the-vc4_plane_.patch b/target/linux/bcm27xx/patches-6.1/950-0951-drm-vc4-Move-the-buffer-offset-out-of-the-vc4_plane_.patch new file mode 100644 index 0000000000..eeb2a93b5c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0951-drm-vc4-Move-the-buffer-offset-out-of-the-vc4_plane_.patch @@ -0,0 +1,154 @@ +From 11cf37e741b439b26fe932750bde841a16a96828 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 25 Sep 2023 16:57:07 +0100 +Subject: [PATCH] drm/vc4: Move the buffer offset out of the vc4_plane_state + +The offset fields in vc4_plane_state are described as being +the offset for each buffer in the bo, however it is used to +store the complete DMA address that is then written into the +register. + +The DMA address including the fb ofset can be retrieved +using drm_fb_dma_get_gem_addr, and the offset adjustment due to +clipping is local to vc4_plane_mode_set. +Drop the offset field from the state, and compute the complete +DMA address in vc4_plane_mode_set. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_drv.h | 5 ---- + drivers/gpu/drm/vc4/vc4_plane.c | 51 +++++++++++++-------------------- + 2 files changed, 20 insertions(+), 36 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -451,11 +451,6 @@ struct vc4_plane_state { + bool is_unity; + bool is_yuv; + +- /* Offset to start scanning out from the start of the plane's +- * BO. +- */ +- u32 offsets[3]; +- + /* Our allocation in LBM for temporary storage during scaling. */ + struct drm_mm_node lbm; + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -450,12 +450,11 @@ static int vc4_plane_setup_clipping_and_ + { + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + struct drm_framebuffer *fb = state->fb; +- struct drm_gem_dma_object *bo; + int num_planes = fb->format->num_planes; + struct drm_crtc_state *crtc_state; + u32 h_subsample = fb->format->hsub; + u32 v_subsample = fb->format->vsub; +- int i, ret; ++ int ret; + + crtc_state = drm_atomic_get_existing_crtc_state(state->state, + state->crtc); +@@ -469,11 +468,6 @@ static int vc4_plane_setup_clipping_and_ + if (ret) + return ret; + +- for (i = 0; i < num_planes; i++) { +- bo = drm_fb_dma_get_gem_obj(fb, i); +- vc4_state->offsets[i] = bo->dma_addr + fb->offsets[i]; +- } +- + vc4_state->src_x = state->src.x1; + vc4_state->src_y = state->src.y1; + vc4_state->src_w[0] = state->src.x2 - vc4_state->src_x; +@@ -896,6 +890,7 @@ static int vc4_plane_mode_set(struct drm + u32 width, height; + u32 hvs_format = format->hvs; + unsigned int rotation; ++ u32 offsets[3] = { 0 }; + int ret, i; + + if (vc4_state->dlist_initialized) +@@ -943,13 +938,8 @@ static int vc4_plane_mode_set(struct drm + * out. + */ + for (i = 0; i < num_planes; i++) { +- vc4_state->offsets[i] += src_y / +- (i ? v_subsample : 1) * +- fb->pitches[i]; +- +- vc4_state->offsets[i] += src_x / +- (i ? h_subsample : 1) * +- fb->format->cpp[i]; ++ offsets[i] += src_y / (i ? v_subsample : 1) * fb->pitches[i]; ++ offsets[i] += src_x / (i ? h_subsample : 1) * fb->format->cpp[i]; + } + + break; +@@ -1004,19 +994,18 @@ static int vc4_plane_mode_set(struct drm + VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) | + VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) | + VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R)); +- vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift); +- vc4_state->offsets[0] += subtile_y << 8; +- vc4_state->offsets[0] += utile_y << 4; ++ offsets[0] += tiles_t * (tiles_w << tile_size_shift); ++ offsets[0] += subtile_y << 8; ++ offsets[0] += utile_y << 4; + + /* Rows of tiles alternate left-to-right and right-to-left. */ + if (tiles_t & 1) { + pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR; +- vc4_state->offsets[0] += (tiles_w - tiles_l) << +- tile_size_shift; +- vc4_state->offsets[0] -= (1 + !tile_y) << 10; ++ offsets[0] += (tiles_w - tiles_l) << tile_size_shift; ++ offsets[0] -= (1 + !tile_y) << 10; + } else { +- vc4_state->offsets[0] += tiles_l << tile_size_shift; +- vc4_state->offsets[0] += tile_y << 10; ++ offsets[0] += tiles_l << tile_size_shift; ++ offsets[0] += tile_y << 10; + } + + break; +@@ -1105,11 +1094,9 @@ static int vc4_plane_mode_set(struct drm + + tile = src_x / pix_per_tile; + +- vc4_state->offsets[i] += param * tile_w * tile; +- vc4_state->offsets[i] += src_y / +- (i ? v_subsample : 1) * +- tile_w; +- vc4_state->offsets[i] += x_off & ~(i ? 1 : 0); ++ offsets[i] += param * tile_w * tile; ++ offsets[i] += src_y / (i ? v_subsample : 1) * tile_w; ++ offsets[i] += x_off & ~(i ? 1 : 0); + } + + pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); +@@ -1253,8 +1240,12 @@ static int vc4_plane_mode_set(struct drm + * The pointers may be any byte address. + */ + vc4_state->ptr0_offset[0] = vc4_state->dlist_count; +- for (i = 0; i < num_planes; i++) +- vc4_dlist_write(vc4_state, vc4_state->offsets[i]); ++ ++ for (i = 0; i < num_planes; i++) { ++ dma_addr_t paddr = drm_fb_dma_get_gem_addr(fb, state, i); ++ ++ vc4_dlist_write(vc4_state, paddr + offsets[i]); ++ } + + /* Pointer Context Word 0/1/2: Written by the HVS */ + for (i = 0; i < num_planes; i++) +@@ -1518,8 +1509,6 @@ static void vc4_plane_atomic_async_updat + sizeof(vc4_state->y_scaling)); + vc4_state->is_unity = new_vc4_state->is_unity; + vc4_state->is_yuv = new_vc4_state->is_yuv; +- memcpy(vc4_state->offsets, new_vc4_state->offsets, +- sizeof(vc4_state->offsets)); + vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill; + + /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0952-drm-vc4-Fix-dlist-debug-not-resetting-the-next-entry.patch b/target/linux/bcm27xx/patches-6.1/950-0952-drm-vc4-Fix-dlist-debug-not-resetting-the-next-entry.patch new file mode 100644 index 0000000000..01ad932415 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0952-drm-vc4-Fix-dlist-debug-not-resetting-the-next-entry.patch @@ -0,0 +1,33 @@ +From 3660abb4a8523e988f1345985e89149804e50ebe Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 24 Aug 2023 15:36:21 +0100 +Subject: [PATCH] drm/vc4: Fix dlist debug not resetting the next entry pointer + +The debug function to display the dlists didn't reset next_entry_start +when starting each display, so resulting in not stopping the +list at the correct place. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -110,7 +110,7 @@ static int vc4_hvs_debugfs_dlist(struct + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hvs *hvs = vc4->hvs; + struct drm_printer p = drm_seq_file_printer(m); +- unsigned int next_entry_start = 0; ++ unsigned int next_entry_start; + unsigned int i, j; + u32 dlist_word, dispstat; + +@@ -124,6 +124,7 @@ static int vc4_hvs_debugfs_dlist(struct + } + + drm_printf(&p, "HVS chan %u:\n", i); ++ next_entry_start = 0; + + for (j = HVS_READ(SCALER_DISPLISTX(i)); j < 256; j++) { + dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j); diff --git a/target/linux/bcm27xx/patches-6.1/950-0953-drm-vc4-Remove-incorrect-limit-from-hvs_dlist-debugf.patch b/target/linux/bcm27xx/patches-6.1/950-0953-drm-vc4-Remove-incorrect-limit-from-hvs_dlist-debugf.patch new file mode 100644 index 0000000000..d41d53ecbe --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0953-drm-vc4-Remove-incorrect-limit-from-hvs_dlist-debugf.patch @@ -0,0 +1,57 @@ +From ebf11a4cfd9f1236fb9eeb7e32e87b18f5f56f16 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 1 Sep 2023 13:45:08 +0100 +Subject: [PATCH] drm: vc4: Remove incorrect limit from hvs_dlist debugfs + function + +The debugfs function to dump dlists aborted at 256 bytes, +when actually the dlist memory is generally significantly +larger but varies based on SoC. + +We already have the correct limit in __vc4_hvs_alloc, so +store it for use in the debugfs dlist function. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_hvs.c | 5 ++++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -341,6 +341,7 @@ struct vc4_hvs { + struct platform_device *pdev; + void __iomem *regs; + u32 __iomem *dlist; ++ unsigned int dlist_mem_size; + + struct clk *core_clk; + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -110,6 +110,7 @@ static int vc4_hvs_debugfs_dlist(struct + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hvs *hvs = vc4->hvs; + struct drm_printer p = drm_seq_file_printer(m); ++ unsigned int dlist_mem_size = hvs->dlist_mem_size; + unsigned int next_entry_start; + unsigned int i, j; + u32 dlist_word, dispstat; +@@ -126,7 +127,7 @@ static int vc4_hvs_debugfs_dlist(struct + drm_printf(&p, "HVS chan %u:\n", i); + next_entry_start = 0; + +- for (j = HVS_READ(SCALER_DISPLISTX(i)); j < 256; j++) { ++ for (j = HVS_READ(SCALER_DISPLISTX(i)); j < dlist_mem_size; j++) { + dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j); + drm_printf(&p, "dlist: %02d: 0x%08x\n", j, + dlist_word); +@@ -1278,6 +1279,8 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v + HVS_BOOTLOADER_DLIST_END, + (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END); + ++ hvs->dlist_mem_size = dlist_size; ++ + /* Set up the HVS LBM memory manager. We could have some more + * complicated data structure that allowed reuse of LBM areas + * between planes when they don't overlap on the screen, but diff --git a/target/linux/bcm27xx/patches-6.1/950-0954-drm-vc4-hvs-Remove-ABORT_ON_EMPTY-flag.patch b/target/linux/bcm27xx/patches-6.1/950-0954-drm-vc4-hvs-Remove-ABORT_ON_EMPTY-flag.patch new file mode 100644 index 0000000000..640b0ea757 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0954-drm-vc4-hvs-Remove-ABORT_ON_EMPTY-flag.patch @@ -0,0 +1,50 @@ +From 712bccec241e84e28ccb725fae87d3255d039f42 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Thu, 22 Jun 2023 14:06:40 +0100 +Subject: [PATCH] drm/vc4: hvs: Remove ABORT_ON_EMPTY flag + +ABORT_ON_EMPTY chooses whether the HVS abandons the current frame +when it experiences an underflow, or attempts to continue. + +In theory the frame should be black from the point of underflow, +compared to a shift of sebsequent pixels to the left. + +Unfortunately it seems to put the HVS is a bad state where it is not +possible to recover simply. This typically requires a reboot +following the 'flip done timed out message'. + +Discussion with Broadcom has suggested we don't use this flag. +All their testing is done with it disabled. + +Additionally setting BLANK_INSERT_EN causes the HDMI to output +blank pixels on an underflow which avoids it losing sync. + +After this change a 'flip done timed out' due to sdram bandwidth +starvation or too low a clock is recoverable once the situation improves. + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 1 + + drivers/gpu/drm/vc4/vc4_regs.h | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1866,6 +1866,7 @@ static void vc4_hdmi_encoder_post_crtc_e + VC4_HD_VID_CTL_CLRRGB | + VC4_HD_VID_CTL_UNDERFLOW_ENABLE | + VC4_HD_VID_CTL_FRAME_COUNTER_RESET | ++ VC4_HD_VID_CTL_BLANK_INSERT_EN | + (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | + (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); + +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -799,6 +799,7 @@ enum { + # define VC4_HD_VID_CTL_CLRSYNC BIT(24) + # define VC4_HD_VID_CTL_CLRRGB BIT(23) + # define VC4_HD_VID_CTL_BLANKPIX BIT(18) ++# define VC4_HD_VID_CTL_BLANK_INSERT_EN BIT(16) + + # define VC4_HD_CSC_CTL_ORDER_MASK VC4_MASK(7, 5) + # define VC4_HD_CSC_CTL_ORDER_SHIFT 5 diff --git a/target/linux/bcm27xx/patches-6.1/950-0955-drm-vc4-Enable-SCALER_CONTROL-early-in-HVS-init.patch b/target/linux/bcm27xx/patches-6.1/950-0955-drm-vc4-Enable-SCALER_CONTROL-early-in-HVS-init.patch new file mode 100644 index 0000000000..3060c0201f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0955-drm-vc4-Enable-SCALER_CONTROL-early-in-HVS-init.patch @@ -0,0 +1,59 @@ +From 542ba979b4fa1e07ff2ad2dabbdc12e92b80ed46 Mon Sep 17 00:00:00 2001 +From: Tim Gover +Date: Thu, 13 Jul 2023 17:47:22 +0100 +Subject: [PATCH] drm/vc4: Enable SCALER_CONTROL early in HVS init + +Always enable SCALER_CONTROL before attempting other HVS +operations. It's safe to write to some parts of the HVS but +in general it's dangerous to do this because it can cause bus +lockups. + +Signed-off-by: Tim Gover +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -1303,6 +1303,10 @@ static int vc4_hvs_hw_init(struct vc4_hv + struct vc4_dev *vc4 = hvs->vc4; + u32 dispctrl, reg; + ++ dispctrl = HVS_READ(SCALER_DISPCTRL); ++ dispctrl |= SCALER_DISPCTRL_ENABLE; ++ HVS_WRITE(SCALER_DISPCTRL, dispctrl); ++ + reg = HVS_READ(SCALER_DISPECTRL); + reg &= ~SCALER_DISPECTRL_DSP2_MUX_MASK; + HVS_WRITE(SCALER_DISPECTRL, +@@ -1324,8 +1328,6 @@ static int vc4_hvs_hw_init(struct vc4_hv + reg | VC4_SET_FIELD(3, SCALER_DISPDITHER_DSP5_MUX)); + + dispctrl = HVS_READ(SCALER_DISPCTRL); +- +- dispctrl |= SCALER_DISPCTRL_ENABLE; + dispctrl |= SCALER_DISPCTRL_DISPEIRQ(0) | + SCALER_DISPCTRL_DISPEIRQ(1) | + SCALER_DISPCTRL_DISPEIRQ(2); +@@ -1521,6 +1523,10 @@ static int vc4_hvs_bind(struct device *d + else + hvs->dlist = hvs->regs + SCALER5_DLIST_START; + ++ ret = vc4_hvs_hw_init(hvs); ++ if (ret) ++ return ret; ++ + /* Upload filter kernels. We only have the one for now, so we + * keep it around for the lifetime of the driver. + */ +@@ -1530,10 +1536,6 @@ static int vc4_hvs_bind(struct device *d + if (ret) + return ret; + +- ret = vc4_hvs_hw_init(hvs); +- if (ret) +- return ret; +- + ret = vc4_hvs_cob_init(hvs); + if (ret) + return ret; diff --git a/target/linux/bcm27xx/patches-6.1/950-0956-dt-bindings-display-Add-BCM2712-HDMI-bindings.patch b/target/linux/bcm27xx/patches-6.1/950-0956-dt-bindings-display-Add-BCM2712-HDMI-bindings.patch new file mode 100644 index 0000000000..dab1fff2e3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0956-dt-bindings-display-Add-BCM2712-HDMI-bindings.patch @@ -0,0 +1,26 @@ +From aed3dadaa6fb4c38275b264ecc0ff5ebe0408b82 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:36:02 +0100 +Subject: [PATCH] dt-bindings: display: Add BCM2712 HDMI bindings + +The BCM2712 HDMI controller uses a slightly different HDMI controller +than the BCM2711, and a completely different PHY. + +Let's introduce a new compatible for it. + +Signed-off-by: Maxime Ripard +--- + .../devicetree/bindings/display/brcm,bcm2711-hdmi.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml +@@ -14,6 +14,8 @@ properties: + enum: + - brcm,bcm2711-hdmi0 + - brcm,bcm2711-hdmi1 ++ - brcm,bcm2712-hdmi0 ++ - brcm,bcm2712-hdmi1 + + reg: + items: diff --git a/target/linux/bcm27xx/patches-6.1/950-0957-dt-bindings-display-Add-BCM2712-HVS-bindings.patch b/target/linux/bcm27xx/patches-6.1/950-0957-dt-bindings-display-Add-BCM2712-HVS-bindings.patch new file mode 100644 index 0000000000..e28100734f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0957-dt-bindings-display-Add-BCM2712-HVS-bindings.patch @@ -0,0 +1,34 @@ +From 2f5a75f9687553d6e91fcc09b233f5f6176b3681 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:36:14 +0100 +Subject: [PATCH] dt-bindings: display: Add BCM2712 HVS bindings + +The BCM2712 has a completely different HVS than the previous +generations, so let's add a new compatible for it. + +Signed-off-by: Maxime Ripard +--- + .../devicetree/bindings/display/brcm,bcm2835-hvs.yaml | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml +@@ -13,6 +13,7 @@ properties: + compatible: + enum: + - brcm,bcm2711-hvs ++ - brcm,bcm2712-hvs + - brcm,bcm2835-hvs + + reg: +@@ -36,7 +37,9 @@ if: + properties: + compatible: + contains: +- const: brcm,bcm2711-hvs ++ enum: ++ - brcm,bcm2711-hvs ++ - brcm,bcm2712-hvs + + then: + required: diff --git a/target/linux/bcm27xx/patches-6.1/950-0958-dt-bindings-display-Add-BCM2712-PixelValve-bindings.patch b/target/linux/bcm27xx/patches-6.1/950-0958-dt-bindings-display-Add-BCM2712-PixelValve-bindings.patch new file mode 100644 index 0000000000..b37c1274ae --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0958-dt-bindings-display-Add-BCM2712-PixelValve-bindings.patch @@ -0,0 +1,28 @@ +From 9f26d5827745df2c59e5559fd59a5045a4ad7ce0 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:36:27 +0100 +Subject: [PATCH] dt-bindings: display: Add BCM2712 PixelValve bindings + +The BCM2712 has 3 different pixelvalves that are similar to the ones +found in the previous generations but with slightly different +capabilities. + +Express that using a new set of compatibles. + +Signed-off-by: Maxime Ripard +--- + .../devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml +@@ -20,6 +20,9 @@ properties: + - brcm,bcm2711-pixelvalve2 + - brcm,bcm2711-pixelvalve3 + - brcm,bcm2711-pixelvalve4 ++ - brcm,bcm2712-pixelvalve0 ++ - brcm,bcm2712-pixelvalve1 ++ - brcm,bcm2712-pixelvalve2 + + reg: + maxItems: 1 diff --git a/target/linux/bcm27xx/patches-6.1/950-0959-dt-bindings-display-Add-BCM2712-MOP-bindings.patch b/target/linux/bcm27xx/patches-6.1/950-0959-dt-bindings-display-Add-BCM2712-MOP-bindings.patch new file mode 100644 index 0000000000..ea537522cc --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0959-dt-bindings-display-Add-BCM2712-MOP-bindings.patch @@ -0,0 +1,28 @@ +From 07f90ad6a81d9ed923ee0da05541718baf49fb3c Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:36:36 +0100 +Subject: [PATCH] dt-bindings: display: Add BCM2712 MOP bindings + +The BCM2712 has a MOP controller which is basically a new revision of +the TXP. + +Express that by adding a new compatible for it. + +Signed-off-by: Maxime Ripard +--- + .../devicetree/bindings/display/brcm,bcm2835-txp.yaml | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml +@@ -11,7 +11,9 @@ maintainers: + + properties: + compatible: +- const: brcm,bcm2835-txp ++ enum: ++ - brcm,bcm2712-mop ++ - brcm,bcm2835-txp + + reg: + maxItems: 1 diff --git a/target/linux/bcm27xx/patches-6.1/950-0960-dt-bindings-display-Add-BCM2712-MOPLET-bindings.patch b/target/linux/bcm27xx/patches-6.1/950-0960-dt-bindings-display-Add-BCM2712-MOPLET-bindings.patch new file mode 100644 index 0000000000..97aaf5bb7a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0960-dt-bindings-display-Add-BCM2712-MOPLET-bindings.patch @@ -0,0 +1,25 @@ +From e4a3722d08c723f1212bfbdcb52710de8340720a Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:36:36 +0100 +Subject: [PATCH] dt-bindings: display: Add BCM2712 MOPLET bindings + +The BCM2712 has a MOPLET controller which is basically a TXP without the +transpose feature. + +Express that by adding a new compatible for it. + +Signed-off-by: Maxime Ripard +--- + Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml +@@ -13,6 +13,7 @@ properties: + compatible: + enum: + - brcm,bcm2712-mop ++ - brcm,bcm2712-moplet + - brcm,bcm2835-txp + + reg: diff --git a/target/linux/bcm27xx/patches-6.1/950-0961-dt-bindings-display-Add-BCM2712-KMS-driver-bindings.patch b/target/linux/bcm27xx/patches-6.1/950-0961-dt-bindings-display-Add-BCM2712-KMS-driver-bindings.patch new file mode 100644 index 0000000000..420c66ce66 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0961-dt-bindings-display-Add-BCM2712-KMS-driver-bindings.patch @@ -0,0 +1,23 @@ +From e66d4b49a027257c347fa57ce6972f08747c0917 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:36:51 +0100 +Subject: [PATCH] dt-bindings: display: Add BCM2712 KMS driver bindings + +The BCM2712 SoC comes with a new variation of the videocore display +pipeline. Let's create a new compatible for it. + +Signed-off-by: Maxime Ripard +--- + Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml +@@ -18,6 +18,7 @@ properties: + compatible: + enum: + - brcm,bcm2711-vc5 ++ - brcm,bcm2712-vc6 + - brcm,bcm2835-vc4 + - brcm,cygnus-vc4 + diff --git a/target/linux/bcm27xx/patches-6.1/950-0962-drm-vc4-drv-Support-BCM2712.patch b/target/linux/bcm27xx/patches-6.1/950-0962-drm-vc4-drv-Support-BCM2712.patch new file mode 100644 index 0000000000..57a797ce18 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0962-drm-vc4-drv-Support-BCM2712.patch @@ -0,0 +1,47 @@ +From 847ec495822ad512dd9f1a58a85dabea01534855 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 15:29:52 +0100 +Subject: [PATCH] drm/vc4: drv: Support BCM2712 + +The BCM2712 has an improved display pipeline, most notably with a +different HVS and only HDMI and writeback outputs. + +Let's introduce it as a new VideoCore generation and compatible. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.c | 5 ++++- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + 2 files changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -310,7 +310,9 @@ static int vc4_drm_bind(struct device *d + + dev->coherent_dma_mask = DMA_BIT_MASK(32); + +- if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-vc5")) ++ if (of_device_is_compatible(dev->of_node, "brcm,bcm2712-vc6")) ++ gen = VC4_GEN_6; ++ else if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-vc5")) + gen = VC4_GEN_5; + else + gen = VC4_GEN_4; +@@ -475,6 +477,7 @@ static int vc4_platform_drm_remove(struc + + static const struct of_device_id vc4_of_match[] = { + { .compatible = "brcm,bcm2711-vc5", }, ++ { .compatible = "brcm,bcm2712-vc6", }, + { .compatible = "brcm,bcm2835-vc4", }, + { .compatible = "brcm,cygnus-vc4", }, + {}, +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -84,6 +84,7 @@ struct vc4_perfmon { + enum vc4_gen { + VC4_GEN_4, + VC4_GEN_5, ++ VC4_GEN_6, + }; + + struct vc4_dev { diff --git a/target/linux/bcm27xx/patches-6.1/950-0963-drm-vc4-hvs-Support-BCM2712-HVS.patch b/target/linux/bcm27xx/patches-6.1/950-0963-drm-vc4-hvs-Support-BCM2712-HVS.patch new file mode 100644 index 0000000000..9659432294 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0963-drm-vc4-hvs-Support-BCM2712-HVS.patch @@ -0,0 +1,2139 @@ +From e84da235223d0209165183c430692dde5c69854c Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 15:25:16 +0100 +Subject: [PATCH] drm/vc4: hvs: Support BCM2712 HVS + +The HVS found in the BCM2712, while having a similar role, is very +different from the one found in the previous SoCs. Indeed, the register +layout is fairly different, and the DLIST format is new as well. + +Let's introduce the needed functions to support the new HVS. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 47 ++- + drivers/gpu/drm/vc4/vc4_drv.c | 8 +- + drivers/gpu/drm/vc4/vc4_drv.h | 18 + + drivers/gpu/drm/vc4/vc4_hvs.c | 626 ++++++++++++++++++++++++++++--- + drivers/gpu/drm/vc4/vc4_kms.c | 102 ++++- + drivers/gpu/drm/vc4/vc4_plane.c | 641 +++++++++++++++++++++++++++++++- + drivers/gpu/drm/vc4/vc4_regs.h | 181 +++++++++ + 7 files changed, 1540 insertions(+), 83 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -82,13 +82,22 @@ static unsigned int + vc4_crtc_get_cob_allocation(struct vc4_dev *vc4, unsigned int channel) + { + struct vc4_hvs *hvs = vc4->hvs; +- u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel)); ++ u32 dispbase, top, base; ++ + /* Top/base are supposed to be 4-pixel aligned, but the + * Raspberry Pi firmware fills the low bits (which are + * presumably ignored). + */ +- u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3; +- u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3; ++ ++ if (vc4->gen >= VC4_GEN_6) { ++ dispbase = HVS_READ(SCALER6_DISPX_COB(channel)); ++ top = VC4_GET_FIELD(dispbase, SCALER6_DISPX_COB_TOP) & ~3; ++ base = VC4_GET_FIELD(dispbase, SCALER6_DISPX_COB_BASE) & ~3; ++ } else { ++ dispbase = HVS_READ(SCALER_DISPBASEX(channel)); ++ top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3; ++ base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3; ++ } + + return top - base + 4; + } +@@ -121,7 +130,10 @@ static bool vc4_crtc_get_scanout_positio + * Read vertical scanline which is currently composed for our + * pixelvalve by the HVS, and also the scaler status. + */ +- val = HVS_READ(SCALER_DISPSTATX(channel)); ++ if (vc4->gen >= VC4_GEN_6) ++ val = HVS_READ(SCALER6_DISPX_STATUS(channel)); ++ else ++ val = HVS_READ(SCALER_DISPSTATX(channel)); + + /* Get optional system timestamp after query. */ + if (etime) +@@ -130,7 +142,12 @@ static bool vc4_crtc_get_scanout_positio + /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ + + /* Vertical position of hvs composed scanline. */ +- *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE); ++ ++ if (vc4->gen >= VC4_GEN_6) ++ *vpos = VC4_GET_FIELD(val, SCALER6_DISPX_STATUS_YLINE); ++ else ++ *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE); ++ + *hpos = 0; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { +@@ -475,8 +492,10 @@ static void require_hvs_enabled(struct d + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hvs *hvs = vc4->hvs; + +- WARN_ON_ONCE((HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE) != +- SCALER_DISPCTRL_ENABLE); ++ if (vc4->gen >= VC4_GEN_6) ++ WARN_ON_ONCE(!(HVS_READ(SCALER6_CONTROL) & SCALER6_CONTROL_HVS_EN)); ++ else ++ WARN_ON_ONCE(!(HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE)); + } + + static int vc4_crtc_disable(struct drm_crtc *crtc, +@@ -804,14 +823,21 @@ static void vc4_crtc_handle_page_flip(st + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hvs *hvs = vc4->hvs; ++ unsigned int current_dlist; + u32 chan = vc4_crtc->current_hvs_channel; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + spin_lock(&vc4_crtc->irq_lock); ++ ++ if (vc4->gen >= VC4_GEN_6) ++ current_dlist = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_DL(chan)), ++ SCALER6_DISPX_DL_LACT); ++ else ++ current_dlist = HVS_READ(SCALER_DISPLACTX(chan)); ++ + if (vc4_crtc->event && +- (vc4_crtc->current_dlist == HVS_READ(SCALER_DISPLACTX(chan)) || +- vc4_crtc->feeds_txp)) { ++ (vc4_crtc->current_dlist == current_dlist || vc4_crtc->feeds_txp)) { + drm_crtc_send_vblank_event(crtc, vc4_crtc->event); + vc4_crtc->event = NULL; + drm_crtc_vblank_put(crtc); +@@ -822,7 +848,8 @@ static void vc4_crtc_handle_page_flip(st + * the CRTC and encoder already reconfigured, leading to + * underruns. This can be seen when reconfiguring the CRTC. + */ +- vc4_hvs_unmask_underrun(hvs, chan); ++ if (vc4->gen < VC4_GEN_6) ++ vc4_hvs_unmask_underrun(hvs, chan); + } + spin_unlock(&vc4_crtc->irq_lock); + spin_unlock_irqrestore(&dev->event_lock, flags); +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -277,6 +277,7 @@ static const struct of_device_id vc4_dma + { .compatible = "brcm,bcm2711-hvs" }, + { .compatible = "brcm,bcm2835-hvs" }, + { .compatible = "brcm,bcm2711-hvs" }, ++ { .compatible = "brcm,bcm2712-hvs" }, + { .compatible = "raspberrypi,rpi-firmware-kms" }, + { .compatible = "brcm,bcm2835-v3d" }, + { .compatible = "brcm,cygnus-v3d" }, +@@ -308,8 +309,6 @@ static int vc4_drm_bind(struct device *d + enum vc4_gen gen; + int ret = 0; + +- dev->coherent_dma_mask = DMA_BIT_MASK(32); +- + if (of_device_is_compatible(dev->of_node, "brcm,bcm2712-vc6")) + gen = VC4_GEN_6; + else if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-vc5")) +@@ -322,6 +321,11 @@ static int vc4_drm_bind(struct device *d + else + driver = &vc4_drm_driver; + ++ if (gen >= VC4_GEN_6) ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36)); ++ else ++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); ++ + node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches, + NULL); + if (node) { +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -345,8 +345,10 @@ struct vc4_hvs { + unsigned int dlist_mem_size; + + struct clk *core_clk; ++ struct clk *disp_clk; + + struct { ++ unsigned int desc; + unsigned int enabled: 1; + } eof_irq[HVS_NUM_CHANNELS]; + +@@ -358,6 +360,11 @@ struct vc4_hvs { + struct drm_mm dlist_mm; + /* Memory manager for the LBM memory used by HVS scaling. */ + struct drm_mm lbm_mm; ++ ++ /* Memory manager for the UPM memory used for prefetching. */ ++ struct drm_mm upm_mm; ++ struct ida upm_handles; ++ + spinlock_t mm_lock; + + struct list_head stale_dlist_entries; +@@ -382,6 +389,8 @@ struct vc4_hvs { + bool vc5_hdmi_enable_4096by2160; + }; + ++#define HVS_UBM_WORD_SIZE 256 ++ + struct vc4_hvs_state { + struct drm_private_state base; + unsigned long core_clock_rate; +@@ -456,6 +465,15 @@ struct vc4_plane_state { + /* Our allocation in LBM for temporary storage during scaling. */ + struct drm_mm_node lbm; + ++ /* Our allocation in UPM for prefetching. */ ++ struct drm_mm_node upm[DRM_FORMAT_MAX_PLANES]; ++ ++ /* The Unified Pre-Fetcher Handle */ ++ unsigned int upm_handle[DRM_FORMAT_MAX_PLANES]; ++ ++ /* Number of lines to pre-fetch */ ++ unsigned int upm_buffer_lines; ++ + /* Set when the plane has per-pixel alpha content or does not cover + * the entire screen. This is a hint to the CRTC that it might need + * to enable background color fill. +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -67,6 +67,80 @@ static const struct debugfs_reg32 vc4_hv + VC4_REG32(SCALER_OLEDCOEF2), + }; + ++static const struct debugfs_reg32 vc6_hvs_regs[] = { ++ VC4_REG32(SCALER6_VERSION), ++ VC4_REG32(SCALER6_CXM_SIZE), ++ VC4_REG32(SCALER6_LBM_SIZE), ++ VC4_REG32(SCALER6_UBM_SIZE), ++ VC4_REG32(SCALER6_COBA_SIZE), ++ VC4_REG32(SCALER6_COB_SIZE), ++ VC4_REG32(SCALER6_CONTROL), ++ VC4_REG32(SCALER6_FETCHER_STATUS), ++ VC4_REG32(SCALER6_FETCH_STATUS), ++ VC4_REG32(SCALER6_HANDLE_ERROR), ++ VC4_REG32(SCALER6_DISP0_CTRL0), ++ VC4_REG32(SCALER6_DISP0_CTRL1), ++ VC4_REG32(SCALER6_DISP0_BGND), ++ VC4_REG32(SCALER6_DISP0_LPTRS), ++ VC4_REG32(SCALER6_DISP0_COB), ++ VC4_REG32(SCALER6_DISP0_STATUS), ++ VC4_REG32(SCALER6_DISP0_DL), ++ VC4_REG32(SCALER6_DISP0_RUN), ++ VC4_REG32(SCALER6_DISP1_CTRL0), ++ VC4_REG32(SCALER6_DISP1_CTRL1), ++ VC4_REG32(SCALER6_DISP1_BGND), ++ VC4_REG32(SCALER6_DISP1_LPTRS), ++ VC4_REG32(SCALER6_DISP1_COB), ++ VC4_REG32(SCALER6_DISP1_STATUS), ++ VC4_REG32(SCALER6_DISP1_DL), ++ VC4_REG32(SCALER6_DISP1_RUN), ++ VC4_REG32(SCALER6_DISP2_CTRL0), ++ VC4_REG32(SCALER6_DISP2_CTRL1), ++ VC4_REG32(SCALER6_DISP2_BGND), ++ VC4_REG32(SCALER6_DISP2_LPTRS), ++ VC4_REG32(SCALER6_DISP2_COB), ++ VC4_REG32(SCALER6_DISP2_STATUS), ++ VC4_REG32(SCALER6_DISP2_DL), ++ VC4_REG32(SCALER6_DISP2_RUN), ++ VC4_REG32(SCALER6_EOLN), ++ VC4_REG32(SCALER6_DL_STATUS), ++ VC4_REG32(SCALER6_BFG_MISC), ++ VC4_REG32(SCALER6_QOS0), ++ VC4_REG32(SCALER6_PROF0), ++ VC4_REG32(SCALER6_QOS1), ++ VC4_REG32(SCALER6_PROF1), ++ VC4_REG32(SCALER6_QOS2), ++ VC4_REG32(SCALER6_PROF2), ++ VC4_REG32(SCALER6_PRI_MAP0), ++ VC4_REG32(SCALER6_PRI_MAP1), ++ VC4_REG32(SCALER6_HISTCTRL), ++ VC4_REG32(SCALER6_HISTBIN0), ++ VC4_REG32(SCALER6_HISTBIN1), ++ VC4_REG32(SCALER6_HISTBIN2), ++ VC4_REG32(SCALER6_HISTBIN3), ++ VC4_REG32(SCALER6_HISTBIN4), ++ VC4_REG32(SCALER6_HISTBIN5), ++ VC4_REG32(SCALER6_HISTBIN6), ++ VC4_REG32(SCALER6_HISTBIN7), ++ VC4_REG32(SCALER6_HDR_CFG_REMAP), ++ VC4_REG32(SCALER6_COL_SPACE), ++ VC4_REG32(SCALER6_HVS_ID), ++ VC4_REG32(SCALER6_CFC1), ++ VC4_REG32(SCALER6_DISP_UPM_ISO0), ++ VC4_REG32(SCALER6_DISP_UPM_ISO1), ++ VC4_REG32(SCALER6_DISP_UPM_ISO2), ++ VC4_REG32(SCALER6_DISP_LBM_ISO0), ++ VC4_REG32(SCALER6_DISP_LBM_ISO1), ++ VC4_REG32(SCALER6_DISP_LBM_ISO2), ++ VC4_REG32(SCALER6_DISP_COB_ISO0), ++ VC4_REG32(SCALER6_DISP_COB_ISO1), ++ VC4_REG32(SCALER6_DISP_COB_ISO2), ++ VC4_REG32(SCALER6_BAD_COB), ++ VC4_REG32(SCALER6_BAD_LBM), ++ VC4_REG32(SCALER6_BAD_UPM), ++ VC4_REG32(SCALER6_BAD_AXI), ++}; ++ + void vc4_hvs_dump_state(struct vc4_hvs *hvs) + { + struct drm_device *drm = &hvs->vc4->base; +@@ -145,6 +219,55 @@ static int vc4_hvs_debugfs_dlist(struct + return 0; + } + ++static int vc6_hvs_debugfs_dlist(struct seq_file *m, void *data) ++{ ++ struct drm_info_node *node = m->private; ++ struct drm_device *dev = node->minor->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct drm_printer p = drm_seq_file_printer(m); ++ unsigned int dlist_mem_size = hvs->dlist_mem_size; ++ unsigned int next_entry_start; ++ unsigned int i; ++ ++ for (i = 0; i < SCALER_CHANNELS_COUNT; i++) { ++ unsigned int active_dlist, dispstat; ++ unsigned int j; ++ ++ dispstat = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_STATUS(i)), ++ SCALER6_DISPX_STATUS_MODE); ++ if (dispstat == SCALER6_DISPX_STATUS_MODE_DISABLED || ++ dispstat == SCALER6_DISPX_STATUS_MODE_EOF) { ++ drm_printf(&p, "HVS chan %u disabled\n", i); ++ continue; ++ } ++ ++ drm_printf(&p, "HVS chan %u:\n", i); ++ ++ active_dlist = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_DL(i)), ++ SCALER6_DISPX_DL_LACT); ++ next_entry_start = 0; ++ ++ for (j = active_dlist; j < dlist_mem_size; j++) { ++ u32 dlist_word; ++ ++ dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j); ++ drm_printf(&p, "dlist: %02d: 0x%08x\n", j, ++ dlist_word); ++ if (!next_entry_start || ++ next_entry_start == j) { ++ if (dlist_word & SCALER_CTL0_END) ++ break; ++ next_entry_start = j + ++ VC4_GET_FIELD(dlist_word, ++ SCALER_CTL0_SIZE); ++ } ++ } ++ } ++ ++ return 0; ++} ++ + static int vc5_hvs_debugfs_gamma(struct seq_file *m, void *data) + { + struct drm_info_node *node = m->private; +@@ -435,6 +558,10 @@ static void vc4_hvs_irq_enable_eof(struc + SCALER5_DISPCTRL_DSPEIEOF(channel)); + break; + ++ case VC4_GEN_6: ++ enable_irq(hvs->eof_irq[channel].desc); ++ break; ++ + default: + break; + } +@@ -463,6 +590,10 @@ static void vc4_hvs_irq_clear_eof(struct + ~SCALER5_DISPCTRL_DSPEIEOF(channel)); + break; + ++ case VC4_GEN_6: ++ disable_irq_nosync(hvs->eof_irq[channel].desc); ++ break; ++ + default: + break; + } +@@ -622,26 +753,32 @@ static void vc4_hvs_dlist_free_work(stru + + u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo) + { +- struct drm_device *drm = &hvs->vc4->base; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; + u8 field = 0; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return 0; + +- switch (fifo) { +- case 0: +- field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), +- SCALER_DISPSTAT1_FRCNT0); +- break; +- case 1: +- field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), +- SCALER_DISPSTAT1_FRCNT1); +- break; +- case 2: +- field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2), +- SCALER_DISPSTAT2_FRCNT2); +- break; ++ if (vc4->gen >= VC4_GEN_6) { ++ field = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_STATUS(fifo)), ++ SCALER6_DISPX_STATUS_FRCNT); ++ } else { ++ switch (fifo) { ++ case 0: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), ++ SCALER_DISPSTAT1_FRCNT0); ++ break; ++ case 1: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), ++ SCALER_DISPSTAT1_FRCNT1); ++ break; ++ case 2: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2), ++ SCALER_DISPSTAT2_FRCNT2); ++ break; ++ } + } + + drm_dev_exit(idx); +@@ -708,6 +845,23 @@ int vc4_hvs_get_fifo_from_output(struct + default: + return -EPIPE; + } ++ ++ case VC4_GEN_6: ++ switch (output) { ++ case 0: ++ return 0; ++ ++ case 2: ++ return 2; ++ ++ case 1: ++ case 3: ++ case 4: ++ return 1; ++ ++ default: ++ return -EPIPE; ++ } + } + + return -EPIPE; +@@ -782,7 +936,41 @@ static int vc4_hvs_init_channel(struct v + return 0; + } + +-void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) ++static int vc6_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc, ++ struct drm_display_mode *mode, bool oneshot) ++{ ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; ++ struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); ++ unsigned int chan = vc4_crtc_state->assigned_channel; ++ bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; ++ u32 disp_ctrl1; ++ int idx; ++ ++ if (!drm_dev_enter(drm, &idx)) ++ return -ENODEV; ++ ++ HVS_WRITE(SCALER6_DISPX_CTRL0(chan), SCALER6_DISPX_CTRL0_RESET); ++ ++ disp_ctrl1 = HVS_READ(SCALER6_DISPX_CTRL1(chan)); ++ disp_ctrl1 &= ~SCALER6_DISPX_CTRL1_INTLACE; ++ HVS_WRITE(SCALER6_DISPX_CTRL1(chan), ++ disp_ctrl1 | (interlace ? SCALER6_DISPX_CTRL1_INTLACE : 0)); ++ ++ HVS_WRITE(SCALER6_DISPX_CTRL0(chan), ++ SCALER6_DISPX_CTRL0_ENB | ++ VC4_SET_FIELD(mode->hdisplay - 1, ++ SCALER6_DISPX_CTRL0_FWIDTH) | ++ (oneshot ? SCALER6_DISPX_CTRL0_ONESHOT : 0) | ++ VC4_SET_FIELD(mode->vdisplay - 1, ++ SCALER6_DISPX_CTRL0_LINES)); ++ ++ drm_dev_exit(idx); ++ ++ return 0; ++} ++ ++static void __vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) + { + struct drm_device *drm = &hvs->vc4->base; + int idx; +@@ -813,6 +1001,42 @@ out: + drm_dev_exit(idx); + } + ++static void __vc6_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) ++{ ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; ++ int idx; ++ ++ if (!drm_dev_enter(drm, &idx)) ++ return; ++ ++ if (HVS_READ(SCALER6_DISPX_CTRL0(chan)) & SCALER6_DISPX_CTRL0_ENB) ++ goto out; ++ ++ HVS_WRITE(SCALER6_DISPX_CTRL0(chan), ++ HVS_READ(SCALER6_DISPX_CTRL0(chan)) | SCALER6_DISPX_CTRL0_RESET); ++ ++ HVS_WRITE(SCALER6_DISPX_CTRL0(chan), ++ HVS_READ(SCALER6_DISPX_CTRL0(chan)) & ~SCALER6_DISPX_CTRL0_ENB); ++ ++ WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_STATUS(chan)), ++ SCALER6_DISPX_STATUS_MODE) != ++ SCALER6_DISPX_STATUS_MODE_DISABLED); ++ ++out: ++ drm_dev_exit(idx); ++} ++ ++void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) ++{ ++ struct vc4_dev *vc4 = hvs->vc4; ++ ++ if (vc4->gen >= VC4_GEN_6) ++ __vc6_hvs_stop_channel(hvs, chan); ++ else ++ __vc4_hvs_stop_channel(hvs, chan); ++} ++ + static int vc4_hvs_gamma_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) + { +@@ -907,8 +1131,14 @@ static void vc4_hvs_install_dlist(struct + return; + + WARN_ON(!vc4_state->mm); +- HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), +- vc4_state->mm->mm_node.start); ++ ++ if (vc4->gen >= VC4_GEN_6) ++ HVS_WRITE(SCALER6_DISPX_LPTRS(vc4_state->assigned_channel), ++ VC4_SET_FIELD(vc4_state->mm->mm_node.start, ++ SCALER6_DISPX_LPTRS_HEADE)); ++ else ++ HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), ++ vc4_state->mm->mm_node.start); + + drm_dev_exit(idx); + } +@@ -965,7 +1195,11 @@ void vc4_hvs_atomic_enable(struct drm_cr + + vc4_hvs_install_dlist(crtc); + vc4_hvs_update_dlist(crtc); +- vc4_hvs_init_channel(vc4->hvs, crtc, mode, oneshot); ++ ++ if (vc4->gen >= VC4_GEN_6) ++ vc6_hvs_init_channel(vc4->hvs, crtc, mode, oneshot); ++ else ++ vc4_hvs_init_channel(vc4->hvs, crtc, mode, oneshot); + } + + void vc4_hvs_atomic_disable(struct drm_crtc *crtc, +@@ -1052,13 +1286,28 @@ void vc4_hvs_atomic_flush(struct drm_crt + WARN_ON(!vc4_state->mm); + WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm->mm_node.size); + +- if (enable_bg_fill) ++ if (enable_bg_fill) { + /* This sets a black background color fill, as is the case + * with other DRM drivers. + */ +- HVS_WRITE(SCALER_DISPBKGNDX(channel), +- HVS_READ(SCALER_DISPBKGNDX(channel)) | +- SCALER_DISPBKGND_FILL); ++ if (vc4->gen >= VC4_GEN_6) ++ HVS_WRITE(SCALER6_DISPX_CTRL1(channel), ++ HVS_READ(SCALER6_DISPX_CTRL1(channel)) | ++ SCALER6_DISPX_CTRL1_BGENB); ++ else ++ HVS_WRITE(SCALER_DISPBKGNDX(channel), ++ HVS_READ(SCALER_DISPBKGNDX(channel)) | ++ SCALER_DISPBKGND_FILL); ++ } else { ++ if (vc4->gen >= VC4_GEN_6) ++ HVS_WRITE(SCALER6_DISPX_CTRL1(channel), ++ HVS_READ(SCALER6_DISPX_CTRL1(channel)) & ++ ~SCALER6_DISPX_CTRL1_BGENB); ++ else ++ HVS_WRITE(SCALER_DISPBKGNDX(channel), ++ HVS_READ(SCALER_DISPBKGNDX(channel)) & ++ ~SCALER_DISPBKGND_FILL); ++ } + + /* Only update DISPLIST if the CRTC was already running and is not + * being disabled. +@@ -1210,6 +1459,27 @@ static irqreturn_t vc4_hvs_irq_handler(i + return irqret; + } + ++static irqreturn_t vc6_hvs_eof_irq_handler(int irq, void *data) ++{ ++ struct drm_device *dev = data; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ unsigned int i; ++ ++ for (i = 0; i < HVS_NUM_CHANNELS; i++) { ++ if (!hvs->eof_irq[i].enabled) ++ continue; ++ ++ if (hvs->eof_irq[i].desc != irq) ++ continue; ++ ++ vc4_hvs_schedule_dlist_sweep(hvs, i); ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ + int vc4_hvs_debugfs_init(struct drm_minor *minor) + { + struct drm_device *drm = minor->dev; +@@ -1232,8 +1502,10 @@ int vc4_hvs_debugfs_init(struct drm_mino + NULL); + } + +- ret = vc4_debugfs_add_file(minor, "hvs_dlists", +- vc4_hvs_debugfs_dlist, NULL); ++ if (vc4->gen >= VC4_GEN_6) ++ ret = vc4_debugfs_add_file(minor, "hvs_dlists", vc6_hvs_debugfs_dlist, NULL); ++ else ++ ret = vc4_debugfs_add_file(minor, "hvs_dlists", vc4_hvs_debugfs_dlist, NULL); + if (ret) + return ret; + +@@ -1256,6 +1528,9 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v + { + struct drm_device *drm = &vc4->base; + struct vc4_hvs *hvs; ++ unsigned int dlist_start; ++ size_t dlist_size; ++ size_t lbm_size; + + hvs = drmm_kzalloc(drm, sizeof(*hvs), GFP_KERNEL); + if (!hvs) +@@ -1270,14 +1545,39 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v + INIT_LIST_HEAD(&hvs->stale_dlist_entries); + INIT_WORK(&hvs->free_dlist_work, vc4_hvs_dlist_free_work); + +- /* Set up the HVS display list memory manager. We never +- * overwrite the setup from the bootloader (just 128b out of +- * our 16K), since we don't want to scramble the screen when +- * transitioning from the firmware's boot setup to runtime. +- */ +- drm_mm_init(&hvs->dlist_mm, +- HVS_BOOTLOADER_DLIST_END, +- (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END); ++ switch (vc4->gen) { ++ case VC4_GEN_4: ++ case VC4_GEN_5: ++ /* Set up the HVS display list memory manager. We never ++ * overwrite the setup from the bootloader (just 128b ++ * out of our 16K), since we don't want to scramble the ++ * screen when transitioning from the firmware's boot ++ * setup to runtime. ++ */ ++ dlist_start = HVS_BOOTLOADER_DLIST_END; ++ dlist_size = (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END; ++ break; ++ ++ case VC4_GEN_6: ++ dlist_start = HVS_BOOTLOADER_DLIST_END; ++ ++ /* ++ * If we are running a test, it means that we can't ++ * access a register. Use a plausible size then. ++ */ ++ if (!kunit_get_current_test()) ++ dlist_size = HVS_READ(SCALER6_CXM_SIZE); ++ else ++ dlist_size = 4096; ++ ++ break; ++ ++ default: ++ drm_err(drm, "Unknown VC4 generation: %d", vc4->gen); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ drm_mm_init(&hvs->dlist_mm, dlist_start, dlist_size); + + hvs->dlist_mem_size = dlist_size; + +@@ -1286,12 +1586,46 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v + * between planes when they don't overlap on the screen, but + * for now we just allocate globally. + */ +- if (vc4->gen == VC4_GEN_4) ++ ++ switch (vc4->gen) { ++ case VC4_GEN_4: + /* 48k words of 2x12-bit pixels */ +- drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024); +- else ++ lbm_size = 48 * SZ_1K; ++ break; ++ ++ case VC4_GEN_5: + /* 60k words of 4x12-bit pixels */ +- drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024); ++ lbm_size = 60 * SZ_1K; ++ break; ++ ++ case VC4_GEN_6: ++ /* ++ * If we are running a test, it means that we can't ++ * access a register. Use a plausible size then. ++ */ ++ lbm_size = 1024; ++ break; ++ ++ default: ++ drm_err(drm, "Unknown VC4 generation: %d", vc4->gen); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ drm_mm_init(&hvs->lbm_mm, 0, lbm_size); ++ ++ if (vc4->gen >= VC4_GEN_6) { ++ ida_init(&hvs->upm_handles); ++ ++ /* ++ * NOTE: On BCM2712, the size can also be read through ++ * the SCALER_UBM_SIZE register. We would need to do a ++ * register access though, which we can't do with kunit ++ * that also uses this function to create its mock ++ * device. ++ */ ++ drm_mm_init(&hvs->upm_mm, 0, 1024 * HVS_UBM_WORD_SIZE); ++ } ++ + + vc4->hvs = hvs; + +@@ -1388,10 +1722,124 @@ static int vc4_hvs_hw_init(struct vc4_hv + return 0; + } + ++#define CFC1_N_NL_CSC_CTRL(x) (0xa000 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C00(x) (0xa008 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C01(x) (0xa00c + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C02(x) (0xa010 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C03(x) (0xa014 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C04(x) (0xa018 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C10(x) (0xa01c + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C11(x) (0xa020 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C12(x) (0xa024 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C13(x) (0xa028 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C14(x) (0xa02c + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C20(x) (0xa030 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C21(x) (0xa034 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C22(x) (0xa038 + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C23(x) (0xa03c + ((x) * 0x3000)) ++#define CFC1_N_MA_CSC_COEFF_C24(x) (0xa040 + ((x) * 0x3000)) ++ ++/* 4 S2.22 multiplication factors, and 1 S9.15 addititive element for each of 3 ++ * output components ++ */ ++struct vc6_csc_coeff_entry { ++ u32 csc[3][5]; ++}; ++ ++static const struct vc6_csc_coeff_entry csc_coeffs[2][3] = { ++ [DRM_COLOR_YCBCR_LIMITED_RANGE] = { ++ [DRM_COLOR_YCBCR_BT601] = { ++ .csc = { ++ { 0x004A8542, 0x0, 0x0066254A, 0x0, 0xFF908A0D }, ++ { 0x004A8542, 0xFFE6ED5D, 0xFFCBF856, 0x0, 0x0043C9A3 }, ++ { 0x004A8542, 0x00811A54, 0x0, 0x0, 0xFF759502 } ++ } ++ }, ++ [DRM_COLOR_YCBCR_BT709] = { ++ .csc = { ++ { 0x004A8542, 0x0, 0x0072BC44, 0x0, 0xFF83F312 }, ++ { 0x004A8542, 0xFFF25A22, 0xFFDDE4D0, 0x0, 0x00267064 }, ++ { 0x004A8542, 0x00873197, 0x0, 0x0, 0xFF6F7DC0 } ++ } ++ }, ++ [DRM_COLOR_YCBCR_BT2020] = { ++ .csc = { ++ { 0x004A8542, 0x0, 0x006B4A17, 0x0, 0xFF8B653F }, ++ { 0x004A8542, 0xFFF402D9, 0xFFDDE4D0, 0x0, 0x0024C7AE }, ++ { 0x004A8542, 0x008912CC, 0x0, 0x0, 0xFF6D9C8B } ++ } ++ } ++ }, ++ [DRM_COLOR_YCBCR_FULL_RANGE] = { ++ [DRM_COLOR_YCBCR_BT601] = { ++ .csc = { ++ { 0x00400000, 0x0, 0x0059BA5E, 0x0, 0xFFA645A1 }, ++ { 0x00400000, 0xFFE9F9AC, 0xFFD24B97, 0x0, 0x0043BABB }, ++ { 0x00400000, 0x00716872, 0x0, 0x0, 0xFF8E978D } ++ } ++ }, ++ [DRM_COLOR_YCBCR_BT709] = { ++ .csc = { ++ { 0x00400000, 0x0, 0x0064C985, 0x0, 0xFF9B367A }, ++ { 0x00400000, 0xFFF402E1, 0xFFE20A40, 0x0, 0x0029F2DE }, ++ { 0x00400000, 0x0076C226, 0x0, 0x0, 0xFF893DD9 } ++ } ++ }, ++ [DRM_COLOR_YCBCR_BT2020] = { ++ .csc = { ++ { 0x00400000, 0x0, 0x005E3F14, 0x0, 0xFFA1C0EB }, ++ { 0x00400000, 0xFFF577F6, 0xFFDB580F, 0x0, 0x002F2FFA }, ++ { 0x00400000, 0x007868DB, 0x0, 0x0, 0xFF879724 } ++ } ++ } ++ } ++}; ++ ++static int vc6_hvs_hw_init(struct vc4_hvs *hvs) ++{ ++ const struct vc6_csc_coeff_entry *coeffs; ++ unsigned int i; ++ ++ HVS_WRITE(SCALER6_CONTROL, ++ SCALER6_CONTROL_HVS_EN | ++ VC4_SET_FIELD(8, SCALER6_CONTROL_PF_LINES) | ++ VC4_SET_FIELD(15, SCALER6_CONTROL_MAX_REQS)); ++ ++ /* Set HVS arbiter priority to max */ ++ HVS_WRITE(SCALER6_PRI_MAP0, 0xffffffff); ++ HVS_WRITE(SCALER6_PRI_MAP1, 0xffffffff); ++ ++ for (i = 0; i < 6; i++) { ++ coeffs = &csc_coeffs[i / 3][i % 3]; ++ ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C00(i), coeffs->csc[0][0]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C01(i), coeffs->csc[0][1]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C02(i), coeffs->csc[0][2]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C03(i), coeffs->csc[0][3]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C04(i), coeffs->csc[0][4]); ++ ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C10(i), coeffs->csc[1][0]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C11(i), coeffs->csc[1][1]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C12(i), coeffs->csc[1][2]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C13(i), coeffs->csc[1][3]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C14(i), coeffs->csc[1][4]); ++ ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C20(i), coeffs->csc[2][0]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C21(i), coeffs->csc[2][1]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C22(i), coeffs->csc[2][2]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C23(i), coeffs->csc[2][3]); ++ HVS_WRITE(CFC1_N_MA_CSC_COEFF_C24(i), coeffs->csc[2][4]); ++ ++ HVS_WRITE(CFC1_N_NL_CSC_CTRL(i), BIT(15)); ++ } ++ ++ return 0; ++} ++ + static int vc4_hvs_cob_init(struct vc4_hvs *hvs) + { + struct vc4_dev *vc4 = hvs->vc4; +- u32 reg, top; ++ u32 reg, top, base; + + /* + * Recompute Composite Output Buffer (COB) allocations for the +@@ -1452,6 +1900,31 @@ static int vc4_hvs_cob_init(struct vc4_h + HVS_WRITE(SCALER_DISPBASE0, reg); + break; + ++ case VC4_GEN_6: ++ #define VC6_COB_LINE_WIDTH 3840 ++ #define VC6_COB_NUM_LINES 4 ++ reg = 0; ++ top = 3840; ++ ++ HVS_WRITE(SCALER6_DISP2_COB, ++ VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) | ++ VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE)); ++ ++ base = top + 16; ++ top += VC6_COB_LINE_WIDTH * VC6_COB_NUM_LINES; ++ ++ HVS_WRITE(SCALER6_DISP1_COB, ++ VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) | ++ VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE)); ++ ++ base = top + 16; ++ top += VC6_COB_LINE_WIDTH * VC6_COB_NUM_LINES; ++ ++ HVS_WRITE(SCALER6_DISP0_COB, ++ VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) | ++ VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE)); ++ break; ++ + default: + return -EINVAL; + } +@@ -1477,10 +1950,16 @@ static int vc4_hvs_bind(struct device *d + return PTR_ERR(hvs); + + hvs->regset.base = hvs->regs; +- hvs->regset.regs = vc4_hvs_regs; +- hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs); + +- if (vc4->gen == VC4_GEN_5) { ++ if (vc4->gen >= VC4_GEN_6) { ++ hvs->regset.regs = vc6_hvs_regs; ++ hvs->regset.nregs = ARRAY_SIZE(vc6_hvs_regs); ++ } else { ++ hvs->regset.regs = vc4_hvs_regs; ++ hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs); ++ } ++ ++ if (vc4->gen >= VC4_GEN_5) { + struct rpi_firmware *firmware; + struct device_node *node; + unsigned int max_rate; +@@ -1494,12 +1973,20 @@ static int vc4_hvs_bind(struct device *d + if (!firmware) + return -EPROBE_DEFER; + +- hvs->core_clk = devm_clk_get(&pdev->dev, NULL); ++ hvs->core_clk = devm_clk_get(&pdev->dev, ++ (vc4->gen >= VC4_GEN_6) ? "core" : NULL); + if (IS_ERR(hvs->core_clk)) { + dev_err(&pdev->dev, "Couldn't get core clock\n"); + return PTR_ERR(hvs->core_clk); + } + ++ hvs->disp_clk = devm_clk_get(&pdev->dev, ++ (vc4->gen >= VC4_GEN_6) ? "disp" : NULL); ++ if (IS_ERR(hvs->disp_clk)) { ++ dev_err(&pdev->dev, "Couldn't get disp clock\n"); ++ return PTR_ERR(hvs->disp_clk); ++ } ++ + max_rate = rpi_firmware_clk_get_max_rate(firmware, + RPI_FIRMWARE_CORE_CLK_ID); + rpi_firmware_put(firmware); +@@ -1516,14 +2003,51 @@ static int vc4_hvs_bind(struct device *d + dev_err(&pdev->dev, "Couldn't enable the core clock\n"); + return ret; + } ++ ++ ret = clk_prepare_enable(hvs->disp_clk); ++ if (ret) { ++ dev_err(&pdev->dev, "Couldn't enable the disp clock\n"); ++ return ret; ++ } + } + +- if (vc4->gen == VC4_GEN_4) +- hvs->dlist = hvs->regs + SCALER_DLIST_START; +- else ++ if (vc4->gen >= VC4_GEN_6) { ++ unsigned int i; ++ ++ for (i = 0; i < HVS_NUM_CHANNELS; i++) { ++ char irq_name[16]; ++ int irq; ++ ++ snprintf(irq_name, sizeof(irq_name), "ch%u-eof", i); ++ ++ irq = platform_get_irq_byname(pdev, irq_name); ++ if (irq < 0) { ++ dev_err(&pdev->dev, ++ "Couldn't get %s interrupt: %d\n", ++ irq_name, irq); ++ return irq; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, ++ irq, ++ vc6_hvs_eof_irq_handler, ++ IRQF_NO_AUTOEN, ++ dev_name(&pdev->dev), ++ drm); ++ ++ hvs->eof_irq[i].desc = irq; ++ } ++ } ++ ++ if (vc4->gen >= VC4_GEN_5) + hvs->dlist = hvs->regs + SCALER5_DLIST_START; ++ else ++ hvs->dlist = hvs->regs + SCALER_DLIST_START; + +- ret = vc4_hvs_hw_init(hvs); ++ if (vc4->gen >= VC4_GEN_6) ++ ret = vc6_hvs_hw_init(hvs); ++ else ++ ret = vc4_hvs_hw_init(hvs); + if (ret) + return ret; + +@@ -1540,10 +2064,12 @@ static int vc4_hvs_bind(struct device *d + if (ret) + return ret; + +- ret = devm_request_irq(dev, platform_get_irq(pdev, 0), +- vc4_hvs_irq_handler, 0, "vc4 hvs", drm); +- if (ret) +- return ret; ++ if (vc4->gen < VC4_GEN_6) { ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_hvs_irq_handler, 0, "vc4 hvs", drm); ++ if (ret) ++ return ret; ++ } + + return 0; + } +@@ -1568,6 +2094,7 @@ static void vc4_hvs_unbind(struct device + drm_mm_remove_node(node); + drm_mm_takedown(&vc4->hvs->lbm_mm); + ++ clk_disable_unprepare(hvs->disp_clk); + clk_disable_unprepare(hvs->core_clk); + + vc4->hvs = NULL; +@@ -1591,6 +2118,7 @@ static int vc4_hvs_dev_remove(struct pla + + static const struct of_device_id vc4_hvs_dt_match[] = { + { .compatible = "brcm,bcm2711-hvs" }, ++ { .compatible = "brcm,bcm2712-hvs" }, + { .compatible = "brcm,bcm2835-hvs" }, + {} + }; +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -329,17 +329,59 @@ static void vc5_hvs_pv_muxing_commit(str + } + } + ++static void vc6_hvs_pv_muxing_commit(struct vc4_dev *vc4, ++ struct drm_atomic_state *state) ++{ ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct drm_crtc_state *crtc_state; ++ struct drm_crtc *crtc; ++ unsigned int i; ++ ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_6); ++ ++ for_each_new_crtc_in_state(state, crtc, crtc_state, i) { ++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); ++ struct vc4_encoder *vc4_encoder; ++ struct drm_encoder *encoder; ++ unsigned char mux; ++ u32 reg; ++ ++ if (!vc4_state->update_muxing) ++ continue; ++ ++ if (vc4_state->assigned_channel != 1) ++ continue; ++ ++ encoder = vc4_get_crtc_encoder(crtc, crtc_state); ++ vc4_encoder = to_vc4_encoder(encoder); ++ switch (vc4_encoder->type) { ++ case VC4_ENCODER_TYPE_HDMI1: ++ mux = 0; ++ break; ++ ++ case VC4_ENCODER_TYPE_TXP: ++ mux = 2; ++ break; ++ ++ default: ++ break; ++ } ++ ++ reg = HVS_READ(SCALER6_CONTROL); ++ HVS_WRITE(SCALER6_CONTROL, ++ (reg & ~SCALER6_CONTROL_DSP1_TARGET_MASK) | ++ VC4_SET_FIELD(mux, SCALER6_CONTROL_DSP1_TARGET)); ++ } ++} ++ + static void vc4_atomic_commit_tail(struct drm_atomic_state *state) + { + struct drm_device *dev = state->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hvs *hvs = vc4->hvs; +- struct drm_crtc_state *new_crtc_state; + struct vc4_hvs_state *new_hvs_state; +- struct drm_crtc *crtc; + struct vc4_hvs_state *old_hvs_state; + unsigned int channel; +- int i; + + old_hvs_state = vc4_hvs_get_old_global_state(state); + if (WARN_ON(IS_ERR(old_hvs_state))) +@@ -349,14 +391,23 @@ static void vc4_atomic_commit_tail(struc + if (WARN_ON(IS_ERR(new_hvs_state))) + return; + +- for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { +- struct vc4_crtc_state *vc4_crtc_state; ++ if (vc4->gen < VC4_GEN_6) { ++ struct drm_crtc_state *new_crtc_state; ++ struct drm_crtc *crtc; ++ int i; ++ ++ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { ++ struct vc4_crtc_state *vc4_crtc_state; + +- if (!new_crtc_state->commit || vc4->firmware_kms) +- continue; ++ if (vc4->firmware_kms) ++ continue; + +- vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); +- vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel); ++ if (!new_crtc_state->commit) ++ continue; ++ ++ vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); ++ vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel); ++ } + } + + for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) { +@@ -378,7 +429,7 @@ static void vc4_atomic_commit_tail(struc + old_hvs_state->fifo_state[channel].pending_commit = NULL; + } + +- if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) { ++ if (vc4->gen >= VC4_GEN_5 && !vc4->firmware_kms) { + unsigned long state_rate = max(old_hvs_state->core_clock_rate, + new_hvs_state->core_clock_rate); + unsigned long core_rate = clamp_t(unsigned long, state_rate, +@@ -391,17 +442,32 @@ static void vc4_atomic_commit_tail(struc + * modeset. + */ + WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate)); ++ WARN_ON(clk_set_min_rate(hvs->disp_clk, core_rate)); + } + + drm_atomic_helper_commit_modeset_disables(dev, state); + +- vc4_ctm_commit(vc4, state); ++ if (vc4->gen <= VC4_GEN_5) ++ vc4_ctm_commit(vc4, state); + + if (!vc4->firmware_kms) { +- if (vc4->gen == VC4_GEN_5) +- vc5_hvs_pv_muxing_commit(vc4, state); +- else ++ switch (vc4->gen) { ++ case VC4_GEN_4: + vc4_hvs_pv_muxing_commit(vc4, state); ++ break; ++ ++ case VC4_GEN_5: ++ vc5_hvs_pv_muxing_commit(vc4, state); ++ break; ++ ++ case VC4_GEN_6: ++ vc6_hvs_pv_muxing_commit(vc4, state); ++ break; ++ ++ default: ++ drm_err(dev, "Unknown VC4 generation: %d", vc4->gen); ++ break; ++ } + } + + drm_atomic_helper_commit_planes(dev, state, +@@ -417,7 +483,7 @@ static void vc4_atomic_commit_tail(struc + + drm_atomic_helper_cleanup_planes(dev, state); + +- if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) { ++ if (vc4->gen >= VC4_GEN_5 && !vc4->firmware_kms) { + unsigned long core_rate = min_t(unsigned long, + hvs->max_core_rate, + new_hvs_state->core_clock_rate); +@@ -429,6 +495,7 @@ static void vc4_atomic_commit_tail(struc + * requirements. + */ + WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate)); ++ WARN_ON(clk_set_min_rate(hvs->disp_clk, core_rate)); + + drm_dbg(dev, "Core clock actual rate: %lu Hz\n", + clk_get_rate(hvs->core_clk)); +@@ -1081,7 +1148,10 @@ int vc4_kms_load(struct drm_device *dev) + return ret; + } + +- if (vc4->gen == VC4_GEN_5) { ++ if (vc4->gen >= VC4_GEN_6) { ++ dev->mode_config.max_width = 8192; ++ dev->mode_config.max_height = 8192; ++ } else if (vc4->gen >= VC4_GEN_5) { + dev->mode_config.max_width = 7680; + dev->mode_config.max_height = 7680; + } else { +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -279,6 +279,7 @@ static bool plane_enabled(struct drm_pla + static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) + { + struct vc4_plane_state *vc4_state; ++ unsigned int i; + + if (WARN_ON(!plane->state)) + return NULL; +@@ -288,6 +289,11 @@ static struct drm_plane_state *vc4_plane + return NULL; + + memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); ++ memset(&vc4_state->upm, 0, sizeof(vc4_state->upm)); ++ ++ for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) ++ vc4_state->upm_handle[i] = 0; ++ + vc4_state->dlist_initialized = 0; + + __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); +@@ -310,14 +316,30 @@ static void vc4_plane_destroy_state(stru + struct drm_plane_state *state) + { + struct vc4_dev *vc4 = to_vc4_dev(plane->dev); ++ struct vc4_hvs *hvs = vc4->hvs; + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ unsigned int i; + + if (drm_mm_node_allocated(&vc4_state->lbm)) { + unsigned long irqflags; + +- spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); ++ spin_lock_irqsave(&hvs->mm_lock, irqflags); + drm_mm_remove_node(&vc4_state->lbm); +- spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); ++ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ } ++ ++ for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) { ++ unsigned long irqflags; ++ ++ if (!drm_mm_node_allocated(&vc4_state->upm[i])) ++ continue; ++ ++ spin_lock_irqsave(&hvs->mm_lock, irqflags); ++ drm_mm_remove_node(&vc4_state->upm[i]); ++ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ ++ if (vc4_state->upm_handle[i] > 0) ++ ida_free(&hvs->upm_handles, vc4_state->upm_handle[i]); + } + + kfree(vc4_state->dlist); +@@ -543,6 +565,11 @@ static void vc4_write_tpz(struct vc4_pla + recip = ~0 / scale; + + vc4_dlist_write(vc4_state, ++ /* ++ * The BCM2712 is lacking BIT(31) compared to ++ * the previous generations, but we don't use ++ * it. ++ */ + VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) | + VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE)); + vc4_dlist_write(vc4_state, +@@ -590,10 +617,15 @@ static void vc4_write_ppf(struct vc4_pla + vc4_dlist_write(vc4_state, + SCALER_PPF_AGC | + VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | ++ /* ++ * The register layout documentation is slightly ++ * different to setup the phase in the BCM2712, ++ * but they seem equivalent. ++ */ + VC4_SET_FIELD(phase, SCALER_PPF_IPHASE)); + } + +-static u32 vc4_lbm_size(struct drm_plane_state *state) ++static u32 __vc4_lbm_size(struct drm_plane_state *state) + { + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); +@@ -641,6 +673,131 @@ static u32 vc4_lbm_size(struct drm_plane + return lbm; + } + ++static unsigned int vc4_lbm_words_per_component(const struct drm_plane_state *state, ++ unsigned int channel) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ ++ switch (vc4_state->y_scaling[channel]) { ++ case VC4_SCALING_PPF: ++ return 4; ++ ++ case VC4_SCALING_TPZ: ++ return 2; ++ ++ default: ++ return 0; ++ } ++} ++ ++static unsigned int vc4_lbm_components(const struct drm_plane_state *state, ++ unsigned int channel) ++{ ++ const struct drm_format_info *info = state->fb->format; ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ ++ if (vc4_state->y_scaling[channel] == VC4_SCALING_NONE) ++ return 0; ++ ++ if (info->is_yuv) ++ return channel ? 2 : 1; ++ ++ if (info->has_alpha) ++ return 4; ++ ++ return 3; ++} ++ ++static unsigned int vc4_lbm_channel_size(const struct drm_plane_state *state, ++ unsigned int channel) ++{ ++ const struct drm_format_info *info = state->fb->format; ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ unsigned int channels_scaled = 0; ++ unsigned int components, words, wpc; ++ unsigned int width, lines; ++ unsigned int i; ++ ++ /* LBM is meant to use the smaller of source or dest width, but there ++ * is a issue with UV scaling that the size required for the second ++ * channel is based on the source width only. ++ */ ++ if (info->hsub > 1 && channel == 1) ++ width = state->src_w >> 16; ++ else ++ width = min(state->src_w >> 16, state->crtc_w); ++ width = round_up(width / info->hsub, 4); ++ ++ wpc = vc4_lbm_words_per_component(state, channel); ++ if (!wpc) ++ return 0; ++ ++ components = vc4_lbm_components(state, channel); ++ if (!components) ++ return 0; ++ ++ if (state->alpha != DRM_BLEND_ALPHA_OPAQUE) ++ components -= 1; ++ ++ words = width * wpc * components; ++ ++ lines = DIV_ROUND_UP(words, 128 / info->hsub); ++ ++ for (i = 0; i < 2; i++) ++ if (vc4_state->y_scaling[channel] != VC4_SCALING_NONE) ++ channels_scaled++; ++ ++ if (channels_scaled == 1) ++ lines = lines / 2; ++ ++ return lines; ++} ++ ++static unsigned int __vc6_lbm_size(const struct drm_plane_state *state) ++{ ++ const struct drm_format_info *info = state->fb->format; ++ ++ if (info->hsub > 1) ++ return max(vc4_lbm_channel_size(state, 0), ++ vc4_lbm_channel_size(state, 1)); ++ else ++ return vc4_lbm_channel_size(state, 0); ++} ++ ++u32 vc4_lbm_size(struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); ++ ++ /* LBM is not needed when there's no vertical scaling. */ ++ if (vc4_state->y_scaling[0] == VC4_SCALING_NONE && ++ vc4_state->y_scaling[1] == VC4_SCALING_NONE) ++ return 0; ++ ++ if (vc4->gen >= VC4_GEN_6) ++ return __vc6_lbm_size(state); ++ else ++ return __vc4_lbm_size(state); ++} ++ ++static size_t vc6_upm_size(const struct drm_plane_state *state, ++ unsigned int plane) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ unsigned int stride = state->fb->pitches[plane]; ++ ++ /* ++ * TODO: This only works for raster formats, and is sub-optimal ++ * for buffers with a stride aligned on 32 bytes. ++ */ ++ unsigned int words_per_line = (stride + 62) / 32; ++ unsigned int fetch_region_size = words_per_line * 32; ++ unsigned int buffer_lines = 2 << vc4_state->upm_buffer_lines; ++ unsigned int buffer_size = fetch_region_size * buffer_lines; ++ ++ return ALIGN(buffer_size, HVS_UBM_WORD_SIZE); ++} ++ + static void vc4_write_scaling_parameters(struct drm_plane_state *state, + int channel) + { +@@ -744,6 +901,10 @@ static int vc4_plane_allocate_lbm(struct + if (!lbm_size) + return 0; + ++ /* ++ * NOTE: BCM2712 doesn't need to be aligned, since the size ++ * returned by vc4_lbm_size() is in words already. ++ */ + if (vc4->gen == VC4_GEN_5) + lbm_size = ALIGN(lbm_size, 64); + else if (vc4->gen == VC4_GEN_4) +@@ -781,6 +942,57 @@ static int vc4_plane_allocate_lbm(struct + return 0; + } + ++static int vc6_plane_allocate_upm(struct drm_plane_state *state) ++{ ++ const struct drm_format_info *info = state->fb->format; ++ struct drm_device *drm = state->plane->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ unsigned int i; ++ int ret; ++ ++ WARN_ON_ONCE(vc4->gen < VC4_GEN_6); ++ ++ vc4_state->upm_buffer_lines = SCALER6_PTR0_UPM_BUFF_SIZE_2_LINES; ++ ++ for (i = 0; i < info->num_planes; i++) { ++ unsigned long irqflags; ++ size_t upm_size; ++ ++ upm_size = vc6_upm_size(state, i); ++ if (!upm_size) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&hvs->mm_lock, irqflags); ++ ret = drm_mm_insert_node_generic(&hvs->upm_mm, ++ &vc4_state->upm[i], ++ upm_size, HVS_UBM_WORD_SIZE, ++ 0, 0); ++ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ if (ret) { ++ drm_err(drm, "Failed to allocate UPM entry: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ida_alloc_range(&hvs->upm_handles, 1, 32, GFP_KERNEL); ++ if (ret < 0) ++ return ret; ++ ++ vc4_state->upm_handle[i] = ret; ++ ++ vc4_state->dlist[vc4_state->ptr0_offset[i]] |= ++ VC4_SET_FIELD(vc4_state->upm[i].start / HVS_UBM_WORD_SIZE, ++ SCALER6_PTR0_UPM_BASE) | ++ VC4_SET_FIELD(vc4_state->upm_handle[i] - 1, ++ SCALER6_PTR0_UPM_HANDLE) | ++ VC4_SET_FIELD(vc4_state->upm_buffer_lines, ++ SCALER6_PTR0_UPM_BUFF_SIZE); ++ } ++ ++ return 0; ++} ++ + /* + * The colorspace conversion matrices are held in 3 entries in the dlist. + * Create an array of them, with entries for each full and limited mode, and +@@ -1355,6 +1567,413 @@ static int vc4_plane_mode_set(struct drm + return 0; + } + ++static u32 vc6_plane_get_csc_mode(struct vc4_plane_state *vc4_state) ++{ ++ struct drm_plane_state *state = &vc4_state->base; ++ u32 ret = 0; ++ ++ if (vc4_state->is_yuv) { ++ enum drm_color_encoding color_encoding = state->color_encoding; ++ enum drm_color_range color_range = state->color_range; ++ ++ ret |= SCALER6_CTL2_CSC_ENABLE; ++ ++ /* CSC pre-loaded with: ++ * 0 = BT601 limited range ++ * 1 = BT709 limited range ++ * 2 = BT2020 limited range ++ * 3 = BT601 full range ++ * 4 = BT709 full range ++ * 5 = BT2020 full range ++ */ ++ if (color_encoding > DRM_COLOR_YCBCR_BT2020) ++ color_encoding = DRM_COLOR_YCBCR_BT601; ++ if (color_range > DRM_COLOR_YCBCR_FULL_RANGE) ++ color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; ++ ++ ret |= VC4_SET_FIELD(color_encoding + (color_range * 3), ++ SCALER6_CTL2_BRCM_CFC_CONTROL); ++ } ++ ++ return ret; ++} ++ ++static int vc6_plane_mode_set(struct drm_plane *plane, ++ struct drm_plane_state *state) ++{ ++ struct drm_device *drm = plane->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ struct drm_framebuffer *fb = state->fb; ++ const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); ++ u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier); ++ int num_planes = fb->format->num_planes; ++ u32 h_subsample = fb->format->hsub; ++ u32 v_subsample = fb->format->vsub; ++ bool mix_plane_alpha; ++ bool covers_screen; ++ u32 scl0, scl1, pitch0; ++ u32 tiling, src_x, src_y; ++ u32 width, height; ++ u32 hvs_format = format->hvs; ++ u32 offsets[3] = { 0 }; ++ unsigned int rotation; ++ int ret, i; ++ ++ if (vc4_state->dlist_initialized) ++ return 0; ++ ++ ret = vc4_plane_setup_clipping_and_scaling(state); ++ if (ret) ++ return ret; ++ ++ width = vc4_state->src_w[0] >> 16; ++ height = vc4_state->src_h[0] >> 16; ++ ++ /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB ++ * and 4:4:4, scl1 should be set to scl0 so both channels of ++ * the scaler do the same thing. For YUV, the Y plane needs ++ * to be put in channel 1 and Cb/Cr in channel 0, so we swap ++ * the scl fields here. ++ */ ++ if (num_planes == 1) { ++ scl0 = vc4_get_scl_field(state, 0); ++ scl1 = scl0; ++ } else { ++ scl0 = vc4_get_scl_field(state, 1); ++ scl1 = vc4_get_scl_field(state, 0); ++ } ++ ++ rotation = drm_rotation_simplify(state->rotation, ++ DRM_MODE_ROTATE_0 | ++ DRM_MODE_REFLECT_X | ++ DRM_MODE_REFLECT_Y); ++ ++ /* We must point to the last line when Y reflection is enabled. */ ++ src_y = vc4_state->src_y >> 16; ++ if (rotation & DRM_MODE_REFLECT_Y) ++ src_y += height - 1; ++ ++ src_x = vc4_state->src_x >> 16; ++ ++ switch (base_format_mod) { ++ case DRM_FORMAT_MOD_LINEAR: ++ tiling = SCALER6_CTL0_ADDR_MODE_LINEAR; ++ ++ /* Adjust the base pointer to the first pixel to be scanned ++ * out. ++ */ ++ for (i = 0; i < num_planes; i++) { ++ offsets[i] += src_y / (i ? v_subsample : 1) * fb->pitches[i]; ++ offsets[i] += src_x / (i ? h_subsample : 1) * fb->format->cpp[i]; ++ } ++ ++ break; ++ ++ case DRM_FORMAT_MOD_BROADCOM_SAND128: ++ case DRM_FORMAT_MOD_BROADCOM_SAND256: { ++ uint32_t param = fourcc_mod_broadcom_param(fb->modifier); ++ u32 components_per_word; ++ u32 starting_offset; ++ u32 fetch_count; ++ ++ if (param > SCALER_TILE_HEIGHT_MASK) { ++ DRM_DEBUG_KMS("SAND height too large (%d)\n", ++ param); ++ return -EINVAL; ++ } ++ ++ if (fb->format->format == DRM_FORMAT_P030) { ++ hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT; ++ tiling = SCALER6_CTL0_ADDR_MODE_128B; ++ } else { ++ hvs_format = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE; ++ ++ switch (base_format_mod) { ++ case DRM_FORMAT_MOD_BROADCOM_SAND128: ++ tiling = SCALER6_CTL0_ADDR_MODE_128B; ++ break; ++ case DRM_FORMAT_MOD_BROADCOM_SAND256: ++ tiling = SCALER6_CTL0_ADDR_MODE_256B; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ /* Adjust the base pointer to the first pixel to be scanned ++ * out. ++ * ++ * For P030, y_ptr [31:4] is the 128bit word for the start pixel ++ * y_ptr [3:0] is the pixel (0-11) contained within that 128bit ++ * word that should be taken as the first pixel. ++ * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the ++ * element within the 128bit word, eg for pixel 3 the value ++ * should be 6. ++ */ ++ for (i = 0; i < num_planes; i++) { ++ u32 tile_w, tile, x_off, pix_per_tile; ++ ++ if (fb->format->format == DRM_FORMAT_P030) { ++ /* ++ * Spec says: bits [31:4] of the given address ++ * should point to the 128-bit word containing ++ * the desired starting pixel, and bits[3:0] ++ * should be between 0 and 11, indicating which ++ * of the 12-pixels in that 128-bit word is the ++ * first pixel to be used ++ */ ++ u32 remaining_pixels = src_x % 96; ++ u32 aligned = remaining_pixels / 12; ++ u32 last_bits = remaining_pixels % 12; ++ ++ x_off = aligned * 16 + last_bits; ++ tile_w = 128; ++ pix_per_tile = 96; ++ } else { ++ switch (base_format_mod) { ++ case DRM_FORMAT_MOD_BROADCOM_SAND128: ++ tile_w = 128; ++ break; ++ case DRM_FORMAT_MOD_BROADCOM_SAND256: ++ tile_w = 256; ++ break; ++ default: ++ return -EINVAL; ++ } ++ pix_per_tile = tile_w / fb->format->cpp[0]; ++ x_off = (src_x % pix_per_tile) / ++ (i ? h_subsample : 1) * ++ fb->format->cpp[i]; ++ } ++ ++ tile = src_x / pix_per_tile; ++ ++ offsets[i] += param * tile_w * tile; ++ offsets[i] += src_y / (i ? v_subsample : 1) * tile_w; ++ offsets[i] += x_off & ~(i ? 1 : 0); ++ } ++ ++ components_per_word = fb->format->format == DRM_FORMAT_P030 ? 24 : 32; ++ starting_offset = src_x % components_per_word; ++ fetch_count = (width + starting_offset + components_per_word - 1) / ++ components_per_word; ++ ++ pitch0 = VC4_SET_FIELD(param, SCALER6_PTR2_PITCH) | ++ VC4_SET_FIELD(fetch_count - 1, SCALER6_PTR2_FETCH_COUNT); ++ break; ++ } ++ ++ default: ++ DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx", ++ (long long)fb->modifier); ++ return -EINVAL; ++ } ++ ++ /* fetch an extra pixel if we don't actually line up with the left edge. */ ++ if ((vc4_state->src_x & 0xffff) && vc4_state->src_x < (state->fb->width << 16)) ++ width++; ++ ++ /* same for the right side */ ++ if (((vc4_state->src_x + vc4_state->src_w[0]) & 0xffff) && ++ vc4_state->src_x + vc4_state->src_w[0] < (state->fb->width << 16)) ++ width++; ++ ++ /* now for the top */ ++ if ((vc4_state->src_y & 0xffff) && vc4_state->src_y < (state->fb->height << 16)) ++ height++; ++ ++ /* and the bottom */ ++ if (((vc4_state->src_y + vc4_state->src_h[0]) & 0xffff) && ++ vc4_state->src_y + vc4_state->src_h[0] < (state->fb->height << 16)) ++ height++; ++ ++ /* for YUV444 hardware wants double the width, otherwise it doesn't ++ * fetch full width of chroma ++ */ ++ if (format->drm == DRM_FORMAT_YUV444 || format->drm == DRM_FORMAT_YVU444) ++ width <<= 1; ++ ++ /* Don't waste cycles mixing with plane alpha if the set alpha ++ * is opaque or there is no per-pixel alpha information. ++ * In any case we use the alpha property value as the fixed alpha. ++ */ ++ mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE && ++ fb->format->has_alpha; ++ ++ /* Control Word 0: Scaling Configuration & Element Validity*/ ++ vc4_dlist_write(vc4_state, ++ SCALER6_CTL0_VALID | ++ VC4_SET_FIELD(tiling, SCALER6_CTL0_ADDR_MODE) | ++ VC4_SET_FIELD(0, SCALER6_CTL0_ALPHA_MASK) | ++ (vc4_state->is_unity ? SCALER6_CTL0_UNITY : 0) | ++ VC4_SET_FIELD(format->pixel_order_hvs5, SCALER6_CTL0_ORDERRGBA) | ++ VC4_SET_FIELD(scl1, SCALER6_CTL0_SCL1_MODE) | ++ VC4_SET_FIELD(scl0, SCALER6_CTL0_SCL0_MODE) | ++ VC4_SET_FIELD(hvs_format, SCALER6_CTL0_PIXEL_FORMAT)); ++ ++ /* Position Word 0: Image Position */ ++ vc4_state->pos0_offset = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(vc4_state->crtc_y, SCALER6_POS0_START_Y) | ++ (rotation & DRM_MODE_REFLECT_X ? SCALER6_POS0_HFLIP : 0) | ++ VC4_SET_FIELD(vc4_state->crtc_x, SCALER6_POS0_START_X)); ++ ++ /* Control Word 2: Alpha Value & CSC */ ++ vc4_dlist_write(vc4_state, ++ vc6_plane_get_csc_mode(vc4_state) | ++ vc4_hvs5_get_alpha_blend_mode(state) | ++ (mix_plane_alpha ? SCALER6_CTL2_ALPHA_MIX : 0) | ++ VC4_SET_FIELD(state->alpha >> 4, SCALER5_CTL2_ALPHA)); ++ ++ /* Position Word 1: Scaled Image Dimensions */ ++ if (!vc4_state->is_unity) ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(vc4_state->crtc_h - 1, ++ SCALER6_POS1_SCL_LINES) | ++ VC4_SET_FIELD(vc4_state->crtc_w - 1, ++ SCALER6_POS1_SCL_WIDTH)); ++ ++ /* Position Word 2: Source Image Size */ ++ vc4_state->pos2_offset = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(height - 1, ++ SCALER6_POS2_SRC_LINES) | ++ VC4_SET_FIELD(width - 1, ++ SCALER6_POS2_SRC_WIDTH)); ++ ++ /* Position Word 3: Context */ ++ vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ ++ /* ++ * TODO: This only covers Raster Scan Order planes ++ */ ++ for (i = 0; i < num_planes; i++) { ++ dma_addr_t paddr = drm_fb_dma_get_gem_addr(fb, state, i); ++ ++ paddr += offsets[i]; ++ ++ /* Pointer Word 0 */ ++ vc4_state->ptr0_offset[i] = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ (rotation & DRM_MODE_REFLECT_Y ? SCALER6_PTR0_VFLIP : 0) | ++ /* ++ * The UPM buffer will be allocated in ++ * vc6_plane_allocate_upm(). ++ */ ++ VC4_SET_FIELD(upper_32_bits(paddr) & 0xf, ++ SCALER6_PTR0_UPPER_ADDR)); ++ ++ /* Pointer Word 1 */ ++ vc4_dlist_write(vc4_state, lower_32_bits(paddr)); ++ ++ /* Pointer Word 2 */ ++ if (base_format_mod != DRM_FORMAT_MOD_BROADCOM_SAND128 && ++ base_format_mod != DRM_FORMAT_MOD_BROADCOM_SAND256) { ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(fb->pitches[i], ++ SCALER6_PTR2_PITCH)); ++ } else { ++ vc4_dlist_write(vc4_state, pitch0); ++ } ++ } ++ ++ /* ++ * Palette Word 0 ++ * TODO: We're not using the palette mode ++ */ ++ ++ /* ++ * Trans Word 0 ++ * TODO: It's only relevant if we set the trans_rgb bit in the ++ * control word 0, and we don't at the moment. ++ */ ++ ++ vc4_state->lbm_offset = 0; ++ ++ if (!vc4_state->is_unity || fb->format->is_yuv) { ++ /* ++ * Reserve a slot for the LBM Base Address. The real value will ++ * be set when calling vc4_plane_allocate_lbm(). ++ */ ++ if (vc4_state->y_scaling[0] != VC4_SCALING_NONE || ++ vc4_state->y_scaling[1] != VC4_SCALING_NONE) { ++ vc4_state->lbm_offset = vc4_state->dlist_count; ++ vc4_dlist_counter_increment(vc4_state); ++ } ++ ++ if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || ++ vc4_state->x_scaling[1] != VC4_SCALING_NONE || ++ vc4_state->y_scaling[0] != VC4_SCALING_NONE || ++ vc4_state->y_scaling[1] != VC4_SCALING_NONE) { ++ if (num_planes > 1) ++ /* ++ * Emit Cb/Cr as channel 0 and Y as channel ++ * 1. This matches how we set up scl0/scl1 ++ * above. ++ */ ++ vc4_write_scaling_parameters(state, 1); ++ ++ vc4_write_scaling_parameters(state, 0); ++ } ++ ++ /* ++ * If any PPF setup was done, then all the kernel ++ * pointers get uploaded. ++ */ ++ if (vc4_state->x_scaling[0] == VC4_SCALING_PPF || ++ vc4_state->y_scaling[0] == VC4_SCALING_PPF || ++ vc4_state->x_scaling[1] == VC4_SCALING_PPF || ++ vc4_state->y_scaling[1] == VC4_SCALING_PPF) { ++ u32 kernel = ++ VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, ++ SCALER_PPF_KERNEL_OFFSET); ++ ++ /* HPPF plane 0 */ ++ vc4_dlist_write(vc4_state, kernel); ++ /* VPPF plane 0 */ ++ vc4_dlist_write(vc4_state, kernel); ++ /* HPPF plane 1 */ ++ vc4_dlist_write(vc4_state, kernel); ++ /* VPPF plane 1 */ ++ vc4_dlist_write(vc4_state, kernel); ++ } ++ } ++ ++ vc4_dlist_write(vc4_state, SCALER6_CTL0_END); ++ ++ vc4_state->dlist[0] |= ++ VC4_SET_FIELD(vc4_state->dlist_count, SCALER6_CTL0_NEXT); ++ ++ /* crtc_* are already clipped coordinates. */ ++ covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 && ++ vc4_state->crtc_w == state->crtc->mode.hdisplay && ++ vc4_state->crtc_h == state->crtc->mode.vdisplay; ++ ++ /* ++ * Background fill might be necessary when the plane has per-pixel ++ * alpha content or a non-opaque plane alpha and could blend from the ++ * background or does not cover the entire screen. ++ */ ++ vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen || ++ state->alpha != DRM_BLEND_ALPHA_OPAQUE; ++ ++ /* ++ * Flag the dlist as initialized to avoid checking it twice in case ++ * the async update check already called vc4_plane_mode_set() and ++ * decided to fallback to sync update because async update was not ++ * possible. ++ */ ++ vc4_state->dlist_initialized = 1; ++ ++ vc4_plane_calc_load(state); ++ ++ drm_dbg_driver(drm, "[PLANE:%d:%s] Computed DLIST size: %u\n", ++ plane->base.id, plane->name, vc4_state->dlist_count); ++ ++ return 0; ++} ++ + /* If a modeset involves changing the setup of a plane, the atomic + * infrastructure will call this to validate a proposed plane setup. + * However, if a plane isn't getting updated, this (and the +@@ -1365,6 +1984,7 @@ static int vc4_plane_mode_set(struct drm + static int vc4_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) + { ++ struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, + plane); + struct vc4_plane_state *vc4_state = to_vc4_plane_state(new_plane_state); +@@ -1375,7 +1995,10 @@ static int vc4_plane_atomic_check(struct + if (!plane_enabled(new_plane_state)) + return 0; + +- ret = vc4_plane_mode_set(plane, new_plane_state); ++ if (vc4->gen >= VC4_GEN_6) ++ ret = vc6_plane_mode_set(plane, new_plane_state); ++ else ++ ret = vc4_plane_mode_set(plane, new_plane_state); + if (ret) + return ret; + +@@ -1383,6 +2006,12 @@ static int vc4_plane_atomic_check(struct + if (ret) + return ret; + ++ if (vc4->gen >= VC4_GEN_6) { ++ ret = vc6_plane_allocate_upm(new_plane_state); ++ if (ret) ++ return ret; ++ } ++ + return 0; + } + +@@ -1716,7 +2345,7 @@ struct drm_plane *vc4_plane_init(struct + }; + + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { +- if (!hvs_formats[i].hvs5_only || vc4->gen == VC4_GEN_5) { ++ if (!hvs_formats[i].hvs5_only || vc4->gen >= VC4_GEN_5) { + formats[num_formats] = hvs_formats[i].drm; + num_formats++; + } +@@ -1731,7 +2360,7 @@ struct drm_plane *vc4_plane_init(struct + return ERR_CAST(vc4_plane); + plane = &vc4_plane->base; + +- if (vc4->gen == VC4_GEN_5) ++ if (vc4->gen >= VC4_GEN_5) + drm_plane_helper_add(plane, &vc5_plane_helper_funcs); + else + drm_plane_helper_add(plane, &vc4_plane_helper_funcs); +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -536,6 +536,130 @@ + + #define SCALER5_DLIST_START 0x00004000 + ++#define SCALER6_VERSION 0x00000000 ++#define SCALER6_CXM_SIZE 0x00000004 ++#define SCALER6_LBM_SIZE 0x00000008 ++#define SCALER6_UBM_SIZE 0x0000000c ++#define SCALER6_COBA_SIZE 0x00000010 ++#define SCALER6_COB_SIZE 0x00000014 ++ ++#define SCALER6_CONTROL 0x00000020 ++# define SCALER6_CONTROL_HVS_EN BIT(31) ++# define SCALER6_CONTROL_PF_LINES_MASK VC4_MASK(22, 18) ++# define SCALER6_CONTROL_ABORT_ON_EMPTY BIT(16) ++# define SCALER6_CONTROL_DSP1_TARGET_MASK VC4_MASK(13, 12) ++# define SCALER6_CONTROL_MAX_REQS_MASK VC4_MASK(7, 4) ++ ++#define SCALER6_FETCHER_STATUS 0x00000024 ++#define SCALER6_FETCH_STATUS 0x00000028 ++#define SCALER6_HANDLE_ERROR 0x0000002c ++ ++#define SCALER6_DISP0_CTRL0 0x00000030 ++#define SCALER6_DISPX_CTRL0(x) \ ++ (SCALER6_DISP0_CTRL0 + ((x) * (SCALER6_DISP1_CTRL0 - SCALER6_DISP0_CTRL0))) ++# define SCALER6_DISPX_CTRL0_ENB BIT(31) ++# define SCALER6_DISPX_CTRL0_RESET BIT(30) ++# define SCALER6_DISPX_CTRL0_FWIDTH_MASK VC4_MASK(28, 16) ++# define SCALER6_DISPX_CTRL0_ONESHOT BIT(15) ++# define SCALER6_DISPX_CTRL0_ONECTX_MASK VC4_MASK(14, 13) ++# define SCALER6_DISPX_CTRL0_LINES_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_DISP0_CTRL1 0x00000034 ++#define SCALER6_DISPX_CTRL1(x) \ ++ (SCALER6_DISP0_CTRL1 + ((x) * (SCALER6_DISP1_CTRL1 - SCALER6_DISP0_CTRL1))) ++# define SCALER6_DISPX_CTRL1_BGENB BIT(8) ++# define SCALER6_DISPX_CTRL1_INTLACE BIT(0) ++ ++#define SCALER6_DISP0_BGND 0x00000038 ++#define SCALER6_DISPX_BGND(x) \ ++ (SCALER6_DISP0_BGND + ((x) * (SCALER6_DISP1_BGND - SCALER6_DISP0_BGND))) ++ ++#define SCALER6_DISP0_LPTRS 0x0000003c ++#define SCALER6_DISPX_LPTRS(x) \ ++ (SCALER6_DISP0_LPTRS + ((x) * (SCALER6_DISP1_LPTRS - SCALER6_DISP0_LPTRS))) ++# define SCALER6_DISPX_LPTRS_HEADE_MASK VC4_MASK(11, 0) ++ ++#define SCALER6_DISP0_COB 0x00000040 ++#define SCALER6_DISPX_COB(x) \ ++ (SCALER6_DISP0_COB + ((x) * (SCALER6_DISP1_COB - SCALER6_DISP0_COB))) ++# define SCALER6_DISPX_COB_TOP_MASK VC4_MASK(31, 16) ++# define SCALER6_DISPX_COB_BASE_MASK VC4_MASK(15, 0) ++ ++#define SCALER6_DISP0_STATUS 0x00000044 ++ ++#define SCALER6_DISPX_STATUS(x) \ ++ (SCALER6_DISP0_STATUS + ((x) * (SCALER6_DISP1_STATUS - SCALER6_DISP0_STATUS))) ++# define SCALER6_DISPX_STATUS_EMPTY BIT(22) ++# define SCALER6_DISPX_STATUS_FRCNT_MASK VC4_MASK(21, 16) ++# define SCALER6_DISPX_STATUS_OFIELD BIT(15) ++# define SCALER6_DISPX_STATUS_MODE_MASK VC4_MASK(14, 13) ++# define SCALER6_DISPX_STATUS_MODE_DISABLED 0 ++# define SCALER6_DISPX_STATUS_MODE_INIT 1 ++# define SCALER6_DISPX_STATUS_MODE_RUN 2 ++# define SCALER6_DISPX_STATUS_MODE_EOF 3 ++# define SCALER6_DISPX_STATUS_YLINE_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_DISP0_DL 0x00000048 ++ ++#define SCALER6_DISPX_DL(x) \ ++ (SCALER6_DISP0_DL + ((x) * (SCALER6_DISP1_DL - SCALER6_DISP0_DL))) ++# define SCALER6_DISPX_DL_LACT_MASK VC4_MASK(11, 0) ++ ++#define SCALER6_DISP0_RUN 0x0000004c ++#define SCALER6_DISP1_CTRL0 0x00000050 ++#define SCALER6_DISP1_CTRL1 0x00000054 ++#define SCALER6_DISP1_BGND 0x00000058 ++#define SCALER6_DISP1_LPTRS 0x0000005c ++#define SCALER6_DISP1_COB 0x00000060 ++#define SCALER6_DISP1_STATUS 0x00000064 ++#define SCALER6_DISP1_DL 0x00000068 ++#define SCALER6_DISP1_RUN 0x0000006c ++#define SCALER6_DISP2_CTRL0 0x00000070 ++#define SCALER6_DISP2_CTRL1 0x00000074 ++#define SCALER6_DISP2_BGND 0x00000078 ++#define SCALER6_DISP2_LPTRS 0x0000007c ++#define SCALER6_DISP2_COB 0x00000080 ++#define SCALER6_DISP2_STATUS 0x00000084 ++#define SCALER6_DISP2_DL 0x00000088 ++#define SCALER6_DISP2_RUN 0x0000008c ++#define SCALER6_EOLN 0x00000090 ++#define SCALER6_DL_STATUS 0x00000094 ++#define SCALER6_BFG_MISC 0x0000009c ++#define SCALER6_QOS0 0x000000a0 ++#define SCALER6_PROF0 0x000000a4 ++#define SCALER6_QOS1 0x000000a8 ++#define SCALER6_PROF1 0x000000ac ++#define SCALER6_QOS2 0x000000b0 ++#define SCALER6_PROF2 0x000000b4 ++#define SCALER6_PRI_MAP0 0x000000b8 ++#define SCALER6_PRI_MAP1 0x000000bc ++#define SCALER6_HISTCTRL 0x000000c0 ++#define SCALER6_HISTBIN0 0x000000c4 ++#define SCALER6_HISTBIN1 0x000000c8 ++#define SCALER6_HISTBIN2 0x000000cc ++#define SCALER6_HISTBIN3 0x000000d0 ++#define SCALER6_HISTBIN4 0x000000d4 ++#define SCALER6_HISTBIN5 0x000000d8 ++#define SCALER6_HISTBIN6 0x000000dc ++#define SCALER6_HISTBIN7 0x000000e0 ++#define SCALER6_HDR_CFG_REMAP 0x000000f4 ++#define SCALER6_COL_SPACE 0x000000f8 ++#define SCALER6_HVS_ID 0x000000fc ++#define SCALER6_CFC1 0x00000100 ++#define SCALER6_DISP_UPM_ISO0 0x00000200 ++#define SCALER6_DISP_UPM_ISO1 0x00000204 ++#define SCALER6_DISP_UPM_ISO2 0x00000208 ++#define SCALER6_DISP_LBM_ISO0 0x0000020c ++#define SCALER6_DISP_LBM_ISO1 0x00000210 ++#define SCALER6_DISP_LBM_ISO2 0x00000214 ++#define SCALER6_DISP_COB_ISO0 0x00000218 ++#define SCALER6_DISP_COB_ISO1 0x0000021c ++#define SCALER6_DISP_COB_ISO2 0x00000220 ++#define SCALER6_BAD_COB 0x00000224 ++#define SCALER6_BAD_LBM 0x00000228 ++#define SCALER6_BAD_UPM 0x0000022c ++#define SCALER6_BAD_AXI 0x00000230 ++ + # define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1) + # define VC4_HDMI_SW_RESET_HDMI BIT(0) + +@@ -1131,4 +1255,61 @@ enum hvs_pixel_format { + #define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0) + #define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0 + ++#define SCALER6_CTL0_END BIT(31) ++#define SCALER6_CTL0_VALID BIT(30) ++#define SCALER6_CTL0_NEXT_MASK VC4_MASK(29, 24) ++#define SCALER6_CTL0_RGB_TRANS BIT(23) ++#define SCALER6_CTL0_ADDR_MODE_MASK VC4_MASK(22, 20) ++#define SCALER6_CTL0_ADDR_MODE_LINEAR 0 ++#define SCALER6_CTL0_ADDR_MODE_128B 1 ++#define SCALER6_CTL0_ADDR_MODE_256B 2 ++#define SCALER6_CTL0_ADDR_MODE_MAP8 3 ++#define SCALER6_CTL0_ADDR_MODE_UIF 4 ++ ++#define SCALER6_CTL0_ALPHA_MASK_MASK VC4_MASK(19, 18) ++#define SCALER6_CTL0_UNITY BIT(15) ++#define SCALER6_CTL0_ORDERRGBA_MASK VC4_MASK(14, 13) ++#define SCALER6_CTL0_SCL1_MODE_MASK VC4_MASK(10, 8) ++#define SCALER6_CTL0_SCL0_MODE_MASK VC4_MASK(7, 5) ++#define SCALER6_CTL0_PIXEL_FORMAT_MASK VC4_MASK(4, 0) ++ ++#define SCALER6_POS0_START_Y_MASK VC4_MASK(28, 16) ++#define SCALER6_POS0_HFLIP BIT(15) ++#define SCALER6_POS0_START_X_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_CTL2_ALPHA_MODE_MASK VC4_MASK(31, 30) ++#define SCALER6_CTL2_ALPHA_PREMULT BIT(29) ++#define SCALER6_CTL2_ALPHA_MIX BIT(28) ++#define SCALER6_CTL2_BFG BIT(26) ++#define SCALER6_CTL2_CSC_ENABLE BIT(25) ++#define SCALER6_CTL2_BRCM_CFC_CONTROL_MASK VC4_MASK(18, 16) ++#define SCALER6_CTL2_ALPHA_MASK VC4_MASK(15, 4) ++ ++#define SCALER6_POS1_SCL_LINES_MASK VC4_MASK(28, 16) ++#define SCALER6_POS1_SCL_WIDTH_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_POS2_SRC_LINES_MASK VC4_MASK(28, 16) ++#define SCALER6_POS2_SRC_WIDTH_MASK VC4_MASK(12, 0) ++ ++#define SCALER6_PTR0_VFLIP BIT(31) ++#define SCALER6_PTR0_UPM_BASE_MASK VC4_MASK(28, 16) ++#define SCALER6_PTR0_UPM_HANDLE_MASK VC4_MASK(14, 10) ++#define SCALER6_PTR0_UPM_BUFF_SIZE_MASK VC4_MASK(9, 8) ++#define SCALER6_PTR0_UPM_BUFF_SIZE_16_LINES 3 ++#define SCALER6_PTR0_UPM_BUFF_SIZE_8_LINES 2 ++#define SCALER6_PTR0_UPM_BUFF_SIZE_4_LINES 1 ++#define SCALER6_PTR0_UPM_BUFF_SIZE_2_LINES 0 ++#define SCALER6_PTR0_UPPER_ADDR_MASK VC4_MASK(7, 0) ++ ++#define SCALER6_PTR2_ALPHA_BPP_MASK VC4_MASK(31, 31) ++#define SCALER6_PTR2_ALPHA_BPP_1BPP 1 ++#define SCALER6_PTR2_ALPHA_BPP_8BPP 0 ++#define SCALER6_PTR2_ALPHA_ORDER_MASK VC4_MASK(30, 30) ++#define SCALER6_PTR2_ALPHA_ORDER_MSB_TO_LSB 1 ++#define SCALER6_PTR2_ALPHA_ORDER_LSB_TO_MSB 0 ++#define SCALER6_PTR2_ALPHA_OFFS_MASK VC4_MASK(29, 27) ++#define SCALER6_PTR2_LSKIP_MASK VC4_MASK(26, 24) ++#define SCALER6_PTR2_PITCH_MASK VC4_MASK(16, 0) ++#define SCALER6_PTR2_FETCH_COUNT_MASK VC4_MASK(26, 16) ++ + #endif /* VC4_REGS_H */ diff --git a/target/linux/bcm27xx/patches-6.1/950-0964-drm-vc4-crtc-Add-support-for-BCM2712-PixelValves.patch b/target/linux/bcm27xx/patches-6.1/950-0964-drm-vc4-crtc-Add-support-for-BCM2712-PixelValves.patch new file mode 100644 index 0000000000..1870158e06 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0964-drm-vc4-crtc-Add-support-for-BCM2712-PixelValves.patch @@ -0,0 +1,144 @@ +From 000f1b7d4dc5b515c755ee25db301e26bded00e1 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 15:33:23 +0100 +Subject: [PATCH] drm/vc4: crtc: Add support for BCM2712 PixelValves + +The PixelValves found on the BCM2712 are similar to the ones found in +the previous generation. + +Compared to BCM2711, the pixelvalves only drive one HDMI controller each +and HDMI1 PixelValve has a FIFO long enough to support 4k at 60Hz. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 53 ++++++++++++++++++++++++++++++++-- + drivers/gpu/drm/vc4/vc4_drv.h | 2 ++ + drivers/gpu/drm/vc4/vc4_regs.h | 5 ++++ + 3 files changed, 58 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -239,6 +239,11 @@ static u32 vc4_get_fifo_full_level(struc + const struct vc4_crtc_data *crtc_data = vc4_crtc_to_vc4_crtc_data(vc4_crtc); + const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc); + struct vc4_dev *vc4 = to_vc4_dev(vc4_crtc->base.dev); ++ ++ /* ++ * NOTE: Could we use register 0x68 (PV_HW_CFG1) to get the FIFO ++ * size? ++ */ + u32 fifo_len_bytes = pv_data->fifo_depth; + + /* +@@ -393,6 +398,12 @@ static void vc4_crtc_config_pv(struct dr + + vc4_crtc_pixelvalve_reset(crtc); + ++ /* ++ * NOTE: The BCM2712 has a H_OTE (Horizontal Odd Timing Enable) ++ * bit that, when set, will allow to specify the timings in ++ * pixels instead of cycles, thus allowing to specify odd ++ * timings. ++ */ + CRTC_WRITE(PV_HORZA, + VC4_SET_FIELD((mode->htotal - mode->hsync_end) * pixel_rep / ppc, + PV_HORZA_HBP) | +@@ -462,11 +473,17 @@ static void vc4_crtc_config_pv(struct dr + if (is_dsi) + CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); + +- if (vc4->gen == VC4_GEN_5) ++ if (vc4->gen >= VC4_GEN_5) + CRTC_WRITE(PV_MUX_CFG, + VC4_SET_FIELD(PV_MUX_CFG_RGB_PIXEL_MUX_MODE_NO_SWAP, + PV_MUX_CFG_RGB_PIXEL_MUX_MODE)); + ++ if (vc4->gen >= VC4_GEN_6) ++ CRTC_WRITE(PV_PIPE_INIT_CTRL, ++ VC4_SET_FIELD(1, PV_PIPE_INIT_CTRL_PV_INIT_WIDTH) | ++ VC4_SET_FIELD(1, PV_PIPE_INIT_CTRL_PV_INIT_IDLE) | ++ PV_PIPE_INIT_CTRL_PV_INIT_EN); ++ + CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR | + vc4_crtc_get_fifo_full_level_bits(vc4_crtc, format) | + VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | +@@ -565,7 +582,11 @@ int vc4_crtc_disable_at_boot(struct drm_ + if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node, + "brcm,bcm2711-pixelvalve2") || + of_device_is_compatible(vc4_crtc->pdev->dev.of_node, +- "brcm,bcm2711-pixelvalve4"))) ++ "brcm,bcm2711-pixelvalve4") || ++ of_device_is_compatible(vc4_crtc->pdev->dev.of_node, ++ "brcm,bcm2712-pixelvalve0") || ++ of_device_is_compatible(vc4_crtc->pdev->dev.of_node, ++ "brcm,bcm2712-pixelvalve1"))) + return 0; + + if (!(CRTC_READ(PV_CONTROL) & PV_CONTROL_EN)) +@@ -1304,6 +1325,32 @@ const struct vc4_pv_data bcm2711_pv4_dat + }, + }; + ++const struct vc4_pv_data bcm2712_pv0_data = { ++ .base = { ++ .debugfs_name = "crtc0_regs", ++ .hvs_available_channels = BIT(0), ++ .hvs_output = 0, ++ }, ++ .fifo_depth = 64, ++ .pixels_per_clock = 2, ++ .encoder_types = { ++ [0] = VC4_ENCODER_TYPE_HDMI0, ++ }, ++}; ++ ++const struct vc4_pv_data bcm2712_pv1_data = { ++ .base = { ++ .debugfs_name = "crtc1_regs", ++ .hvs_available_channels = BIT(1), ++ .hvs_output = 1, ++ }, ++ .fifo_depth = 64, ++ .pixels_per_clock = 2, ++ .encoder_types = { ++ [0] = VC4_ENCODER_TYPE_HDMI1, ++ }, ++}; ++ + static const struct of_device_id vc4_crtc_dt_match[] = { + { .compatible = "brcm,bcm2835-pixelvalve0", .data = &bcm2835_pv0_data }, + { .compatible = "brcm,bcm2835-pixelvalve1", .data = &bcm2835_pv1_data }, +@@ -1313,6 +1360,8 @@ static const struct of_device_id vc4_crt + { .compatible = "brcm,bcm2711-pixelvalve2", .data = &bcm2711_pv2_data }, + { .compatible = "brcm,bcm2711-pixelvalve3", .data = &bcm2711_pv3_data }, + { .compatible = "brcm,bcm2711-pixelvalve4", .data = &bcm2711_pv4_data }, ++ { .compatible = "brcm,bcm2712-pixelvalve0", .data = &bcm2712_pv0_data }, ++ { .compatible = "brcm,bcm2712-pixelvalve1", .data = &bcm2712_pv1_data }, + {} + }; + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -583,6 +583,8 @@ extern const struct vc4_pv_data bcm2711_ + extern const struct vc4_pv_data bcm2711_pv2_data; + extern const struct vc4_pv_data bcm2711_pv3_data; + extern const struct vc4_pv_data bcm2711_pv4_data; ++extern const struct vc4_pv_data bcm2712_pv0_data; ++extern const struct vc4_pv_data bcm2712_pv1_data; + + struct vc5_gamma_entry { + u32 x_c_terms; +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -215,6 +215,11 @@ + # define PV_MUX_CFG_RGB_PIXEL_MUX_MODE_SHIFT 2 + # define PV_MUX_CFG_RGB_PIXEL_MUX_MODE_NO_SWAP 8 + ++#define PV_PIPE_INIT_CTRL 0x94 ++# define PV_PIPE_INIT_CTRL_PV_INIT_WIDTH_MASK VC4_MASK(11, 8) ++# define PV_PIPE_INIT_CTRL_PV_INIT_IDLE_MASK VC4_MASK(7, 4) ++# define PV_PIPE_INIT_CTRL_PV_INIT_EN BIT(0) ++ + #define SCALER_CHANNELS_COUNT 3 + + #define SCALER_DISPCTRL 0x00000000 diff --git a/target/linux/bcm27xx/patches-6.1/950-0965-drm-vc4-hdmi-Add-support-for-BCM2712-HDMI-controller.patch b/target/linux/bcm27xx/patches-6.1/950-0965-drm-vc4-hdmi-Add-support-for-BCM2712-HDMI-controller.patch new file mode 100644 index 0000000000..7cb4e5661d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0965-drm-vc4-hdmi-Add-support-for-BCM2712-HDMI-controller.patch @@ -0,0 +1,1057 @@ +From 1bb54596ae2a9a36f4aa9f8f2ba941320f463811 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 15:34:30 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add support for BCM2712 HDMI controllers + +The HDMI controllers found in the BCM2712 are largely the ones found in +the BCM2711 with a different PHY. + +There's some difference with how timings are split between registers, +and HDMI1 is now able to run at 4k/60Hz. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 82 +++- + drivers/gpu/drm/vc4/vc4_hdmi.h | 4 + + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 640 ++++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 217 ++++++++++ + 4 files changed, 937 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1127,6 +1127,7 @@ static void vc4_hdmi_encoder_post_crtc_d + { + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); + unsigned long flags; + int idx; + +@@ -1143,14 +1144,25 @@ static void vc4_hdmi_encoder_post_crtc_d + + HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB); + ++ if (vc4->gen >= VC4_GEN_6) ++ HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | ++ VC4_HD_VID_CTL_BLANKPIX); ++ + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + mdelay(1); + +- spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); +- HDMI_WRITE(HDMI_VID_CTL, +- HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); +- spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ /* ++ * TODO: This should work on BCM2712, but doesn't for some ++ * reason and result in a system lockup. ++ */ ++ if (vc4->gen < VC4_GEN_6) { ++ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++ HDMI_WRITE(HDMI_VID_CTL, ++ HDMI_READ(HDMI_VID_CTL) & ++ ~VC4_HD_VID_CTL_ENABLE); ++ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++ } + + vc4_hdmi_disable_scrambling(encoder); + +@@ -1757,7 +1769,6 @@ static void vc4_hdmi_encoder_pre_crtc_co + goto err_put_runtime_pm; + } + +- + vc4_hdmi_cec_update_clk_div(vc4_hdmi); + + if (tmds_char_rate > 297000000) +@@ -1862,6 +1873,7 @@ static void vc4_hdmi_encoder_post_crtc_e + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + + HDMI_WRITE(HDMI_VID_CTL, ++ HDMI_READ(HDMI_VID_CTL) | + VC4_HD_VID_CTL_ENABLE | + VC4_HD_VID_CTL_CLRRGB | + VC4_HD_VID_CTL_UNDERFLOW_ENABLE | +@@ -3796,7 +3808,9 @@ static int vc4_hdmi_bind(struct device * + return ret; + + if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") || +- of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1")) && ++ of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1") || ++ of_device_is_compatible(dev->of_node, "brcm,bcm2712-hdmi0") || ++ of_device_is_compatible(dev->of_node, "brcm,bcm2712-hdmi1")) && + HDMI_READ(HDMI_VID_CTL) & VC4_HD_VID_CTL_ENABLE) { + clk_prepare_enable(vc4_hdmi->pixel_clock); + clk_prepare_enable(vc4_hdmi->hsm_clock); +@@ -3931,10 +3945,66 @@ static const struct vc4_hdmi_variant bcm + .hp_detect = vc5_hdmi_hp_detect, + }; + ++static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = { ++ .encoder_type = VC4_ENCODER_TYPE_HDMI0, ++ .debugfs_name = "hdmi0_regs", ++ .card_name = "vc4-hdmi-0", ++ .max_pixel_clock = 600000000, ++ .registers = vc6_hdmi_hdmi0_fields, ++ .num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields), ++ .phy_lane_mapping = { ++ PHY_LANE_0, ++ PHY_LANE_1, ++ PHY_LANE_2, ++ PHY_LANE_CK, ++ }, ++ .unsupported_odd_h_timings = true, ++ .external_irq_controller = true, ++ ++ .init_resources = vc5_hdmi_init_resources, ++ .csc_setup = vc5_hdmi_csc_setup, ++ .reset = vc5_hdmi_reset, ++ .set_timings = vc5_hdmi_set_timings, ++ .phy_init = vc6_hdmi_phy_init, ++ .phy_disable = vc6_hdmi_phy_disable, ++ .channel_map = vc5_hdmi_channel_map, ++ .supports_hdr = true, ++ .hp_detect = vc5_hdmi_hp_detect, ++}; ++ ++static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = { ++ .encoder_type = VC4_ENCODER_TYPE_HDMI1, ++ .debugfs_name = "hdmi1_regs", ++ .card_name = "vc4-hdmi-1", ++ .max_pixel_clock = 600000000, ++ .registers = vc6_hdmi_hdmi1_fields, ++ .num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields), ++ .phy_lane_mapping = { ++ PHY_LANE_0, ++ PHY_LANE_1, ++ PHY_LANE_2, ++ PHY_LANE_CK, ++ }, ++ .unsupported_odd_h_timings = true, ++ .external_irq_controller = true, ++ ++ .init_resources = vc5_hdmi_init_resources, ++ .csc_setup = vc5_hdmi_csc_setup, ++ .reset = vc5_hdmi_reset, ++ .set_timings = vc5_hdmi_set_timings, ++ .phy_init = vc6_hdmi_phy_init, ++ .phy_disable = vc6_hdmi_phy_disable, ++ .channel_map = vc5_hdmi_channel_map, ++ .supports_hdr = true, ++ .hp_detect = vc5_hdmi_hp_detect, ++}; ++ + static const struct of_device_id vc4_hdmi_dt_match[] = { + { .compatible = "brcm,bcm2835-hdmi", .data = &bcm2835_variant }, + { .compatible = "brcm,bcm2711-hdmi0", .data = &bcm2711_hdmi0_variant }, + { .compatible = "brcm,bcm2711-hdmi1", .data = &bcm2711_hdmi1_variant }, ++ { .compatible = "brcm,bcm2712-hdmi0", .data = &bcm2712_hdmi0_variant }, ++ { .compatible = "brcm,bcm2712-hdmi1", .data = &bcm2712_hdmi1_variant }, + {} + }; + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -284,4 +284,8 @@ void vc5_hdmi_phy_disable(struct vc4_hdm + void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi); + void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi); + ++void vc6_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, ++ struct vc4_hdmi_connector_state *vc4_conn_state); ++void vc6_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi); ++ + #endif /* _VC4_HDMI_H_ */ +--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +@@ -125,6 +125,48 @@ + #define VC4_HDMI_RM_FORMAT_SHIFT_SHIFT 24 + #define VC4_HDMI_RM_FORMAT_SHIFT_MASK VC4_MASK(25, 24) + ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_BG_PWRUP BIT(8) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_LDO_PWRUP BIT(7) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_BIAS_PWRUP BIT(6) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_RNDGEN_PWRUP BIT(4) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_CK_PWRUP BIT(3) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_2_PWRUP BIT(2) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_1_PWRUP BIT(1) ++#define VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_0_PWRUP BIT(0) ++ ++#define VC6_HDMI_TX_PHY_PLL_REFCLK_REFCLK_SEL_CMOS BIT(13) ++#define VC6_HDMI_TX_PHY_PLL_REFCLK_REFFRQ_MASK VC4_MASK(9, 0) ++ ++#define VC6_HDMI_TX_PHY_PLL_POST_KDIV_CLK0_SEL_MASK VC4_MASK(3, 2) ++#define VC6_HDMI_TX_PHY_PLL_POST_KDIV_KDIV_MASK VC4_MASK(1, 0) ++ ++#define VC6_HDMI_TX_PHY_PLL_VCOCLK_DIV_VCODIV_EN BIT(10) ++#define VC6_HDMI_TX_PHY_PLL_VCOCLK_DIV_VCODIV_MASK VC4_MASK(9, 0) ++ ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL_MASK VC4_MASK(31, 28) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE_MASK VC4_MASK(27, 27) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL_MASK VC4_MASK(26, 26) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN_MASK VC4_MASK(25, 25) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL_MASK VC4_MASK(24, 23) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN_MASK VC4_MASK(22, 22) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL_MASK VC4_MASK(21, 21) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN_MASK VC4_MASK(20, 20) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL_MASK VC4_MASK(19, 18) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN_MASK VC4_MASK(17, 17) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN_MASK VC4_MASK(16, 16) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL_MASK VC4_MASK(15, 12) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN_MASK VC4_MASK(11, 11) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT_MASK VC4_MASK(10, 8) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT_MASK VC4_MASK(7, 5) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING_MASK VC4_MASK(4, 3) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING_MASK VC4_MASK(2, 1) ++#define VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN_MASK VC4_MASK(0, 0) ++ ++#define VC6_HDMI_TX_PHY_PLL_RESET_CTL_PLL_PLLPOST_RESETB BIT(1) ++#define VC6_HDMI_TX_PHY_PLL_RESET_CTL_PLL_RESETB BIT(0) ++ ++#define VC6_HDMI_TX_PHY_PLL_POWERUP_CTL_PLL_PWRUP BIT(0) ++ + #define OSCILLATOR_FREQUENCY 54000000 + + void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, +@@ -558,3 +600,601 @@ void vc5_hdmi_phy_rng_disable(struct vc4 + VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + } ++ ++#define VC6_VCO_MIN_FREQ (8ULL * 1000 * 1000 * 1000) ++#define VC6_VCO_MAX_FREQ (12ULL * 1000 * 1000 * 1000) ++ ++static unsigned long long ++vc6_phy_get_vco_freq(unsigned long long tmds_rate, unsigned int *vco_div) ++{ ++ unsigned int min_div; ++ unsigned int max_div; ++ unsigned int div; ++ ++ div = 0; ++ while (tmds_rate * div * 10 < VC6_VCO_MIN_FREQ) ++ div++; ++ min_div = div; ++ ++ while (tmds_rate * (div + 1) * 10 < VC6_VCO_MAX_FREQ) ++ div++; ++ max_div = div; ++ ++ div = min_div + (max_div - min_div) / 2; ++ ++ *vco_div = div; ++ return tmds_rate * div * 10; ++} ++ ++struct vc6_phy_lane_settings { ++ unsigned int ext_current_ctl:4; ++ unsigned int ffe_enable:1; ++ unsigned int slew_rate_ctl:1; ++ unsigned int ffe_post_tap_en:1; ++ unsigned int ldmos_bias_ctl:2; ++ unsigned int com_mode_ldmos_en:1; ++ unsigned int edge_sel:1; ++ unsigned int ext_current_src_hs_en:1; ++ unsigned int term_ctl:2; ++ unsigned int ext_current_src_en:1; ++ unsigned int int_current_src_en:1; ++ unsigned int int_current_ctl:4; ++ unsigned int int_current_src_hs_en:1; ++ unsigned int main_tap_current_select:3; ++ unsigned int post_tap_current_select:3; ++ unsigned int slew_ctl_slow_loading:2; ++ unsigned int slew_ctl_slow_driving:2; ++ unsigned int ffe_pre_tap_en:1; ++}; ++ ++struct vc6_phy_settings { ++ unsigned long long min_rate; ++ unsigned long long max_rate; ++ struct vc6_phy_lane_settings channel[3]; ++ struct vc6_phy_lane_settings clock; ++}; ++ ++static const struct vc6_phy_settings vc6_hdmi_phy_settings[] = { ++ { ++ 0, 222000000, ++ { ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* 200mA */ ++ .int_current_ctl = 8, ++ ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* 200mA */ ++ .int_current_ctl = 8, ++ ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* 200mA */ ++ .int_current_ctl = 8, ++ ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* 200mA */ ++ .int_current_ctl = 8, ++ ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ }, ++ { ++ 222000001, 297000000, ++ { ++ { ++ /* 200mA and 180mA ?! */ ++ .ext_current_ctl = 12, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* 100 Ohm */ ++ .term_ctl = 1, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ }, ++ { ++ /* 200mA and 180mA ?! */ ++ .ext_current_ctl = 12, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* 100 Ohm */ ++ .term_ctl = 1, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ }, ++ { ++ /* 200mA and 180mA ?! */ ++ .ext_current_ctl = 12, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* 100 Ohm */ ++ .term_ctl = 1, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ }, ++ }, ++ { ++ /* 200mA and 180mA ?! */ ++ .ext_current_ctl = 12, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* 100 Ohm */ ++ .term_ctl = 1, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ ++ /* Internal Current Source Half Swing Enable*/ ++ .int_current_src_hs_en = 1, ++ }, ++ }, ++ { ++ 297000001, 597000044, ++ { ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, ++ ++ /* Normal Slew Rate Control */ ++ .slew_rate_ctl = 1, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* 50 Ohms */ ++ .term_ctl = 3, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ ++ /* 200mA */ ++ .int_current_ctl = 8, ++ ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, ++ ++ /* Normal Slew Rate Control */ ++ .slew_rate_ctl = 1, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* 50 Ohms */ ++ .term_ctl = 3, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ ++ /* 200mA */ ++ .int_current_ctl = 8, ++ ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, ++ ++ /* Normal Slew Rate Control */ ++ .slew_rate_ctl = 1, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* 50 Ohms */ ++ .term_ctl = 3, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ ++ /* 200mA */ ++ .int_current_ctl = 8, ++ ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ }, ++ { ++ /* 200mA */ ++ .ext_current_ctl = 8, ++ ++ /* Normal Slew Rate Control */ ++ .slew_rate_ctl = 1, ++ ++ /* 0.85V */ ++ .ldmos_bias_ctl = 1, ++ ++ /* External Current Source Half Swing Enable*/ ++ .ext_current_src_hs_en = 1, ++ ++ /* 50 Ohms */ ++ .term_ctl = 3, ++ ++ /* Enable External Current Source */ ++ .ext_current_src_en = 1, ++ ++ /* Enable Internal Current Source */ ++ .int_current_src_en = 1, ++ ++ /* 200mA */ ++ .int_current_ctl = 8, ++ ++ /* Internal Current Source Half Swing Enable*/ ++ .int_current_src_hs_en = 1, ++ ++ /* 17.6 mA */ ++ .main_tap_current_select = 7, ++ }, ++ }, ++}; ++ ++static const struct vc6_phy_settings * ++vc6_phy_get_settings(unsigned long long tmds_rate) ++{ ++ unsigned int count = ARRAY_SIZE(vc6_hdmi_phy_settings); ++ unsigned int i; ++ ++ for (i = 0; i < count; i++) { ++ const struct vc6_phy_settings *s = &vc6_hdmi_phy_settings[i]; ++ ++ if (tmds_rate >= s->min_rate && tmds_rate <= s->max_rate) ++ return s; ++ } ++ ++ /* ++ * If the pixel clock exceeds our max setting, try the max ++ * setting anyway. ++ */ ++ return &vc6_hdmi_phy_settings[count - 1]; ++} ++ ++static const struct vc6_phy_lane_settings * ++vc6_phy_get_channel_settings(enum vc4_hdmi_phy_channel chan, ++ unsigned long long tmds_rate) ++{ ++ const struct vc6_phy_settings *settings = vc6_phy_get_settings(tmds_rate); ++ ++ if (chan == PHY_LANE_CK) ++ return &settings->clock; ++ ++ return &settings->channel[chan]; ++} ++ ++static void vc6_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi) ++{ ++ lockdep_assert_held(&vc4_hdmi->hw_lock); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); ++ HDMI_WRITE(HDMI_TX_PHY_POWERUP_CTL, 0); ++} ++ ++void vc6_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, ++ struct vc4_hdmi_connector_state *conn_state) ++{ ++ const struct vc6_phy_lane_settings *chan0_settings; ++ const struct vc6_phy_lane_settings *chan1_settings; ++ const struct vc6_phy_lane_settings *chan2_settings; ++ const struct vc6_phy_lane_settings *clock_settings; ++ const struct vc4_hdmi_variant *variant = vc4_hdmi->variant; ++ unsigned long long pixel_freq = conn_state->tmds_char_rate; ++ unsigned long long vco_freq; ++ unsigned char word_sel; ++ unsigned long flags; ++ unsigned int vco_div; ++ ++ vco_freq = vc6_phy_get_vco_freq(pixel_freq, &vco_div); ++ ++ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++ ++ vc6_hdmi_reset_phy(vc4_hdmi); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_0, 0x810c6000); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_1, 0x00b8c451); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_2, 0x46402e31); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_3, 0x00b8c005); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_4, 0x42410261); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_5, 0xcc021001); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_6, 0xc8301c80); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_7, 0xb0804444); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_MISC_8, 0xf80f8000); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_REFCLK, ++ VC6_HDMI_TX_PHY_PLL_REFCLK_REFCLK_SEL_CMOS | ++ VC4_SET_FIELD(54, VC6_HDMI_TX_PHY_PLL_REFCLK_REFFRQ)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0x7f); ++ ++ HDMI_WRITE(HDMI_RM_OFFSET, ++ VC4_HDMI_RM_OFFSET_ONLY | ++ VC4_SET_FIELD(phy_get_rm_offset(vco_freq), ++ VC4_HDMI_RM_OFFSET_OFFSET)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_VCOCLK_DIV, ++ VC6_HDMI_TX_PHY_PLL_VCOCLK_DIV_VCODIV_EN | ++ VC4_SET_FIELD(vco_div, ++ VC6_HDMI_TX_PHY_PLL_VCOCLK_DIV_VCODIV)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CFG, ++ VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CFG_PDIV)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_POST_KDIV, ++ VC4_SET_FIELD(2, VC6_HDMI_TX_PHY_PLL_POST_KDIV_CLK0_SEL) | ++ VC4_SET_FIELD(1, VC6_HDMI_TX_PHY_PLL_POST_KDIV_KDIV)); ++ ++ chan0_settings = ++ vc6_phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_0], ++ pixel_freq); ++ HDMI_WRITE(HDMI_TX_PHY_CTL_0, ++ VC4_SET_FIELD(chan0_settings->ext_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan0_settings->ffe_enable, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE) | ++ VC4_SET_FIELD(chan0_settings->slew_rate_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL) | ++ VC4_SET_FIELD(chan0_settings->ffe_post_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN) | ++ VC4_SET_FIELD(chan0_settings->ldmos_bias_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL) | ++ VC4_SET_FIELD(chan0_settings->com_mode_ldmos_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN) | ++ VC4_SET_FIELD(chan0_settings->edge_sel, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL) | ++ VC4_SET_FIELD(chan0_settings->ext_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan0_settings->term_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL) | ++ VC4_SET_FIELD(chan0_settings->ext_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan0_settings->int_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan0_settings->int_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan0_settings->int_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan0_settings->main_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan0_settings->post_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan0_settings->slew_ctl_slow_loading, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING) | ++ VC4_SET_FIELD(chan0_settings->slew_ctl_slow_driving, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING) | ++ VC4_SET_FIELD(chan0_settings->ffe_pre_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN)); ++ ++ chan1_settings = ++ vc6_phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_1], ++ pixel_freq); ++ HDMI_WRITE(HDMI_TX_PHY_CTL_1, ++ VC4_SET_FIELD(chan1_settings->ext_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan1_settings->ffe_enable, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE) | ++ VC4_SET_FIELD(chan1_settings->slew_rate_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL) | ++ VC4_SET_FIELD(chan1_settings->ffe_post_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN) | ++ VC4_SET_FIELD(chan1_settings->ldmos_bias_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL) | ++ VC4_SET_FIELD(chan1_settings->com_mode_ldmos_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN) | ++ VC4_SET_FIELD(chan1_settings->edge_sel, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL) | ++ VC4_SET_FIELD(chan1_settings->ext_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan1_settings->term_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL) | ++ VC4_SET_FIELD(chan1_settings->ext_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan1_settings->int_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan1_settings->int_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan1_settings->int_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan1_settings->main_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan1_settings->post_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan1_settings->slew_ctl_slow_loading, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING) | ++ VC4_SET_FIELD(chan1_settings->slew_ctl_slow_driving, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING) | ++ VC4_SET_FIELD(chan1_settings->ffe_pre_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN)); ++ ++ chan2_settings = ++ vc6_phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_2], ++ pixel_freq); ++ HDMI_WRITE(HDMI_TX_PHY_CTL_2, ++ VC4_SET_FIELD(chan2_settings->ext_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan2_settings->ffe_enable, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE) | ++ VC4_SET_FIELD(chan2_settings->slew_rate_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL) | ++ VC4_SET_FIELD(chan2_settings->ffe_post_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN) | ++ VC4_SET_FIELD(chan2_settings->ldmos_bias_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL) | ++ VC4_SET_FIELD(chan2_settings->com_mode_ldmos_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN) | ++ VC4_SET_FIELD(chan2_settings->edge_sel, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL) | ++ VC4_SET_FIELD(chan2_settings->ext_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan2_settings->term_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL) | ++ VC4_SET_FIELD(chan2_settings->ext_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan2_settings->int_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(chan2_settings->int_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL) | ++ VC4_SET_FIELD(chan2_settings->int_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(chan2_settings->main_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan2_settings->post_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(chan2_settings->slew_ctl_slow_loading, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING) | ++ VC4_SET_FIELD(chan2_settings->slew_ctl_slow_driving, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING) | ++ VC4_SET_FIELD(chan2_settings->ffe_pre_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN)); ++ ++ clock_settings = ++ vc6_phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_CK], ++ pixel_freq); ++ HDMI_WRITE(HDMI_TX_PHY_CTL_CK, ++ VC4_SET_FIELD(clock_settings->ext_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_CTL) | ++ VC4_SET_FIELD(clock_settings->ffe_enable, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_ENABLE) | ++ VC4_SET_FIELD(clock_settings->slew_rate_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_RATE_CTL) | ++ VC4_SET_FIELD(clock_settings->ffe_post_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_POST_TAP_EN) | ++ VC4_SET_FIELD(clock_settings->ldmos_bias_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_LDMOS_BIAS_CTL) | ++ VC4_SET_FIELD(clock_settings->com_mode_ldmos_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_COM_MODE_LDMOS_EN) | ++ VC4_SET_FIELD(clock_settings->edge_sel, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EDGE_SEL) | ++ VC4_SET_FIELD(clock_settings->ext_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(clock_settings->term_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_TERM_CTL) | ++ VC4_SET_FIELD(clock_settings->ext_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_EXT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(clock_settings->int_current_src_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_EN) | ++ VC4_SET_FIELD(clock_settings->int_current_ctl, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_CTL) | ++ VC4_SET_FIELD(clock_settings->int_current_src_hs_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_INT_CURRENT_SRC_HS_EN) | ++ VC4_SET_FIELD(clock_settings->main_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_MAIN_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(clock_settings->post_tap_current_select, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_POST_TAP_CURRENT_SELECT) | ++ VC4_SET_FIELD(clock_settings->slew_ctl_slow_loading, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_LOADING) | ++ VC4_SET_FIELD(clock_settings->slew_ctl_slow_driving, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_SLEW_CTL_SLOW_DRIVING) | ++ VC4_SET_FIELD(clock_settings->ffe_pre_tap_en, ++ VC6_HDMI_TX_PHY_HDMI_CTRL_CHX_FFE_PRE_TAP_EN)); ++ ++ if (pixel_freq >= 340000000) ++ word_sel = 3; ++ else ++ word_sel = 0; ++ HDMI_WRITE(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, word_sel); ++ ++ HDMI_WRITE(HDMI_TX_PHY_POWERUP_CTL, ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_BG_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_LDO_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_BIAS_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_CK_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_2_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_1_PWRUP | ++ VC6_HDMI_TX_PHY_HDMI_POWERUP_CTL_TX_0_PWRUP); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_POWERUP_CTL, ++ VC6_HDMI_TX_PHY_PLL_POWERUP_CTL_PLL_PWRUP); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_PLL_RESET_CTL) & ++ ~VC6_HDMI_TX_PHY_PLL_RESET_CTL_PLL_RESETB); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_PLL_RESET_CTL) | ++ VC6_HDMI_TX_PHY_PLL_RESET_CTL_PLL_RESETB); ++ ++ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ++} ++ ++void vc6_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) ++{ ++} +--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +@@ -111,13 +111,30 @@ enum vc4_hdmi_field { + HDMI_TX_PHY_CTL_1, + HDMI_TX_PHY_CTL_2, + HDMI_TX_PHY_CTL_3, ++ HDMI_TX_PHY_CTL_CK, + HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, + HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, + HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, + HDMI_TX_PHY_PLL_CFG, ++ HDMI_TX_PHY_PLL_CFG_PDIV, + HDMI_TX_PHY_PLL_CTL_0, + HDMI_TX_PHY_PLL_CTL_1, ++ HDMI_TX_PHY_PLL_MISC_0, ++ HDMI_TX_PHY_PLL_MISC_1, ++ HDMI_TX_PHY_PLL_MISC_2, ++ HDMI_TX_PHY_PLL_MISC_3, ++ HDMI_TX_PHY_PLL_MISC_4, ++ HDMI_TX_PHY_PLL_MISC_5, ++ HDMI_TX_PHY_PLL_MISC_6, ++ HDMI_TX_PHY_PLL_MISC_7, ++ HDMI_TX_PHY_PLL_MISC_8, ++ HDMI_TX_PHY_PLL_POST_KDIV, ++ HDMI_TX_PHY_PLL_POWERUP_CTL, ++ HDMI_TX_PHY_PLL_REFCLK, ++ HDMI_TX_PHY_PLL_RESET_CTL, ++ HDMI_TX_PHY_PLL_VCOCLK_DIV, + HDMI_TX_PHY_POWERDOWN_CTL, ++ HDMI_TX_PHY_POWERUP_CTL, + HDMI_TX_PHY_RESET_CTL, + HDMI_TX_PHY_TMDS_CLK_WORD_SEL, + HDMI_VEC_INTERFACE_CFG, +@@ -383,6 +400,206 @@ static const struct vc4_hdmi_register __ + + VC5_RM_REG(HDMI_RM_CONTROL, 0x000), + VC5_RM_REG(HDMI_RM_OFFSET, 0x018), ++ VC5_RM_REG(HDMI_RM_FORMAT, 0x01c), ++ ++ VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000), ++ ++ VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044), ++ ++ VC5_CSC_REG(HDMI_CSC_CTL, 0x000), ++ VC5_CSC_REG(HDMI_CSC_12_11, 0x004), ++ VC5_CSC_REG(HDMI_CSC_14_13, 0x008), ++ VC5_CSC_REG(HDMI_CSC_22_21, 0x00c), ++ VC5_CSC_REG(HDMI_CSC_24_23, 0x010), ++ VC5_CSC_REG(HDMI_CSC_32_31, 0x014), ++ VC5_CSC_REG(HDMI_CSC_34_33, 0x018), ++ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c), ++}; ++ ++static const struct vc4_hdmi_register __maybe_unused vc6_hdmi_hdmi0_fields[] = { ++ VC4_HD_REG(HDMI_DVP_CTL, 0x0000), ++ VC4_HD_REG(HDMI_MAI_CTL, 0x0010), ++ VC4_HD_REG(HDMI_MAI_THR, 0x0014), ++ VC4_HD_REG(HDMI_MAI_FMT, 0x0018), ++ VC4_HD_REG(HDMI_MAI_DATA, 0x001c), ++ VC4_HD_REG(HDMI_MAI_SMP, 0x0020), ++ VC4_HD_REG(HDMI_VID_CTL, 0x0044), ++ VC4_HD_REG(HDMI_FRAME_COUNT, 0x0060), ++ ++ VC4_HDMI_REG(HDMI_FIFO_CTL, 0x07c), ++ VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0c0), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0c4), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0cc), ++ VC4_HDMI_REG(HDMI_CRP_CFG, 0x0d0), ++ VC4_HDMI_REG(HDMI_CTS_0, 0x0d4), ++ VC4_HDMI_REG(HDMI_CTS_1, 0x0d8), ++ VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e8), ++ VC4_HDMI_REG(HDMI_HORZA, 0x0ec), ++ VC4_HDMI_REG(HDMI_HORZB, 0x0f0), ++ VC4_HDMI_REG(HDMI_VERTA0, 0x0f4), ++ VC4_HDMI_REG(HDMI_VERTB0, 0x0f8), ++ VC4_HDMI_REG(HDMI_VERTA1, 0x100), ++ VC4_HDMI_REG(HDMI_VERTB1, 0x104), ++ VC4_HDMI_REG(HDMI_MISC_CONTROL, 0x114), ++ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x0a4), ++ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a8), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_1, 0x148), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_2, 0x14c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_3, 0x150), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_4, 0x158), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_5, 0x15c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_6, 0x160), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_7, 0x164), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_8, 0x168), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_9, 0x16c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_10, 0x170), ++ VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x18c), ++ VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x194), ++ VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x198), ++ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1c8), ++ VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1e4), ++ ++ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0f0), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f4), ++ ++ VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), ++ VC5_PHY_REG(HDMI_TX_PHY_POWERUP_CTL, 0x004), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_CK, 0x014), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_REFCLK, 0x01c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_POST_KDIV, 0x028), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_VCOCLK_DIV, 0x02c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x044), ++ VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x054), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_0, 0x060), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_1, 0x064), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_2, 0x068), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_3, 0x06c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_4, 0x070), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_5, 0x074), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_6, 0x078), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_7, 0x07c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_8, 0x080), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_RESET_CTL, 0x190), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_POWERUP_CTL, 0x194), ++ ++ VC5_RM_REG(HDMI_RM_CONTROL, 0x000), ++ VC5_RM_REG(HDMI_RM_OFFSET, 0x018), ++ VC5_RM_REG(HDMI_RM_FORMAT, 0x01c), ++ ++ VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000), ++ ++ VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044), ++ ++ VC5_CSC_REG(HDMI_CSC_CTL, 0x000), ++ VC5_CSC_REG(HDMI_CSC_12_11, 0x004), ++ VC5_CSC_REG(HDMI_CSC_14_13, 0x008), ++ VC5_CSC_REG(HDMI_CSC_22_21, 0x00c), ++ VC5_CSC_REG(HDMI_CSC_24_23, 0x010), ++ VC5_CSC_REG(HDMI_CSC_32_31, 0x014), ++ VC5_CSC_REG(HDMI_CSC_34_33, 0x018), ++ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c), ++}; ++ ++static const struct vc4_hdmi_register __maybe_unused vc6_hdmi_hdmi1_fields[] = { ++ VC4_HD_REG(HDMI_DVP_CTL, 0x0000), ++ VC4_HD_REG(HDMI_MAI_CTL, 0x0030), ++ VC4_HD_REG(HDMI_MAI_THR, 0x0034), ++ VC4_HD_REG(HDMI_MAI_FMT, 0x0038), ++ VC4_HD_REG(HDMI_MAI_DATA, 0x003c), ++ VC4_HD_REG(HDMI_MAI_SMP, 0x0040), ++ VC4_HD_REG(HDMI_VID_CTL, 0x0048), ++ VC4_HD_REG(HDMI_FRAME_COUNT, 0x0064), ++ ++ VC4_HDMI_REG(HDMI_FIFO_CTL, 0x07c), ++ VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0c0), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0c4), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0cc), ++ VC4_HDMI_REG(HDMI_CRP_CFG, 0x0d0), ++ VC4_HDMI_REG(HDMI_CTS_0, 0x0d4), ++ VC4_HDMI_REG(HDMI_CTS_1, 0x0d8), ++ VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e8), ++ VC4_HDMI_REG(HDMI_HORZA, 0x0ec), ++ VC4_HDMI_REG(HDMI_HORZB, 0x0f0), ++ VC4_HDMI_REG(HDMI_VERTA0, 0x0f4), ++ VC4_HDMI_REG(HDMI_VERTB0, 0x0f8), ++ VC4_HDMI_REG(HDMI_VERTA1, 0x100), ++ VC4_HDMI_REG(HDMI_VERTB1, 0x104), ++ VC4_HDMI_REG(HDMI_MISC_CONTROL, 0x114), ++ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x0a4), ++ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a8), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_1, 0x148), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_2, 0x14c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_3, 0x150), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_4, 0x158), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_5, 0x15c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_6, 0x160), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_7, 0x164), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_8, 0x168), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_9, 0x16c), ++ VC4_HDMI_REG(HDMI_FORMAT_DET_10, 0x170), ++ VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x18c), ++ VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x194), ++ VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x198), ++ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1c8), ++ VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1e4), ++ ++ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0f0), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f4), ++ ++ VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), ++ VC5_PHY_REG(HDMI_TX_PHY_POWERUP_CTL, 0x004), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_CK, 0x014), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_REFCLK, 0x01c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_POST_KDIV, 0x028), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_VCOCLK_DIV, 0x02c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x044), ++ VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x054), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_0, 0x060), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_1, 0x064), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_2, 0x068), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_3, 0x06c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_4, 0x070), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_5, 0x074), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_6, 0x078), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_7, 0x07c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_MISC_8, 0x080), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_RESET_CTL, 0x190), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_POWERUP_CTL, 0x194), ++ ++ VC5_RM_REG(HDMI_RM_CONTROL, 0x000), ++ VC5_RM_REG(HDMI_RM_OFFSET, 0x018), + VC5_RM_REG(HDMI_RM_FORMAT, 0x01c), + + VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000), diff --git a/target/linux/bcm27xx/patches-6.1/950-0966-drm-vc4-txp-Introduce-structure-to-deal-with-revisio.patch b/target/linux/bcm27xx/patches-6.1/950-0966-drm-vc4-txp-Introduce-structure-to-deal-with-revisio.patch new file mode 100644 index 0000000000..c54ab0d360 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0966-drm-vc4-txp-Introduce-structure-to-deal-with-revisio.patch @@ -0,0 +1,117 @@ +From a68e8ffc3314612b0d00d491c8cdd61ae1d9af4e Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 25 Apr 2023 10:12:32 +0200 +Subject: [PATCH] drm/vc4: txp: Introduce structure to deal with revision + differences + +The BCM2712 will have several TXP with small differences. Let's add a +structure tied to the compatible to deal with those differences. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.c | 4 ++-- + drivers/gpu/drm/vc4/vc4_drv.h | 6 +++++- + drivers/gpu/drm/vc4/vc4_txp.c | 23 ++++++++++++++++------- + 3 files changed, 23 insertions(+), 10 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c +@@ -51,7 +51,7 @@ struct vc4_mock_desc { + + static const struct vc4_mock_desc vc4_mock = + VC4_MOCK_DESC( +- VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data, ++ VC4_MOCK_CRTC_DESC(&vc4_txp_data.base, + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, + DRM_MODE_ENCODER_VIRTUAL, + DRM_MODE_CONNECTOR_WRITEBACK)), +@@ -77,7 +77,7 @@ static const struct vc4_mock_desc vc4_mo + + static const struct vc4_mock_desc vc5_mock = + VC4_MOCK_DESC( +- VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data, ++ VC4_MOCK_CRTC_DESC(&vc4_txp_data.base, + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, + DRM_MODE_ENCODER_VIRTUAL, + DRM_MODE_CONNECTOR_WRITEBACK)), +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -561,7 +561,11 @@ struct vc4_crtc_data { + int hvs_output; + }; + +-extern const struct vc4_crtc_data vc4_txp_crtc_data; ++struct vc4_txp_data { ++ struct vc4_crtc_data base; ++}; ++ ++extern const struct vc4_txp_data vc4_txp_data; + + struct vc4_pv_data { + struct vc4_crtc_data base; +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -159,6 +159,7 @@ + + struct vc4_txp { + struct vc4_crtc base; ++ const struct vc4_txp_data *data; + + struct platform_device *pdev; + +@@ -488,17 +489,20 @@ static irqreturn_t vc4_txp_interrupt(int + return IRQ_HANDLED; + } + +-const struct vc4_crtc_data vc4_txp_crtc_data = { +- .name = "txp", +- .debugfs_name = "txp_regs", +- .hvs_available_channels = BIT(2), +- .hvs_output = 2, ++const struct vc4_txp_data vc4_txp_data = { ++ .base = { ++ .name = "txp", ++ .debugfs_name = "txp_regs", ++ .hvs_available_channels = BIT(2), ++ .hvs_output = 2, ++ }, + }; + + static int vc4_txp_bind(struct device *dev, struct device *master, void *data) + { + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); ++ const struct vc4_txp_data *txp_data; + struct vc4_encoder *vc4_encoder; + struct drm_encoder *encoder; + struct vc4_crtc *vc4_crtc; +@@ -513,6 +517,11 @@ static int vc4_txp_bind(struct device *d + if (!txp) + return -ENOMEM; + ++ txp_data = of_device_get_match_data(dev); ++ if (!txp_data) ++ return -ENODEV; ++ ++ txp->data = txp_data; + txp->pdev = pdev; + txp->regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(txp->regs)) +@@ -523,7 +532,7 @@ static int vc4_txp_bind(struct device *d + vc4_crtc->regset.regs = txp_regs; + vc4_crtc->regset.nregs = ARRAY_SIZE(txp_regs); + +- ret = vc4_crtc_init(drm, pdev, vc4_crtc, &vc4_txp_crtc_data, ++ ret = vc4_crtc_init(drm, pdev, vc4_crtc, &txp_data->base, + &vc4_txp_crtc_funcs, &vc4_txp_crtc_helper_funcs, true); + if (ret) + return ret; +@@ -584,7 +593,7 @@ static int vc4_txp_remove(struct platfor + } + + static const struct of_device_id vc4_txp_dt_match[] = { +- { .compatible = "brcm,bcm2835-txp" }, ++ { .compatible = "brcm,bcm2835-txp", .data = &vc4_txp_data }, + { /* sentinel */ }, + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-0967-drm-vc4-txp-Rename-TXP-data-structure.patch b/target/linux/bcm27xx/patches-6.1/950-0967-drm-vc4-txp-Rename-TXP-data-structure.patch new file mode 100644 index 0000000000..9303f86734 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0967-drm-vc4-txp-Rename-TXP-data-structure.patch @@ -0,0 +1,66 @@ +From 7d345345b70f00bf4c673a68da7d1cf0faf5cc47 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 25 Apr 2023 10:21:53 +0200 +Subject: [PATCH] drm/vc4: txp: Rename TXP data structure + +The TXP data structure has a name too generic for the multiple variants +we'll have to support. Let's rename it to mention the SoC it applies to. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.c | 4 ++-- + drivers/gpu/drm/vc4/vc4_drv.h | 2 +- + drivers/gpu/drm/vc4/vc4_txp.c | 4 ++-- + 3 files changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c +@@ -51,7 +51,7 @@ struct vc4_mock_desc { + + static const struct vc4_mock_desc vc4_mock = + VC4_MOCK_DESC( +- VC4_MOCK_CRTC_DESC(&vc4_txp_data.base, ++ VC4_MOCK_CRTC_DESC(&bcm2835_txp_data.base, + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, + DRM_MODE_ENCODER_VIRTUAL, + DRM_MODE_CONNECTOR_WRITEBACK)), +@@ -77,7 +77,7 @@ static const struct vc4_mock_desc vc4_mo + + static const struct vc4_mock_desc vc5_mock = + VC4_MOCK_DESC( +- VC4_MOCK_CRTC_DESC(&vc4_txp_data.base, ++ VC4_MOCK_CRTC_DESC(&bcm2835_txp_data.base, + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, + DRM_MODE_ENCODER_VIRTUAL, + DRM_MODE_CONNECTOR_WRITEBACK)), +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -565,7 +565,7 @@ struct vc4_txp_data { + struct vc4_crtc_data base; + }; + +-extern const struct vc4_txp_data vc4_txp_data; ++extern const struct vc4_txp_data bcm2835_txp_data; + + struct vc4_pv_data { + struct vc4_crtc_data base; +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -489,7 +489,7 @@ static irqreturn_t vc4_txp_interrupt(int + return IRQ_HANDLED; + } + +-const struct vc4_txp_data vc4_txp_data = { ++const struct vc4_txp_data bcm2835_txp_data = { + .base = { + .name = "txp", + .debugfs_name = "txp_regs", +@@ -593,7 +593,7 @@ static int vc4_txp_remove(struct platfor + } + + static const struct of_device_id vc4_txp_dt_match[] = { +- { .compatible = "brcm,bcm2835-txp", .data = &vc4_txp_data }, ++ { .compatible = "brcm,bcm2835-txp", .data = &bcm2835_txp_data }, + { /* sentinel */ }, + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-0968-drm-vc4-txp-Add-byte-enable-toggle-bit.patch b/target/linux/bcm27xx/patches-6.1/950-0968-drm-vc4-txp-Add-byte-enable-toggle-bit.patch new file mode 100644 index 0000000000..cea9062b19 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0968-drm-vc4-txp-Add-byte-enable-toggle-bit.patch @@ -0,0 +1,56 @@ +From e8dbad6d506b6fac992fdf74a7e3a66a38e554c3 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 27 Apr 2023 09:30:33 +0200 +Subject: [PATCH] drm/vc4: txp: Add byte enable toggle bit + +The MOPLET doesn't have the BYTE_ENABLE field to set, but the TXP and +MOP do, so let's add a boolean to control whether or not we need to set +it. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_txp.c | 6 +++++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -563,6 +563,7 @@ struct vc4_crtc_data { + + struct vc4_txp_data { + struct vc4_crtc_data base; ++ unsigned int has_byte_enable:1; + }; + + extern const struct vc4_txp_data bcm2835_txp_data; +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -291,6 +291,7 @@ static void vc4_txp_connector_atomic_com + struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state, + conn); + struct vc4_txp *txp = connector_to_vc4_txp(conn); ++ const struct vc4_txp_data *txp_data = txp->data; + struct drm_gem_dma_object *gem; + struct drm_display_mode *mode; + struct drm_framebuffer *fb; +@@ -313,9 +314,11 @@ static void vc4_txp_connector_atomic_com + return; + + ctrl = TXP_GO | TXP_EI | +- VC4_SET_FIELD(0xf, TXP_BYTE_ENABLE) | + VC4_SET_FIELD(txp_fmts[i], TXP_FORMAT); + ++ if (txp_data->has_byte_enable) ++ ctrl |= VC4_SET_FIELD(0xf, TXP_BYTE_ENABLE); ++ + if (fb->format->has_alpha) + ctrl |= TXP_ALPHA_ENABLE; + else +@@ -496,6 +499,7 @@ const struct vc4_txp_data bcm2835_txp_da + .hvs_available_channels = BIT(2), + .hvs_output = 2, + }, ++ .has_byte_enable = true, + }; + + static int vc4_txp_bind(struct device *dev, struct device *master, void *data) diff --git a/target/linux/bcm27xx/patches-6.1/950-0969-drm-vc4-txp-Add-horizontal-and-vertical-size-offset-.patch b/target/linux/bcm27xx/patches-6.1/950-0969-drm-vc4-txp-Add-horizontal-and-vertical-size-offset-.patch new file mode 100644 index 0000000000..290473e834 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0969-drm-vc4-txp-Add-horizontal-and-vertical-size-offset-.patch @@ -0,0 +1,59 @@ +From a51e4acdab01540e1006e43f38e5befb40002de0 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 27 Apr 2023 09:47:54 +0200 +Subject: [PATCH] drm/vc4: txp: Add horizontal and vertical size offset toggle + bit + +The new writeback controllers that can be found on the BCM2712 require +to have their horizontal and vertical size reduced by one. + +Let's tie that behaviour to the compatible so we can support both the +new and old controllers. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_txp.c | 14 ++++++++++++-- + 2 files changed, 13 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -564,6 +564,7 @@ struct vc4_crtc_data { + struct vc4_txp_data { + struct vc4_crtc_data base; + unsigned int has_byte_enable:1; ++ unsigned int size_minus_one:1; + }; + + extern const struct vc4_txp_data bcm2835_txp_data; +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -295,6 +295,8 @@ static void vc4_txp_connector_atomic_com + struct drm_gem_dma_object *gem; + struct drm_display_mode *mode; + struct drm_framebuffer *fb; ++ unsigned int hdisplay; ++ unsigned int vdisplay; + u32 ctrl; + int idx; + int i; +@@ -334,9 +336,17 @@ static void vc4_txp_connector_atomic_com + gem = drm_fb_dma_get_gem_obj(fb, 0); + TXP_WRITE(TXP_DST_PTR, gem->dma_addr + fb->offsets[0]); + TXP_WRITE(TXP_DST_PITCH, fb->pitches[0]); ++ ++ hdisplay = mode->hdisplay ?: 1; ++ vdisplay = mode->vdisplay ?: 1; ++ if (txp_data->size_minus_one) { ++ hdisplay -= 1; ++ vdisplay -= 1; ++ } ++ + TXP_WRITE(TXP_DIM, +- VC4_SET_FIELD(mode->hdisplay, TXP_WIDTH) | +- VC4_SET_FIELD(mode->vdisplay, TXP_HEIGHT)); ++ VC4_SET_FIELD(hdisplay, TXP_WIDTH) | ++ VC4_SET_FIELD(vdisplay, TXP_HEIGHT)); + + TXP_WRITE(TXP_DST_CTRL, ctrl); + diff --git a/target/linux/bcm27xx/patches-6.1/950-0970-drm-vc4-txp-Handle-40-bits-DMA-Addresses.patch b/target/linux/bcm27xx/patches-6.1/950-0970-drm-vc4-txp-Handle-40-bits-DMA-Addresses.patch new file mode 100644 index 0000000000..5d1fbcb119 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0970-drm-vc4-txp-Handle-40-bits-DMA-Addresses.patch @@ -0,0 +1,59 @@ +From ddb9aa80692ed5d35e4ee4688c36789620f78c5c Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 14 Apr 2023 17:47:11 +0200 +Subject: [PATCH] drm/vc4: txp: Handle 40-bits DMA Addresses + +The BCM2712 MOP and MOPLET can handle addresses larger than 32bits +through an extra register. We can easily support it and make it +conditional based on the compatible through a boolean in our variant +structure. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_txp.c | 10 +++++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -565,6 +565,7 @@ struct vc4_txp_data { + struct vc4_crtc_data base; + unsigned int has_byte_enable:1; + unsigned int size_minus_one:1; ++ unsigned int supports_40bit_addresses:1; + }; + + extern const struct vc4_txp_data bcm2835_txp_data; +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -145,6 +145,8 @@ + /* Number of lines received and committed to memory. */ + #define TXP_PROGRESS 0x10 + ++#define TXP_DST_PTR_HIGH 0x1c ++ + #define TXP_READ(offset) \ + ({ \ + kunit_fail_current_test("Accessing a register in a unit test!\n"); \ +@@ -297,6 +299,7 @@ static void vc4_txp_connector_atomic_com + struct drm_framebuffer *fb; + unsigned int hdisplay; + unsigned int vdisplay; ++ dma_addr_t addr; + u32 ctrl; + int idx; + int i; +@@ -334,7 +337,12 @@ static void vc4_txp_connector_atomic_com + return; + + gem = drm_fb_dma_get_gem_obj(fb, 0); +- TXP_WRITE(TXP_DST_PTR, gem->dma_addr + fb->offsets[0]); ++ addr = gem->dma_addr + fb->offsets[0]; ++ TXP_WRITE(TXP_DST_PTR, lower_32_bits(addr)); ++ ++ if (txp_data->supports_40bit_addresses) ++ TXP_WRITE(TXP_DST_PTR_HIGH, upper_32_bits(addr) & 0xff); ++ + TXP_WRITE(TXP_DST_PITCH, fb->pitches[0]); + + hdisplay = mode->hdisplay ?: 1; diff --git a/target/linux/bcm27xx/patches-6.1/950-0971-drm-vc4-txp-Move-the-encoder-type-in-the-variant-str.patch b/target/linux/bcm27xx/patches-6.1/950-0971-drm-vc4-txp-Move-the-encoder-type-in-the-variant-str.patch new file mode 100644 index 0000000000..0445c4f509 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0971-drm-vc4-txp-Move-the-encoder-type-in-the-variant-str.patch @@ -0,0 +1,44 @@ +From 2e8f4fa23af4bb794e9b2284a53aa40bbfdd3cbb Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 27 Apr 2023 11:26:10 +0200 +Subject: [PATCH] drm/vc4: txp: Move the encoder type in the variant structure + +We'll have multiple TXP instances in the BCM2712, so we can't use a +single encoder type anymore. Let's tie the encoder type to the +compatible. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_txp.c | 3 ++- + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -563,6 +563,7 @@ struct vc4_crtc_data { + + struct vc4_txp_data { + struct vc4_crtc_data base; ++ enum vc4_encoder_type encoder_type; + unsigned int has_byte_enable:1; + unsigned int size_minus_one:1; + unsigned int supports_40bit_addresses:1; +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -517,6 +517,7 @@ const struct vc4_txp_data bcm2835_txp_da + .hvs_available_channels = BIT(2), + .hvs_output = 2, + }, ++ .encoder_type = VC4_ENCODER_TYPE_TXP, + .has_byte_enable = true, + }; + +@@ -560,7 +561,7 @@ static int vc4_txp_bind(struct device *d + return ret; + + vc4_encoder = &txp->encoder; +- txp->encoder.type = VC4_ENCODER_TYPE_TXP; ++ txp->encoder.type = txp_data->encoder_type; + + encoder = &vc4_encoder->base; + encoder->possible_crtcs = drm_crtc_mask(&vc4_crtc->base); diff --git a/target/linux/bcm27xx/patches-6.1/950-0972-drm-vc4-txp-Add-a-new-TXP-encoder-type.patch b/target/linux/bcm27xx/patches-6.1/950-0972-drm-vc4-txp-Add-a-new-TXP-encoder-type.patch new file mode 100644 index 0000000000..f832fc1ed5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0972-drm-vc4-txp-Add-a-new-TXP-encoder-type.patch @@ -0,0 +1,475 @@ +From 68a00ca7b1d7809ac7be736c02238c142e629127 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 27 Apr 2023 11:49:28 +0200 +Subject: [PATCH] drm/vc4: txp: Add a new TXP encoder type + +Starting with BCM2712, we'll have a two TXP. Let's follow the HDMI +example and add two encoder types for TXP: TXP0 and TXP1. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.c | 4 +- + .../gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 106 +++++++++--------- + drivers/gpu/drm/vc4/vc4_drv.h | 3 +- + drivers/gpu/drm/vc4/vc4_kms.c | 2 +- + drivers/gpu/drm/vc4/vc4_txp.c | 2 +- + 5 files changed, 59 insertions(+), 58 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c +@@ -52,7 +52,7 @@ struct vc4_mock_desc { + static const struct vc4_mock_desc vc4_mock = + VC4_MOCK_DESC( + VC4_MOCK_CRTC_DESC(&bcm2835_txp_data.base, +- VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP0, + DRM_MODE_ENCODER_VIRTUAL, + DRM_MODE_CONNECTOR_WRITEBACK)), + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv0_data, +@@ -78,7 +78,7 @@ static const struct vc4_mock_desc vc4_mo + static const struct vc4_mock_desc vc5_mock = + VC4_MOCK_DESC( + VC4_MOCK_CRTC_DESC(&bcm2835_txp_data.base, +- VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP0, + DRM_MODE_ENCODER_VIRTUAL, + DRM_MODE_CONNECTOR_WRITEBACK)), + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv0_data, +--- a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c +@@ -91,7 +91,7 @@ static const struct encoder_constraint v + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 1), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1), +- ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 2), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP0, 2), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 2), + }; + +@@ -99,7 +99,7 @@ static const struct encoder_constraint v + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1), +- ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 0, 2), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP0, 0, 2), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 0, 1, 2), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 0, 1, 2), + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 0, 1, 2), +@@ -208,7 +208,7 @@ static const struct pv_muxing_param vc4_ + VC4_PV_MUXING_TEST("1 output: DSI1", + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("1 output: TXP", +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("2 outputs: DSI0, HDMI0", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_HDMI0), +@@ -220,7 +220,7 @@ static const struct pv_muxing_param vc4_ + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("2 outputs: DSI0, TXP", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("2 outputs: DPI, HDMI0", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_HDMI0), +@@ -232,19 +232,19 @@ static const struct pv_muxing_param vc4_ + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("2 outputs: DPI, TXP", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("2 outputs: HDMI0, DSI1", + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("2 outputs: HDMI0, TXP", + VC4_ENCODER_TYPE_HDMI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("2 outputs: VEC, DSI1", + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("2 outputs: VEC, TXP", + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, DSI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_HDMI0, +@@ -252,7 +252,7 @@ static const struct pv_muxing_param vc4_ + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, TXP", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_HDMI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +@@ -260,7 +260,7 @@ static const struct pv_muxing_param vc4_ + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, DSI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_HDMI0, +@@ -268,7 +268,7 @@ static const struct pv_muxing_param vc4_ + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_HDMI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +@@ -276,7 +276,7 @@ static const struct pv_muxing_param vc4_ + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + }; + + KUNIT_ARRAY_PARAM(vc4_test_pv_muxing, +@@ -288,7 +288,7 @@ static const struct pv_muxing_param vc4_ + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_DSI0), + VC4_PV_MUXING_TEST("TXP/DSI1 Conflict", +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC4_PV_MUXING_TEST("HDMI0/VEC Conflict", + VC4_ENCODER_TYPE_HDMI0, +@@ -297,22 +297,22 @@ static const struct pv_muxing_param vc4_ + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, TXP", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, HDMI0, DSI1, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + }; + + KUNIT_ARRAY_PARAM(vc4_test_pv_muxing_invalid, +@@ -343,7 +343,7 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("2 outputs: DPI, TXP", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: DPI, VEC", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC), +@@ -361,7 +361,7 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("2 outputs: DSI0, TXP", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: DSI0, VEC", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC), +@@ -373,7 +373,7 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_VEC), + VC5_PV_MUXING_TEST("2 outputs: DSI1, TXP", + VC4_ENCODER_TYPE_DSI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), +@@ -385,7 +385,7 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_VEC), + VC5_PV_MUXING_TEST("2 outputs: HDMI0, TXP", + VC4_ENCODER_TYPE_HDMI0, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: HDMI0, HDMI1", + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), +@@ -394,14 +394,14 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_VEC), + VC5_PV_MUXING_TEST("2 outputs: HDMI1, TXP", + VC4_ENCODER_TYPE_HDMI1, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("2 outputs: TXP, VEC", +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_VEC), + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +@@ -416,15 +416,15 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, DSI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI0", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI0", + VC4_ENCODER_TYPE_DPI, +@@ -441,7 +441,7 @@ static const struct pv_muxing_param vc5_ + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP), ++ VC4_ENCODER_TYPE_TXP0), + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +@@ -456,15 +456,15 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, DSI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI0", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI0, +@@ -491,17 +491,17 @@ static const struct pv_muxing_param vc5_ + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0", + VC4_ENCODER_TYPE_DPI, +@@ -520,17 +520,17 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, DSI1, HDMI0, HDMI1", +@@ -541,19 +541,19 @@ static const struct pv_muxing_param vc5_ + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0, HDMI1", +@@ -564,24 +564,24 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI0, +@@ -600,17 +600,17 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, DSI1, HDMI0, HDMI1", +@@ -621,19 +621,19 @@ static const struct pv_muxing_param vc5_ + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0, HDMI1", +@@ -644,27 +644,27 @@ static const struct pv_muxing_param vc5_ + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DSI0, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: VEC, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DPI, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0, HDMI1", + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_VEC, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_HDMI1), +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -511,7 +511,8 @@ enum vc4_encoder_type { + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_SMI, + VC4_ENCODER_TYPE_DPI, +- VC4_ENCODER_TYPE_TXP, ++ VC4_ENCODER_TYPE_TXP0, ++ VC4_ENCODER_TYPE_TXP1, + }; + + struct vc4_encoder { +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -359,7 +359,7 @@ static void vc6_hvs_pv_muxing_commit(str + mux = 0; + break; + +- case VC4_ENCODER_TYPE_TXP: ++ case VC4_ENCODER_TYPE_TXP0: + mux = 2; + break; + +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -517,7 +517,7 @@ const struct vc4_txp_data bcm2835_txp_da + .hvs_available_channels = BIT(2), + .hvs_output = 2, + }, +- .encoder_type = VC4_ENCODER_TYPE_TXP, ++ .encoder_type = VC4_ENCODER_TYPE_TXP0, + .has_byte_enable = true, + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-0973-drm-vc4-txp-Add-support-for-BCM2712-MOP.patch b/target/linux/bcm27xx/patches-6.1/950-0973-drm-vc4-txp-Add-support-for-BCM2712-MOP.patch new file mode 100644 index 0000000000..aec0753408 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0973-drm-vc4-txp-Add-support-for-BCM2712-MOP.patch @@ -0,0 +1,64 @@ +From 831c6e8c68a66678e8329a382823dc83c483dcc8 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 27 Apr 2023 09:30:49 +0200 +Subject: [PATCH] drm/vc4: txp: Add support for BCM2712 MOP + +The BCM2712 has an evolution of what used to be called TXP in the +earlier SoCs, but is now called MOP. + +There's a few differences still, so we can add a new compatible to deal +with them easily. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_txp.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -388,6 +388,7 @@ static const struct drm_connector_funcs + static void vc4_txp_encoder_disable(struct drm_encoder *encoder) + { + struct drm_device *drm = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_txp *txp = encoder_to_vc4_txp(encoder); + int idx; + +@@ -406,7 +407,8 @@ static void vc4_txp_encoder_disable(stru + WARN_ON(TXP_READ(TXP_DST_CTRL) & TXP_BUSY); + } + +- TXP_WRITE(TXP_DST_CTRL, TXP_POWERDOWN); ++ if (vc4->gen < VC4_GEN_6) ++ TXP_WRITE(TXP_DST_CTRL, TXP_POWERDOWN); + + drm_dev_exit(idx); + } +@@ -510,6 +512,19 @@ static irqreturn_t vc4_txp_interrupt(int + return IRQ_HANDLED; + } + ++const struct vc4_txp_data bcm2712_mop_data = { ++ .base = { ++ .name = "mop", ++ .debugfs_name = "mop_regs", ++ .hvs_available_channels = BIT(2), ++ .hvs_output = 2, ++ }, ++ .encoder_type = VC4_ENCODER_TYPE_TXP0, ++ .has_byte_enable = true, ++ .size_minus_one = true, ++ .supports_40bit_addresses = true, ++}; ++ + const struct vc4_txp_data bcm2835_txp_data = { + .base = { + .name = "txp", +@@ -616,6 +631,7 @@ static int vc4_txp_remove(struct platfor + } + + static const struct of_device_id vc4_txp_dt_match[] = { ++ { .compatible = "brcm,bcm2712-mop", .data = &bcm2712_mop_data }, + { .compatible = "brcm,bcm2835-txp", .data = &bcm2835_txp_data }, + { /* sentinel */ }, + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-0974-drm-vc4-txp-Add-BCM2712-MOPLET-support.patch b/target/linux/bcm27xx/patches-6.1/950-0974-drm-vc4-txp-Add-BCM2712-MOPLET-support.patch new file mode 100644 index 0000000000..b2a28bd144 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0974-drm-vc4-txp-Add-BCM2712-MOPLET-support.patch @@ -0,0 +1,42 @@ +From b239fc6a68fea2b073c4cb48884fbb697014ac2b Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 20 Feb 2023 17:16:01 +0100 +Subject: [PATCH] drm/vc4: txp: Add BCM2712 MOPLET support + +The BCM2712 features a simpler TXP called MOPLET. Let's add support for +it. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_txp.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -525,6 +525,18 @@ const struct vc4_txp_data bcm2712_mop_da + .supports_40bit_addresses = true, + }; + ++const struct vc4_txp_data bcm2712_moplet_data = { ++ .base = { ++ .name = "moplet", ++ .debugfs_name = "moplet_regs", ++ .hvs_available_channels = BIT(1), ++ .hvs_output = 4, ++ }, ++ .encoder_type = VC4_ENCODER_TYPE_TXP1, ++ .size_minus_one = true, ++ .supports_40bit_addresses = true, ++}; ++ + const struct vc4_txp_data bcm2835_txp_data = { + .base = { + .name = "txp", +@@ -632,6 +644,7 @@ static int vc4_txp_remove(struct platfor + + static const struct of_device_id vc4_txp_dt_match[] = { + { .compatible = "brcm,bcm2712-mop", .data = &bcm2712_mop_data }, ++ { .compatible = "brcm,bcm2712-moplet", .data = &bcm2712_moplet_data }, + { .compatible = "brcm,bcm2835-txp", .data = &bcm2835_txp_data }, + { /* sentinel */ }, + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-0975-drm-vc4-Add-additional-warn_on.patch b/target/linux/bcm27xx/patches-6.1/950-0975-drm-vc4-Add-additional-warn_on.patch new file mode 100644 index 0000000000..0fc95e5f6b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0975-drm-vc4-Add-additional-warn_on.patch @@ -0,0 +1,240 @@ +From bb05ccd66342643b1cd9a0a48cec3ebdc3eed511 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 21 Feb 2023 14:38:32 +0100 +Subject: [PATCH] drm/vc4: Add additional warn_on + +Some code path in vc4 are conditional to a generation and cannot be +executed on others. Let's put a WARN_ON if that ever happens. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 32 ++++++++++++++++++++++++++++++-- + drivers/gpu/drm/vc4/vc4_kms.c | 6 ++++++ + drivers/gpu/drm/vc4/vc4_plane.c | 19 +++++++++++++++++++ + 3 files changed, 55 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -417,12 +417,15 @@ static int vc4_hvs_upload_linear_kernel( + static void vc4_hvs_lut_load(struct vc4_hvs *hvs, + struct vc4_crtc *vc4_crtc) + { +- struct drm_device *drm = &hvs->vc4->base; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; + struct drm_crtc *crtc = &vc4_crtc->base; + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + int idx; + u32 i; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); ++ + if (!drm_dev_enter(drm, &idx)) + return; + +@@ -758,6 +761,8 @@ u8 vc4_hvs_get_fifo_frame_count(struct v + u8 field = 0; + int idx; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); ++ + if (!drm_dev_enter(drm, &idx)) + return 0; + +@@ -791,6 +796,8 @@ int vc4_hvs_get_fifo_from_output(struct + u32 reg; + int ret; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); ++ + switch (vc4->gen) { + case VC4_GEN_4: + return output; +@@ -880,6 +887,8 @@ static int vc4_hvs_init_channel(struct v + u32 dispctrl; + int idx; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); ++ + if (!drm_dev_enter(drm, &idx)) + return -ENODEV; + +@@ -947,6 +956,8 @@ static int vc6_hvs_init_channel(struct v + u32 disp_ctrl1; + int idx; + ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_6); ++ + if (!drm_dev_enter(drm, &idx)) + return -ENODEV; + +@@ -972,9 +983,12 @@ static int vc6_hvs_init_channel(struct v + + static void __vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) + { +- struct drm_device *drm = &hvs->vc4->base; ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; + int idx; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); ++ + if (!drm_dev_enter(drm, &idx)) + return; + +@@ -1007,6 +1021,8 @@ static void __vc6_hvs_stop_channel(struc + struct drm_device *drm = &vc4->base; + int idx; + ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_6); ++ + if (!drm_dev_enter(drm, &idx)) + return; + +@@ -1234,6 +1250,8 @@ void vc4_hvs_atomic_flush(struct drm_crt + bool found = false; + int idx; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); ++ + if (!drm_dev_enter(dev, &idx)) { + vc4_crtc_send_vblank(crtc); + return; +@@ -1324,6 +1342,8 @@ void vc4_hvs_atomic_flush(struct drm_crt + if (crtc->state->color_mgmt_changed) { + u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(channel)); + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); ++ + if (crtc->state->gamma_lut) { + if (vc4->gen == VC4_GEN_4) { + vc4_hvs_update_gamma_lut(hvs, vc4_crtc); +@@ -1363,6 +1383,8 @@ void vc4_hvs_mask_underrun(struct vc4_hv + u32 dispctrl; + int idx; + ++ WARN_ON(vc4->gen > VC4_GEN_5); ++ + if (!drm_dev_enter(drm, &idx)) + return; + +@@ -1383,6 +1405,8 @@ void vc4_hvs_unmask_underrun(struct vc4_ + u32 dispctrl; + int idx; + ++ WARN_ON(vc4->gen > VC4_GEN_5); ++ + if (!drm_dev_enter(drm, &idx)) + return; + +@@ -1417,6 +1441,8 @@ static irqreturn_t vc4_hvs_irq_handler(i + u32 status; + u32 dspeislur; + ++ WARN_ON(vc4->gen > VC4_GEN_5); ++ + /* + * NOTE: We don't need to protect the register access using + * drm_dev_enter() there because the interrupt handler lifetime +@@ -1466,6 +1492,8 @@ static irqreturn_t vc6_hvs_eof_irq_handl + struct vc4_hvs *hvs = vc4->hvs; + unsigned int i; + ++ WARN_ON(vc4->gen < VC4_GEN_6); ++ + for (i = 0; i < HVS_NUM_CHANNELS; i++) { + if (!hvs->eof_irq[i].enabled) + continue; +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -147,6 +147,8 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru + if (vc4->firmware_kms) + return; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_5); ++ + if (ctm_state->fifo) { + HVS_WRITE(SCALER_OLEDCOEF2, + VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]), +@@ -222,6 +224,8 @@ static void vc4_hvs_pv_muxing_commit(str + struct drm_crtc *crtc; + unsigned int i; + ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_4); ++ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); +@@ -265,6 +269,8 @@ static void vc5_hvs_pv_muxing_commit(str + unsigned int i; + u32 reg; + ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_5); ++ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -555,8 +555,11 @@ static int vc4_plane_setup_clipping_and_ + + static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) + { ++ struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev); + u32 scale, recip; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); ++ + scale = src / dst; + + /* The specs note that while the reciprocal would be defined +@@ -581,10 +584,13 @@ static void vc4_write_tpz(struct vc4_pla + + static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, u32 xy, int channel, int chroma_offset) + { ++ struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev); + u32 scale = src / dst; + s32 offset, offset2; + s32 phase; + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); ++ + /* Start the phase at 1/2 pixel from the 1st pixel at src_x. + 1/4 pixel for YUV, plus the offset for chroma siting */ + if (channel) { +@@ -801,8 +807,11 @@ static size_t vc6_upm_size(const struct + static void vc4_write_scaling_parameters(struct drm_plane_state *state, + int channel) + { ++ struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); ++ + /* Ch0 H-PPF Word 0: Scaling Parameters */ + if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) { + vc4_write_ppf(vc4_state, +@@ -1040,6 +1049,11 @@ static const u32 colorspace_coeffs[2][DR + + static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state) + { ++ struct drm_device *dev = state->state->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_4); ++ + if (!state->fb->format->has_alpha) + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED, + SCALER_POS2_ALPHA_MODE); +@@ -1061,6 +1075,11 @@ static u32 vc4_hvs4_get_alpha_blend_mode + + static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state) + { ++ struct drm_device *dev = state->state->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ ++ WARN_ON_ONCE(vc4->gen != VC4_GEN_5 && vc4->gen != VC4_GEN_6); ++ + if (!state->fb->format->has_alpha) + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, + SCALER5_CTL2_ALPHA_MODE); diff --git a/target/linux/bcm27xx/patches-6.1/950-0976-drm-vc4-tests-Switch-generation-mockup-to-a-switch.patch b/target/linux/bcm27xx/patches-6.1/950-0976-drm-vc4-tests-Switch-generation-mockup-to-a-switch.patch new file mode 100644 index 0000000000..0751d46536 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0976-drm-vc4-tests-Switch-generation-mockup-to-a-switch.patch @@ -0,0 +1,47 @@ +From 336917ca87807b8a4bb08855b4dcb0477289c765 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:35:16 +0100 +Subject: [PATCH] drm/vc4: tests: Switch generation mockup to a switch + +Testing whether the VideoCore generation we want to mock is vc5 or vc4 +worked so far, but will be difficult to extend to support BCM2712 (VC6). + +Convert to a switch. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c +@@ -155,13 +155,27 @@ static int __build_mock(struct kunit *te + + static struct vc4_dev *__mock_device(struct kunit *test, enum vc4_gen gen) + { ++ const struct vc4_mock_desc *desc; ++ const struct drm_driver *drv; + struct drm_device *drm; +- const struct drm_driver *drv = (gen == VC4_GEN_5) ? &vc5_drm_driver : &vc4_drm_driver; +- const struct vc4_mock_desc *desc = (gen == VC4_GEN_5) ? &vc5_mock : &vc4_mock; + struct vc4_dev *vc4; + struct device *dev; + int ret; + ++ switch (gen) { ++ case VC4_GEN_4: ++ drv = &vc4_drm_driver; ++ desc = &vc4_mock; ++ break; ++ case VC4_GEN_5: ++ drv = &vc5_drm_driver; ++ desc = &vc5_mock; ++ break; ++ ++ default: ++ return NULL; ++ } ++ + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + diff --git a/target/linux/bcm27xx/patches-6.1/950-0977-drm-vc4-tests-Drop-drm-parameter-for-vc4_find_crtc_f.patch b/target/linux/bcm27xx/patches-6.1/950-0977-drm-vc4-tests-Drop-drm-parameter-for-vc4_find_crtc_f.patch new file mode 100644 index 0000000000..42c4be9b8b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0977-drm-vc4-tests-Drop-drm-parameter-for-vc4_find_crtc_f.patch @@ -0,0 +1,63 @@ +From 70e906d3c688491e181446afa27bea32ce241d6a Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 24 Mar 2023 09:58:15 +0100 +Subject: [PATCH] drm/vc4: tests: Drop drm parameter for + vc4_find_crtc_for_encoder + +The DRM device pointer and the DRM encoder pointer are redundant, since +the latter is attached to the former and we can just follow the +drm_encoder->dev pointer. + +Let's remove the drm_device pointer argument. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.h | 2 +- + drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 4 ++-- + drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h +@@ -7,9 +7,9 @@ + + static inline + struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit *test, +- struct drm_device *drm, + struct drm_encoder *encoder) + { ++ struct drm_device *drm = encoder->dev; + struct drm_crtc *crtc; + + KUNIT_ASSERT_EQ(test, hweight32(encoder->possible_crtcs), 1); +--- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c +@@ -77,7 +77,7 @@ int vc4_mock_atomic_add_output(struct ku + encoder = vc4_find_encoder_by_type(drm, type); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder); + +- crtc = vc4_find_crtc_for_encoder(test, drm, encoder); ++ crtc = vc4_find_crtc_for_encoder(test, encoder); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + + output = container_of(encoder, struct vc4_dummy_output, encoder.base); +@@ -115,7 +115,7 @@ int vc4_mock_atomic_del_output(struct ku + encoder = vc4_find_encoder_by_type(drm, type); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder); + +- crtc = vc4_find_crtc_for_encoder(test, drm, encoder); ++ crtc = vc4_find_crtc_for_encoder(test, encoder); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + + crtc_state = drm_atomic_get_crtc_state(state, crtc); +--- a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c +@@ -132,7 +132,7 @@ get_vc4_crtc_state_for_encoder(struct ku + encoder = vc4_find_encoder_by_type(drm, type); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder); + +- crtc = vc4_find_crtc_for_encoder(test, drm, encoder); ++ crtc = vc4_find_crtc_for_encoder(test, encoder); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); diff --git a/target/linux/bcm27xx/patches-6.1/950-0978-drm-vc4-tests-Return-the-allocated-output.patch b/target/linux/bcm27xx/patches-6.1/950-0978-drm-vc4-tests-Return-the-allocated-output.patch new file mode 100644 index 0000000000..6f49d52f32 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0978-drm-vc4-tests-Return-the-allocated-output.patch @@ -0,0 +1,174 @@ +From 14e97c5765579eaab3c8372701750ffa30e4c7da Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 24 Mar 2023 10:02:59 +0100 +Subject: [PATCH] drm/vc4: tests: Return the allocated output + +Some tests will need to retrieve the output that was just allocated by +vc4_mock_atomic_add_output(). + +Instead of making them look them up in the DRM device, we can simply +make vc4_mock_atomic_add_output() return an error pointer that holds the +allocated output instead of the error code. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.h | 7 ++-- + drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 9 +++-- + .../gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 37 +++++++++++-------- + 3 files changed, 30 insertions(+), 23 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h +@@ -53,9 +53,10 @@ struct vc4_dummy_output *vc4_dummy_outpu + struct vc4_dev *vc4_mock_device(struct kunit *test); + struct vc4_dev *vc5_mock_device(struct kunit *test); + +-int vc4_mock_atomic_add_output(struct kunit *test, +- struct drm_atomic_state *state, +- enum vc4_encoder_type type); ++struct vc4_dummy_output * ++vc4_mock_atomic_add_output(struct kunit *test, ++ struct drm_atomic_state *state, ++ enum vc4_encoder_type type); + int vc4_mock_atomic_del_output(struct kunit *test, + struct drm_atomic_state *state, + enum vc4_encoder_type type); +--- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c +@@ -61,9 +61,10 @@ static const struct drm_display_mode def + DRM_SIMPLE_MODE(640, 480, 64, 48) + }; + +-int vc4_mock_atomic_add_output(struct kunit *test, +- struct drm_atomic_state *state, +- enum vc4_encoder_type type) ++struct vc4_dummy_output * ++vc4_mock_atomic_add_output(struct kunit *test, ++ struct drm_atomic_state *state, ++ enum vc4_encoder_type type) + { + struct drm_device *drm = state->dev; + struct drm_connector_state *conn_state; +@@ -96,7 +97,7 @@ int vc4_mock_atomic_add_output(struct ku + + crtc_state->active = true; + +- return 0; ++ return output; + } + + int vc4_mock_atomic_del_output(struct kunit *test, +--- a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c +@@ -683,10 +683,11 @@ static void drm_vc4_test_pv_muxing(struc + int ret; + + for (i = 0; i < params->nencoders; i++) { ++ struct vc4_dummy_output *output; + enum vc4_encoder_type enc_type = params->encoders[i]; + +- ret = vc4_mock_atomic_add_output(test, state, enc_type); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, enc_type); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + } + + ret = drm_atomic_check_only(state); +@@ -712,10 +713,11 @@ static void drm_vc4_test_pv_muxing_inval + int ret; + + for (i = 0; i < params->nencoders; i++) { ++ struct vc4_dummy_output *output; + enum vc4_encoder_type enc_type = params->encoders[i]; + +- ret = vc4_mock_atomic_add_output(test, state, enc_type); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, enc_type); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + } + + ret = drm_atomic_check_only(state); +@@ -804,6 +806,7 @@ static void drm_test_vc5_pv_muxing_bugs_ + { + struct drm_modeset_acquire_ctx ctx; + struct drm_atomic_state *state; ++ struct vc4_dummy_output *output; + struct vc4_crtc_state *new_vc4_crtc_state; + struct vc4_hvs_state *new_hvs_state; + unsigned int hdmi0_channel; +@@ -823,8 +826,8 @@ static void drm_test_vc5_pv_muxing_bugs_ + + state->acquire_ctx = &ctx; + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); +@@ -850,8 +853,8 @@ static void drm_test_vc5_pv_muxing_bugs_ + + state->acquire_ctx = &ctx; + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); +@@ -880,6 +883,7 @@ static void drm_test_vc5_pv_muxing_bugs_ + { + struct drm_modeset_acquire_ctx ctx; + struct drm_atomic_state *state; ++ struct vc4_dummy_output *output; + struct vc4_crtc_state *new_vc4_crtc_state; + struct vc4_hvs_state *new_hvs_state; + unsigned int old_hdmi0_channel; +@@ -899,11 +903,11 @@ static void drm_test_vc5_pv_muxing_bugs_ + + state->acquire_ctx = &ctx; + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); +@@ -971,6 +975,7 @@ drm_test_vc5_pv_muxing_bugs_subsequent_c + { + struct drm_modeset_acquire_ctx ctx; + struct drm_atomic_state *state; ++ struct vc4_dummy_output *output; + struct vc4_crtc_state *new_vc4_crtc_state; + struct drm_device *drm; + struct vc4_dev *vc4; +@@ -987,8 +992,8 @@ drm_test_vc5_pv_muxing_bugs_subsequent_c + + state->acquire_ctx = &ctx; + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); +@@ -1003,8 +1008,8 @@ drm_test_vc5_pv_muxing_bugs_subsequent_c + + state->acquire_ctx = &ctx; + +- ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); + + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); diff --git a/target/linux/bcm27xx/patches-6.1/950-0979-drm-vc4-tests-Add-BCM2712-mock-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0979-drm-vc4-tests-Add-BCM2712-mock-driver.patch new file mode 100644 index 0000000000..8c12375284 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0979-drm-vc4-tests-Add-BCM2712-mock-driver.patch @@ -0,0 +1,87 @@ +From 04bec005b049604f862765b35ebd71c2a69b9e7c Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 17 Feb 2023 13:38:10 +0100 +Subject: [PATCH] drm/vc4: tests: Add BCM2712 mock driver + +The BCM2712 has a simpler pipeline that can only output to a writeback +connector and two HDMI controllers. + +Let's allow our kunit tests to create a mock of that pipeline. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.c | 29 ++++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/tests/vc4_mock.h | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 2 ++ + 3 files changed, 32 insertions(+) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c +@@ -106,6 +106,26 @@ static const struct vc4_mock_desc vc5_mo + DRM_MODE_CONNECTOR_HDMIA)), + ); + ++static const struct vc4_mock_desc vc6_mock = ++ VC4_MOCK_DESC( ++ VC4_MOCK_CRTC_DESC(&bcm2712_mop_data.base, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP0, ++ DRM_MODE_ENCODER_VIRTUAL, ++ DRM_MODE_CONNECTOR_WRITEBACK)), ++ VC4_MOCK_CRTC_DESC(&bcm2712_moplet_data.base, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP1, ++ DRM_MODE_ENCODER_VIRTUAL, ++ DRM_MODE_CONNECTOR_WRITEBACK)), ++ VC4_MOCK_PIXELVALVE_DESC(&bcm2712_pv0_data, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0, ++ DRM_MODE_ENCODER_TMDS, ++ DRM_MODE_CONNECTOR_HDMIA)), ++ VC4_MOCK_PIXELVALVE_DESC(&bcm2712_pv1_data, ++ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI1, ++ DRM_MODE_ENCODER_TMDS, ++ DRM_MODE_CONNECTOR_HDMIA)), ++); ++ + static int __build_one_pipe(struct kunit *test, struct drm_device *drm, + const struct vc4_mock_pipe_desc *pipe) + { +@@ -171,6 +191,10 @@ static struct vc4_dev *__mock_device(str + drv = &vc5_drm_driver; + desc = &vc5_mock; + break; ++ case VC4_GEN_6: ++ drv = &vc5_drm_driver; ++ desc = &vc6_mock; ++ break; + + default: + return NULL; +@@ -212,3 +236,8 @@ struct vc4_dev *vc5_mock_device(struct k + { + return __mock_device(test, VC4_GEN_5); + } ++ ++struct vc4_dev *vc6_mock_device(struct kunit *test) ++{ ++ return __mock_device(test, VC4_GEN_6); ++} +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h +@@ -52,6 +52,7 @@ struct vc4_dummy_output *vc4_dummy_outpu + + struct vc4_dev *vc4_mock_device(struct kunit *test); + struct vc4_dev *vc5_mock_device(struct kunit *test); ++struct vc4_dev *vc6_mock_device(struct kunit *test); + + struct vc4_dummy_output * + vc4_mock_atomic_add_output(struct kunit *test, +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -570,6 +570,8 @@ struct vc4_txp_data { + unsigned int supports_40bit_addresses:1; + }; + ++extern const struct vc4_txp_data bcm2712_mop_data; ++extern const struct vc4_txp_data bcm2712_moplet_data; + extern const struct vc4_txp_data bcm2835_txp_data; + + struct vc4_pv_data { diff --git a/target/linux/bcm27xx/patches-6.1/950-0980-drm-vc4-tests-Add-tests-for-BCM2712-PixelValve-Muxin.patch b/target/linux/bcm27xx/patches-6.1/950-0980-drm-vc4-tests-Add-tests-for-BCM2712-PixelValve-Muxin.patch new file mode 100644 index 0000000000..6c0db592c9 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0980-drm-vc4-tests-Add-tests-for-BCM2712-PixelValve-Muxin.patch @@ -0,0 +1,138 @@ +From 77c14764ae164b7969e65437a87aca25b30d8b80 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 14 Apr 2023 11:14:22 +0200 +Subject: [PATCH] drm/vc4: tests: Add tests for BCM2712 PixelValve Muxing + +The BCM2712 has a simpler pipeline than the BCM2711, and thus the muxing +requirements are different. Create some tests to make sure we get proper +muxing decisions. + +Signed-off-by: Maxime Ripard +--- + .../gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 81 +++++++++++++++++++ + 1 file changed, 81 insertions(+) + +--- a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c +@@ -105,6 +105,13 @@ static const struct encoder_constraint v + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 0, 1, 2), + }; + ++static const struct encoder_constraint vc6_encoder_constraints[] = { ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 0), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 1), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP1, 1), ++ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP0, 2), ++}; ++ + static bool check_vc4_encoder_constraints(enum vc4_encoder_type type, unsigned int channel) + { + return __check_encoder_constraints(vc4_encoder_constraints, +@@ -119,6 +126,13 @@ static bool check_vc5_encoder_constraint + type, channel); + } + ++static bool check_vc6_encoder_constraints(enum vc4_encoder_type type, unsigned int channel) ++{ ++ return __check_encoder_constraints(vc6_encoder_constraints, ++ ARRAY_SIZE(vc6_encoder_constraints), ++ type, channel); ++} ++ + static struct vc4_crtc_state * + get_vc4_crtc_state_for_encoder(struct kunit *test, + const struct drm_atomic_state *state, +@@ -196,6 +210,9 @@ static void vc4_test_pv_muxing_desc(cons + #define VC5_PV_MUXING_TEST(_name, ...) \ + PV_MUXING_TEST(_name, vc5_mock_device, check_vc5_encoder_constraints, __VA_ARGS__) + ++#define VC6_PV_MUXING_TEST(_name, ...) \ ++ PV_MUXING_TEST(_name, vc6_mock_device, check_vc6_encoder_constraints, __VA_ARGS__) ++ + static const struct pv_muxing_param vc4_test_pv_muxing_params[] = { + VC4_PV_MUXING_TEST("1 output: DSI0", + VC4_ENCODER_TYPE_DSI0), +@@ -674,6 +691,54 @@ KUNIT_ARRAY_PARAM(vc5_test_pv_muxing_inv + vc5_test_pv_muxing_invalid_params, + vc4_test_pv_muxing_desc); + ++static const struct pv_muxing_param vc6_test_pv_muxing_params[] = { ++ VC6_PV_MUXING_TEST("1 output: HDMI0", ++ VC4_ENCODER_TYPE_HDMI0), ++ VC6_PV_MUXING_TEST("1 output: HDMI1", ++ VC4_ENCODER_TYPE_HDMI1), ++ VC6_PV_MUXING_TEST("1 output: MOPLET", ++ VC4_ENCODER_TYPE_TXP1), ++ VC6_PV_MUXING_TEST("1 output: MOP", ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("2 outputs: HDMI0, HDMI1", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_HDMI1), ++ VC6_PV_MUXING_TEST("2 outputs: HDMI0, MOPLET", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_TXP1), ++ VC6_PV_MUXING_TEST("2 outputs: HDMI0, MOP", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("2 outputs: HDMI1, MOP", ++ VC4_ENCODER_TYPE_HDMI1, ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("2 outputs: MOPLET, MOP", ++ VC4_ENCODER_TYPE_TXP1, ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("3 outputs: HDMI0, HDMI1, MOP", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_HDMI1, ++ VC4_ENCODER_TYPE_TXP0), ++ VC6_PV_MUXING_TEST("3 outputs: HDMI0, MOPLET, MOP", ++ VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_TXP1, ++ VC4_ENCODER_TYPE_TXP0), ++}; ++ ++KUNIT_ARRAY_PARAM(vc6_test_pv_muxing, ++ vc6_test_pv_muxing_params, ++ vc4_test_pv_muxing_desc); ++ ++static const struct pv_muxing_param vc6_test_pv_muxing_invalid_params[] = { ++ VC6_PV_MUXING_TEST("HDMI1/MOPLET Conflict", ++ VC4_ENCODER_TYPE_HDMI1, ++ VC4_ENCODER_TYPE_TXP1), ++}; ++ ++KUNIT_ARRAY_PARAM(vc6_test_pv_muxing_invalid, ++ vc6_test_pv_muxing_invalid_params, ++ vc4_test_pv_muxing_desc); ++ + static void drm_vc4_test_pv_muxing(struct kunit *test) + { + const struct pv_muxing_param *params = test->param_value; +@@ -797,6 +862,21 @@ static struct kunit_suite vc5_pv_muxing_ + .test_cases = vc5_pv_muxing_tests, + }; + ++static struct kunit_case vc6_pv_muxing_tests[] = { ++ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing, ++ vc6_test_pv_muxing_gen_params), ++ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid, ++ vc6_test_pv_muxing_invalid_gen_params), ++ {} ++}; ++ ++static struct kunit_suite vc6_pv_muxing_test_suite = { ++ .name = "vc6-pv-muxing-combinations", ++ .init = vc4_pv_muxing_test_init, ++ .exit = vc4_pv_muxing_test_exit, ++ .test_cases = vc6_pv_muxing_tests, ++}; ++ + /* See + * https://lore.kernel.org/all/3e113525-aa89-b1e2-56b7-ca55bd41d057@samsung.com/ + * and +@@ -1040,5 +1120,6 @@ static struct kunit_suite vc5_pv_muxing_ + kunit_test_suites( + &vc4_pv_muxing_test_suite, + &vc5_pv_muxing_test_suite, ++ &vc6_pv_muxing_test_suite, + &vc5_pv_muxing_bugs_test_suite + ); diff --git a/target/linux/bcm27xx/patches-6.1/950-0981-drm-vc4-fkms-Rename-plane-related-functions.patch b/target/linux/bcm27xx/patches-6.1/950-0981-drm-vc4-fkms-Rename-plane-related-functions.patch new file mode 100644 index 0000000000..455c64ad2e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0981-drm-vc4-fkms-Rename-plane-related-functions.patch @@ -0,0 +1,64 @@ +From 3d849ab48cecab55862a4f2742f11937d66ba54b Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 14 Apr 2023 11:21:34 +0200 +Subject: [PATCH] drm/vc4: fkms: Rename plane related functions + +The name collide with the Full KMS functions that are going to be made +public. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -670,8 +670,8 @@ static int vc4_plane_to_mb(struct drm_pl + return 0; + } + +-static int vc4_plane_atomic_check(struct drm_plane *plane, +- struct drm_atomic_state *state) ++static int vc4_fkms_plane_atomic_check(struct drm_plane *plane, ++ struct drm_atomic_state *state) + { + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, + plane); +@@ -728,7 +728,7 @@ static int vc4_plane_atomic_async_check( + } + + /* Called during init to allocate the plane's atomic state. */ +-static void vc4_plane_reset(struct drm_plane *plane) ++static void vc4_fkms_plane_reset(struct drm_plane *plane) + { + struct vc4_plane_state *vc4_state; + +@@ -788,7 +788,7 @@ static bool vc4_fkms_format_mod_supporte + } + } + +-static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) ++static struct drm_plane_state *vc4_fkms_plane_duplicate_state(struct drm_plane *plane) + { + struct vc4_plane_state *vc4_state; + +@@ -809,8 +809,8 @@ static const struct drm_plane_funcs vc4_ + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = vc4_plane_destroy, + .set_property = NULL, +- .reset = vc4_plane_reset, +- .atomic_duplicate_state = vc4_plane_duplicate_state, ++ .reset = vc4_fkms_plane_reset, ++ .atomic_duplicate_state = vc4_fkms_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .format_mod_supported = vc4_fkms_format_mod_supported, + }; +@@ -818,7 +818,7 @@ static const struct drm_plane_funcs vc4_ + static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .cleanup_fb = NULL, +- .atomic_check = vc4_plane_atomic_check, ++ .atomic_check = vc4_fkms_plane_atomic_check, + .atomic_update = vc4_plane_atomic_update, + .atomic_disable = vc4_plane_atomic_disable, + .atomic_async_check = vc4_plane_atomic_async_check, diff --git a/target/linux/bcm27xx/patches-6.1/950-0982-drm-vc4-tests-Use-custom-plane-state-for-mock.patch b/target/linux/bcm27xx/patches-6.1/950-0982-drm-vc4-tests-Use-custom-plane-state-for-mock.patch new file mode 100644 index 0000000000..0105753a91 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0982-drm-vc4-tests-Use-custom-plane-state-for-mock.patch @@ -0,0 +1,95 @@ +From 14fe42ff341741d60ba338c401855dee7fb68754 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 14 Apr 2023 11:24:37 +0200 +Subject: [PATCH] drm/vc4: tests: Use custom plane state for mock + +The current mock planes were just using the regular drm_plane_state, +while the driver expect struct vc4_plane_state that subclasses +drm_plane_state. + +Hook the proper implementations of reset, duplicate_state, destroy and +atomic_check to create vc4_plane_state. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 7 ++++--- + drivers/gpu/drm/vc4/vc4_drv.h | 6 ++++++ + drivers/gpu/drm/vc4/vc4_plane.c | 12 ++++++------ + 3 files changed, 16 insertions(+), 9 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c +@@ -10,12 +10,13 @@ + #include "vc4_mock.h" + + static const struct drm_plane_helper_funcs vc4_dummy_plane_helper_funcs = { ++ .atomic_check = vc4_plane_atomic_check, + }; + + static const struct drm_plane_funcs vc4_dummy_plane_funcs = { +- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, +- .reset = drm_atomic_helper_plane_reset, ++ .atomic_destroy_state = vc4_plane_destroy_state, ++ .atomic_duplicate_state = vc4_plane_duplicate_state, ++ .reset = vc4_plane_reset, + }; + + static const uint32_t vc4_dummy_plane_formats[] = { +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -1145,6 +1145,12 @@ int vc4_kms_load(struct drm_device *dev) + struct drm_plane *vc4_plane_init(struct drm_device *dev, + enum drm_plane_type type, + uint32_t possible_crtcs); ++void vc4_plane_reset(struct drm_plane *plane); ++void vc4_plane_destroy_state(struct drm_plane *plane, ++ struct drm_plane_state *state); ++struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane); ++int vc4_plane_atomic_check(struct drm_plane *plane, ++ struct drm_atomic_state *state); + int vc4_plane_create_additional_planes(struct drm_device *dev); + u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); + u32 vc4_plane_dlist_size(const struct drm_plane_state *state); +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -276,7 +276,7 @@ static bool plane_enabled(struct drm_pla + return state->fb && !WARN_ON(!state->crtc); + } + +-static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) ++struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) + { + struct vc4_plane_state *vc4_state; + unsigned int i; +@@ -312,8 +312,8 @@ static struct drm_plane_state *vc4_plane + return &vc4_state->base; + } + +-static void vc4_plane_destroy_state(struct drm_plane *plane, +- struct drm_plane_state *state) ++void vc4_plane_destroy_state(struct drm_plane *plane, ++ struct drm_plane_state *state) + { + struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + struct vc4_hvs *hvs = vc4->hvs; +@@ -348,7 +348,7 @@ static void vc4_plane_destroy_state(stru + } + + /* Called during init to allocate the plane's atomic state. */ +-static void vc4_plane_reset(struct drm_plane *plane) ++void vc4_plane_reset(struct drm_plane *plane) + { + struct vc4_plane_state *vc4_state; + +@@ -2000,8 +2000,8 @@ static int vc6_plane_mode_set(struct drm + * compute the dlist here and have all active plane dlists get updated + * in the CRTC's flush. + */ +-static int vc4_plane_atomic_check(struct drm_plane *plane, +- struct drm_atomic_state *state) ++int vc4_plane_atomic_check(struct drm_plane *plane, ++ struct drm_atomic_state *state) + { + struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, diff --git a/target/linux/bcm27xx/patches-6.1/950-0983-drm-vc4-tests-Add-function-to-lookup-a-plane-for-a-C.patch b/target/linux/bcm27xx/patches-6.1/950-0983-drm-vc4-tests-Add-function-to-lookup-a-plane-for-a-C.patch new file mode 100644 index 0000000000..ebab218cf3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0983-drm-vc4-tests-Add-function-to-lookup-a-plane-for-a-C.patch @@ -0,0 +1,36 @@ +From 3320e449e40eeb49b601dcbbd4bd72b8cb8f3054 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 14 Apr 2023 11:26:58 +0200 +Subject: [PATCH] drm/vc4: tests: Add function to lookup a plane for a CRTC + +Some tests will need to find a plane to run a test on for a given CRTC. +Let's create a small helper to do that. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.h | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h +@@ -21,6 +21,20 @@ struct drm_crtc *vc4_find_crtc_for_encod + return NULL; + } + ++static inline ++struct drm_plane *vc4_mock_find_plane_for_crtc(struct kunit *test, ++ struct drm_crtc *crtc) ++{ ++ struct drm_device *drm = crtc->dev; ++ struct drm_plane *plane; ++ ++ drm_for_each_plane(plane, drm) ++ if (plane->possible_crtcs & drm_crtc_mask(crtc)) ++ return plane; ++ ++ return NULL; ++} ++ + struct vc4_dummy_plane { + struct vc4_plane plane; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-0984-drm-vc4-tests-Add-helper-to-add-a-new-plane-to-a-sta.patch b/target/linux/bcm27xx/patches-6.1/950-0984-drm-vc4-tests-Add-helper-to-add-a-new-plane-to-a-sta.patch new file mode 100644 index 0000000000..7d230294fc --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0984-drm-vc4-tests-Add-helper-to-add-a-new-plane-to-a-sta.patch @@ -0,0 +1,62 @@ +From a2f912c44b98acb6c10c977db105e199011c09b5 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 14 Apr 2023 12:57:53 +0200 +Subject: [PATCH] drm/vc4: tests: Add helper to add a new plane to a state + +We'll start to add some tests for the plane state logic, so let's create +a helper to add a plane to an existing atomic state. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock.h | 4 ++++ + drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 22 ++++++++++++++++++++++ + 2 files changed, 26 insertions(+) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h +@@ -42,6 +42,10 @@ struct vc4_dummy_plane { + struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test, + struct drm_device *drm, + enum drm_plane_type type); ++struct drm_plane * ++vc4_mock_atomic_add_plane(struct kunit *test, ++ struct drm_atomic_state *state, ++ struct drm_crtc *crtc); + + struct vc4_dummy_crtc { + struct vc4_crtc crtc; +--- a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + + #include ++#include + #include + #include + #include +@@ -46,3 +47,24 @@ struct vc4_dummy_plane *vc4_dummy_plane( + + return dummy_plane; + } ++ ++struct drm_plane * ++vc4_mock_atomic_add_plane(struct kunit *test, ++ struct drm_atomic_state *state, ++ struct drm_crtc *crtc) ++{ ++ struct drm_plane_state *plane_state; ++ struct drm_plane *plane; ++ int ret; ++ ++ plane = vc4_mock_find_plane_for_crtc(test, crtc); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane); ++ ++ plane_state = drm_atomic_get_plane_state(state, plane); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_state); ++ ++ ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); ++ KUNIT_EXPECT_EQ(test, ret, 0); ++ ++ return plane; ++} diff --git a/target/linux/bcm27xx/patches-6.1/950-0985-drm-vc4-tests-Support-a-few-more-plane-formats.patch b/target/linux/bcm27xx/patches-6.1/950-0985-drm-vc4-tests-Support-a-few-more-plane-formats.patch new file mode 100644 index 0000000000..191181dbb6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0985-drm-vc4-tests-Support-a-few-more-plane-formats.patch @@ -0,0 +1,26 @@ +From 418d2e0e652c3870c29dd2e462f052a88fa027da Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 14 Apr 2023 12:59:05 +0200 +Subject: [PATCH] drm/vc4: tests: Support a few more plane formats + +We'll start testing our planes code in situations where we will use more +than XRGB8888, so let's add a few common pixel formats. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c +@@ -21,7 +21,10 @@ static const struct drm_plane_funcs vc4_ + }; + + static const uint32_t vc4_dummy_plane_formats[] = { ++ DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_YUV420, ++ DRM_FORMAT_YUV422, + }; + + struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test, diff --git a/target/linux/bcm27xx/patches-6.1/950-0986-drm-vc4-tests-Introduce-a-test-for-LBM-buffer-size.patch b/target/linux/bcm27xx/patches-6.1/950-0986-drm-vc4-tests-Introduce-a-test-for-LBM-buffer-size.patch new file mode 100644 index 0000000000..5902d141ef --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0986-drm-vc4-tests-Introduce-a-test-for-LBM-buffer-size.patch @@ -0,0 +1,358 @@ +From 39ae36d19bf6e59e3091f8f0ec6f4eac59aaf6f2 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 14 Apr 2023 13:43:32 +0200 +Subject: [PATCH] drm/vc4: tests: Introduce a test for LBM buffer size + +The BCM2712 comes with a different LBM size computation than the +previous generations, so let's add the few examples provided as kunit +tests to make sure we always satisfy those requirements. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/Makefile | 3 +- + drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c | 327 ++++++++++++++++++ + 2 files changed, 329 insertions(+), 1 deletion(-) + create mode 100644 drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c + +--- a/drivers/gpu/drm/vc4/Makefile ++++ b/drivers/gpu/drm/vc4/Makefile +@@ -31,7 +31,8 @@ vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \ + tests/vc4_mock_crtc.o \ + tests/vc4_mock_output.o \ + tests/vc4_mock_plane.o \ +- tests/vc4_test_pv_muxing.o ++ tests/vc4_test_pv_muxing.o \ ++ tests/vc4_test_lbm_size.o + + vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o + +--- /dev/null ++++ b/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c +@@ -0,0 +1,327 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../../drm_crtc_internal.h" ++#include "../../drm_internal.h" ++ ++#include ++ ++#include "../vc4_drv.h" ++ ++#include "vc4_mock.h" ++ ++u32 vc4_lbm_size(struct drm_plane_state *state); ++ ++struct vc4_lbm_size_priv { ++ struct vc4_dev *vc4; ++ struct drm_file *file; ++ struct drm_modeset_acquire_ctx ctx; ++ struct drm_atomic_state *state; ++}; ++ ++struct vc4_lbm_size_param { ++ unsigned int src_w, src_h; ++ unsigned int crtc_w, crtc_h; ++ bool forced_alpha; ++ u32 fourcc; ++ enum vc4_scaling_mode expected_x_scaling[2]; ++ enum vc4_scaling_mode expected_y_scaling[2]; ++ unsigned int expected_lbm_size; ++}; ++ ++static const struct vc4_lbm_size_param vc4_test_lbm_size_params[] = { ++ { ++ .src_w = 256, ++ .crtc_w = 256, ++ .src_h = 256, ++ .crtc_h = 512, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 32, ++ }, ++ { ++ .src_w = 256, ++ .crtc_w = 179, ++ .src_h = 256, ++ .crtc_h = 512, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_PPF, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 23, ++ }, ++ { ++ .src_w = 256, ++ .crtc_w = 256, ++ .src_h = 256, ++ .crtc_h = 512, ++ .fourcc = DRM_FORMAT_XRGB8888, ++ .expected_x_scaling = { VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 24, ++ }, ++ { ++ .src_w = 100, ++ .crtc_w = 73, ++ .src_h = 100, ++ .crtc_h = 73, ++ .fourcc = DRM_FORMAT_XRGB8888, ++ .expected_x_scaling = { VC4_SCALING_PPF, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 8, ++ }, ++ { ++ .src_w = 256, ++ .crtc_w = 256, ++ .src_h = 256, ++ .crtc_h = 512, ++ .forced_alpha = true, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 24, ++ }, ++ { ++ .src_w = 100, ++ .crtc_w = 73, ++ .src_h = 100, ++ .crtc_h = 73, ++ .forced_alpha = true, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_PPF, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, }, ++ .expected_lbm_size = 8, ++ }, ++ { ++ .src_w = 256, ++ .crtc_w = 94, ++ .src_h = 256, ++ .crtc_h = 94, ++ .fourcc = DRM_FORMAT_ARGB8888, ++ .expected_x_scaling = { VC4_SCALING_TPZ, }, ++ .expected_y_scaling = { VC4_SCALING_TPZ, }, ++ .expected_lbm_size = 6, ++ }, ++ ++/* ++ * TODO: Those tests reflect the LBM size calculation examples, but the ++ * driver ends up taking different scaler filters decisions, and thus ++ * doesn't end up with the same sizes. It would be valuable to have ++ * those tests, but the driver doesn't take a bad decision either, so ++ * it's not clear what we should do at this point. ++ */ ++#if 0 ++ { ++ .src_w = 320, ++ .crtc_w = 320, ++ .src_h = 320, ++ .crtc_h = 320, ++ .fourcc = DRM_FORMAT_YUV420, ++ .expected_x_scaling = { VC4_SCALING_NONE, VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_NONE, VC4_SCALING_PPF, }, ++ .expected_lbm_size = 10, ++ }, ++ { ++ .src_w = 512, ++ .crtc_w = 512, ++ .src_h = 512, ++ .crtc_h = 256, ++ .fourcc = DRM_FORMAT_YUV420, ++ .expected_x_scaling = { VC4_SCALING_NONE, VC4_SCALING_NONE, }, ++ .expected_y_scaling = { VC4_SCALING_TPZ, VC4_SCALING_NONE, }, ++ .expected_lbm_size = 5, ++ }, ++ { ++ .src_w = 486, ++ .crtc_w = 157, ++ .src_h = 404, ++ .crtc_h = 929, ++ .fourcc = DRM_FORMAT_YUV422, ++ .expected_x_scaling = { VC4_SCALING_PPF, VC4_SCALING_PPF, }, ++ .expected_y_scaling = { VC4_SCALING_PPF, VC4_SCALING_PPF, }, ++ .expected_lbm_size = 20, ++ }, ++ { ++ .src_w = 320, ++ .crtc_w = 128, ++ .src_h = 176, ++ .crtc_h = 70, ++ .fourcc = DRM_FORMAT_YUV420, ++ .expected_x_scaling = { VC4_SCALING_TPZ, VC4_SCALING_TPZ, }, ++ .expected_y_scaling = { VC4_SCALING_TPZ, VC4_SCALING_TPZ, }, ++ .expected_lbm_size = 8, ++ }, ++#endif ++}; ++ ++static void vc4_test_lbm_size_desc(const struct vc4_lbm_size_param *t, char *desc) ++{ ++ snprintf(desc, KUNIT_PARAM_DESC_SIZE, ++ "%ux%u to %ux%u %s(%p4cc)", ++ t->src_w, t->src_h, ++ t->crtc_w, t->crtc_h, ++ t->forced_alpha ? "with forced alpha " : "", ++ &t->fourcc); ++} ++ ++KUNIT_ARRAY_PARAM(vc4_test_lbm_size, ++ vc4_test_lbm_size_params, ++ vc4_test_lbm_size_desc); ++ ++static void drm_vc4_test_vc4_lbm_size(struct kunit *test) ++{ ++ const struct vc4_lbm_size_param *params = test->param_value; ++ const struct vc4_lbm_size_priv *priv = test->priv; ++ const struct drm_format_info *info; ++ struct drm_mode_fb_cmd2 fb_req = { }; ++ struct drm_atomic_state *state = priv->state; ++ struct vc4_plane_state *vc4_plane_state; ++ struct drm_plane_state *plane_state; ++ struct vc4_dummy_output *output; ++ struct drm_framebuffer *fb; ++ struct drm_plane *plane; ++ struct drm_crtc *crtc; ++ unsigned int i; ++ int ret; ++ ++ info = drm_format_info(params->fourcc); ++ KUNIT_ASSERT_NOT_NULL(test, info); ++ ++ output = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, output); ++ ++ crtc = vc4_find_crtc_for_encoder(test, &output->encoder.base); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); ++ ++ plane = vc4_mock_atomic_add_plane(test, state, crtc); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane); ++ ++ plane_state = drm_atomic_get_plane_state(state, plane); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_state); ++ ++ vc4_plane_state = to_vc4_plane_state(plane_state); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4_plane_state); ++ ++ fb_req.pixel_format = params->fourcc; ++ fb_req.width = params->src_w; ++ fb_req.height = params->src_h; ++ ++ for (i = 0; i < info->num_planes; i++) { ++ struct drm_mode_create_dumb dumb_args = { }; ++ ++ dumb_args.width = params->src_w; ++ dumb_args.height = params->src_h; ++ dumb_args.bpp = drm_format_info_bpp(info, i); ++ ++ ret = drm_mode_create_dumb(state->dev, &dumb_args, priv->file); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ ++ fb_req.handles[i] = dumb_args.handle; ++ fb_req.pitches[i] = dumb_args.pitch; ++ } ++ ++ fb = drm_internal_framebuffer_create(state->dev, &fb_req, priv->file); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb); ++ ++ drm_atomic_set_fb_for_plane(plane_state, fb); ++ ++ plane_state->src_x = 0; ++ plane_state->src_y = 0; ++ plane_state->src_h = params->src_h << 16; ++ plane_state->src_w = params->src_w << 16; ++ ++ plane_state->crtc_x = 0; ++ plane_state->crtc_y = 0; ++ plane_state->crtc_h = params->crtc_h; ++ plane_state->crtc_w = params->crtc_w; ++ ++ if (params->forced_alpha) ++ plane_state->alpha = 128; ++ ++ ret = drm_atomic_check_only(state); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ ++ KUNIT_EXPECT_EQ(test, vc4_plane_state->lbm.size, params->expected_lbm_size); ++ ++ for (i = 0; i < 2; i++) { ++ KUNIT_EXPECT_EQ(test, ++ vc4_plane_state->x_scaling[i], ++ params->expected_x_scaling[i]); ++ KUNIT_EXPECT_EQ(test, ++ vc4_plane_state->y_scaling[i], ++ params->expected_y_scaling[i]); ++ } ++ ++ drm_framebuffer_put(fb); ++ ++ for (i = 0; i < info->num_planes; i++) ++ drm_mode_destroy_dumb(state->dev, fb_req.handles[i], priv->file); ++} ++ ++static struct kunit_case vc4_lbm_size_tests[] = { ++ KUNIT_CASE_PARAM(drm_vc4_test_vc4_lbm_size, ++ vc4_test_lbm_size_gen_params), ++ {} ++}; ++ ++static int vc4_lbm_size_test_init(struct kunit *test) ++{ ++ struct drm_atomic_state *state; ++ struct vc4_lbm_size_priv *priv; ++ struct drm_device *drm; ++ struct vc4_dev *vc4; ++ ++ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); ++ KUNIT_ASSERT_NOT_NULL(test, priv); ++ test->priv = priv; ++ ++ vc4 = vc6_mock_device(test); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4); ++ priv->vc4 = vc4; ++ ++ priv->file = drm_file_alloc(priv->vc4->base.primary); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->file); ++ ++ drm_modeset_acquire_init(&priv->ctx, 0); ++ ++ drm = &vc4->base; ++ state = drm_atomic_state_alloc(drm); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); ++ ++ state->acquire_ctx = &priv->ctx; ++ ++ priv->state = state; ++ ++ return 0; ++} ++ ++static void vc4_lbm_size_test_exit(struct kunit *test) ++{ ++ struct vc4_lbm_size_priv *priv = test->priv; ++ struct vc4_dev *vc4 = priv->vc4; ++ struct drm_device *drm = &vc4->base; ++ struct drm_atomic_state *state = priv->state; ++ ++ drm_atomic_state_put(state); ++ drm_modeset_drop_locks(&priv->ctx); ++ drm_modeset_acquire_fini(&priv->ctx); ++ drm_file_free(priv->file); ++ drm_dev_unregister(drm); ++ drm_kunit_helper_free_device(test, vc4->dev); ++} ++ ++static struct kunit_suite vc4_lbm_size_test_suite = { ++ .name = "vc4-lbm-size", ++ .init = vc4_lbm_size_test_init, ++ .exit = vc4_lbm_size_test_exit, ++ .test_cases = vc4_lbm_size_tests, ++}; ++ ++kunit_test_suite(vc4_lbm_size_test_suite); diff --git a/target/linux/bcm27xx/patches-6.1/950-0987-drm-vc4-kms-Avoid-setting-core-and-disp-clocks-for-h.patch b/target/linux/bcm27xx/patches-6.1/950-0987-drm-vc4-kms-Avoid-setting-core-and-disp-clocks-for-h.patch new file mode 100644 index 0000000000..f20b0cf3f8 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0987-drm-vc4-kms-Avoid-setting-core-and-disp-clocks-for-h.patch @@ -0,0 +1,40 @@ +From 352d96c9e50012f2b5e5dde9933af8d570e7dc81 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Mon, 17 Jul 2023 17:45:32 +0100 +Subject: [PATCH] drm/vc4: kms: Avoid setting core and disp clocks for hdmi + modes + +On 2712, the firmware always runs these clock at a speed sufficient +for dual 4kp60. + +The requests here prevent the gpu from going into its lowest voltage +mode, so just skip the clock requests. + +With this applied the idle voltage on my pi 5 reduces from 0.7424V +to 0.72V. + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_kms.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -435,7 +435,7 @@ static void vc4_atomic_commit_tail(struc + old_hvs_state->fifo_state[channel].pending_commit = NULL; + } + +- if (vc4->gen >= VC4_GEN_5 && !vc4->firmware_kms) { ++ if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) { + unsigned long state_rate = max(old_hvs_state->core_clock_rate, + new_hvs_state->core_clock_rate); + unsigned long core_rate = clamp_t(unsigned long, state_rate, +@@ -489,7 +489,7 @@ static void vc4_atomic_commit_tail(struc + + drm_atomic_helper_cleanup_planes(dev, state); + +- if (vc4->gen >= VC4_GEN_5 && !vc4->firmware_kms) { ++ if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) { + unsigned long core_rate = min_t(unsigned long, + hvs->max_core_rate, + new_hvs_state->core_clock_rate); diff --git a/target/linux/bcm27xx/patches-6.1/950-0988-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch b/target/linux/bcm27xx/patches-6.1/950-0988-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch new file mode 100644 index 0000000000..b489bbc7f7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0988-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch @@ -0,0 +1,240 @@ +From bb0839405b61da6e6ae7141f7433f6a121725e6f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 31 Aug 2023 11:45:38 +0100 +Subject: [PATCH] drm/vc4: Assign LBM memory during atomic_flush. + +Avoid double buffering LBM allocations by making the +allocation a single alloc per crtc at atomic_flush. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c | 2 +- + drivers/gpu/drm/vc4/vc4_drv.h | 8 ++-- + drivers/gpu/drm/vc4/vc4_hvs.c | 47 ++++++++++++++++++- + drivers/gpu/drm/vc4/vc4_plane.c | 38 +++------------ + 4 files changed, 58 insertions(+), 37 deletions(-) + +--- a/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c ++++ b/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c +@@ -248,7 +248,7 @@ static void drm_vc4_test_vc4_lbm_size(st + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + +- KUNIT_EXPECT_EQ(test, vc4_plane_state->lbm.size, params->expected_lbm_size); ++ KUNIT_EXPECT_EQ(test, vc4_plane_state->lbm_size, params->expected_lbm_size); + + for (i = 0; i < 2; i++) { + KUNIT_EXPECT_EQ(test, +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -437,6 +437,8 @@ struct vc4_plane_state { + u32 dlist_size; /* Number of dwords allocated for the display list */ + u32 dlist_count; /* Number of used dwords in the display list. */ + ++ u32 lbm_size; /* LBM requirements for this plane */ ++ + /* Offset in the dlist to various words, for pageflip or + * cursor updates. + */ +@@ -462,9 +464,6 @@ struct vc4_plane_state { + bool is_unity; + bool is_yuv; + +- /* Our allocation in LBM for temporary storage during scaling. */ +- struct drm_mm_node lbm; +- + /* Our allocation in UPM for prefetching. */ + struct drm_mm_node upm[DRM_FORMAT_MAX_PLANES]; + +@@ -661,6 +660,9 @@ struct vc4_crtc { + * access to that value. + */ + unsigned int current_hvs_channel; ++ ++ /* @lbm: Our allocation in LBM for temporary storage during scaling. */ ++ struct drm_mm_node lbm; + }; + + static inline struct vc4_crtc * +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -1103,6 +1103,7 @@ int vc4_hvs_atomic_check(struct drm_crtc + struct drm_plane *plane; + const struct drm_plane_state *plane_state; + u32 dlist_count = 0; ++ u32 lbm_count = 0; + + /* The pixelvalve can only feed one encoder (and encoders are + * 1:1 with connectors.) +@@ -1111,6 +1112,8 @@ int vc4_hvs_atomic_check(struct drm_crtc + return -EINVAL; + + drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) { ++ const struct vc4_plane_state *vc4_plane_state = ++ to_vc4_plane_state(plane_state); + u32 plane_dlist_count = vc4_plane_dlist_size(plane_state); + + drm_dbg_driver(dev, "[CRTC:%d:%s] Found [PLANE:%d:%s] with DLIST size: %u\n", +@@ -1119,6 +1122,7 @@ int vc4_hvs_atomic_check(struct drm_crtc + plane_dlist_count); + + dlist_count += plane_dlist_count; ++ lbm_count += vc4_plane_state->lbm_size; + } + + dlist_count++; /* Account for SCALER_CTL0_END. */ +@@ -1132,6 +1136,8 @@ int vc4_hvs_atomic_check(struct drm_crtc + + vc4_state->mm = alloc; + ++ /* FIXME: Check total lbm allocation here */ ++ + return vc4_hvs_gamma_check(crtc, state); + } + +@@ -1246,7 +1252,10 @@ void vc4_hvs_atomic_flush(struct drm_crt + bool debug_dump_regs = false; + bool enable_bg_fill = false; + u32 __iomem *dlist_start, *dlist_next; ++ unsigned long irqflags; + unsigned int zpos = 0; ++ u32 lbm_offset = 0; ++ u32 lbm_size = 0; + bool found = false; + int idx; + +@@ -1265,6 +1274,35 @@ void vc4_hvs_atomic_flush(struct drm_crt + vc4_hvs_dump_state(hvs); + } + ++ drm_atomic_crtc_for_each_plane(plane, crtc) { ++ vc4_plane_state = to_vc4_plane_state(plane->state); ++ lbm_size += vc4_plane_state->lbm_size; ++ } ++ ++ if (drm_mm_node_allocated(&vc4_crtc->lbm)) { ++ spin_lock_irqsave(&vc4_crtc->irq_lock, irqflags); ++ drm_mm_remove_node(&vc4_crtc->lbm); ++ spin_unlock_irqrestore(&vc4_crtc->irq_lock, irqflags); ++ } ++ ++ if (lbm_size) { ++ int ret; ++ ++ spin_lock_irqsave(&vc4_crtc->irq_lock, irqflags); ++ ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, ++ &vc4_crtc->lbm, ++ lbm_size, 1, ++ 0, 0); ++ spin_unlock_irqrestore(&vc4_crtc->irq_lock, irqflags); ++ ++ if (ret) { ++ pr_err("Failed to allocate LBM ret %d\n", ret); ++ return; ++ } ++ } ++ ++ lbm_offset = vc4_crtc->lbm.start; ++ + dlist_start = vc4->hvs->dlist + vc4_state->mm->mm_node.start; + dlist_next = dlist_start; + +@@ -1276,6 +1314,8 @@ void vc4_hvs_atomic_flush(struct drm_crt + if (plane->state->normalized_zpos != zpos) + continue; + ++ vc4_plane_state = to_vc4_plane_state(plane->state); ++ + /* Is this the first active plane? */ + if (dlist_next == dlist_start) { + /* We need to enable background fill when a plane +@@ -1286,10 +1326,15 @@ void vc4_hvs_atomic_flush(struct drm_crt + * already needs it or all planes on top blend from + * the first or a lower plane. + */ +- vc4_plane_state = to_vc4_plane_state(plane->state); + enable_bg_fill = vc4_plane_state->needs_bg_fill; + } + ++ if (vc4_plane_state->lbm_size) { ++ vc4_plane_state->dlist[vc4_plane_state->lbm_offset] = ++ lbm_offset; ++ lbm_offset += vc4_plane_state->lbm_size; ++ } ++ + dlist_next += vc4_plane_write_dlist(plane, dlist_next); + + found = true; +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -288,7 +288,6 @@ struct drm_plane_state *vc4_plane_duplic + if (!vc4_state) + return NULL; + +- memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); + memset(&vc4_state->upm, 0, sizeof(vc4_state->upm)); + + for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) +@@ -320,14 +319,6 @@ void vc4_plane_destroy_state(struct drm_ + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + unsigned int i; + +- if (drm_mm_node_allocated(&vc4_state->lbm)) { +- unsigned long irqflags; +- +- spin_lock_irqsave(&hvs->mm_lock, irqflags); +- drm_mm_remove_node(&vc4_state->lbm); +- spin_unlock_irqrestore(&hvs->mm_lock, irqflags); +- } +- + for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) { + unsigned long irqflags; + +@@ -903,12 +894,13 @@ static int vc4_plane_allocate_lbm(struct + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct drm_plane *plane = state->plane; + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); +- unsigned long irqflags; + u32 lbm_size; + + lbm_size = vc4_lbm_size(state); +- if (!lbm_size) ++ if (!lbm_size) { ++ vc4_state->lbm_size = 0; + return 0; ++ } + + /* + * NOTE: BCM2712 doesn't need to be aligned, since the size +@@ -925,28 +917,10 @@ static int vc4_plane_allocate_lbm(struct + if (WARN_ON(!vc4_state->lbm_offset)) + return -EINVAL; + +- /* Allocate the LBM memory that the HVS will use for temporary +- * storage due to our scaling/format conversion. ++ /* FIXME: Add loop here that ensures that the total LBM assigned in this ++ * state is less than the total lbm size + */ +- if (!drm_mm_node_allocated(&vc4_state->lbm)) { +- int ret; +- +- spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); +- ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, +- &vc4_state->lbm, +- lbm_size, 1, +- 0, 0); +- spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); +- +- if (ret) { +- drm_err(drm, "Failed to allocate LBM entry: %d\n", ret); +- return ret; +- } +- } else { +- WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); +- } +- +- vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start; ++ vc4_state->lbm_size = lbm_size; + + return 0; + } diff --git a/target/linux/bcm27xx/patches-6.1/950-0989-drm-panel-simple-Alter-the-timing-for-the-Pi-7-DSI-d.patch b/target/linux/bcm27xx/patches-6.1/950-0989-drm-panel-simple-Alter-the-timing-for-the-Pi-7-DSI-d.patch new file mode 100644 index 0000000000..ef70de7ee4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0989-drm-panel-simple-Alter-the-timing-for-the-Pi-7-DSI-d.patch @@ -0,0 +1,33 @@ +From b1bd2f406eab321be642decd6aee6b6222aec62b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 28 Jul 2023 17:40:27 +0100 +Subject: [PATCH] drm/panel: simple: Alter the timing for the Pi 7" DSI display + +vc4 has always fixed up the timing, so the values defined have +never actually appeared on the wire. +The display appears to want a slightly longer HFP, so extend +the timings and recompute the clock to give the same frame rate. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/panel/panel-simple.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -3241,11 +3241,11 @@ static const struct panel_desc qishenglo + }; + + static const struct drm_display_mode raspberrypi_7inch_mode = { +- .clock = 25979400 / 1000, ++ .clock = 27777, + .hdisplay = 800, +- .hsync_start = 800 + 2, +- .hsync_end = 800 + 2 + 2, +- .htotal = 800 + 2 + 2 + 46, ++ .hsync_start = 800 + 59, ++ .hsync_end = 800 + 59 + 2, ++ .htotal = 800 + 59 + 2 + 46, + .vdisplay = 480, + .vsync_start = 480 + 7, + .vsync_end = 480 + 7 + 2, diff --git a/target/linux/bcm27xx/patches-6.1/950-0990-drm-panel-waveshare-Fix-up-timings-for-10.1-panel.patch b/target/linux/bcm27xx/patches-6.1/950-0990-drm-panel-waveshare-Fix-up-timings-for-10.1-panel.patch new file mode 100644 index 0000000000..0a4203fbc5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0990-drm-panel-waveshare-Fix-up-timings-for-10.1-panel.patch @@ -0,0 +1,33 @@ +From c7cf33911d477fe55a91a9e4d84dad857b244ae3 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 28 Jul 2023 18:10:53 +0100 +Subject: [PATCH] drm/panel: waveshare: Fix up timings for 10.1" panel + +The 10.1" panel doesn't work with the timings defined. vc4 +will always have been fixing up the timing due to the limited +integer divider, so compute the fixed up mode and use it +directly. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/panel/panel-waveshare-dsi.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/panel/panel-waveshare-dsi.c ++++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c +@@ -112,11 +112,11 @@ static const struct drm_display_mode ws_ + * https://www.waveshare.com/product/raspberry-pi/displays/10.1inch-dsi-lcd-c.htm + */ + static const struct drm_display_mode ws_panel_10_1_mode = { +- .clock = 76800, ++ .clock = 83333, + .hdisplay = 1280, +- .hsync_start = 1280 + 40, +- .hsync_end = 1280 + 40 + 20, +- .htotal = 1280 + 40 + 20 + 40, ++ .hsync_start = 1280 + 156, ++ .hsync_end = 1280 + 156 + 20, ++ .htotal = 1280 + 156 + 20 + 40, + .vdisplay = 800, + .vsync_start = 800 + 40, + .vsync_end = 800 + 40 + 48, diff --git a/target/linux/bcm27xx/patches-6.1/950-0991-media-i2c-imx477-Fix-locking-in-imx477_init_controls.patch b/target/linux/bcm27xx/patches-6.1/950-0991-media-i2c-imx477-Fix-locking-in-imx477_init_controls.patch new file mode 100644 index 0000000000..9d7869af9c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0991-media-i2c-imx477-Fix-locking-in-imx477_init_controls.patch @@ -0,0 +1,34 @@ +From 72c25bbb761de2b2acd9f8b652d63e2a2f1caeed Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Mon, 11 Sep 2023 12:17:25 +0300 +Subject: [PATCH] media: i2c: imx477: Fix locking in imx477_init_controls() + +The driver does not lock the imx477 mutex when calling +imx477_set_framing_limits(), leading to: + +WARNING: CPU: 3 PID: 426 at drivers/media/v4l2-core/v4l2-ctrls-api.c:934 __v4l2_ctrl_modify_range+0x1a0/0x210 [ +videodev] + +Fix this by taking the lock. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/i2c/imx477.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/media/i2c/imx477.c ++++ b/drivers/media/i2c/imx477.c +@@ -2069,9 +2069,13 @@ static int imx477_init_controls(struct i + + imx477->sd.ctrl_handler = ctrl_hdlr; + ++ mutex_lock(&imx477->mutex); ++ + /* Setup exposure and frame/line length limits. */ + imx477_set_framing_limits(imx477); + ++ mutex_unlock(&imx477->mutex); ++ + return 0; + + error: diff --git a/target/linux/bcm27xx/patches-6.1/950-0994-overlays-Fix-vc4-kms-dsi-7inch.patch b/target/linux/bcm27xx/patches-6.1/950-0994-overlays-Fix-vc4-kms-dsi-7inch.patch new file mode 100644 index 0000000000..10339e2774 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0994-overlays-Fix-vc4-kms-dsi-7inch.patch @@ -0,0 +1,57 @@ +From 2ff65ffbdeb0c8764985af19df2a687a126136f4 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 29 Sep 2023 16:55:28 +0100 +Subject: [PATCH] overlays: Fix vc4-kms-dsi-7inch + +Fix the touchscreen. + +See: https://github.com/raspberrypi/linux/issues/5619 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/edt-ft5406.dtsi | 13 ++++--------- + .../boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts | 2 +- + 2 files changed, 5 insertions(+), 10 deletions(-) + +--- a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi ++++ b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi +@@ -22,11 +22,13 @@ + }; + }; + +- fragment@12 { +- target = <&i2cbus>; ++ ts_i2c_frag: fragment@12 { ++ target = <&i2c_csi_dsi>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; ++ status = "okay"; ++ + ft5406: ts@38 { + compatible = "edt,edt-ft5506"; + reg = <0x38>; +@@ -37,13 +39,6 @@ + }; + }; + +- ts_i2c_frag: fragment@13 { +- target = <&i2c_csi_dsi>; +- i2cbus: __overlay__ { +- status = "okay"; +- }; +- }; +- + __overrides__ { + sizex = <&ft5406>,"touchscreen-size-x:0"; + sizey = <&ft5406>,"touchscreen-size-y:0"; +--- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts +@@ -119,6 +119,6 @@ + <&panel_disp>, "reg:0=0", + <®_bridge>, "reg:0=0", + <®_bridge>, "regulator-name=bridge_reg_0"; +- disable_touch = <0>, "-10-11-12"; ++ disable_touch = <&ft5406>, "status=disabled"; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-0996-ASoC-hdmi-codec-Fix-broken-channel-map-reporting.patch b/target/linux/bcm27xx/patches-6.1/950-0996-ASoC-hdmi-codec-Fix-broken-channel-map-reporting.patch new file mode 100644 index 0000000000..c8fd2a2f90 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0996-ASoC-hdmi-codec-Fix-broken-channel-map-reporting.patch @@ -0,0 +1,56 @@ +From a1caea3c996f6bfa8c9568f521257f4e473285fb Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Fri, 29 Sep 2023 21:50:28 +0200 +Subject: [PATCH] ASoC: hdmi-codec: Fix broken channel map reporting + +Commit b84b53149476b22cc3b8677b771fb4cf06d1d455 upstream. + +Commit 4e0871333661 ("ASoC: hdmi-codec: fix channel info for +compressed formats") accidentally changed hcp->chmap_idx from +ca_id, the CEA channel allocation ID, to idx, the index to +the table of channel mappings ordered by preference. + +This resulted in wrong channel maps being reported to userspace, +eg for 5.1 "FL,FR,LFE,FC" was reported instead of the expected +"FL,FR,LFE,FC,RL,RR": + +~ # speaker-test -c 6 -t sine +... + 0 - Front Left + 3 - Front Center + 1 - Front Right + 2 - LFE + 4 - Unknown + 5 - Unknown + +~ # amixer cget iface=PCM,name='Playback Channel Map' | grep ': values' + : values=3,4,8,7,0,0,0,0 + +Switch this back to ca_id in case of PCM audio so the correct channel +map is reported again and set it to HDMI_CODEC_CHMAP_IDX_UNKNOWN in +case of non-PCM audio so the PCM channel map control returns "Unknown" +channels (value 0). + +Fixes: 4e0871333661 ("ASoC: hdmi-codec: fix channel info for compressed formats") +Cc: stable@vger.kernel.org +Signed-off-by: Matthias Reichl +Link: https://lore.kernel.org/r/20230929195027.97136-1-hias@horus.com +Signed-off-by: Mark Brown +--- + sound/soc/codecs/hdmi-codec.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -520,7 +520,10 @@ static int hdmi_codec_fill_codec_params( + hp->sample_rate = sample_rate; + hp->channels = channels; + +- hcp->chmap_idx = idx; ++ if (pcm_audio) ++ hcp->chmap_idx = ca_id; ++ else ++ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + + return 0; + } diff --git a/target/linux/bcm27xx/patches-6.1/950-0997-media-rp1-cfe-Fix-use-of-freed-memory-on-errors.patch b/target/linux/bcm27xx/patches-6.1/950-0997-media-rp1-cfe-Fix-use-of-freed-memory-on-errors.patch new file mode 100644 index 0000000000..7f1b505336 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0997-media-rp1-cfe-Fix-use-of-freed-memory-on-errors.patch @@ -0,0 +1,48 @@ +From 3922bebc11fcc8459c798cfcb582828f9bbaa9e9 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Thu, 28 Sep 2023 11:33:53 +0300 +Subject: [PATCH] media: rp1: cfe: Fix use of freed memory on errors + +cfe_probe_complete() calls cfe_put() on both success and fail code paths. +This works for the success path, but causes the cfe_device struct to be +freed, even if it will be used later in the teardown code. + +Fix this by making the ref handling a bit saner: Let the video nodes +have the refs as they do now, but also keep a ref in the "main" driver, +released only at cfe_remove() time. This way the driver does not depend +on the video nodes keeping the refs. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -1837,17 +1837,10 @@ static int cfe_probe_complete(struct cfe + goto unregister; + } + +- /* +- * Release the initial reference, all references are now owned by the +- * video devices. +- */ +- cfe_put(cfe); + return 0; + + unregister: + cfe_unregister_nodes(cfe); +- cfe_put(cfe); +- + return ret; + } + +@@ -2129,6 +2122,8 @@ static int cfe_remove(struct platform_de + + v4l2_device_unregister(&cfe->v4l2_dev); + ++ cfe_put(cfe); ++ + return 0; + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-0998-media-rp1-cfe-Fix-width-height-in-cfe_start_channel.patch b/target/linux/bcm27xx/patches-6.1/950-0998-media-rp1-cfe-Fix-width-height-in-cfe_start_channel.patch new file mode 100644 index 0000000000..d49856c32d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0998-media-rp1-cfe-Fix-width-height-in-cfe_start_channel.patch @@ -0,0 +1,88 @@ +From 84c9958dd71b8a4dcf16cbf6fdb867c668652634 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Wed, 27 Sep 2023 16:00:39 +0300 +Subject: [PATCH] media: rp1: cfe: Fix width & height in cfe_start_channel() + +The logic for handling width & height in cfe_start_channel() is somewhat +odd and, afaics, broken. The code reads: + +bool start_fe = is_fe_enabled(cfe) && + test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); + +if (start_fe || is_image_output_node(node)) { + width = node->fmt.fmt.pix.width; + height = node->fmt.fmt.pix.height; +} + +cfe_start_channel() is called for all video nodes that will be used. So +this means that if, say, fe_stats is enabled as the last node, start_fe +will be true, and width and height will be taken from fe_stats' node. +The width and height will thus contain garbage, which then gets +programmed to the csi2 registers. + +It seems that this often still works fine, though, probably if the width +& height are large enough. + +Drop the above code, and instead get the width & height from the csi2 +subdev's sink pad for the csi2 channel that is used. For metadata the +width & height will be 0 as before. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -763,20 +763,16 @@ static void cfe_start_channel(struct cfe + struct v4l2_mbus_framefmt *source_fmt; + const struct cfe_fmt *fmt; + unsigned long flags; +- unsigned int width = 0, height = 0; + bool start_fe = is_fe_enabled(cfe) && + test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); + + cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); + +- if (start_fe || is_image_output_node(node)) { +- width = node->fmt.fmt.pix.width; +- height = node->fmt.fmt.pix.height; +- } +- + state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); + + if (start_fe) { ++ unsigned int width, height; ++ + WARN_ON(!is_fe_enabled(cfe)); + cfe_dbg("%s: %s using csi2 channel %d\n", + __func__, node_desc[FE_OUT0].name, +@@ -785,6 +781,9 @@ static void cfe_start_channel(struct cfe + source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, cfe->fe_csi2_channel); + fmt = find_format_by_code(source_fmt->code); + ++ width = source_fmt->width; ++ height = source_fmt->height; ++ + /* + * Start the associated CSI2 Channel as well. + * +@@ -800,6 +799,8 @@ static void cfe_start_channel(struct cfe + } + + if (is_csi2_node(node)) { ++ unsigned int width = 0, height = 0; ++ + u32 mode = CSI2_MODE_NORMAL; + + source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, +@@ -807,6 +808,9 @@ static void cfe_start_channel(struct cfe + fmt = find_format_by_code(source_fmt->code); + + if (is_image_output_node(node)) { ++ width = source_fmt->width; ++ height = source_fmt->height; ++ + if (node->fmt.fmt.pix.pixelformat == + fmt->remap[CFE_REMAP_16BIT]) + mode = CSI2_MODE_REMAP; diff --git a/target/linux/bcm27xx/patches-6.1/950-0999-media-rp1-csi2-Fix-missing-reg-writes.patch b/target/linux/bcm27xx/patches-6.1/950-0999-media-rp1-csi2-Fix-missing-reg-writes.patch new file mode 100644 index 0000000000..2a3915b6e3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0999-media-rp1-csi2-Fix-missing-reg-writes.patch @@ -0,0 +1,36 @@ +From 62e8ab88d2c230dad122aabe2ad0e227d7ceba40 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Thu, 28 Sep 2023 10:42:22 +0300 +Subject: [PATCH] media: rp1: csi2: Fix missing reg writes + +The driver has two places where it writes a register based on a +condition, and when that condition is false, the driver presumes that +the register has the reset value. This is not a good idea, so fix those +places to always write the register. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/csi2.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -253,6 +253,7 @@ void csi2_start_channel(struct csi2_devi + */ + set_field(&ctrl, 0x3ff, LC_MASK); + set_field(&ctrl, 0x00, CH_MODE_MASK); ++ csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), 0); + } + + set_field(&ctrl, dt, DT_MASK); +@@ -277,8 +278,8 @@ void csi2_open_rx(struct csi2_device *cs + { + dphy_start(&csi2->dphy); + +- if (!csi2->multipacket_line) +- csi2_reg_write(csi2, CSI2_CTRL, EOP_IS_EOL); ++ csi2_reg_write(csi2, CSI2_CTRL, ++ csi2->multipacket_line ? 0 : EOP_IS_EOL); + } + + void csi2_close_rx(struct csi2_device *csi2) diff --git a/target/linux/bcm27xx/patches-6.1/950-1000-media-rp1-fe-Use-0-not-1-when-working-with-unsigned-.patch b/target/linux/bcm27xx/patches-6.1/950-1000-media-rp1-fe-Use-0-not-1-when-working-with-unsigned-.patch new file mode 100644 index 0000000000..f468b7ac48 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1000-media-rp1-fe-Use-0-not-1-when-working-with-unsigned-.patch @@ -0,0 +1,33 @@ +From 455c4ae2c70348a5842835d2f67f7cd8e665a2a6 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Thu, 21 Sep 2023 16:03:07 +0300 +Subject: [PATCH] media: rp1: fe: Use ~0, not -1, when working with unsigned + values + +Use ~0, not -1, when working with unsigned values (-1 is not unsigned). + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +@@ -372,7 +372,7 @@ void pisp_fe_submit_job(struct pisp_fe_d + void pisp_fe_start(struct pisp_fe_device *fe) + { + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_RESET); +- pisp_fe_reg_write(fe, FE_INT_STATUS, -1); ++ pisp_fe_reg_write(fe, FE_INT_STATUS, ~0); + pisp_fe_reg_write(fe, FE_INT_EN, FE_INT_EOF | FE_INT_SOF | FE_INT_LINES0 | FE_INT_LINES1); + fe->inframe_count = 0; + } +@@ -383,7 +383,7 @@ void pisp_fe_stop(struct pisp_fe_device + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_ABORT); + usleep_range(1000, 2000); + WARN_ON(pisp_fe_reg_read(fe, FE_STATUS)); +- pisp_fe_reg_write(fe, FE_INT_STATUS, -1); ++ pisp_fe_reg_write(fe, FE_INT_STATUS, ~0); + } + + static struct pisp_fe_device *to_pisp_fe_device(struct v4l2_subdev *subdev) diff --git a/target/linux/bcm27xx/patches-6.1/950-1001-media-rp1-cfe-Fix-verbose-debug-print.patch b/target/linux/bcm27xx/patches-6.1/950-1001-media-rp1-cfe-Fix-verbose-debug-print.patch new file mode 100644 index 0000000000..3344c32d29 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1001-media-rp1-cfe-Fix-verbose-debug-print.patch @@ -0,0 +1,26 @@ +From bf1709d2cf2b57c4ea98b8363156835249ae02cc Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 22 Sep 2023 12:41:35 +0300 +Subject: [PATCH] media: rp1: cfe: Fix verbose debug print + +The debug print in cfe_schedule_next_csi2_job() is printed every frame, +and should thus use cfe_dbg_irq() to avoid spamming, rather than cfe_dbg(). + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -518,8 +518,8 @@ static void cfe_schedule_next_csi2_job(s + node->next_frm = buf; + list_del(&buf->list); + +- cfe_dbg("%s: [%s] buffer:%p\n", +- __func__, node_desc[node->id].name, &buf->vb.vb2_buf); ++ cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, ++ node_desc[node->id].name, &buf->vb.vb2_buf); + + if (is_meta_node(node)) { + size = node->fmt.fmt.meta.buffersize; diff --git a/target/linux/bcm27xx/patches-6.1/950-1002-media-rp1-cfe-Rename-xxx_dbg_irq-to-xxx_dbg_verbose.patch b/target/linux/bcm27xx/patches-6.1/950-1002-media-rp1-cfe-Rename-xxx_dbg_irq-to-xxx_dbg_verbose.patch new file mode 100644 index 0000000000..14fa0447df --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1002-media-rp1-cfe-Rename-xxx_dbg_irq-to-xxx_dbg_verbose.patch @@ -0,0 +1,227 @@ +From a1ea528e187ee045aeff929ff0f4b2e53fdd970f Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Wed, 4 Oct 2023 10:12:37 +0300 +Subject: [PATCH] media: rp1: cfe: Rename xxx_dbg_irq() to xxx_dbg_verbose() + +Rename the xxx_dbg_irq() macros to xxx_dbg_verbose(), as they can be +used to verbose debugs outside irq context too. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 40 +++++++++---------- + .../media/platform/raspberrypi/rp1_cfe/cfe.h | 2 +- + .../media/platform/raspberrypi/rp1_cfe/csi2.c | 26 ++++++------ + .../platform/raspberrypi/rp1_cfe/pisp_fe.c | 12 +++--- + 4 files changed, 40 insertions(+), 40 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -49,11 +49,11 @@ + #define CFE_MODULE_NAME "rp1-cfe" + #define CFE_VERSION "1.0" + +-bool cfe_debug_irq; ++bool cfe_debug_verbose; + +-#define cfe_dbg_irq(fmt, arg...) \ ++#define cfe_dbg_verbose(fmt, arg...) \ + do { \ +- if (cfe_debug_irq) \ ++ if (cfe_debug_verbose) \ + dev_dbg(&cfe->pdev->dev, fmt, ##arg); \ + } while (0) + #define cfe_dbg(fmt, arg...) dev_dbg(&cfe->pdev->dev, fmt, ##arg) +@@ -518,8 +518,8 @@ static void cfe_schedule_next_csi2_job(s + node->next_frm = buf; + list_del(&buf->list); + +- cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, +- node_desc[node->id].name, &buf->vb.vb2_buf); ++ cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__, ++ node_desc[node->id].name, &buf->vb.vb2_buf); + + if (is_meta_node(node)) { + size = node->fmt.fmt.meta.buffersize; +@@ -550,8 +550,8 @@ static void cfe_schedule_next_pisp_job(s + buf = list_first_entry(&node->dma_queue, struct cfe_buffer, + list); + +- cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, +- node_desc[node->id].name, &buf->vb.vb2_buf); ++ cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__, ++ node_desc[node->id].name, &buf->vb.vb2_buf); + + node->next_frm = buf; + vb2_bufs[node_desc[i].link_pad] = &buf->vb.vb2_buf; +@@ -573,8 +573,8 @@ static bool cfe_check_job_ready(struct c + continue; + + if (list_empty(&node->dma_queue)) { +- cfe_dbg_irq("%s: [%s] has no buffer, unable to schedule job\n", +- __func__, node_desc[i].name); ++ cfe_dbg_verbose("%s: [%s] has no buffer, unable to schedule job\n", ++ __func__, node_desc[i].name); + return false; + } + } +@@ -592,7 +592,7 @@ static void cfe_prepare_next_job(struct + /* Flag if another job is ready after this. */ + cfe->job_ready = cfe_check_job_ready(cfe); + +- cfe_dbg_irq("%s: end with scheduled job\n", __func__); ++ cfe_dbg_verbose("%s: end with scheduled job\n", __func__); + } + + static void cfe_process_buffer_complete(struct cfe_node *node, +@@ -600,8 +600,8 @@ static void cfe_process_buffer_complete( + { + struct cfe_device *cfe = node->cfe; + +- cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, node_desc[node->id].name, +- &node->cur_frm->vb.vb2_buf); ++ cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__, ++ node_desc[node->id].name, &node->cur_frm->vb.vb2_buf); + + node->cur_frm->vb.sequence = sequence; + vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); +@@ -621,8 +621,8 @@ static void cfe_sof_isr_handler(struct c + { + struct cfe_device *cfe = node->cfe; + +- cfe_dbg_irq("%s: [%s] seq %u\n", __func__, node_desc[node->id].name, +- cfe->sequence); ++ cfe_dbg_verbose("%s: [%s] seq %u\n", __func__, node_desc[node->id].name, ++ cfe->sequence); + + node->cur_frm = node->next_frm; + node->next_frm = NULL; +@@ -651,8 +651,8 @@ static void cfe_eof_isr_handler(struct c + { + struct cfe_device *cfe = node->cfe; + +- cfe_dbg_irq("%s: [%s] seq %u\n", __func__, node_desc[node->id].name, +- cfe->sequence); ++ cfe_dbg_verbose("%s: [%s] seq %u\n", __func__, node_desc[node->id].name, ++ cfe->sequence); + + if (node->cur_frm) + cfe_process_buffer_complete(node, cfe->sequence); +@@ -921,8 +921,8 @@ static int cfe_buffer_prepare(struct vb2 + struct cfe_buffer *buf = to_cfe_buffer(vb); + unsigned long size; + +- cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, node_desc[node->id].name, +- vb); ++ cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__, ++ node_desc[node->id].name, vb); + + size = is_image_output_node(node) ? node->fmt.fmt.pix.sizeimage : + node->fmt.fmt.meta.buffersize; +@@ -954,8 +954,8 @@ static void cfe_buffer_queue(struct vb2_ + struct cfe_buffer *buf = to_cfe_buffer(vb); + unsigned long flags; + +- cfe_dbg_irq("%s: [%s] buffer:%p\n", __func__, node_desc[node->id].name, +- vb); ++ cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__, ++ node_desc[node->id].name, vb); + + spin_lock_irqsave(&cfe->state_lock, flags); + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h +@@ -11,7 +11,7 @@ + #include + #include + +-extern bool cfe_debug_irq; ++extern bool cfe_debug_verbose; + + enum cfe_remap_types { + CFE_REMAP_16BIT, +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -16,9 +16,9 @@ + #include "csi2.h" + #include "cfe.h" + +-#define csi2_dbg_irq(fmt, arg...) \ ++#define csi2_dbg_verbose(fmt, arg...) \ + do { \ +- if (cfe_debug_irq) \ ++ if (cfe_debug_verbose) \ + dev_dbg(csi2->v4l2_dev->dev, fmt, ##arg); \ + } while (0) + #define csi2_dbg(fmt, arg...) dev_dbg(csi2->v4l2_dev->dev, fmt, ##arg) +@@ -154,7 +154,7 @@ void csi2_isr(struct csi2_device *csi2, + u32 status; + + status = csi2_reg_read(csi2, CSI2_STATUS); +- csi2_dbg_irq("ISR: STA: 0x%x\n", status); ++ csi2_dbg_verbose("ISR: STA: 0x%x\n", status); + + /* Write value back to clear the interrupts */ + csi2_reg_write(csi2, CSI2_STATUS, status); +@@ -167,16 +167,16 @@ void csi2_isr(struct csi2_device *csi2, + + dbg = csi2_reg_read(csi2, CSI2_CH_DEBUG(i)); + +- csi2_dbg_irq("ISR: [%u], %s%s%s%s%s frame: %u line: %u\n", i, +- (status & IRQ_FS(i)) ? "FS " : "", +- (status & IRQ_FE(i)) ? "FE " : "", +- (status & IRQ_FE_ACK(i)) ? "FE_ACK " : "", +- (status & IRQ_LE(i)) ? "LE " : "", +- (status & IRQ_LE_ACK(i)) ? "LE_ACK " : "", +- dbg >> 16, +- csi2->num_lines[i] ? +- ((dbg & 0xffff) % csi2->num_lines[i]) : +- 0); ++ csi2_dbg_verbose("ISR: [%u], %s%s%s%s%s frame: %u line: %u\n", ++ i, (status & IRQ_FS(i)) ? "FS " : "", ++ (status & IRQ_FE(i)) ? "FE " : "", ++ (status & IRQ_FE_ACK(i)) ? "FE_ACK " : "", ++ (status & IRQ_LE(i)) ? "LE " : "", ++ (status & IRQ_LE_ACK(i)) ? "LE_ACK " : "", ++ dbg >> 16, ++ csi2->num_lines[i] ? ++ ((dbg & 0xffff) % csi2->num_lines[i]) : ++ 0); + + sof[i] = !!(status & IRQ_FS(i)); + eof[i] = !!(status & IRQ_FE_ACK(i)); +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +@@ -114,9 +114,9 @@ static const struct pisp_fe_config_param + sizeof(struct pisp_fe_output_config) }, + }; + +-#define pisp_fe_dbg_irq(fmt, arg...) \ ++#define pisp_fe_dbg_verbose(fmt, arg...) \ + do { \ +- if (cfe_debug_irq) \ ++ if (cfe_debug_verbose) \ + dev_dbg(fe->v4l2_dev->dev, fmt, ##arg); \ + } while (0) + #define pisp_fe_dbg(fmt, arg...) dev_dbg(fe->v4l2_dev->dev, fmt, ##arg) +@@ -202,9 +202,9 @@ void pisp_fe_isr(struct pisp_fe_device * + int_status = pisp_fe_reg_read(fe, FE_INT_STATUS); + pisp_fe_reg_write(fe, FE_INT_STATUS, int_status); + +- pisp_fe_dbg_irq("%s: status 0x%x out 0x%x frame 0x%x error 0x%x int 0x%x\n", +- __func__, status, out_status, frame_status, error_status, +- int_status); ++ pisp_fe_dbg_verbose("%s: status 0x%x out 0x%x frame 0x%x error 0x%x int 0x%x\n", ++ __func__, status, out_status, frame_status, error_status, ++ int_status); + + /* We do not report interrupts for the input/stream pad. */ + for (i = 0; i < FE_NUM_PADS - 1; i++) { +@@ -339,7 +339,7 @@ void pisp_fe_submit_job(struct pisp_fe_d + * sequence of relaxed writes which follow. + */ + status = pisp_fe_reg_read(fe, FE_STATUS); +- pisp_fe_dbg_irq("%s: status = 0x%x\n", __func__, status); ++ pisp_fe_dbg_verbose("%s: status = 0x%x\n", __func__, status); + if (WARN_ON(status & FE_STATUS_QUEUED)) + return; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1003-media-rp1-Add-back-reg-write-debug-prints.patch b/target/linux/bcm27xx/patches-6.1/950-1003-media-rp1-Add-back-reg-write-debug-prints.patch new file mode 100644 index 0000000000..c86f7a3e17 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1003-media-rp1-Add-back-reg-write-debug-prints.patch @@ -0,0 +1,41 @@ +From 8240f1328ead0152f116b385b3169f8f010a7869 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 22 Sep 2023 12:39:33 +0300 +Subject: [PATCH] media: rp1: Add back reg write debug prints + +Add back debug prints in csi2 and pisp_fe reg_write() functions, but use +the 'irq' variants to avoid spamming in normal situation. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/csi2.c | 1 + + drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c | 2 ++ + 2 files changed, 3 insertions(+) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -92,6 +92,7 @@ static inline u32 csi2_reg_read(struct c + static inline void csi2_reg_write(struct csi2_device *csi2, u32 offset, u32 val) + { + writel(val, csi2->base + offset); ++ csi2_dbg_verbose("csi2: write 0x%04x -> 0x%03x\n", val, offset); + } + + static inline void set_field(u32 *valp, u32 field, u32 mask) +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +@@ -132,12 +132,14 @@ static inline void pisp_fe_reg_write(str + u32 val) + { + writel(val, fe->base + offset); ++ pisp_fe_dbg_verbose("fe: write 0x%04x -> 0x%03x\n", val, offset); + } + + static inline void pisp_fe_reg_write_relaxed(struct pisp_fe_device *fe, u32 offset, + u32 val) + { + writel_relaxed(val, fe->base + offset); ++ pisp_fe_dbg_verbose("fe: write 0x%04x -> 0x%03x\n", val, offset); + } + + static int pisp_regs_show(struct seq_file *s, void *data) diff --git a/target/linux/bcm27xx/patches-6.1/950-1004-media-rp1-cfe-Add-verbose-debug-module-parameter.patch b/target/linux/bcm27xx/patches-6.1/950-1004-media-rp1-cfe-Add-verbose-debug-module-parameter.patch new file mode 100644 index 0000000000..f44cb50d10 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1004-media-rp1-cfe-Add-verbose-debug-module-parameter.patch @@ -0,0 +1,23 @@ +From f2553458c0c1942731447aac3878f51aa1b326a7 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Wed, 4 Oct 2023 10:19:47 +0300 +Subject: [PATCH] media: rp1: cfe: Add verbose debug module parameter + +Expose the verbose debug flag as a module parameter. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -50,6 +50,8 @@ + #define CFE_VERSION "1.0" + + bool cfe_debug_verbose; ++module_param_named(verbose_debug, cfe_debug_verbose, bool, 0644); ++MODULE_PARM_DESC(verbose_debug, "verbose debugging messages"); + + #define cfe_dbg_verbose(fmt, arg...) \ + do { \ diff --git a/target/linux/bcm27xx/patches-6.1/950-1005-media-rp1-csi2-Track-CSI-2-errors.patch b/target/linux/bcm27xx/patches-6.1/950-1005-media-rp1-csi2-Track-CSI-2-errors.patch new file mode 100644 index 0000000000..9d8da81887 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1005-media-rp1-csi2-Track-CSI-2-errors.patch @@ -0,0 +1,245 @@ +From b19c2b5f88f141e58044e5d1012f867d46f74bf3 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Thu, 21 Sep 2023 18:18:53 +0300 +Subject: [PATCH] media: rp1: csi2: Track CSI-2 errors + +Track the errors from the CSI-2 receiver: overflows and discards. These +are recorded in a table which can be read by the userspace via debugfs. + +As tracking the errors may cause much more interrupt load, the tracking +needs to be enabled with a module parameter. + +Note that the recording is not perfect: we only record the last +discarded DT for each discard type, instead of recording all of them. +This means that e.g. if the device is discarding two unmatched DTs, the +debugfs file only shows the last one recorded. Recording all of them +would need a more sophisticated recording system to avoid the need of a +very large table, or dynamic allocation. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/csi2.c | 123 ++++++++++++++++++ + .../media/platform/raspberrypi/rp1_cfe/csi2.h | 16 +++ + 2 files changed, 139 insertions(+) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -16,6 +16,10 @@ + #include "csi2.h" + #include "cfe.h" + ++static bool csi2_track_errors; ++module_param_named(track_csi2_errors, csi2_track_errors, bool, 0); ++MODULE_PARM_DESC(track_csi2_errors, "track csi-2 errors"); ++ + #define csi2_dbg_verbose(fmt, arg...) \ + do { \ + if (cfe_debug_verbose) \ +@@ -32,9 +36,28 @@ + #define CSI2_DISCARDS_INACTIVE 0x00c + #define CSI2_DISCARDS_UNMATCHED 0x010 + #define CSI2_DISCARDS_LEN_LIMIT 0x014 ++ ++#define CSI2_DISCARDS_AMOUNT_SHIFT 0 ++#define CSI2_DISCARDS_AMOUNT_MASK GENMASK(23, 0) ++#define CSI2_DISCARDS_DT_SHIFT 24 ++#define CSI2_DISCARDS_DT_MASK GENMASK(29, 24) ++#define CSI2_DISCARDS_VC_SHIFT 30 ++#define CSI2_DISCARDS_VC_MASK GENMASK(31, 30) ++ + #define CSI2_LLEV_PANICS 0x018 + #define CSI2_ULEV_PANICS 0x01c + #define CSI2_IRQ_MASK 0x020 ++#define CSI2_IRQ_MASK_IRQ_OVERFLOW BIT(0) ++#define CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW BIT(1) ++#define CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT BIT(2) ++#define CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED BIT(3) ++#define CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE BIT(4) ++#define CSI2_IRQ_MASK_IRQ_ALL \ ++ (CSI2_IRQ_MASK_IRQ_OVERFLOW | CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW | \ ++ CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT | \ ++ CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED | \ ++ CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE) ++ + #define CSI2_CTRL 0x024 + #define CSI2_CH_CTRL(x) ((x) * 0x40 + 0x28) + #define CSI2_CH_ADDR0(x) ((x) * 0x40 + 0x2c) +@@ -149,6 +172,92 @@ static int csi2_regs_show(struct seq_fil + + DEFINE_SHOW_ATTRIBUTE(csi2_regs); + ++static int csi2_errors_show(struct seq_file *s, void *data) ++{ ++ struct csi2_device *csi2 = s->private; ++ unsigned long flags; ++ u32 discards_table[DISCARDS_TABLE_NUM_VCS][DISCARDS_TABLE_NUM_ENTRIES]; ++ u32 discards_dt_table[DISCARDS_TABLE_NUM_ENTRIES]; ++ u32 overflows; ++ ++ spin_lock_irqsave(&csi2->errors_lock, flags); ++ ++ memcpy(discards_table, csi2->discards_table, sizeof(discards_table)); ++ memcpy(discards_dt_table, csi2->discards_dt_table, ++ sizeof(discards_dt_table)); ++ overflows = csi2->overflows; ++ ++ csi2->overflows = 0; ++ memset(csi2->discards_table, 0, sizeof(discards_table)); ++ memset(csi2->discards_dt_table, 0, sizeof(discards_dt_table)); ++ ++ spin_unlock_irqrestore(&csi2->errors_lock, flags); ++ ++ seq_printf(s, "Overflows %u\n", overflows); ++ seq_puts(s, "Discards:\n"); ++ seq_puts(s, "VC OVLF LEN UNMATCHED INACTIVE\n"); ++ ++ for (unsigned int vc = 0; vc < DISCARDS_TABLE_NUM_VCS; ++vc) { ++ seq_printf(s, "%u %10u %10u %10u %10u\n", vc, ++ discards_table[vc][DISCARDS_TABLE_OVERFLOW], ++ discards_table[vc][DISCARDS_TABLE_LENGTH_LIMIT], ++ discards_table[vc][DISCARDS_TABLE_UNMATCHED], ++ discards_table[vc][DISCARDS_TABLE_INACTIVE]); ++ } ++ ++ seq_printf(s, "Last DT %10u %10u %10u %10u\n", ++ discards_dt_table[DISCARDS_TABLE_OVERFLOW], ++ discards_dt_table[DISCARDS_TABLE_LENGTH_LIMIT], ++ discards_dt_table[DISCARDS_TABLE_UNMATCHED], ++ discards_dt_table[DISCARDS_TABLE_INACTIVE]); ++ ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(csi2_errors); ++ ++static void csi2_isr_handle_errors(struct csi2_device *csi2, u32 status) ++{ ++ spin_lock(&csi2->errors_lock); ++ ++ if (status & IRQ_OVERFLOW) ++ csi2->overflows++; ++ ++ for (unsigned int i = 0; i < DISCARDS_TABLE_NUM_ENTRIES; ++i) { ++ static const u32 discard_bits[] = { ++ IRQ_DISCARD_OVERFLOW, ++ IRQ_DISCARD_LEN_LIMIT, ++ IRQ_DISCARD_UNMATCHED, ++ IRQ_DISCARD_INACTIVE, ++ }; ++ static const u8 discard_regs[] = { ++ CSI2_DISCARDS_OVERFLOW, ++ CSI2_DISCARDS_LEN_LIMIT, ++ CSI2_DISCARDS_UNMATCHED, ++ CSI2_DISCARDS_INACTIVE, ++ }; ++ u32 amount; ++ u8 dt, vc; ++ u32 v; ++ ++ if (!(status & discard_bits[i])) ++ continue; ++ ++ v = csi2_reg_read(csi2, discard_regs[i]); ++ csi2_reg_write(csi2, discard_regs[i], 0); ++ ++ amount = (v & CSI2_DISCARDS_AMOUNT_MASK) >> ++ CSI2_DISCARDS_AMOUNT_SHIFT; ++ dt = (v & CSI2_DISCARDS_DT_MASK) >> CSI2_DISCARDS_DT_SHIFT; ++ vc = (v & CSI2_DISCARDS_VC_MASK) >> CSI2_DISCARDS_VC_SHIFT; ++ ++ csi2->discards_table[vc][i] += amount; ++ csi2->discards_dt_table[i] = dt; ++ } ++ ++ spin_unlock(&csi2->errors_lock); ++} ++ + void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof, bool *lci) + { + unsigned int i; +@@ -183,6 +292,9 @@ void csi2_isr(struct csi2_device *csi2, + eof[i] = !!(status & IRQ_FE_ACK(i)); + lci[i] = !!(status & IRQ_LE_ACK(i)); + } ++ ++ if (csi2_track_errors) ++ csi2_isr_handle_errors(csi2, status); + } + + void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, +@@ -277,6 +389,9 @@ void csi2_stop_channel(struct csi2_devic + + void csi2_open_rx(struct csi2_device *csi2) + { ++ csi2_reg_write(csi2, CSI2_IRQ_MASK, ++ csi2_track_errors ? CSI2_IRQ_MASK_IRQ_ALL : 0); ++ + dphy_start(&csi2->dphy); + + csi2_reg_write(csi2, CSI2_CTRL, +@@ -286,6 +401,8 @@ void csi2_open_rx(struct csi2_device *cs + void csi2_close_rx(struct csi2_device *csi2) + { + dphy_stop(&csi2->dphy); ++ ++ csi2_reg_write(csi2, CSI2_IRQ_MASK, 0); + } + + static struct csi2_device *to_csi2_device(struct v4l2_subdev *subdev) +@@ -398,11 +515,17 @@ int csi2_init(struct csi2_device *csi2, + { + unsigned int i, ret; + ++ spin_lock_init(&csi2->errors_lock); ++ + csi2->dphy.dev = csi2->v4l2_dev->dev; + dphy_probe(&csi2->dphy); + + debugfs_create_file("csi2_regs", 0444, debugfs, csi2, &csi2_regs_fops); + ++ if (csi2_track_errors) ++ debugfs_create_file("csi2_errors", 0444, debugfs, csi2, ++ &csi2_errors_fops); ++ + for (i = 0; i < CSI2_NUM_CHANNELS * 2; i++) + csi2->pad[i].flags = i < CSI2_NUM_CHANNELS ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h +@@ -17,6 +17,8 @@ + + #define CSI2_NUM_CHANNELS 4 + ++#define DISCARDS_TABLE_NUM_VCS 4 ++ + enum csi2_mode { + CSI2_MODE_NORMAL, + CSI2_MODE_REMAP, +@@ -37,6 +39,14 @@ struct csi2_cfg { + u32 buffer_size; + }; + ++enum discards_table_index { ++ DISCARDS_TABLE_OVERFLOW = 0, ++ DISCARDS_TABLE_LENGTH_LIMIT, ++ DISCARDS_TABLE_UNMATCHED, ++ DISCARDS_TABLE_INACTIVE, ++ DISCARDS_TABLE_NUM_ENTRIES, ++}; ++ + struct csi2_device { + /* Parent V4l2 device */ + struct v4l2_device *v4l2_dev; +@@ -53,6 +63,12 @@ struct csi2_device { + + struct media_pad pad[CSI2_NUM_CHANNELS * 2]; + struct v4l2_subdev sd; ++ ++ /* lock for csi2 errors counters */ ++ spinlock_t errors_lock; ++ u32 overflows; ++ u32 discards_table[DISCARDS_TABLE_NUM_VCS][DISCARDS_TABLE_NUM_ENTRIES]; ++ u32 discards_dt_table[DISCARDS_TABLE_NUM_ENTRIES]; + }; + + void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof, bool *lci); diff --git a/target/linux/bcm27xx/patches-6.1/950-1006-media-rp1-cfe-Drop-unused-field.patch b/target/linux/bcm27xx/patches-6.1/950-1006-media-rp1-cfe-Drop-unused-field.patch new file mode 100644 index 0000000000..b53a5b6154 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1006-media-rp1-cfe-Drop-unused-field.patch @@ -0,0 +1,31 @@ +From d6bd676b49cf10046665efde820b0cc00dc43994 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Thu, 28 Sep 2023 17:04:07 +0300 +Subject: [PATCH] media: rp1: cfe: Drop unused field + +Drop 'sensor_embedded_data' field, as it is unused. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -292,7 +292,6 @@ struct cfe_device { + struct csi2_device csi2; + struct pisp_fe_device fe; + +- bool sensor_embedded_data; + int fe_csi2_channel; + + unsigned int sequence; +@@ -1821,8 +1820,6 @@ static int cfe_probe_complete(struct cfe + + cfe->v4l2_dev.notify = cfe_notify; + +- cfe->sensor_embedded_data = (cfe->sensor->entity.num_pads >= 2); +- + for (i = 0; i < NUM_NODES; i++) { + ret = cfe_register_node(cfe, i); + if (ret) { diff --git a/target/linux/bcm27xx/patches-6.1/950-1007-media-rp1-csi2-Set-values-for-enum-csi2_mode.patch b/target/linux/bcm27xx/patches-6.1/950-1007-media-rp1-csi2-Set-values-for-enum-csi2_mode.patch new file mode 100644 index 0000000000..126ee2c493 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1007-media-rp1-csi2-Set-values-for-enum-csi2_mode.patch @@ -0,0 +1,30 @@ +From c56b53d62116b4672962124afab02f3beada4244 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 29 Sep 2023 12:57:23 +0300 +Subject: [PATCH] media: rp1: csi2: Set values for enum csi2_mode + +Set hardcoded values for enum csi2_mode, as the values will be +programmed to HW registers. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/csi2.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h +@@ -20,10 +20,10 @@ + #define DISCARDS_TABLE_NUM_VCS 4 + + enum csi2_mode { +- CSI2_MODE_NORMAL, +- CSI2_MODE_REMAP, +- CSI2_MODE_COMPRESSED, +- CSI2_MODE_FE_STREAMING ++ CSI2_MODE_NORMAL = 0, ++ CSI2_MODE_REMAP = 1, ++ CSI2_MODE_COMPRESSED = 2, ++ CSI2_MODE_FE_STREAMING = 3, + }; + + enum csi2_compression_mode { diff --git a/target/linux/bcm27xx/patches-6.1/950-1008-media-rp1-fe-Fix-default-mbus-code.patch b/target/linux/bcm27xx/patches-6.1/950-1008-media-rp1-fe-Fix-default-mbus-code.patch new file mode 100644 index 0000000000..e4ea9e1d16 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1008-media-rp1-fe-Fix-default-mbus-code.patch @@ -0,0 +1,27 @@ +From 5edacf33de9e0349dd5a02ad684bfceae1d5565f Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 29 Sep 2023 13:29:15 +0300 +Subject: [PATCH] media: rp1: fe: Fix default mbus code + +When pisp_fe_pad_set_fmt() is given an mbus code that CFE does not +support, it currently defaults to MEDIA_BUS_FMT_SBGGR10_1X10. This is +not correct, as FE does not support SBGGR10. + +Set the default to MEDIA_BUS_FMT_SRGGB16_1X16 instead. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +@@ -437,7 +437,7 @@ static int pisp_fe_pad_set_fmt(struct v4 + case FE_OUTPUT1_PAD: + cfe_fmt = find_format_by_code(format->format.code); + if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT)) +- cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10); ++ cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16); + + format->format.code = cfe_fmt->code; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1009-media-rp1-cfe-Fix-default-meta-format-s-field.patch b/target/linux/bcm27xx/patches-6.1/950-1009-media-rp1-cfe-Fix-default-meta-format-s-field.patch new file mode 100644 index 0000000000..2ac5e0e88a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1009-media-rp1-cfe-Fix-default-meta-format-s-field.patch @@ -0,0 +1,25 @@ +From 47fd9528bc1d93dd07ce9baa19c736966b536bd9 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Mon, 2 Oct 2023 14:38:07 +0300 +Subject: [PATCH] media: rp1: cfe: Fix default meta format's field + +Set default meta format's field to V4L2_FIELD_NONE, instead of zeroing +it which indicates V4L2_FIELD_ANY. Metadata doesn't have fields, so NONE +makes sense, and furthermore the default v4l2 link validation will check +for matching fields, or that the sink field is NONE. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -110,6 +110,7 @@ const struct v4l2_mbus_framefmt cfe_defa + .width = 8192, + .height = 1, + .code = MEDIA_BUS_FMT_SENSOR_DATA, ++ .field = V4L2_FIELD_NONE, + }; + + enum node_ids { diff --git a/target/linux/bcm27xx/patches-6.1/950-1010-media-rp1-cfe-Fail-streaming-if-FE_CONFIG-node-is-no.patch b/target/linux/bcm27xx/patches-6.1/950-1010-media-rp1-cfe-Fail-streaming-if-FE_CONFIG-node-is-no.patch new file mode 100644 index 0000000000..de469c3565 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1010-media-rp1-cfe-Fail-streaming-if-FE_CONFIG-node-is-no.patch @@ -0,0 +1,31 @@ +From 3e2203b265ddd8630fea0fbb69b3a2ec1496f773 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 4 Oct 2023 09:39:59 +0100 +Subject: [PATCH] media: rp1: cfe: Fail streaming if FE_CONFIG node is not + enabled + +When the FE is enabled, ensure that the FE_CONFIG node is enabled. +Otherwise fail cfe_start_streaming() entirely. + +Signed-off-by: Naushir Patuck +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -997,6 +997,14 @@ static int cfe_start_streaming(struct vb + goto err_streaming; + } + ++ /* When using the Frontend, we must enable the FE_CONFIG node. */ ++ if (is_fe_enabled(cfe) && ++ !check_state(cfe, NODE_ENABLED, cfe->node[FE_CONFIG].id)) { ++ cfe_err("FE enabled, but FE_CONFIG node is not\n"); ++ ret = -EINVAL; ++ goto err_streaming; ++ } ++ + ret = media_pipeline_start(&node->pad, &cfe->pipe); + if (ret < 0) { + cfe_err("Failed to start media pipeline: %d\n", ret); diff --git a/target/linux/bcm27xx/patches-6.1/950-1011-media-i2c-Move-Kconfig-entry-for-IMX477-to-the-camer.patch b/target/linux/bcm27xx/patches-6.1/950-1011-media-i2c-Move-Kconfig-entry-for-IMX477-to-the-camer.patch new file mode 100644 index 0000000000..37e1a86e16 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1011-media-i2c-Move-Kconfig-entry-for-IMX477-to-the-camer.patch @@ -0,0 +1,51 @@ +From 52811174f534824f5e5bcdb681f0c508aa335244 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 4 Oct 2023 11:09:10 +0100 +Subject: [PATCH] media: i2c: Move Kconfig entry for IMX477 to the camera + sensor section + +It was accidentally placed in the audio decoder section. + +Signed-off-by: Naushir Patuck +--- + drivers/media/i2c/Kconfig | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -270,6 +270,17 @@ config VIDEO_IMX412 + To compile this driver as a module, choose M here: the + module will be called imx412. + ++config VIDEO_IMX477 ++ tristate "Sony IMX477 sensor support" ++ depends on I2C && VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ help ++ This is a Video4Linux2 sensor driver for the Sony ++ IMX477 camera. Also supports the Sony IMX378. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called imx477. ++ + config VIDEO_IMX519 + tristate "Arducam IMX519 sensor support" + depends on I2C && VIDEO_DEV +@@ -1106,17 +1117,6 @@ config VIDEO_UDA1342 + To compile this driver as a module, choose M here: the + module will be called uda1342. + +-config VIDEO_IMX477 +- tristate "Sony IMX477 sensor support" +- depends on I2C && VIDEO_DEV +- select VIDEO_V4L2_SUBDEV_API +- help +- This is a Video4Linux2 sensor driver for the Sony +- IMX477 camera. Also supports the Sony IMX378. +- +- To compile this driver as a module, choose M here: the +- module will be called imx477. +- + config VIDEO_VP27SMPX + tristate "Panasonic VP27's internal MPX" + depends on VIDEO_DEV && I2C diff --git a/target/linux/bcm27xx/patches-6.1/950-1013-drm-Look-for-an-alias-for-the-displays-to-use-as-the.patch b/target/linux/bcm27xx/patches-6.1/950-1013-drm-Look-for-an-alias-for-the-displays-to-use-as-the.patch new file mode 100644 index 0000000000..8de6c372c0 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1013-drm-Look-for-an-alias-for-the-displays-to-use-as-the.patch @@ -0,0 +1,109 @@ +From 3aa1f2477545ea6298bc6f2d7ffae68f090af9b8 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 28 Sep 2023 18:27:09 +0100 +Subject: [PATCH] drm: Look for an alias for the displays to use as the DRM + device name + +Allow DT aliases of eg DSI2 to force make DRM allocate the +display with the requested name. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/drm_connector.c | 60 ++++++++++++++++++++++++++++++--- + 1 file changed, 56 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -81,6 +81,7 @@ struct drm_conn_prop_enum_list { + int type; + const char *name; + struct ida ida; ++ int first_dyn_num; + }; + + /* +@@ -110,12 +111,41 @@ static struct drm_conn_prop_enum_list dr + { DRM_MODE_CONNECTOR_USB, "USB" }, + }; + ++#define MAX_DT_NODE_NAME_LEN 20 ++#define DT_DRM_NODE_PREFIX "drm_" ++ ++static void drm_connector_get_of_name(int type, char *node_name, int length) ++{ ++ int i = 0; ++ ++ strcpy(node_name, DT_DRM_NODE_PREFIX); ++ ++ do { ++ node_name[i + strlen(DT_DRM_NODE_PREFIX)] = ++ tolower(drm_connector_enum_list[type].name[i]); ++ ++ } while (drm_connector_enum_list[type].name[i++] && ++ i < length); ++ ++ node_name[length - 1] = '\0'; ++} ++ + void drm_connector_ida_init(void) + { +- int i; ++ int i, id; ++ char node_name[MAX_DT_NODE_NAME_LEN]; + +- for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) ++ for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) { + ida_init(&drm_connector_enum_list[i].ida); ++ ++ drm_connector_get_of_name(i, node_name, MAX_DT_NODE_NAME_LEN); ++ ++ id = of_alias_get_highest_id(node_name); ++ if (id > 0) ++ drm_connector_enum_list[i].first_dyn_num = id + 1; ++ else ++ drm_connector_enum_list[i].first_dyn_num = 1; ++ } + } + + void drm_connector_ida_destroy(void) +@@ -222,7 +252,9 @@ static int __drm_connector_init(struct d + struct i2c_adapter *ddc) + { + struct drm_mode_config *config = &dev->mode_config; ++ char node_name[MAX_DT_NODE_NAME_LEN]; + int ret; ++ int id; + struct ida *connector_ida = + &drm_connector_enum_list[connector_type].ida; + +@@ -252,8 +284,28 @@ static int __drm_connector_init(struct d + ret = 0; + + connector->connector_type = connector_type; +- connector->connector_type_id = +- ida_alloc_min(connector_ida, 1, GFP_KERNEL); ++ connector->connector_type_id = 0; ++ ++ drm_connector_get_of_name(connector_type, node_name, MAX_DT_NODE_NAME_LEN); ++ id = of_alias_get_id(dev->dev->of_node, node_name); ++ if (id > 0) { ++ /* Try and allocate the requested ID ++ * Valid range is 1 to 31, hence ignoring 0 as an error ++ */ ++ int type_id = ida_alloc_range(connector_ida, id, id, GFP_KERNEL); ++ ++ if (type_id > 0) ++ connector->connector_type_id = type_id; ++ else ++ drm_err(dev, "Failed to acquire type ID %d for interface type %s, ret %d\n", ++ id, drm_connector_enum_list[connector_type].name, ++ type_id); ++ } ++ if (!connector->connector_type_id) ++ connector->connector_type_id = ++ ida_alloc_min(connector_ida, ++ drm_connector_enum_list[connector_type].first_dyn_num, ++ GFP_KERNEL); + if (connector->connector_type_id < 0) { + ret = connector->connector_type_id; + goto out_put_id; diff --git a/target/linux/bcm27xx/patches-6.1/950-1014-dt-Add-DSI1-and-DSI2-aliases-to-2712.patch b/target/linux/bcm27xx/patches-6.1/950-1014-dt-Add-DSI1-and-DSI2-aliases-to-2712.patch new file mode 100644 index 0000000000..6d79cb6c4d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1014-dt-Add-DSI1-and-DSI2-aliases-to-2712.patch @@ -0,0 +1,24 @@ +From 7ec42740a45b21bca859cde5b7cbe2f09ef3d586 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 28 Sep 2023 18:40:36 +0100 +Subject: [PATCH] dt: Add DSI1 and DSI2 aliases to 2712 + +In order to keep the DRM names consistent as DSI-1 and DSI-2, add +aliases to the Pi5 DT. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -785,6 +785,8 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + gpio4 = &pinctrl_aon; + usb0 = &rp1_usb0; + usb1 = &rp1_usb1; ++ drm_dsi1 = &dsi0; ++ drm_dsi2 = &dsi1; + }; + + __overrides__ { diff --git a/target/linux/bcm27xx/patches-6.1/950-1015-vc4-drm-Remove-the-clear-of-SCALER_DISPBKGND_FILL.patch b/target/linux/bcm27xx/patches-6.1/950-1015-vc4-drm-Remove-the-clear-of-SCALER_DISPBKGND_FILL.patch new file mode 100644 index 0000000000..a4c8aeadd3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1015-vc4-drm-Remove-the-clear-of-SCALER_DISPBKGND_FILL.patch @@ -0,0 +1,64 @@ +From e6e0631fdeb0cd7d4c50e629b4b298e0b76e885b Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Wed, 4 Oct 2023 16:02:39 +0100 +Subject: [PATCH] vc4/drm: Remove the clear of SCALER_DISPBKGND_FILL + +Since "drm/vc4: hvs: Support BCM2712 HVS" booting Pi4 +with dual 4kp30 displays connected fails with: +vc4-drm gpu: [drm] *ERROR* [CRTC:107:pixelvalve-4] flip_done timed out + +It has been tracked down to the referenced commit adding a +path to clear the SCALER_DISPBKGND_FILL when not required. + +Dual 4kp30 works with a core clock of 297MHz when background fill +is enabled, but requires a higher value with it disabled. +320MHz still fails, while 330MHz seems okay. + +Lets always enable background fill for Pi0-4. + +Fixes: e84da235223d ("drm/vc4: hvs: Support BCM2712 HVS") + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -1349,27 +1349,25 @@ void vc4_hvs_atomic_flush(struct drm_crt + WARN_ON(!vc4_state->mm); + WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm->mm_node.size); + +- if (enable_bg_fill) { ++ if (vc4->gen >= VC4_GEN_6) { + /* This sets a black background color fill, as is the case + * with other DRM drivers. + */ +- if (vc4->gen >= VC4_GEN_6) ++ if (enable_bg_fill) + HVS_WRITE(SCALER6_DISPX_CTRL1(channel), + HVS_READ(SCALER6_DISPX_CTRL1(channel)) | + SCALER6_DISPX_CTRL1_BGENB); + else +- HVS_WRITE(SCALER_DISPBKGNDX(channel), +- HVS_READ(SCALER_DISPBKGNDX(channel)) | +- SCALER_DISPBKGND_FILL); +- } else { +- if (vc4->gen >= VC4_GEN_6) + HVS_WRITE(SCALER6_DISPX_CTRL1(channel), + HVS_READ(SCALER6_DISPX_CTRL1(channel)) & + ~SCALER6_DISPX_CTRL1_BGENB); +- else +- HVS_WRITE(SCALER_DISPBKGNDX(channel), +- HVS_READ(SCALER_DISPBKGNDX(channel)) & +- ~SCALER_DISPBKGND_FILL); ++ } else { ++ /* we can actually run with a lower core clock when background ++ * fill is enabled on VC4_GEN_5 so leave it enabled always. ++ */ ++ HVS_WRITE(SCALER_DISPBKGNDX(channel), ++ HVS_READ(SCALER_DISPBKGNDX(channel)) | ++ SCALER_DISPBKGND_FILL); + } + + /* Only update DISPLIST if the CRTC was already running and is not diff --git a/target/linux/bcm27xx/patches-6.1/950-1017-gpio-brcmstb-Use-dynamic-GPIO-base-numbers.patch b/target/linux/bcm27xx/patches-6.1/950-1017-gpio-brcmstb-Use-dynamic-GPIO-base-numbers.patch new file mode 100644 index 0000000000..9bf9e6d96d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1017-gpio-brcmstb-Use-dynamic-GPIO-base-numbers.patch @@ -0,0 +1,117 @@ +From 450d617786926b27c25e930241efbd2e37d66bb8 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 6 Oct 2023 16:30:35 +0100 +Subject: [PATCH] gpio: brcmstb: Use dynamic GPIO base numbers + +Forcing a gpiochip to have a fixed base number now leads to a warning +message. Remove the need to do so by calculating hwirq numbers based +on bank numbers. + +Signed-off-by: Phil Elwell +Fixes: 3b0213d56eb7 ("gpio: Add GPIO support for Broadcom STB SoCs") +--- + drivers/gpio/gpio-brcmstb.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +--- a/drivers/gpio/gpio-brcmstb.c ++++ b/drivers/gpio/gpio-brcmstb.c +@@ -50,7 +50,6 @@ struct brcmstb_gpio_priv { + struct irq_domain *irq_domain; + struct irq_chip irq_chip; + int parent_irq; +- int gpio_base; + int num_gpios; + int parent_wake_irq; + }; +@@ -92,7 +91,7 @@ brcmstb_gpio_get_active_irqs(struct brcm + static int brcmstb_gpio_hwirq_to_offset(irq_hw_number_t hwirq, + struct brcmstb_gpio_bank *bank) + { +- return hwirq - (bank->gc.base - bank->parent_priv->gpio_base); ++ return hwirq - bank->id * 32; + } + + static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank, +@@ -117,8 +116,9 @@ static void brcmstb_gpio_set_imask(struc + static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) + { + struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); ++ struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc); + /* gc_offset is relative to this gpio_chip; want real offset */ +- int hwirq = offset + (gc->base - priv->gpio_base); ++ int hwirq = offset + bank->id * 32; + + if (hwirq >= priv->num_gpios) + return -ENXIO; +@@ -263,7 +263,7 @@ static void brcmstb_gpio_irq_bank_handle + { + struct brcmstb_gpio_priv *priv = bank->parent_priv; + struct irq_domain *domain = priv->irq_domain; +- int hwbase = bank->gc.base - priv->gpio_base; ++ int hwbase = bank->id * 32; + unsigned long status; + + while ((status = brcmstb_gpio_get_active_irqs(bank))) { +@@ -414,7 +414,7 @@ static int brcmstb_gpio_of_xlate(struct + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) + return -EINVAL; + +- offset = gpiospec->args[0] - (gc->base - priv->gpio_base); ++ offset = gpiospec->args[0] - bank->id * 32; + if (offset >= gc->ngpio || offset < 0) + return -EINVAL; + +@@ -598,8 +598,8 @@ static int brcmstb_gpio_probe(struct pla + const __be32 *p; + u32 bank_width; + int num_banks = 0; ++ int num_gpios = 0; + int err; +- static int gpio_base; + unsigned long flags = 0; + bool need_wakeup_event = false; + +@@ -614,7 +614,6 @@ static int brcmstb_gpio_probe(struct pla + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); + +- priv->gpio_base = gpio_base; + priv->reg_base = reg_base; + priv->pdev = pdev; + +@@ -656,7 +655,7 @@ static int brcmstb_gpio_probe(struct pla + dev_dbg(dev, "Width 0 found: Empty bank @ %d\n", + num_banks); + num_banks++; +- gpio_base += MAX_GPIO_PER_BANK; ++ num_gpios += MAX_GPIO_PER_BANK; + continue; + } + +@@ -698,7 +697,7 @@ static int brcmstb_gpio_probe(struct pla + err = -ENOMEM; + goto fail; + } +- gc->base = gpio_base; ++ gc->base = -1; + gc->of_gpio_n_cells = 2; + gc->of_xlate = brcmstb_gpio_of_xlate; + /* not all ngpio lines are valid, will use bank width later */ +@@ -722,7 +721,7 @@ static int brcmstb_gpio_probe(struct pla + bank->id); + goto fail; + } +- gpio_base += gc->ngpio; ++ num_gpios += gc->ngpio; + + dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id, + gc->base, gc->ngpio, bank->width); +@@ -733,7 +732,7 @@ static int brcmstb_gpio_probe(struct pla + num_banks++; + } + +- priv->num_gpios = gpio_base - priv->gpio_base; ++ priv->num_gpios = num_gpios; + if (priv->parent_irq > 0) { + err = brcmstb_gpio_irq_setup(pdev, priv); + if (err) diff --git a/target/linux/bcm27xx/patches-6.1/950-1018-media-rpivid-Allow-use-of-iommu-in-rpivid.patch b/target/linux/bcm27xx/patches-6.1/950-1018-media-rpivid-Allow-use-of-iommu-in-rpivid.patch new file mode 100644 index 0000000000..a6d199a8c7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1018-media-rpivid-Allow-use-of-iommu-in-rpivid.patch @@ -0,0 +1,57 @@ +From 1770efc97981dbf756a18f5eb7615c4bafab665b Mon Sep 17 00:00:00 2001 +From: John Cox +Date: Mon, 2 Oct 2023 15:12:52 +0100 +Subject: [PATCH] media/rpivid: Allow use of iommu in rpivid + +In order to use iommu on hevc set dma mask_and_coherent in probe. +I am assured dma_set_mask_and_coherent is benign on Pi4 (which has +no iommu) and it seems to be so in practice. +Also adds a bit of debug to make internal buffer allocation failure +easier to spot in future + +Signed-off-by: John Cox +--- + drivers/staging/media/rpivid/rpivid.c | 7 +++++++ + drivers/staging/media/rpivid/rpivid_h265.c | 12 ++++++++++-- + 2 files changed, 17 insertions(+), 2 deletions(-) + +--- a/drivers/staging/media/rpivid/rpivid.c ++++ b/drivers/staging/media/rpivid/rpivid.c +@@ -360,6 +360,13 @@ static int rpivid_probe(struct platform_ + snprintf(vfd->name, sizeof(vfd->name), "%s", rpivid_video_device.name); + video_set_drvdata(vfd, dev); + ++ ret = dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(36)); ++ if (ret) { ++ v4l2_err(&dev->v4l2_dev, ++ "Failed dma_set_mask_and_coherent\n"); ++ goto err_v4l2; ++ } ++ + dev->m2m_dev = v4l2_m2m_init(&rpivid_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, +--- a/drivers/staging/media/rpivid/rpivid_h265.c ++++ b/drivers/staging/media/rpivid/rpivid_h265.c +@@ -2495,11 +2495,19 @@ static int rpivid_h265_start(struct rpiv + for (i = 0; i != ARRAY_SIZE(ctx->pu_bufs); ++i) { + // Don't actually need a kernel mapping here + if (gptr_alloc(dev, ctx->pu_bufs + i, pu_alloc, +- DMA_ATTR_NO_KERNEL_MAPPING)) ++ DMA_ATTR_NO_KERNEL_MAPPING)) { ++ v4l2_err(&dev->v4l2_dev, ++ "Failed to alloc %#zx PU%d buffer\n", ++ pu_alloc, i); + goto fail; ++ } + if (gptr_alloc(dev, ctx->coeff_bufs + i, coeff_alloc, +- DMA_ATTR_NO_KERNEL_MAPPING)) ++ DMA_ATTR_NO_KERNEL_MAPPING)) { ++ v4l2_err(&dev->v4l2_dev, ++ "Failed to alloc %#zx Coeff%d buffer\n", ++ pu_alloc, i); + goto fail; ++ } + } + aux_q_init(ctx); + diff --git a/target/linux/bcm27xx/patches-6.1/950-1019-dts-bcm2712-Add-iommu-to-rpivid.patch b/target/linux/bcm27xx/patches-6.1/950-1019-dts-bcm2712-Add-iommu-to-rpivid.patch new file mode 100644 index 0000000000..9f7c8674fb --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1019-dts-bcm2712-Add-iommu-to-rpivid.patch @@ -0,0 +1,22 @@ +From 10ff8ba24c68f704ecf5a58878617dfe149a14c6 Mon Sep 17 00:00:00 2001 +From: John Cox +Date: Mon, 2 Oct 2023 15:15:13 +0100 +Subject: [PATCH] dts/bcm2712: Add iommu to rpivid + +Add iommu to rpivid so it can cope with scatter/gather + +Signed-off-by: John Cox +--- + arch/arm/boot/dts/bcm2712.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/boot/dts/bcm2712.dtsi ++++ b/arch/arm/boot/dts/bcm2712.dtsi +@@ -1158,6 +1158,7 @@ + clocks = <&firmware_clocks 11>; + clock-names = "hevc"; + status = "disabled"; ++ iommus = <&iommu2>; + }; + + sdio1: mmc@fff000 { diff --git a/target/linux/bcm27xx/patches-6.1/950-1020-drivers-media-rp1_cfe-Remove-PISP-specific-MBUS-form.patch b/target/linux/bcm27xx/patches-6.1/950-1020-drivers-media-rp1_cfe-Remove-PISP-specific-MBUS-form.patch new file mode 100644 index 0000000000..fabc96e422 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1020-drivers-media-rp1_cfe-Remove-PISP-specific-MBUS-form.patch @@ -0,0 +1,117 @@ +From b5c3cc7fd9fca73352310e61092fb445b56a362a Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Tue, 10 Oct 2023 12:41:15 +0100 +Subject: [PATCH] drivers: media: rp1_cfe: Remove PISP specific MBUS formats + +Remove the MEDIA_BUS_FMT_PISP* format codcs entirely. For the image +pad formats, use the 16-bit Bayer format mbus codes instead. For the +config and stats pad formats, use MEDIA_BUS_FMT_FIXED. + +Signed-off-by: Naushir Patuck +--- + .../media/platform/raspberrypi/rp1_cfe/cfe_fmts.h | 10 ++++++---- + .../media/platform/raspberrypi/rp1_cfe/pisp_fe.c | 11 ++++------- + include/uapi/linux/media-bus-format.h | 14 -------------- + 3 files changed, 10 insertions(+), 25 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h +@@ -215,25 +215,25 @@ static const struct cfe_fmt formats[] = + /* PiSP Compressed Mode 1 */ + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_RGGB, +- .code = MEDIA_BUS_FMT_PISP_COMP1_RGGB, ++ .code = MEDIA_BUS_FMT_SRGGB16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_BGGR, +- .code = MEDIA_BUS_FMT_PISP_COMP1_BGGR, ++ .code = MEDIA_BUS_FMT_SBGGR16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_GBRG, +- .code = MEDIA_BUS_FMT_PISP_COMP1_GBRG, ++ .code = MEDIA_BUS_FMT_SGBRG16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_GRBG, +- .code = MEDIA_BUS_FMT_PISP_COMP1_GRBG, ++ .code = MEDIA_BUS_FMT_SGRBG16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, +@@ -283,10 +283,12 @@ static const struct cfe_fmt formats[] = + /* Frontend formats */ + { + .fourcc = V4L2_META_FMT_RPI_FE_CFG, ++ .code = MEDIA_BUS_FMT_FIXED, + .flags = CFE_FORMAT_FLAG_META_OUT, + }, + { + .fourcc = V4L2_META_FMT_RPI_FE_STATS, ++ .code = MEDIA_BUS_FMT_FIXED, + .flags = CFE_FORMAT_FLAG_META_CAP, + }, + }; +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +@@ -404,7 +404,7 @@ static int pisp_fe_init_cfg(struct v4l2_ + + fmt = v4l2_subdev_get_pad_format(sd, state, FE_CONFIG_PAD); + *fmt = cfe_default_meta_format; +- fmt->code = MEDIA_BUS_FMT_PISP_FE_CONFIG; ++ fmt->code = MEDIA_BUS_FMT_FIXED; + + fmt = v4l2_subdev_get_pad_format(sd, state, FE_OUTPUT0_PAD); + *fmt = cfe_default_format; +@@ -416,7 +416,7 @@ static int pisp_fe_init_cfg(struct v4l2_ + + fmt = v4l2_subdev_get_pad_format(sd, state, FE_STATS_PAD); + *fmt = cfe_default_meta_format; +- fmt->code = MEDIA_BUS_FMT_PISP_FE_STATS; ++ fmt->code = MEDIA_BUS_FMT_FIXED; + + return 0; + } +@@ -443,12 +443,9 @@ static int pisp_fe_pad_set_fmt(struct v4 + + break; + +- case FE_CONFIG_PAD: +- format->format.code = MEDIA_BUS_FMT_PISP_FE_CONFIG; +- break; +- + case FE_STATS_PAD: +- format->format.code = MEDIA_BUS_FMT_PISP_FE_STATS; ++ case FE_CONFIG_PAD: ++ format->format.code = MEDIA_BUS_FMT_FIXED; + break; + } + +--- a/include/uapi/linux/media-bus-format.h ++++ b/include/uapi/linux/media-bus-format.h +@@ -175,18 +175,4 @@ + /* Sensor ancillary metadata formats - next is 0x7002 */ + #define MEDIA_BUS_FMT_SENSOR_DATA 0x7002 + +-/* PiSP Formats */ +-#define MEDIA_BUS_FMT_PISP_COMP1_RGGB 0x8001 +-#define MEDIA_BUS_FMT_PISP_COMP1_GRBG 0x8002 +-#define MEDIA_BUS_FMT_PISP_COMP1_GBRG 0x8003 +-#define MEDIA_BUS_FMT_PISP_COMP1_BGGR 0x8004 +-#define MEDIA_BUS_FMT_PISP_COMP2_RGGB 0x8005 +-#define MEDIA_BUS_FMT_PISP_COMP2_GRBG 0x8006 +-#define MEDIA_BUS_FMT_PISP_COMP2_GBRG 0x8007 +-#define MEDIA_BUS_FMT_PISP_COMP2_BGGR 0x8008 +- +-#define MEDIA_BUS_FMT_PISP_FE_CONFIG 0x8100 +-#define MEDIA_BUS_FMT_PISP_FE_STATS 0x8101 +-#define MEDIA_BUS_FMT_PISP_BE_CONFIG 0x8200 +- + #endif /* __LINUX_MEDIA_BUS_FORMAT_H */ diff --git a/target/linux/bcm27xx/patches-6.1/950-1022-vc04_services-bcm2835-codec-Correct-alignment-requir.patch b/target/linux/bcm27xx/patches-6.1/950-1022-vc04_services-bcm2835-codec-Correct-alignment-requir.patch new file mode 100644 index 0000000000..313ca37738 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1022-vc04_services-bcm2835-codec-Correct-alignment-requir.patch @@ -0,0 +1,53 @@ +From 9f4002165439d02a63760e68948246e3af764318 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 11 Oct 2023 15:05:38 +0100 +Subject: [PATCH] vc04_services: bcm2835-codec: Correct alignment requirements + for YUYV + +The firmware wants the YUYV format stride alignment to be to a multiple +of 32pixels / 64 bytes. The kernel driver was configuring it to a multiple +of 16 pixels / 32 bytes, which then failed when it tried starting to +stream. + +Correct the alignment requirements. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -206,28 +206,28 @@ static const struct bcm2835_codec_fmt su + }, { + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, +- .bytesperline_align = { 32, 32, 32, 32, 32 }, ++ .bytesperline_align = { 64, 64, 64, 64, 64 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_YUYV, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, +- .bytesperline_align = { 32, 32, 32, 32, 32 }, ++ .bytesperline_align = { 64, 64, 64, 64, 64 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_UYVY, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .depth = 16, +- .bytesperline_align = { 32, 32, 32, 32, 32 }, ++ .bytesperline_align = { 64, 64, 64, 64, 64 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_YVYU, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .depth = 16, +- .bytesperline_align = { 32, 32, 32, 32, 32 }, ++ .bytesperline_align = { 64, 64, 64, 64, 64 }, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_VYUY, + .size_multiplier_x2 = 2, diff --git a/target/linux/bcm27xx/patches-6.1/950-1025-input-touchscreen-edt-ft5x06-Suppress-bogus-data-on-.patch b/target/linux/bcm27xx/patches-6.1/950-1025-input-touchscreen-edt-ft5x06-Suppress-bogus-data-on-.patch new file mode 100644 index 0000000000..fe956c2ed4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1025-input-touchscreen-edt-ft5x06-Suppress-bogus-data-on-.patch @@ -0,0 +1,96 @@ +From dd802fc03b1c71b4297e87068077bfcf9810300a Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Wed, 11 Oct 2023 15:14:59 +0100 +Subject: [PATCH] input: touchscreen: edt-ft5x06: Suppress bogus data on + startup + +When polled without the use of IRQ, FT5x06 registers may return +undefined initial data, causing unwanted touches or event spamming. +A simple way to filter this out is to suppress touches until the +TD_STATUS register changes for the first time. + +Increase the delay before first polling to 300ms, to avoid +transient I2C read flakiness that seems to occur after reset. + +Signed-off-by: Nick Hollinghurst +--- + drivers/input/touchscreen/edt-ft5x06.c | 31 +++++++++++++++++++++++--- + 1 file changed, 28 insertions(+), 3 deletions(-) + +--- a/drivers/input/touchscreen/edt-ft5x06.c ++++ b/drivers/input/touchscreen/edt-ft5x06.c +@@ -75,6 +75,8 @@ + #define EDT_DEFAULT_NUM_X 1024 + #define EDT_DEFAULT_NUM_Y 1024 + ++#define RESET_DELAY_MS 300 /* reset deassert to I2C */ ++#define FIRST_POLL_DELAY_MS 300 /* in addition to the above */ + #define POLL_INTERVAL_MS 17 /* 17ms = 60fps */ + + enum edt_pmode { +@@ -134,6 +136,7 @@ struct edt_ft5x06_ts_data { + + char name[EDT_NAME_LEN]; + char fw_version[EDT_NAME_LEN]; ++ int init_td_status; + + struct edt_reg_addr reg_addr; + enum edt_ver version; +@@ -268,12 +271,33 @@ static irqreturn_t edt_ft5x06_ts_isr(int + * points. + */ + num_points = min(rdbuf[2] & 0xf, tsdata->max_support_points); ++ ++ /* When polling FT5x06 without IRQ: initial register contents ++ * could be stale or undefined; discard all readings until ++ * TD_STATUS changes for the first time (or num_points is 0). ++ */ ++ if (tsdata->init_td_status) { ++ if (tsdata->init_td_status < 0) ++ tsdata->init_td_status = rdbuf[2]; ++ ++ if (num_points && rdbuf[2] == tsdata->init_td_status) ++ goto out; ++ ++ tsdata->init_td_status = 0; ++ } ++ + if (num_points) { + datalen = tplen * num_points + crclen; + cmd = offset; + error = edt_ft5x06_ts_readwrite(tsdata->client, + sizeof(cmd), &cmd, + datalen, &rdbuf[offset]); ++ if (error) { ++ dev_err_ratelimited(dev, ++ "Unable to fetch data, error: %d\n", ++ error); ++ goto out; ++ } + } + } + +@@ -1294,7 +1318,7 @@ static int edt_ft5x06_ts_probe(struct i2 + if (tsdata->reset_gpio) { + usleep_range(5000, 6000); + gpiod_set_value_cansleep(tsdata->reset_gpio, 0); +- msleep(300); ++ msleep(RESET_DELAY_MS); + } + + input = devm_input_allocate_device(&client->dev); +@@ -1384,11 +1408,12 @@ static int edt_ft5x06_ts_probe(struct i2 + return error; + } + } else { ++ tsdata->init_td_status = -1; /* filter bogus initial data */ + INIT_WORK(&tsdata->work_i2c_poll, + edt_ft5x06_ts_work_i2c_poll); + timer_setup(&tsdata->timer, edt_ft5x06_ts_irq_poll_timer, 0); +- tsdata->timer.expires = jiffies + +- msecs_to_jiffies(POLL_INTERVAL_MS); ++ tsdata->timer.expires = ++ jiffies + msecs_to_jiffies(FIRST_POLL_DELAY_MS); + add_timer(&tsdata->timer); + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-1029-overlays-mcp23017-allow-specification-of-the-i2c-bus.patch b/target/linux/bcm27xx/patches-6.1/950-1029-overlays-mcp23017-allow-specification-of-the-i2c-bus.patch new file mode 100644 index 0000000000..8cb35e1a79 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1029-overlays-mcp23017-allow-specification-of-the-i2c-bus.patch @@ -0,0 +1,97 @@ +From 27f0e0e195568c06f21ce380f0736bdd219baf3c Mon Sep 17 00:00:00 2001 +From: Janis Streib +Date: Sun, 15 Oct 2023 21:08:40 +0200 +Subject: [PATCH] overlays: mcp23017: allow specification of the i2c bus + +Analogous to i2c-rtc-overlay.dts + +See: https://github.com/raspberrypi/linux/pull/5650 +--- + arch/arm/boot/dts/overlays/README | 10 ++++++ + .../boot/dts/overlays/mcp23017-overlay.dts | 36 +++++++++++++++++-- + 2 files changed, 44 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2810,6 +2810,16 @@ Params: gpiopin Gpio pin + + mcp23008 Configure an MCP23008 instead. + noints Disable the interrupt GPIO line. ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ i2c_csi_dsi Choose the I2C0 bus on GPIOs 44&45 ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ i2c4 Choose the I2C4 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ i2c5 Choose the I2C5 bus (configure with the i2c5 ++ overlay - BCM2711 only) ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) + + + Name: mcp23s17 +--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts +@@ -7,7 +7,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2c1>; ++ target = <&i2cbus>; + __overlay__ { + status = "okay"; + }; +@@ -24,7 +24,7 @@ + }; + + fragment@2 { +- target = <&i2c1>; ++ target = <&i2cbus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; +@@ -58,12 +58,44 @@ + }; + }; + ++ frag100: fragment@100 { ++ target = <&i2c1>; ++ i2cbus: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@101 { ++ target = <&i2c0if>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&i2c0mux>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { + gpiopin = <&mcp23017_pins>,"brcm,pins:0", + <&mcp23017_irq>,"interrupts:0"; + addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0"; + mcp23008 = <0>,"=3"; + noints = <0>,"!1!4"; ++ i2c0 = <&frag100>, "target:0=",<&i2c0>; ++ i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, ++ <0>,"+101+102"; ++ i2c3 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c3"; ++ i2c4 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c4"; ++ i2c5 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c5"; ++ i2c6 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c6"; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1030-dts-bcm2712-Set-default-I2C-baudrates-to-100kHz.patch b/target/linux/bcm27xx/patches-6.1/950-1030-dts-bcm2712-Set-default-I2C-baudrates-to-100kHz.patch new file mode 100644 index 0000000000..e9422f1daa --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1030-dts-bcm2712-Set-default-I2C-baudrates-to-100kHz.patch @@ -0,0 +1,46 @@ +From 0339c8c61ca6b54c529f699e7bafd65cda9f3733 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 16 Oct 2023 09:06:25 +0100 +Subject: [PATCH] dts: bcm2712: Set default I2C baudrates to 100kHz + +The RP1 I2C interfaces were being left with their default clock rates, +apparently 400kHz. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 2 ++ + arch/arm/boot/dts/bcm2712-rpi.dtsi | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -250,11 +250,13 @@ i2c0mux: &rp1_gpio {}; + i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only + pinctrl-0 = <&rp1_i2c6_38_39>; + pinctrl-names = "default"; ++ clock-frequency = <100000>; + }; + + i2c_csi_dsi1: &i2c4 { // Note: This is for MIPI1 connector only + pinctrl-0 = <&rp1_i2c4_40_41>; + pinctrl-names = "default"; ++ clock-frequency = <100000>; + }; + + i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility +--- a/arch/arm/boot/dts/bcm2712-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2712-rpi.dtsi +@@ -204,11 +204,13 @@ uart4: &rp1_uart4 { }; + i2c_vc: &i2c0 { // This is pins 27,28 on the header (not MIPI) + pinctrl-0 = <&rp1_i2c0_0_1>; + pinctrl-names = "default"; ++ clock-frequency = <100000>; + }; + + i2c_arm: &i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&rp1_i2c1_2_3>; ++ clock-frequency = <100000>; + }; + + &i2c2 { diff --git a/target/linux/bcm27xx/patches-6.1/950-1031-vc_mem-Add-the-DMA-memcpy-support-from-bcm2708_fb.patch b/target/linux/bcm27xx/patches-6.1/950-1031-vc_mem-Add-the-DMA-memcpy-support-from-bcm2708_fb.patch new file mode 100644 index 0000000000..23d428789f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1031-vc_mem-Add-the-DMA-memcpy-support-from-bcm2708_fb.patch @@ -0,0 +1,345 @@ +From 2a47ccf97c6a91bc56f8cfb387d47f59cc347dd5 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Sat, 14 Oct 2023 14:57:49 +0100 +Subject: [PATCH] vc_mem: Add the DMA memcpy support from bcm2708_fb + +bcm2708_fb is disabled by the vc4-kms-v3d overlay, which means that the +DMA memcpy support it provides is not available to allow vclog to read +the VC logs from the top 16MB on Pi 2 and Pi 3. Add the code to the +vc_mem driver, which will still be enabled. + +It ought to be possible to do a proper DMA_MEM_TO_MEM copy via the +generic DMA customer API, but that can be a later step. + +Signed-off-by: Phil Elwell +--- + drivers/char/broadcom/vc_mem.c | 259 +++++++++++++++++++++++++++++++++ + 1 file changed, 259 insertions(+) + +--- a/drivers/char/broadcom/vc_mem.c ++++ b/drivers/char/broadcom/vc_mem.c +@@ -23,9 +23,21 @@ + #include + #include + #include ++#include ++#include ++#include + + #define DRIVER_NAME "vc-mem" + ++/* N.B. These use a different magic value for compatibility with bmc7208_fb */ ++#define VC_MEM_IOC_DMACOPY _IOW('z', 0x22, struct vc_mem_dmacopy) ++#define VC_MEM_IOC_DMACOPY32 _IOW('z', 0x22, struct vc_mem_dmacopy32) ++ ++/* address with no aliases */ ++#define INTALIAS_NORMAL(x) ((x) & ~0xc0000000) ++/* cache coherent but non-allocating in L1 and L2 */ ++#define INTALIAS_L1L2_NONALLOCATING(x) (((x) & ~0xc0000000) | 0x80000000) ++ + /* Device (/dev) related variables */ + static dev_t vc_mem_devnum; + static struct class *vc_mem_class; +@@ -36,6 +48,20 @@ static int vc_mem_inited; + static struct dentry *vc_mem_debugfs_entry; + #endif + ++struct vc_mem_dmacopy { ++ void *dst; ++ __u32 src; ++ __u32 length; ++}; ++ ++#ifdef CONFIG_COMPAT ++struct vc_mem_dmacopy32 { ++ compat_uptr_t dst; ++ __u32 src; ++ __u32 length; ++}; ++#endif ++ + /* + * Videocore memory addresses and size + * +@@ -62,6 +88,20 @@ static uint phys_addr; + static uint mem_size; + static uint mem_base; + ++struct vc_mem_dma { ++ struct device *dev; ++ int dma_chan; ++ int dma_irq; ++ void __iomem *dma_chan_base; ++ wait_queue_head_t dma_waitq; ++ void *cb_base; /* DMA control blocks */ ++ dma_addr_t cb_handle; ++}; ++ ++struct { u32 base, length; } gpu_mem; ++static struct mutex dma_mutex; ++static struct vc_mem_dma vc_mem_dma; ++ + static int + vc_mem_open(struct inode *inode, struct file *file) + { +@@ -99,6 +139,189 @@ vc_mem_get_current_size(void) + } + EXPORT_SYMBOL_GPL(vc_mem_get_current_size); + ++static int ++vc_mem_dma_init(void) ++{ ++ struct vc_mem_dma *vcdma = &vc_mem_dma; ++ struct platform_device *pdev; ++ struct device_node *fwnode; ++ struct rpi_firmware *fw; ++ struct device *dev; ++ u32 revision; ++ int rc; ++ ++ if (vcdma->dev) ++ return 0; ++ ++ fwnode = of_find_node_by_path("/system"); ++ rc = of_property_read_u32(fwnode, "linux,revision", &revision); ++ revision = (revision >> 12) & 0xf; ++ if (revision != 1 && revision != 2) { ++ /* Only BCM2709 and BCM2710 may have logs where the ARMs ++ * can't see them. ++ */ ++ return -ENXIO; ++ } ++ ++ fwnode = rpi_firmware_find_node(); ++ if (!fwnode) ++ return -ENXIO; ++ ++ pdev = of_find_device_by_node(fwnode); ++ dev = &pdev->dev; ++ ++ rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); ++ if (rc) ++ return rc; ++ ++ fw = rpi_firmware_get(fwnode); ++ if (!fw) ++ return -ENXIO; ++ rc = rpi_firmware_property(fw, RPI_FIRMWARE_GET_VC_MEMORY, ++ &gpu_mem, sizeof(gpu_mem)); ++ if (rc) ++ return rc; ++ ++ gpu_mem.base = INTALIAS_NORMAL(gpu_mem.base); ++ ++ if (!gpu_mem.base || !gpu_mem.length) { ++ dev_err(dev, "%s: unable to determine gpu memory (%x,%x)\n", ++ __func__, gpu_mem.base, gpu_mem.length); ++ return -EFAULT; ++ } ++ ++ vcdma->cb_base = dma_alloc_wc(dev, SZ_4K, &vcdma->cb_handle, GFP_KERNEL); ++ if (!vcdma->cb_base) { ++ dev_err(dev, "failed to allocate DMA CBs\n"); ++ return -ENOMEM; ++ } ++ ++ rc = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK, ++ &vcdma->dma_chan_base, ++ &vcdma->dma_irq); ++ if (rc < 0) { ++ dev_err(dev, "failed to allocate a DMA channel\n"); ++ goto free_cb; ++ } ++ ++ vcdma->dma_chan = rc; ++ ++ init_waitqueue_head(&vcdma->dma_waitq); ++ ++ vcdma->dev = dev; ++ ++ return 0; ++ ++free_cb: ++ dma_free_wc(dev, SZ_4K, vcdma->cb_base, vcdma->cb_handle); ++ ++ return rc; ++} ++ ++static void ++vc_mem_dma_uninit(void) ++{ ++ struct vc_mem_dma *vcdma = &vc_mem_dma; ++ ++ if (vcdma->dev) { ++ bcm_dma_chan_free(vcdma->dma_chan); ++ dma_free_wc(vcdma->dev, SZ_4K, vcdma->cb_base, vcdma->cb_handle); ++ vcdma->dev = NULL; ++ } ++} ++ ++static int dma_memcpy(struct vc_mem_dma *vcdma, dma_addr_t dst, dma_addr_t src, ++ int size) ++{ ++ struct bcm2708_dma_cb *cb = vcdma->cb_base; ++ int burst_size = (vcdma->dma_chan == 0) ? 8 : 2; ++ ++ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH | ++ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH | ++ BCM2708_DMA_D_INC; ++ cb->dst = dst; ++ cb->src = src; ++ cb->length = size; ++ cb->stride = 0; ++ cb->pad[0] = 0; ++ cb->pad[1] = 0; ++ cb->next = 0; ++ ++ bcm_dma_start(vcdma->dma_chan_base, vcdma->cb_handle); ++ bcm_dma_wait_idle(vcdma->dma_chan_base); ++ ++ return 0; ++} ++ ++static long vc_mem_copy(struct vc_mem_dmacopy *ioparam) ++{ ++ struct vc_mem_dma *vcdma = &vc_mem_dma; ++ size_t size = PAGE_SIZE; ++ const u32 dma_xfer_chunk = 256; ++ u32 *buf = NULL; ++ dma_addr_t bus_addr; ++ long rc = 0; ++ size_t offset; ++ ++ /* restrict this to root user */ ++ if (!uid_eq(current_euid(), GLOBAL_ROOT_UID)) ++ return -EFAULT; ++ ++ if (mutex_lock_interruptible(&dma_mutex)) ++ return -EINTR; ++ ++ rc = vc_mem_dma_init(); ++ if (rc) ++ goto out; ++ ++ vcdma = &vc_mem_dma; ++ ++ if (INTALIAS_NORMAL(ioparam->src) < gpu_mem.base || ++ INTALIAS_NORMAL(ioparam->src) >= gpu_mem.base + gpu_mem.length) { ++ pr_err("%s: invalid memory access %x (%x-%x)", __func__, ++ INTALIAS_NORMAL(ioparam->src), gpu_mem.base, ++ gpu_mem.base + gpu_mem.length); ++ rc = -EFAULT; ++ goto out; ++ } ++ ++ buf = dma_alloc_coherent(vcdma->dev, PAGE_ALIGN(size), &bus_addr, ++ GFP_ATOMIC); ++ if (!buf) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ for (offset = 0; offset < ioparam->length; offset += size) { ++ size_t remaining = ioparam->length - offset; ++ size_t s = min(size, remaining); ++ u8 *p = (u8 *)((uintptr_t)ioparam->src + offset); ++ u8 *q = (u8 *)ioparam->dst + offset; ++ ++ rc = dma_memcpy(vcdma, bus_addr, ++ INTALIAS_L1L2_NONALLOCATING((u32)(uintptr_t)p), ++ (s + dma_xfer_chunk - 1) & ~(dma_xfer_chunk - 1)); ++ if (rc) { ++ dev_err(vcdma->dev, "dma_memcpy failed\n"); ++ break; ++ } ++ if (copy_to_user(q, buf, s) != 0) { ++ pr_err("%s: copy_to_user failed\n", __func__); ++ rc = -EFAULT; ++ break; ++ } ++ } ++ ++out: ++ if (buf) ++ dma_free_coherent(vcdma->dev, PAGE_ALIGN(size), buf, ++ bus_addr); ++ ++ mutex_unlock(&dma_mutex); ++ ++ return rc; ++} ++ + static long + vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + { +@@ -163,6 +386,21 @@ vc_mem_ioctl(struct file *file, unsigned + } + break; + } ++ case VC_MEM_IOC_DMACOPY: ++ { ++ struct vc_mem_dmacopy ioparam; ++ /* Get the parameter data. ++ */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam))) { ++ pr_err("%s: copy_from_user failed\n", __func__); ++ rc = -EFAULT; ++ break; ++ } ++ ++ rc = vc_mem_copy(&ioparam); ++ break; ++ } + default: + { + return -ENOTTY; +@@ -193,6 +431,24 @@ vc_mem_compat_ioctl(struct file *file, u + + break; + ++ case VC_MEM_IOC_DMACOPY32: ++ { ++ struct vc_mem_dmacopy32 param32; ++ struct vc_mem_dmacopy param; ++ /* Get the parameter data. ++ */ ++ if (copy_from_user(¶m32, (void *)arg, sizeof(param32))) { ++ pr_err("%s: copy_from_user failed\n", __func__); ++ rc = -EFAULT; ++ break; ++ } ++ param.dst = compat_ptr(param32.dst); ++ param.src = param32.src; ++ param.length = param32.length; ++ rc = vc_mem_copy(¶m); ++ break; ++ } ++ + default: + rc = vc_mem_ioctl(file, cmd, arg); + break; +@@ -330,6 +586,7 @@ vc_mem_init(void) + vc_mem_debugfs_init(dev); + #endif + ++ mutex_init(&dma_mutex); + vc_mem_inited = 1; + return 0; + +@@ -352,6 +609,7 @@ vc_mem_exit(void) + { + pr_debug("%s: called\n", __func__); + ++ vc_mem_dma_uninit(); + if (vc_mem_inited) { + #ifdef CONFIG_DEBUG_FS + vc_mem_debugfs_deinit(); +@@ -360,6 +618,7 @@ vc_mem_exit(void) + class_destroy(vc_mem_class); + cdev_del(&vc_mem_cdev); + unregister_chrdev_region(vc_mem_devnum, 1); ++ vc_mem_inited = 0; + } + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-1032-drm-vc4-Correct-address-offset-for-planes-with-src_-.patch b/target/linux/bcm27xx/patches-6.1/950-1032-drm-vc4-Correct-address-offset-for-planes-with-src_-.patch new file mode 100644 index 0000000000..32112f949b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1032-drm-vc4-Correct-address-offset-for-planes-with-src_-.patch @@ -0,0 +1,48 @@ +From 6ab30a5dd3fb2ccbd918f147e91eb9bfe9849970 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 16 Oct 2023 12:13:38 +0100 +Subject: [PATCH] drm/vc4: Correct address offset for planes with src_[xy] + offsets + +11cf37e741b4 switched to using drm_fb_dma_get_gem_addr instead of +drm_fb_dma_get_gem_obj and adding fb->offset[]. + +However the tiled formats need to compute the offset in a more +involved manner than drm_fb_dma_get_gem_addr applies, and we +were ending up with the offset for src_[xy] being applied twice. + +Switch back to using drm_fb_dma_get_gem_obj and fully computing +the offsets ourselves. + +Fixes: 11cf37e741b4 ("drm/vc4: Move the buffer offset out of the vc4_plane_state") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_plane.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1447,9 +1447,9 @@ static int vc4_plane_mode_set(struct drm + vc4_state->ptr0_offset[0] = vc4_state->dlist_count; + + for (i = 0; i < num_planes; i++) { +- dma_addr_t paddr = drm_fb_dma_get_gem_addr(fb, state, i); ++ struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, i); + +- vc4_dlist_write(vc4_state, paddr + offsets[i]); ++ vc4_dlist_write(vc4_state, bo->dma_addr + fb->offsets[i] + offsets[i]); + } + + /* Pointer Context Word 0/1/2: Written by the HVS */ +@@ -1842,9 +1842,8 @@ static int vc6_plane_mode_set(struct drm + * TODO: This only covers Raster Scan Order planes + */ + for (i = 0; i < num_planes; i++) { +- dma_addr_t paddr = drm_fb_dma_get_gem_addr(fb, state, i); +- +- paddr += offsets[i]; ++ struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, i); ++ dma_addr_t paddr = bo->dma_addr + fb->offsets[i] + offsets[i]; + + /* Pointer Word 0 */ + vc4_state->ptr0_offset[i] = vc4_state->dlist_count; diff --git a/target/linux/bcm27xx/patches-6.1/950-1033-drivers-media-rp1_cfe-Fix-link-validate-test-for-pix.patch b/target/linux/bcm27xx/patches-6.1/950-1033-drivers-media-rp1_cfe-Fix-link-validate-test-for-pix.patch new file mode 100644 index 0000000000..3e1d504da0 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1033-drivers-media-rp1_cfe-Fix-link-validate-test-for-pix.patch @@ -0,0 +1,69 @@ +From c14550658832026e82111f2a89b3f7bf567afc1c Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Tue, 17 Oct 2023 09:35:44 +0100 +Subject: [PATCH] drivers: media: rp1_cfe: Fix link validate test for pixel + format + +Now that we have removed unique PISP media bus codes, the cfe format +table has multiple entries with the same media bus code for 16-bit +formats. The test in cfe_video_link_validate() did not account for this. +Fix it by testing the media bus code and the V4L2 pixelformat 4cc +together. + +As a drive-by, ensure we have a valid CSI2 datatype id when programming +the hardware block. + +Signed-off-by: Naushir Patuck +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -786,6 +786,9 @@ static void cfe_start_channel(struct cfe + width = source_fmt->width; + height = source_fmt->height; + ++ /* Must have a valid CSI2 datatype. */ ++ WARN_ON(!fmt->csi_dt); ++ + /* + * Start the associated CSI2 Channel as well. + * +@@ -809,6 +812,9 @@ static void cfe_start_channel(struct cfe + node_desc[node->id].link_pad - CSI2_NUM_CHANNELS); + fmt = find_format_by_code(source_fmt->code); + ++ /* Must have a valid CSI2 datatype. */ ++ WARN_ON(!fmt->csi_dt); ++ + if (is_image_output_node(node)) { + width = source_fmt->width; + height = source_fmt->height; +@@ -1504,7 +1510,8 @@ static int cfe_video_link_validate(struc + + if (is_image_output_node(node)) { + struct v4l2_pix_format *pix_fmt = &node->fmt.fmt.pix; +- const struct cfe_fmt *fmt; ++ const struct cfe_fmt *fmt = NULL; ++ unsigned int i; + + if (source_fmt->width != pix_fmt->width || + source_fmt->height != pix_fmt->height) { +@@ -1516,8 +1523,14 @@ static int cfe_video_link_validate(struc + goto out; + } + +- fmt = find_format_by_code(source_fmt->code); +- if (!fmt || fmt->fourcc != pix_fmt->pixelformat) { ++ for (i = 0; i < ARRAY_SIZE(formats); i++) { ++ if (formats[i].code == source_fmt->code && ++ formats[i].fourcc == pix_fmt->pixelformat) { ++ fmt = &formats[i]; ++ break; ++ } ++ } ++ if (!fmt) { + cfe_err("Format mismatch!\n"); + ret = -EINVAL; + goto out; diff --git a/target/linux/bcm27xx/patches-6.1/950-1034-dts-bcm2712-Use-the-new-model-name.patch b/target/linux/bcm27xx/patches-6.1/950-1034-dts-bcm2712-Use-the-new-model-name.patch new file mode 100644 index 0000000000..f30456835a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1034-dts-bcm2712-Use-the-new-model-name.patch @@ -0,0 +1,23 @@ +From b6bfece0d9ddf21e1526fead81340ef02f98f6ad Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 17 Oct 2023 17:28:11 +0100 +Subject: [PATCH] dts: bcm2712: Use the new model name + +"Model B" is no more - "Raspberry Pi 5" is the official name. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -52,7 +52,7 @@ + + / { + compatible = "raspberrypi,5-model-b", "brcm,bcm2712"; +- model = "Raspberry Pi 5 Model B"; ++ model = "Raspberry Pi 5"; + + /* Will be filled by the bootloader */ + memory@0 { diff --git a/target/linux/bcm27xx/patches-6.1/950-1035-fbdev-Allow-client-to-request-a-particular-dev-fbN-n.patch b/target/linux/bcm27xx/patches-6.1/950-1035-fbdev-Allow-client-to-request-a-particular-dev-fbN-n.patch new file mode 100644 index 0000000000..df87a1b757 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1035-fbdev-Allow-client-to-request-a-particular-dev-fbN-n.patch @@ -0,0 +1,93 @@ +From 0c7fb448e0e0e47c2b3be64e438208682c6a5e61 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 9 Oct 2023 16:32:45 +0100 +Subject: [PATCH] fbdev: Allow client to request a particular /dev/fbN node + +Add a flag custom_fb_num to denote that the client has +requested a specific fbdev node number via node. + +Signed-off-by: Dave Stevenson +--- + drivers/video/fbdev/core/fbmem.c | 24 +++++++++++++++++------- + include/linux/fb.h | 2 ++ + 2 files changed, 19 insertions(+), 7 deletions(-) + +--- a/drivers/video/fbdev/core/fbmem.c ++++ b/drivers/video/fbdev/core/fbmem.c +@@ -52,6 +52,7 @@ static DEFINE_MUTEX(registration_lock); + + struct fb_info *registered_fb[FB_MAX] __read_mostly; + int num_registered_fb __read_mostly; ++int min_dynamic_fb __read_mostly; + #define for_each_registered_fb(i) \ + for (i = 0; i < FB_MAX; i++) \ + if (!registered_fb[i]) {} else +@@ -1579,19 +1580,22 @@ static int do_register_framebuffer(struc + return -ENXIO; + + num_registered_fb++; +- for (i = 0 ; i < FB_MAX; i++) +- if (!registered_fb[i]) +- break; +- fb_info->node = i; ++ if (!fb_info->custom_fb_num || fb_info->node >= FB_MAX || registered_fb[fb_info->node]) { ++ for (i = min_dynamic_fb ; i < FB_MAX; i++) ++ if (!registered_fb[i]) ++ break; ++ fb_info->node = i; ++ } + refcount_set(&fb_info->count, 1); + mutex_init(&fb_info->lock); + mutex_init(&fb_info->mm_lock); + + fb_info->dev = device_create(fb_class, fb_info->device, +- MKDEV(FB_MAJOR, i), NULL, "fb%d", i); ++ MKDEV(FB_MAJOR, fb_info->node), NULL, "fb%d", fb_info->node); + if (IS_ERR(fb_info->dev)) { + /* Not fatal */ +- printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev)); ++ printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", ++ fb_info->node, PTR_ERR(fb_info->dev)); + fb_info->dev = NULL; + } else + fb_init_device(fb_info); +@@ -1624,7 +1628,7 @@ static int do_register_framebuffer(struc + + fb_var_to_videomode(&mode, &fb_info->var); + fb_add_videomode(&mode, &fb_info->modelist); +- registered_fb[i] = fb_info; ++ registered_fb[fb_info->node] = fb_info; + + #ifdef CONFIG_GUMSTIX_AM200EPD + { +@@ -1719,6 +1723,12 @@ static int fb_aperture_acquire_for_platf + return ret; + } + ++void fb_set_lowest_dynamic_fb(int min_fb_dev) ++{ ++ min_dynamic_fb = min_fb_dev; ++} ++EXPORT_SYMBOL(fb_set_lowest_dynamic_fb); ++ + /** + * register_framebuffer - registers a frame buffer device + * @fb_info: frame buffer info structure +--- a/include/linux/fb.h ++++ b/include/linux/fb.h +@@ -512,6 +512,7 @@ struct fb_info { + } *apertures; + + bool skip_vt_switch; /* no VT switch on suspend/resume required */ ++ bool custom_fb_num; /* Use value in node as the preferred node number */ + }; + + static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { +@@ -614,6 +615,7 @@ extern ssize_t fb_sys_write(struct fb_in + size_t count, loff_t *ppos); + + /* drivers/video/fbmem.c */ ++extern void fb_set_lowest_dynamic_fb(int min_fb_dev); + extern int register_framebuffer(struct fb_info *fb_info); + extern void unregister_framebuffer(struct fb_info *fb_info); + extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); diff --git a/target/linux/bcm27xx/patches-6.1/950-1036-drm-fb-helper-Look-up-preferred-fbdev-node-number-fr.patch b/target/linux/bcm27xx/patches-6.1/950-1036-drm-fb-helper-Look-up-preferred-fbdev-node-number-fr.patch new file mode 100644 index 0000000000..3e360be77b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1036-drm-fb-helper-Look-up-preferred-fbdev-node-number-fr.patch @@ -0,0 +1,41 @@ +From 1216ea56c2e30aee4975b4dcce79ebd199afaf8f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 9 Oct 2023 16:34:36 +0100 +Subject: [PATCH] drm/fb-helper: Look up preferred fbdev node number from DT + +For situations where there are multiple DRM cards in a system, +add a query of DT for "drm_fb" designations for cards to set +their preferred /dev/fbN designation. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/drm_fb_helper.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/drm_fb_helper.c ++++ b/drivers/gpu/drm/drm_fb_helper.c +@@ -1932,7 +1932,7 @@ __drm_fb_helper_initial_config_and_unloc + struct drm_device *dev = fb_helper->dev; + struct fb_info *info; + unsigned int width, height; +- int ret; ++ int ret, id; + + width = dev->mode_config.max_width; + height = dev->mode_config.max_height; +@@ -1967,6 +1967,15 @@ __drm_fb_helper_initial_config_and_unloc + * register the fbdev emulation instance in kernel_fb_helper_list. */ + mutex_unlock(&fb_helper->lock); + ++ id = of_alias_get_highest_id("drm_fb"); ++ if (id >= 0) ++ fb_set_lowest_dynamic_fb(id + 1); ++ ++ id = of_alias_get_id(dev->dev->of_node, "drm_fb"); ++ if (id >= 0) { ++ info->node = id; ++ info->custom_fb_num = true; ++ } + ret = register_framebuffer(info); + if (ret < 0) + return ret; diff --git a/target/linux/bcm27xx/patches-6.1/950-1037-dt-Add-overrides-for-drm-framebuffer-allocations-on-.patch b/target/linux/bcm27xx/patches-6.1/950-1037-dt-Add-overrides-for-drm-framebuffer-allocations-on-.patch new file mode 100644 index 0000000000..924c1b9f19 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1037-dt-Add-overrides-for-drm-framebuffer-allocations-on-.patch @@ -0,0 +1,72 @@ +From 61b138adaeaddefe749f421a3b69c67d4a49a8e3 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 11 Oct 2023 11:03:51 +0100 +Subject: [PATCH] dt: Add overrides for drm framebuffer allocations on Pi5 + +Adds dtparam overrides to the base Pi5 DT such that vc4, +DSI0, DSI1, or DPI can be requested to be /dev/fb[012]. +No override is specified by default, so the order will be +based on probe order (aka semi-random). Any device that +doesn't have an override specified will be placed above +all specified overrides. Having an fb1 or fb2 override but +no fb0 one will result in no console via fbcon. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 12 ++++++++++++ + arch/arm/boot/dts/overlays/README | 24 ++++++++++++++++++++++++ + 2 files changed, 36 insertions(+) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -824,5 +824,17 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + act_led_trigger = <&act_led>, "linux,default-trigger"; + pwr_led_activelow = <&pwr_led>, "gpios:8"; + pwr_led_trigger = <&pwr_led>, "linux,default-trigger"; ++ drm_fb0_rp1_dsi0 = <&aliases>, "drm_fb0=",&dsi0; ++ drm_fb0_rp1_dsi1 = <&aliases>, "drm_fb0=",&dsi1; ++ drm_fb0_rp1_dpi = <&aliases>, "drm_fb0=",&dpi; ++ drm_fb0_vc4 = <&aliases>, "drm_fb0=",&vc4; ++ drm_fb1_rp1_dsi0 = <&aliases>, "drm_fb1=",&dsi0; ++ drm_fb1_rp1_dsi1 = <&aliases>, "drm_fb1=",&dsi1; ++ drm_fb1_rp1_dpi = <&aliases>, "drm_fb1=",&dpi; ++ drm_fb1_vc4 = <&aliases>, "drm_fb1=",&vc4; ++ drm_fb2_rp1_dsi0 = <&aliases>, "drm_fb2=",&dsi0; ++ drm_fb2_rp1_dsi1 = <&aliases>, "drm_fb2=",&dsi1; ++ drm_fb2_rp1_dpi = <&aliases>, "drm_fb2=",&dpi; ++ drm_fb2_vc4 = <&aliases>, "drm_fb2=",&vc4; + }; + }; +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -173,6 +173,30 @@ Params: + cooling_fan Enables the Pi 5 cooling fan (enabled + automatically by the firmware) + ++ drm_fb0_rp1_dpi Assign /dev/fb0 to the RP1 DPI output ++ ++ drm_fb0_rp1_dsi0 Assign /dev/fb0 to the RP1 DSI0 output ++ ++ drm_fb0_rp1_dsi1 Assign /dev/fb0 to the RP1 DSI1 output ++ ++ drm_fb0_vc4 Assign /dev/fb0 to the vc4 outputs ++ ++ drm_fb1_rp1_dpi Assign /dev/fb1 to the RP1 DPI output ++ ++ drm_fb1_rp1_dsi0 Assign /dev/fb1 to the RP1 DSI0 output ++ ++ drm_fb1_rp1_dsi1 Assign /dev/fb1 to the RP1 DSI1 output ++ ++ drm_fb1_vc4 Assign /dev/fb1 to the vc4 outputs ++ ++ drm_fb2_rp1_dpi Assign /dev/fb2 to the RP1 DPI output ++ ++ drm_fb2_rp1_dsi0 Assign /dev/fb2 to the RP1 DSI0 output ++ ++ drm_fb2_rp1_dsi1 Assign /dev/fb2 to the RP1 DSI1 output ++ ++ drm_fb2_vc4 Assign /dev/fb2 to the vc4 outputs ++ + eee Enable Energy Efficient Ethernet support for + compatible devices (default "on"). See also + "tx_lpi_timer". Pi3B+ only. diff --git a/target/linux/bcm27xx/patches-6.1/950-1039-drm-connector-Change-DRM-card-alias-from-underscore-.patch b/target/linux/bcm27xx/patches-6.1/950-1039-drm-connector-Change-DRM-card-alias-from-underscore-.patch new file mode 100644 index 0000000000..57782d51c3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1039-drm-connector-Change-DRM-card-alias-from-underscore-.patch @@ -0,0 +1,26 @@ +From f429fc1a072d4bb35e622a1012a5a52914eba4e3 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 19 Oct 2023 10:34:58 +0100 +Subject: [PATCH] drm/connector: Change DRM card alias from underscore to + hyphen + +Apparently aliases are only allowed lower case and hyphens, +so swap the use of underscore to hyphen. + +Fixes: 3aa1f2477545 ("drm: Look for an alias for the displays to use as the DRM device name") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/drm_connector.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -112,7 +112,7 @@ static struct drm_conn_prop_enum_list dr + }; + + #define MAX_DT_NODE_NAME_LEN 20 +-#define DT_DRM_NODE_PREFIX "drm_" ++#define DT_DRM_NODE_PREFIX "drm-" + + static void drm_connector_get_of_name(int type, char *node_name, int length) + { diff --git a/target/linux/bcm27xx/patches-6.1/950-1040-dt-Alter-alias-names-from-_-to-for-drm_dsiN.patch b/target/linux/bcm27xx/patches-6.1/950-1040-dt-Alter-alias-names-from-_-to-for-drm_dsiN.patch new file mode 100644 index 0000000000..0536924d05 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1040-dt-Alter-alias-names-from-_-to-for-drm_dsiN.patch @@ -0,0 +1,24 @@ +From e33170e21494279801e9f17eeb910ec45ebd740c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 19 Oct 2023 10:28:43 +0100 +Subject: [PATCH] dt: Alter alias names from _ to - for drm_dsiN + +Fixes: 7ec42740a45b ("dt: Add DSI1 and DSI2 aliases to 2712") +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -787,8 +787,8 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + gpio4 = &pinctrl_aon; + usb0 = &rp1_usb0; + usb1 = &rp1_usb1; +- drm_dsi1 = &dsi0; +- drm_dsi2 = &dsi1; ++ drm-dsi1 = &dsi0; ++ drm-dsi2 = &dsi1; + }; + + __overrides__ { diff --git a/target/linux/bcm27xx/patches-6.1/950-1041-drm-fb_helper-Change-query-for-FB-designation-from-d.patch b/target/linux/bcm27xx/patches-6.1/950-1041-drm-fb_helper-Change-query-for-FB-designation-from-d.patch new file mode 100644 index 0000000000..78e5b89be4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1041-drm-fb_helper-Change-query-for-FB-designation-from-d.patch @@ -0,0 +1,28 @@ +From 0e9e925112fabdbd448e17947796317a6dbca96e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 19 Oct 2023 10:32:04 +0100 +Subject: [PATCH] drm/fb_helper: Change query for FB designation from drm_fb to + drm-fb + +Fixes: 1216ea56c2e3 ("drm/fb-helper: Look up preferred fbdev node number from DT") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/drm_fb_helper.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/drm_fb_helper.c ++++ b/drivers/gpu/drm/drm_fb_helper.c +@@ -1967,11 +1967,11 @@ __drm_fb_helper_initial_config_and_unloc + * register the fbdev emulation instance in kernel_fb_helper_list. */ + mutex_unlock(&fb_helper->lock); + +- id = of_alias_get_highest_id("drm_fb"); ++ id = of_alias_get_highest_id("drm-fb"); + if (id >= 0) + fb_set_lowest_dynamic_fb(id + 1); + +- id = of_alias_get_id(dev->dev->of_node, "drm_fb"); ++ id = of_alias_get_id(dev->dev->of_node, "drm-fb"); + if (id >= 0) { + info->node = id; + info->custom_fb_num = true; diff --git a/target/linux/bcm27xx/patches-6.1/950-1042-dt-Alter-alias-names-from-_-to-for-drm_fbN_-override.patch b/target/linux/bcm27xx/patches-6.1/950-1042-dt-Alter-alias-names-from-_-to-for-drm_fbN_-override.patch new file mode 100644 index 0000000000..42865dc7ff --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1042-dt-Alter-alias-names-from-_-to-for-drm_fbN_-override.patch @@ -0,0 +1,43 @@ +From 87be94059193d0bc64d52a9535df4fb1891c72fe Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 19 Oct 2023 10:29:20 +0100 +Subject: [PATCH] dt: Alter alias names from _ to - for drm_fbN_* overrides + +Fixes: 61b138adaead ("dt: Add overrides for drm framebuffer allocations on Pi5") +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -824,17 +824,17 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + act_led_trigger = <&act_led>, "linux,default-trigger"; + pwr_led_activelow = <&pwr_led>, "gpios:8"; + pwr_led_trigger = <&pwr_led>, "linux,default-trigger"; +- drm_fb0_rp1_dsi0 = <&aliases>, "drm_fb0=",&dsi0; +- drm_fb0_rp1_dsi1 = <&aliases>, "drm_fb0=",&dsi1; +- drm_fb0_rp1_dpi = <&aliases>, "drm_fb0=",&dpi; +- drm_fb0_vc4 = <&aliases>, "drm_fb0=",&vc4; +- drm_fb1_rp1_dsi0 = <&aliases>, "drm_fb1=",&dsi0; +- drm_fb1_rp1_dsi1 = <&aliases>, "drm_fb1=",&dsi1; +- drm_fb1_rp1_dpi = <&aliases>, "drm_fb1=",&dpi; +- drm_fb1_vc4 = <&aliases>, "drm_fb1=",&vc4; +- drm_fb2_rp1_dsi0 = <&aliases>, "drm_fb2=",&dsi0; +- drm_fb2_rp1_dsi1 = <&aliases>, "drm_fb2=",&dsi1; +- drm_fb2_rp1_dpi = <&aliases>, "drm_fb2=",&dpi; +- drm_fb2_vc4 = <&aliases>, "drm_fb2=",&vc4; ++ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; ++ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; ++ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; ++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; ++ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0; ++ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1; ++ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi; ++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; ++ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0; ++ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; ++ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; ++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-1044-Typo-in-overlays-README.patch b/target/linux/bcm27xx/patches-6.1/950-1044-Typo-in-overlays-README.patch new file mode 100644 index 0000000000..19720e8645 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1044-Typo-in-overlays-README.patch @@ -0,0 +1,21 @@ +From cb8a4adb586c5e926e415ac0dae3ffb4af30b0a9 Mon Sep 17 00:00:00 2001 +From: Andrew Scheller +Date: Thu, 19 Oct 2023 14:13:36 +0100 +Subject: [PATCH] Typo in overlays README + +touchscreen-size-y for rpi-ft5406 defaults to 480, not 600 +--- + arch/arm/boot/dts/overlays/README | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -3738,7 +3738,7 @@ Name: rpi-ft5406 + Info: Official Raspberry Pi display touchscreen + Load: dtoverlay=rpi-ft5406,= + Params: touchscreen-size-x Touchscreen X resolution (default 800) +- touchscreen-size-y Touchscreen Y resolution (default 600); ++ touchscreen-size-y Touchscreen Y resolution (default 480); + touchscreen-inverted-x Invert touchscreen X coordinates (default 0); + touchscreen-inverted-y Invert touchscreen Y coordinates (default 0); + touchscreen-swapped-x-y Swap X and Y cordinates (default 0); diff --git a/target/linux/bcm27xx/patches-6.1/950-1045-dts-bcm2712-Add-the-krnbt-parameter.patch b/target/linux/bcm27xx/patches-6.1/950-1045-dts-bcm2712-Add-the-krnbt-parameter.patch new file mode 100644 index 0000000000..95940dd830 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1045-dts-bcm2712-Add-the-krnbt-parameter.patch @@ -0,0 +1,23 @@ +From 4cb97982f88d8fb623ace5a9511198e442e993ba Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 20 Oct 2023 17:15:25 +0100 +Subject: [PATCH] dts: bcm2712: Add the krnbt parameter + +Add a Pi 5 implementation of the krnbt parameter, for symmetry and +for tinkering purposes. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -809,6 +809,7 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; + i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; + i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; ++ krnbt = <&bluetooth>, "status"; + nvme = <&pciex1>, "status"; + pciex1 = <&pciex1>, "status"; + pciex1_gen = <&pciex1> , "max-link-speed:0"; diff --git a/target/linux/bcm27xx/patches-6.1/950-1047-drm-vc4_fkms-Fix-up-interrupt-handler-for-both-2835-.patch b/target/linux/bcm27xx/patches-6.1/950-1047-drm-vc4_fkms-Fix-up-interrupt-handler-for-both-2835-.patch new file mode 100644 index 0000000000..99b8426e1c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1047-drm-vc4_fkms-Fix-up-interrupt-handler-for-both-2835-.patch @@ -0,0 +1,109 @@ +From 4137b49989ce710305e476d0bd1086d7d906ff50 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 20 Oct 2023 17:09:54 +0100 +Subject: [PATCH] drm/vc4_fkms: Fix up interrupt handler for both 2835/2711 and + 2712 + +2712 has switched from using the SMI peripheral to another interrupt +source for the vsync interrupt, so handle both sources cleanly. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++++------ + 1 file changed, 38 insertions(+), 10 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -47,9 +47,15 @@ struct get_display_cfg { + u32 max_pixel_clock[2]; //Max pixel clock for each display + }; + ++enum vc4_fkms_revision { ++ BCM2835_6_7, ++ BCM2711, ++ BCM2712, ++}; ++ + struct vc4_fkms { + struct get_display_cfg cfg; +- bool bcm2711; ++ enum vc4_fkms_revision revision; + }; + + #define PLANES_PER_CRTC 8 +@@ -1149,7 +1155,7 @@ vc4_crtc_mode_valid(struct drm_crtc *crt + /* Pi4 can't generate odd horizontal timings on HDMI, so reject modes + * that would set them. + */ +- if (fkms->bcm2711 && ++ if (fkms->revision >= BCM2711 && + (vc4_crtc->display_number == 2 || vc4_crtc->display_number == 7) && + !(mode->flags & DRM_MODE_FLAG_DBLCLK) && + ((mode->hdisplay | /* active */ +@@ -1267,6 +1273,20 @@ static irqreturn_t vc4_crtc_irq_handler( + return ret; + } + ++static irqreturn_t vc4_crtc2712_irq_handler(int irq, void *data) ++{ ++ struct vc4_crtc **crtc_list = data; ++ int i; ++ ++ for (i = 0; crtc_list[i]; i++) { ++ if (crtc_list[i]->vblank_enabled) ++ drm_crtc_handle_vblank(&crtc_list[i]->base); ++ vc4_crtc_handle_page_flip(crtc_list[i]); ++ } ++ ++ return IRQ_HANDLED; ++} ++ + static int vc4_fkms_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, +@@ -1352,9 +1372,12 @@ static const struct drm_crtc_helper_func + }; + + static const struct of_device_id vc4_firmware_kms_dt_match[] = { +- { .compatible = "raspberrypi,rpi-firmware-kms" }, ++ { .compatible = "raspberrypi,rpi-firmware-kms", ++ .data = (void *)BCM2835_6_7 }, + { .compatible = "raspberrypi,rpi-firmware-kms-2711", +- .data = (void *)1 }, ++ .data = (void *)BCM2711 }, ++ { .compatible = "raspberrypi,rpi-firmware-kms-2712", ++ .data = (void *)BCM2712 }, + {} + }; + +@@ -1924,8 +1947,7 @@ static int vc4_fkms_bind(struct device * + match = of_match_device(vc4_firmware_kms_dt_match, dev); + if (!match) + return -ENODEV; +- if (match->data) +- fkms->bcm2711 = true; ++ fkms->revision = (enum vc4_fkms_revision)match->data; + + firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0); + vc4->firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); +@@ -1992,10 +2014,16 @@ static int vc4_fkms_bind(struct device * + if (IS_ERR(crtc_list[0]->regs)) + DRM_ERROR("Oh dear, failed to map registers\n"); + +- writel(0, crtc_list[0]->regs + SMICS); +- ret = devm_request_irq(dev, platform_get_irq(pdev, 0), +- vc4_crtc_irq_handler, 0, +- "vc4 firmware kms", crtc_list); ++ if (fkms->revision >= BCM2712) { ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_crtc2712_irq_handler, 0, ++ "vc4 firmware kms", crtc_list); ++ } else { ++ writel(0, crtc_list[0]->regs + SMICS); ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_crtc_irq_handler, 0, ++ "vc4 firmware kms", crtc_list); ++ } + if (ret) + DRM_ERROR("Oh dear, failed to register IRQ\n"); + } else { diff --git a/target/linux/bcm27xx/patches-6.1/950-1048-dt-Switch-bcm2712-firmware-kms-node-to-using-the-271.patch b/target/linux/bcm27xx/patches-6.1/950-1048-dt-Switch-bcm2712-firmware-kms-node-to-using-the-271.patch new file mode 100644 index 0000000000..9dea2d0fff --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1048-dt-Switch-bcm2712-firmware-kms-node-to-using-the-271.patch @@ -0,0 +1,25 @@ +From 5a52cae54a05499a8487f392cf5dfc3d8a837e6f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 20 Oct 2023 17:12:09 +0100 +Subject: [PATCH] dt: Switch bcm2712 firmware-kms node to using the 2712 + compatible + +With the new compatible to handle the interrupts correctly, switch +the base dt to use it. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2712.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2712.dtsi ++++ b/arch/arm/boot/dts/bcm2712.dtsi +@@ -103,7 +103,7 @@ + }; + + firmwarekms: firmwarekms@7d503000 { +- compatible = "raspberrypi,rpi-firmware-kms"; ++ compatible = "raspberrypi,rpi-firmware-kms-2712"; + /* SUN_L2 interrupt reg */ + reg = <0x7d503000 0x18>; + interrupt-parent = <&cpu_l2_irq>; diff --git a/target/linux/bcm27xx/patches-6.1/950-1049-drivers-media-imx477-Disable-the-scaler.patch b/target/linux/bcm27xx/patches-6.1/950-1049-drivers-media-imx477-Disable-the-scaler.patch new file mode 100644 index 0000000000..841fa42440 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1049-drivers-media-imx477-Disable-the-scaler.patch @@ -0,0 +1,35 @@ +From f075893e9b0e241879998c0b12cf8af0ba7737da Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Mon, 23 Oct 2023 10:03:03 +0100 +Subject: [PATCH] drivers: media: imx477: Disable the scaler + +The horizontal scaler was enabled for the 2028x1520 and 2028x1080 modes, +with a scale factor of 1. It caused a single column of bad pixels on the +right edge of the image. Since scaling is not needed for these modes, +disable it entirely. + +Signed-off-by: Naushir Patuck +--- + drivers/media/i2c/imx477.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/media/i2c/imx477.c ++++ b/drivers/media/i2c/imx477.c +@@ -632,7 +632,7 @@ static const struct imx477_reg mode_2028 + {0x9e9f, 0x00}, + {0xa2a9, 0x60}, + {0xa2b7, 0x00}, +- {0x0401, 0x01}, ++ {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x20}, + {0x0408, 0x00}, +@@ -733,7 +733,7 @@ static const struct imx477_reg mode_2028 + {0x9e9f, 0x00}, + {0xa2a9, 0x60}, + {0xa2b7, 0x00}, +- {0x0401, 0x01}, ++ {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x20}, + {0x0408, 0x00}, diff --git a/target/linux/bcm27xx/patches-6.1/950-1050-dt-Add-drm_fbN_vc4-overrides-for-Pi0-4.patch b/target/linux/bcm27xx/patches-6.1/950-1050-dt-Add-drm_fbN_vc4-overrides-for-Pi0-4.patch new file mode 100644 index 0000000000..77f30a345d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1050-dt-Add-drm_fbN_vc4-overrides-for-Pi0-4.patch @@ -0,0 +1,37 @@ +From eccaa8588fca9c9ec950664f1d5894bd826b57b0 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 23 Oct 2023 14:10:15 +0100 +Subject: [PATCH] dt: Add drm_fbN_vc4 overrides for Pi0-4 + +Follows up '61b138adaead ("dt: Add overrides for drm framebuffer +allocations on Pi5")' with an equivalent for Pi0-4. + +These will have no effect on most normal systems, but drm_fb0_vc4 +will stop SPI displays jumping in and claiming /dev/fb0. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm270x-rpi.dtsi | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm270x-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi +@@ -1,7 +1,7 @@ + /* Downstream modifications to bcm2835-rpi.dtsi */ + + / { +- aliases { ++ aliases: aliases { + aux = &aux; + sound = &sound; + soc = &soc; +@@ -98,6 +98,9 @@ + sdio_overclock = <&mmc>,"brcm,overclock-50:0", + <&mmcnr>,"brcm,overclock-50:0"; + axiperf = <&axiperf>,"status"; ++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; ++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; ++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1051-fixup-overlays-mcp23017-allow-specification-of-the-i.patch b/target/linux/bcm27xx/patches-6.1/950-1051-fixup-overlays-mcp23017-allow-specification-of-the-i.patch new file mode 100644 index 0000000000..5016e78778 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1051-fixup-overlays-mcp23017-allow-specification-of-the-i.patch @@ -0,0 +1,95 @@ +From 3ed6d34d53e94ecbebc64c8fa3d1b6d3c41db8fb Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 24 Oct 2023 09:58:52 +0100 +Subject: [PATCH] fixup! overlays: mcp23017: allow specification of the i2c bus + +The incorrect fragment order (*) caused broke the interrupt usage, and +while it was being fixed the lack of a reference to the pinctrl +declaration was noticed. + +See: https://github.com/raspberrypi/linux/issues/5677 + +Signed-off-by: Phil Elwell + +(*) Ideally all fragments would appear in the file in the order in which +they should be merged, but that is easy to forget and can be awkward, so +the firmware merges all "intra" fragments (those that target other +fragments in the overlay) before "inter" fragments (those that target +the base DTB). However, intra fragments that target other intra +fragments is a level of nesting too far for this logic to cope, so they +must appear before the fragments they target. +--- + .../boot/dts/overlays/mcp23017-overlay.dts | 42 ++++++++++--------- + 1 file changed, 22 insertions(+), 20 deletions(-) + +--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts +@@ -24,30 +24,13 @@ + }; + + fragment@2 { +- target = <&i2cbus>; +- __overlay__ { +- #address-cells = <1>; +- #size-cells = <0>; +- +- mcp23017: mcp@20 { +- compatible = "microchip,mcp23017"; +- reg = <0x20>; +- gpio-controller; +- #gpio-cells = <2>; +- +- status = "okay"; +- }; +- }; +- }; +- +- fragment@3 { + target = <&mcp23017>; + __dormant__ { + compatible = "microchip,mcp23008"; + }; + }; + +- fragment@4 { ++ fragment@3 { + target = <&mcp23017>; + mcp23017_irq: __overlay__ { + #interrupt-cells=<2>; +@@ -58,6 +41,25 @@ + }; + }; + ++ fragment@4 { ++ target = <&i2cbus>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ mcp23017: mcp@20 { ++ compatible = "microchip,mcp23017"; ++ pinctrl-name = "default"; ++ pinctrl-0 = <&mcp23017_pins>; ++ reg = <0x20>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ status = "okay"; ++ }; ++ }; ++ }; ++ + frag100: fragment@100 { + target = <&i2c1>; + i2cbus: __overlay__ { +@@ -83,8 +85,8 @@ + gpiopin = <&mcp23017_pins>,"brcm,pins:0", + <&mcp23017_irq>,"interrupts:0"; + addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0"; +- mcp23008 = <0>,"=3"; +- noints = <0>,"!1!4"; ++ mcp23008 = <0>,"=2"; ++ noints = <0>,"!1!3"; + i2c0 = <&frag100>, "target:0=",<&i2c0>; + i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, + <0>,"+101+102"; diff --git a/target/linux/bcm27xx/patches-6.1/950-1052-drivers-media-pisp_be-Add-back-V4L2_PIX_FMT_RPI_BE-f.patch b/target/linux/bcm27xx/patches-6.1/950-1052-drivers-media-pisp_be-Add-back-V4L2_PIX_FMT_RPI_BE-f.patch new file mode 100644 index 0000000000..7fe0c50740 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1052-drivers-media-pisp_be-Add-back-V4L2_PIX_FMT_RPI_BE-f.patch @@ -0,0 +1,54 @@ +From 8d53cc5b4b2a6f9baed7a0aa801a39ad9dce9bf8 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 26 Oct 2023 08:55:24 +0100 +Subject: [PATCH] drivers: media: pisp_be: Add back V4L2_PIX_FMT_RPI_BE format + +Add the opaque V4L2_PIX_FMT_RPI_BE format back to the format list as it +is needed for the verification test suite. Also set the default format +to YUV420 non-multiplanar. + +Signed-off-by: Naushir Patuck +--- + drivers/media/platform/raspberrypi/pisp_be/pisp_be.c | 9 ++++++--- + .../media/platform/raspberrypi/pisp_be/pisp_be_formats.h | 5 +++++ + 2 files changed, 11 insertions(+), 3 deletions(-) + +--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c +@@ -1230,8 +1230,11 @@ static int try_format(struct v4l2_format + return verify_be_pix_format(f, node); + + fmt = find_format(pixfmt); +- if (!fmt) +- fmt = find_format(V4L2_PIX_FMT_YUV420M); ++ if (!fmt) { ++ dev_dbg(pispbe->dev, "%s: [%s] Format not found, defaulting to YUV420\n", ++ __func__, NODE_NAME(node)); ++ fmt = find_format(V4L2_PIX_FMT_YUV420); ++ } + + f->fmt.pix_mp.pixelformat = fmt->fourcc; + f->fmt.pix_mp.num_planes = fmt->num_planes; +@@ -1576,7 +1579,7 @@ static void node_set_default_format(stru + } else { + struct v4l2_format f = {0}; + +- f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M; ++ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420; + f.fmt.pix_mp.width = 1920; + f.fmt.pix_mp.height = 1080; + f.type = node->buf_type; +--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h +@@ -457,6 +457,11 @@ static const struct pisp_be_format suppo + .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, + .colorspace_default = V4L2_COLORSPACE_RAW, + }, ++ /* Opaque BE format for HW verification. */ ++ { ++ .fourcc = V4L2_PIX_FMT_RPI_BE, ++ .align = 32, ++ }, + }; + + static const struct pisp_be_format meta_out_supported_formats[] = { diff --git a/target/linux/bcm27xx/patches-6.1/950-1053-dt-bindings-PCI-brcmstb-add-optional-property-brcm-t.patch b/target/linux/bcm27xx/patches-6.1/950-1053-dt-bindings-PCI-brcmstb-add-optional-property-brcm-t.patch new file mode 100644 index 0000000000..3ef42e7967 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1053-dt-bindings-PCI-brcmstb-add-optional-property-brcm-t.patch @@ -0,0 +1,32 @@ +From f1154884295a4bd00d6ebcaf01fa30141145903d Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 20 Sep 2023 10:04:15 +0100 +Subject: [PATCH] dt-bindings: PCI: brcmstb: add optional property - + "brcm,tperst-clk-ms" + +This property can be used to delay deassertion of external fundamental +reset, which may be useful for endpoints that require an extended time for +internal setup to complete. + +Signed-off-by: Jonathan Bell +--- + Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml ++++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml +@@ -77,6 +77,14 @@ properties: + minItems: 1 + maxItems: 3 + ++ brcm,tperst-clk-ms: ++ category: optional ++ type: int ++ description: u32 giving the number of milliseconds to extend ++ the time between internal release of fundamental reset and ++ the deassertion of the external PERST# pin. This has the ++ effect of increasing the Tperst_clk phase of link init. ++ + required: + - compatible + - reg diff --git a/target/linux/bcm27xx/patches-6.1/950-1054-drivers-pci-brcmstb-optionally-extend-Tperst_clk-tim.patch b/target/linux/bcm27xx/patches-6.1/950-1054-drivers-pci-brcmstb-optionally-extend-Tperst_clk-tim.patch new file mode 100644 index 0000000000..021e210591 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1054-drivers-pci-brcmstb-optionally-extend-Tperst_clk-tim.patch @@ -0,0 +1,71 @@ +From 4b0c6453808a662869a43c504913f3b7ed64486a Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 20 Sep 2023 13:01:11 +0100 +Subject: [PATCH] drivers: pci: brcmstb: optionally extend Tperst_clk time + during link-up + +The RC has a feature that allows for manual control over the deassertion +of the PERST# output pin, which allows the time between refclk active +and reset deassert at the EP to be increased. + +Signed-off-by: Jonathan Bell +--- + drivers/pci/controller/pcie-brcmstb.c | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -138,6 +138,7 @@ + + #define PCIE_MISC_HARD_PCIE_HARD_DEBUG pcie->reg_offsets[PCIE_HARD_DEBUG] + #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK 0x8 + #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 + #define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000 + #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK 0x00200000 +@@ -352,6 +353,7 @@ struct brcm_pcie { + bool (*rc_mode)(struct brcm_pcie *pcie); + struct subdev_regulators *sr; + bool ep_wakeup_capable; ++ u32 tperst_clk_ms; + }; + + static inline bool is_bmips(const struct brcm_pcie *pcie) +@@ -1388,9 +1390,28 @@ static int brcm_pcie_start_link(struct b + u16 nlw, cls, lnksta; + bool ssc_good = false; + int ret, i; ++ u32 tmp; + + /* Unassert the fundamental reset */ +- pcie->perst_set(pcie, 0); ++ if (pcie->tperst_clk_ms) { ++ /* ++ * Increase Tperst_clk time by forcing PERST# output low while ++ * the internal reset is released, so the PLL generates stable ++ * refclk output further in advance of PERST# deassertion. ++ */ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK); ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ ++ pcie->perst_set(pcie, 0); ++ msleep(pcie->tperst_clk_ms); ++ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK); ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ } else { ++ pcie->perst_set(pcie, 0); ++ } + + /* + * Wait for 100ms after PERST# deassertion; see PCIe CEM specification +@@ -1923,6 +1944,7 @@ static int brcm_pcie_probe(struct platfo + pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc"); + pcie->l1ss = of_property_read_bool(np, "brcm,enable-l1ss"); + pcie->rcb_mps_mode = of_property_read_bool(np, "brcm,enable-mps-rcb"); ++ of_property_read_u32(np, "brcm,tperst-clk-ms", &pcie->tperst_clk_ms); + + ret = clk_prepare_enable(pcie->clk); + if (ret) { diff --git a/target/linux/bcm27xx/patches-6.1/950-1055-arm-dt-add-dtparams-for-PCIe-reset-timing-override.patch b/target/linux/bcm27xx/patches-6.1/950-1055-arm-dt-add-dtparams-for-PCIe-reset-timing-override.patch new file mode 100644 index 0000000000..a81d0383ac --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1055-arm-dt-add-dtparams-for-PCIe-reset-timing-override.patch @@ -0,0 +1,59 @@ +From db90a5e5fc2fbd843b29eb8110ed5e03604a2887 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 20 Sep 2023 13:04:54 +0100 +Subject: [PATCH] arm: dt: add dtparams for PCIe reset timing override + +The Pi 5 variant gets two parameters so that the CM4-compatible +name will also work on Pi 5. + +Signed-off-by: Jonathan Bell +--- + arch/arm/boot/dts/bcm2711-rpi-cm4.dts | 2 ++ + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 2 ++ + arch/arm/boot/dts/overlays/README | 7 +++++++ + 3 files changed, 11 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts +@@ -446,5 +446,7 @@ i2c_csi_dsi0: &i2c0 { + cam1_reg = <&cam1_reg>,"status"; + cam1_reg_gpio = <&cam1_reg>,"gpio:4", + <&cam1_reg>,"gpio:0=", <&gpio>; ++ ++ pcie_tperst_clk_ms = <&pcie0>,"brcm,tperst-clk-ms:0"; + }; + }; +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -814,6 +814,8 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + pciex1 = <&pciex1>, "status"; + pciex1_gen = <&pciex1> , "max-link-speed:0"; + pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; ++ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; ++ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; + random = <&random>, "status"; + rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; + spi = <&spi0>, "status"; +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -280,6 +280,10 @@ Params: + (2711 only, but not applicable on CM4S) + N.B. USB-A ports on 4B are subsequently disabled + ++ pcie_tperst_clk_ms Add N milliseconds between PCIe reference clock ++ activation and PERST# deassertion ++ (CM4 and 2712, default "0") ++ + pciex1 Set to "on" to enable the external PCIe link + (2712 only, default "off") + +@@ -290,6 +294,9 @@ Params: + PCIe link for devices that have broken + implementations (2712 only, default "off") + ++ pciex1_tperst_clk_ms Alias for pcie_tperst_clk_ms ++ (2712 only, default "0") ++ + spi Set to "on" to enable the spi interfaces + (default "off") + diff --git a/target/linux/bcm27xx/patches-6.1/950-1056-arm-dt-bcm2712-don-t-unconditionally-enable-MPS-read.patch b/target/linux/bcm27xx/patches-6.1/950-1056-arm-dt-bcm2712-don-t-unconditionally-enable-MPS-read.patch new file mode 100644 index 0000000000..b08a5720d5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1056-arm-dt-bcm2712-don-t-unconditionally-enable-MPS-read.patch @@ -0,0 +1,35 @@ +From cb013b6602de32c647ed08faf899596664a18635 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Thu, 26 Oct 2023 13:47:54 +0100 +Subject: [PATCH] arm: dt: bcm2712: don't unconditionally enable MPS read + completions + +RP1 supports it, but it's not a given that an arbitrary EP device +on PCIE2 will. Migrate the property to the rp1_target fragment. + +Signed-off-by: Jonathan Bell +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 1 + + arch/arm/boot/dts/bcm2712.dtsi | 1 - + 2 files changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -160,6 +160,7 @@ + }; + + rp1_target: &pcie2 { ++ brcm,enable-mps-rcb; + brcm,vdm-qos-map = <0xbbaa9888>; + aspm-no-l0s; + status = "okay"; +--- a/arch/arm/boot/dts/bcm2712.dtsi ++++ b/arch/arm/boot/dts/bcm2712.dtsi +@@ -1086,7 +1086,6 @@ + 0x00 0x00000000 + 0x10 0x00000000>; + +- brcm,enable-mps-rcb; + brcm,enable-l1ss; + status = "disabled"; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-1057-drivers-media-imx477-Set-horizontal-binning-when-dis.patch b/target/linux/bcm27xx/patches-6.1/950-1057-drivers-media-imx477-Set-horizontal-binning-when-dis.patch new file mode 100644 index 0000000000..e6122e1a6b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1057-drivers-media-imx477-Set-horizontal-binning-when-dis.patch @@ -0,0 +1,39 @@ +From 8dcc16f0adc50f5cb8a11a6dde238131d0ca45a0 Mon Sep 17 00:00:00 2001 +From: David Plowman +Date: Fri, 27 Oct 2023 12:14:22 +0100 +Subject: [PATCH] drivers: media: imx477: Set horizontal binning when disabling + the scaler + +The horizontal scaler has been disabled but actually the sensor is not +binning horizontally, resulting in images that are stretched 2x +horizontally (missing the right half of the field of view completely). + +Therefore we must additionally set the horizontal binning mode. There +is only marginal change in output quality and noise levels. + +Signed-off-by: David Plowman +Fixes: f075893e9b0e ("drivers: media: imx477: Disable the scaler") +--- + drivers/media/i2c/imx477.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/media/i2c/imx477.c ++++ b/drivers/media/i2c/imx477.c +@@ -607,7 +607,7 @@ static const struct imx477_reg mode_2028 + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0900, 0x01}, +- {0x0901, 0x12}, ++ {0x0901, 0x22}, + {0x0902, 0x02}, + {0x3140, 0x02}, + {0x3c00, 0x00}, +@@ -708,7 +708,7 @@ static const struct imx477_reg mode_2028 + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0900, 0x01}, +- {0x0901, 0x12}, ++ {0x0901, 0x22}, + {0x0902, 0x02}, + {0x3140, 0x02}, + {0x3c00, 0x00}, diff --git a/target/linux/bcm27xx/patches-6.1/950-1058-fixup-arch-arm64-Add-Revision-Serial-Model-to-cpuinf.patch b/target/linux/bcm27xx/patches-6.1/950-1058-fixup-arch-arm64-Add-Revision-Serial-Model-to-cpuinf.patch new file mode 100644 index 0000000000..adedaf6d4b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1058-fixup-arch-arm64-Add-Revision-Serial-Model-to-cpuinf.patch @@ -0,0 +1,25 @@ +From e641fd7a50987ad6b7ce1ab36189bc8817295e42 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 31 Oct 2023 16:34:56 +0000 +Subject: [PATCH] fixup! arch/arm64: Add Revision, Serial, Model to cpuinfo + +Delete the Hardware string, which is pointless and misleading. + +See: https://github.com/raspberrypi/bookworm-feedback/issues/129 + +Signed-off-by: Phil Elwell +--- + arch/arm64/kernel/cpuinfo.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/arch/arm64/kernel/cpuinfo.c ++++ b/arch/arm64/kernel/cpuinfo.c +@@ -224,8 +224,6 @@ static int c_show(struct seq_file *m, vo + seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr)); + } + +- seq_printf(m, "Hardware\t: BCM2835\n"); +- + np = of_find_node_by_path("/system"); + if (np) { + if (!of_property_read_u32(np, "linux,revision", &revision)) diff --git a/target/linux/bcm27xx/patches-6.1/950-1060-dts-bcm2710-rpi-zero-2-w-Remove-WLAN-firmwares.patch b/target/linux/bcm27xx/patches-6.1/950-1060-dts-bcm2710-rpi-zero-2-w-Remove-WLAN-firmwares.patch new file mode 100644 index 0000000000..18c12cd10f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1060-dts-bcm2710-rpi-zero-2-w-Remove-WLAN-firmwares.patch @@ -0,0 +1,35 @@ +From e86c43b86179fba90a1d9dd5acb554767af6740f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 12 Jun 2023 15:23:55 +0100 +Subject: [PATCH] dts: bcm2710-rpi-zero-2-w: Remove WLAN firmwares + +With careful use of qualified firmware names there is no need for the +ability to override the device names based on Device Tree properties. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts | 13 ------------- + 1 file changed, 13 deletions(-) + +--- a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts +@@ -161,19 +161,6 @@ + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; +- +- firmwares { +- fw_43436p { +- chipid = <43430>; +- revmask = <4>; +- fw_base = "brcm/brcmfmac43436-sdio"; +- }; +- fw_43436s { +- chipid = <43430>; +- revmask = <2>; +- fw_base = "brcm/brcmfmac43436s-sdio"; +- }; +- }; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1061-drivers-media-cfe-Set-the-CSI-2-link-frequency-corre.patch b/target/linux/bcm27xx/patches-6.1/950-1061-drivers-media-cfe-Set-the-CSI-2-link-frequency-corre.patch new file mode 100644 index 0000000000..d5aeae5333 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1061-drivers-media-cfe-Set-the-CSI-2-link-frequency-corre.patch @@ -0,0 +1,111 @@ +From a11312709f46b71bf320a9dcc8cf4e09056552cd Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 1 Nov 2023 13:25:54 +0000 +Subject: [PATCH] drivers: media: cfe: Set the CSI-2 link frequency correctly + +Use the sensor provided link frequency to set the DPHY timing parameters +on stream_on. This replaces the hard-coded 999 MHz value currently being +used. As a fallback, revert to the original 999 Mhz link frequency. + +As a drive-by, fix a 80-character line formatting error. + +Signed-off-by: Naushir Patuck +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 63 +++++++++++++++++-- + 1 file changed, 58 insertions(+), 5 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -780,7 +780,8 @@ static void cfe_start_channel(struct cfe + __func__, node_desc[FE_OUT0].name, + cfe->fe_csi2_channel); + +- source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, cfe->fe_csi2_channel); ++ source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, ++ cfe->fe_csi2_channel); + fmt = find_format_by_code(source_fmt->code); + + width = source_fmt->width; +@@ -982,6 +983,59 @@ static void cfe_buffer_queue(struct vb2_ + spin_unlock_irqrestore(&cfe->state_lock, flags); + } + ++static u64 sensor_link_frequency(struct cfe_device *cfe) ++{ ++ struct v4l2_mbus_framefmt *source_fmt; ++ struct v4l2_subdev_state *state; ++ struct media_entity *entity; ++ struct v4l2_subdev *subdev; ++ const struct cfe_fmt *fmt; ++ struct media_pad *pad; ++ s64 link_freq; ++ ++ state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); ++ source_fmt = v4l2_subdev_get_pad_format(&cfe->csi2.sd, state, 0); ++ fmt = find_format_by_code(source_fmt->code); ++ v4l2_subdev_unlock_state(state); ++ ++ /* ++ * Walk up the media graph to find either the sensor entity, or another ++ * entity that advertises the V4L2_CID_LINK_FREQ or V4L2_CID_PIXEL_RATE ++ * control through the subdev. ++ */ ++ entity = &cfe->csi2.sd.entity; ++ while (1) { ++ pad = &entity->pads[0]; ++ if (!(pad->flags & MEDIA_PAD_FL_SINK)) ++ goto err; ++ ++ pad = media_pad_remote_pad_first(pad); ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) ++ goto err; ++ ++ entity = pad->entity; ++ subdev = media_entity_to_v4l2_subdev(entity); ++ if (entity->function == MEDIA_ENT_F_CAM_SENSOR || ++ v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ) || ++ v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE)) ++ break; ++ } ++ ++ link_freq = v4l2_get_link_freq(subdev->ctrl_handler, fmt->depth, ++ cfe->csi2.active_data_lanes * 2); ++ if (link_freq < 0) ++ goto err; ++ ++ /* x2 for DDR. */ ++ link_freq *= 2; ++ cfe_info("Using a link frequency of %lld Hz\n", link_freq); ++ return link_freq; ++ ++err: ++ cfe_err("Unable to determine sensor link frequency, using 999 MHz\n"); ++ return 999 * 1000000UL; ++} ++ + static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count) + { + struct v4l2_mbus_config mbus_config = { 0 }; +@@ -1049,10 +1103,11 @@ static int cfe_start_streaming(struct vb + goto err_disable_cfe; + } + +- cfe_dbg("Starting sensor streaming\n"); +- ++ cfe_dbg("Configuring CSI-2 block\n"); ++ cfe->csi2.dphy.dphy_freq = sensor_link_frequency(cfe) / 1000000UL; + csi2_open_rx(&cfe->csi2); + ++ cfe_dbg("Starting sensor streaming\n"); + cfe->sequence = 0; + ret = v4l2_subdev_call(cfe->sensor, video, s_stream, 1); + if (ret < 0) { +@@ -1945,8 +2000,6 @@ static int of_cfe_connect_subdevs(struct + } + } + +- /* TODO: Get the frequency from devicetree */ +- cfe->csi2.dphy.dphy_freq = 999; + cfe->csi2.dphy.num_lanes = ep.bus.mipi_csi2.num_data_lanes; + cfe->csi2.bus_flags = ep.bus.mipi_csi2.flags; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1062-dts-bcm2712-rpi-5-b-Create-some-dummy-nodes.patch b/target/linux/bcm27xx/patches-6.1/950-1062-dts-bcm2712-rpi-5-b-Create-some-dummy-nodes.patch new file mode 100644 index 0000000000..722714d56a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1062-dts-bcm2712-rpi-5-b-Create-some-dummy-nodes.patch @@ -0,0 +1,42 @@ +From fb78b2617e70e58e03e0d50e674758fdd2a80d45 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 2 Nov 2023 10:39:11 +0000 +Subject: [PATCH] dts: bcm2712-rpi-5-b: Create some dummy nodes + +The kernel now treats multiple fragments targeting the same node as an +error. For this reason, it is important that labels created just for +compatibility with other systems (e.g. i2c0if and i2c0mux) are +attached to unique nodes, not just tacked onto existing nodes. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -157,6 +157,12 @@ + dummy: dummy { + // A target for unwanted overlay fragments + }; ++ ++ ++ // A few extra labels to keep overlays happy ++ ++ i2c0if: i2c0if {}; ++ i2c0mux: i2c0mux {}; + }; + + rp1_target: &pcie2 { +@@ -243,11 +249,6 @@ aux: &dummy {}; + + #include "bcm2712-rpi.dtsi" + +-// A few extra labels to keep overlays happy +- +-i2c0if: &rp1_gpio {}; +-i2c0mux: &rp1_gpio {}; +- + i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only + pinctrl-0 = <&rp1_i2c6_38_39>; + pinctrl-names = "default"; diff --git a/target/linux/bcm27xx/patches-6.1/950-1063-dts-rp1-Add-spi6-fix-spi1-address-cells.patch b/target/linux/bcm27xx/patches-6.1/950-1063-dts-rp1-Add-spi6-fix-spi1-address-cells.patch new file mode 100644 index 0000000000..41ab025555 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1063-dts-rp1-Add-spi6-fix-spi1-address-cells.patch @@ -0,0 +1,49 @@ +From cd66a0832351762b496bdce6f2f94a871d11484e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 2 Nov 2023 13:12:55 +0000 +Subject: [PATCH] dts: rp1: Add spi6, fix spi1 #address-cells + +spi6 won't be useful on Pi 5 because it can't be enabled on the 40-pin +header, but include it for completeness. + +Also fix the #address-cells value for spi1, otherwise the kernel will +reject attempts to apply the, say, spi1-2cs overlay at runtime. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/rp1.dtsi | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/rp1.dtsi ++++ b/arch/arm/boot/dts/rp1.dtsi +@@ -187,7 +187,7 @@ + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS>; + clock-names = "ssi_clk"; +- #address-cells = <0>; ++ #address-cells = <1>; + #size-cells = <0>; + num-cs = <2>; + dmas = <&rp1_dma RP1_DMA_SPI1_TX>, +@@ -262,6 +262,21 @@ + dma-names = "tx", "rx"; + status = "disabled"; + }; ++ ++ rp1_spi6: spi@68000 { ++ reg = <0xc0 0x40068000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI6_TX>, ++ <&rp1_dma RP1_DMA_SPI6_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; + + // SPI7 is a target/slave interface + rp1_spi7: spi@6c000 { diff --git a/target/linux/bcm27xx/patches-6.1/950-1064-overlays-uart-n-pi5-Add-the-pinctrl-0-property.patch b/target/linux/bcm27xx/patches-6.1/950-1064-overlays-uart-n-pi5-Add-the-pinctrl-0-property.patch new file mode 100644 index 0000000000..b6e0c323db --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1064-overlays-uart-n-pi5-Add-the-pinctrl-0-property.patch @@ -0,0 +1,67 @@ +From 17f135b742c4edb340afb365873c3a574f7e16cb Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 2 Nov 2023 17:05:46 +0000 +Subject: [PATCH] overlays: uart-pi5: Add the pinctrl-0 property + +Without the pinctrl-0 property in the overlays, the UARTs may not be +mapped correctly. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/uart0-pi5-overlay.dts | 1 + + arch/arm/boot/dts/overlays/uart1-pi5-overlay.dts | 1 + + arch/arm/boot/dts/overlays/uart2-pi5-overlay.dts | 1 + + arch/arm/boot/dts/overlays/uart3-pi5-overlay.dts | 1 + + arch/arm/boot/dts/overlays/uart4-pi5-overlay.dts | 1 + + 5 files changed, 5 insertions(+) + +--- a/arch/arm/boot/dts/overlays/uart0-pi5-overlay.dts ++++ b/arch/arm/boot/dts/overlays/uart0-pi5-overlay.dts +@@ -8,6 +8,7 @@ + target = <&uart0>; + frag0: __overlay__ { + status = "okay"; ++ pinctrl-0 = <&uart0_pins>; + }; + }; + +--- a/arch/arm/boot/dts/overlays/uart1-pi5-overlay.dts ++++ b/arch/arm/boot/dts/overlays/uart1-pi5-overlay.dts +@@ -8,6 +8,7 @@ + target = <&uart1>; + frag0: __overlay__ { + status = "okay"; ++ pinctrl-0 = <&uart1_pins>; + }; + }; + +--- a/arch/arm/boot/dts/overlays/uart2-pi5-overlay.dts ++++ b/arch/arm/boot/dts/overlays/uart2-pi5-overlay.dts +@@ -8,6 +8,7 @@ + target = <&uart2>; + frag0: __overlay__ { + status = "okay"; ++ pinctrl-0 = <&uart2_pins>; + }; + }; + +--- a/arch/arm/boot/dts/overlays/uart3-pi5-overlay.dts ++++ b/arch/arm/boot/dts/overlays/uart3-pi5-overlay.dts +@@ -8,6 +8,7 @@ + target = <&uart3>; + frag0: __overlay__ { + status = "okay"; ++ pinctrl-0 = <&uart3_pins>; + }; + }; + +--- a/arch/arm/boot/dts/overlays/uart4-pi5-overlay.dts ++++ b/arch/arm/boot/dts/overlays/uart4-pi5-overlay.dts +@@ -8,6 +8,7 @@ + target = <&uart4>; + frag0: __overlay__ { + status = "okay"; ++ pinctrl-0 = <&uart4_pins>; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1065-drivers-media-imx477-Add-V4L2_CID_LINK_FREQ-control.patch b/target/linux/bcm27xx/patches-6.1/950-1065-drivers-media-imx477-Add-V4L2_CID_LINK_FREQ-control.patch new file mode 100644 index 0000000000..f0a652b520 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1065-drivers-media-imx477-Add-V4L2_CID_LINK_FREQ-control.patch @@ -0,0 +1,51 @@ +From c9a785d57c302d5f1d4de4e67fa57522e66c7882 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Mon, 6 Nov 2023 09:40:50 +0000 +Subject: [PATCH] drivers: media: imx477: Add V4L2_CID_LINK_FREQ control + +Add V4L2_CID_LINK_FREQ as a read-only control with a value of 450 Mhz. +This will be used by the CFE driver to corretly setup the DPHY timing +parameters in the CSI-2 block. + +Signed-off-by: Naushir Patuck +--- + drivers/media/i2c/imx477.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/media/i2c/imx477.c ++++ b/drivers/media/i2c/imx477.c +@@ -164,6 +164,10 @@ struct imx477_mode { + struct imx477_reg_list reg_list; + }; + ++static const s64 imx477_link_freq_menu[] = { ++ IMX477_DEFAULT_LINK_FREQ, ++}; ++ + static const struct imx477_reg mode_common_regs[] = { + {0x0136, 0x18}, + {0x0137, 0x00}, +@@ -1110,6 +1114,7 @@ struct imx477 { + struct v4l2_ctrl_handler ctrl_handler; + /* V4L2 Controls */ + struct v4l2_ctrl *pixel_rate; ++ struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hflip; +@@ -1997,6 +2002,15 @@ static int imx477_init_controls(struct i + IMX477_PIXEL_RATE, 1, + IMX477_PIXEL_RATE); + ++ /* LINK_FREQ is also read only */ ++ imx477->link_freq = ++ v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx477_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(imx477_link_freq_menu) - 1, 0, ++ imx477_link_freq_menu); ++ if (imx477->link_freq) ++ imx477->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ + /* + * Create the controls here, but mode specific limits are setup + * in the imx477_set_framing_limits() call below. diff --git a/target/linux/bcm27xx/patches-6.1/950-1066-drivers-media-imx477-Correctly-set-IMX477_PIXEL_RATE.patch b/target/linux/bcm27xx/patches-6.1/950-1066-drivers-media-imx477-Correctly-set-IMX477_PIXEL_RATE.patch new file mode 100644 index 0000000000..f62fbbe13d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1066-drivers-media-imx477-Correctly-set-IMX477_PIXEL_RATE.patch @@ -0,0 +1,24 @@ +From 46913ee0590ee0e3f607ab189be19a4d0ce785f2 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Mon, 6 Nov 2023 09:42:37 +0000 +Subject: [PATCH] drivers: media: imx477: Correctly set IMX477_PIXEL_RATE as a + r/o control + +This control is meant to be read-only, mark it as such. + +Signed-off-by: Naushir Patuck +--- + drivers/media/i2c/imx477.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/media/i2c/imx477.c ++++ b/drivers/media/i2c/imx477.c +@@ -2001,6 +2001,8 @@ static int imx477_init_controls(struct i + IMX477_PIXEL_RATE, + IMX477_PIXEL_RATE, 1, + IMX477_PIXEL_RATE); ++ if (imx477->pixel_rate) ++ imx477->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* LINK_FREQ is also read only */ + imx477->link_freq = diff --git a/target/linux/bcm27xx/patches-6.1/950-1067-drm-vc4-Correct-logic-on-stopping-an-HVS-channel.patch b/target/linux/bcm27xx/patches-6.1/950-1067-drm-vc4-Correct-logic-on-stopping-an-HVS-channel.patch new file mode 100644 index 0000000000..948d79bfdb --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1067-drm-vc4-Correct-logic-on-stopping-an-HVS-channel.patch @@ -0,0 +1,52 @@ +From 6e9f68bba01b9c36a77b68c4b3167c317da986da Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 26 Oct 2023 17:46:13 +0100 +Subject: [PATCH] drm/vc4: Correct logic on stopping an HVS channel + +When factoring out __vc4_hvs_stop_channel, the logic got inverted from + if (condition) + // stop channel +to + if (condition) + goto out + //stop channel + out: +and also changed the exact register writes used to stop the channel. + +Correct the logic so that the channel is actually stopped, and revert +to the original register writes. + +Fixes: 6d01a106b4c8 ("drm/vc4: crtc: Move HVS init and close to a function") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -992,13 +992,11 @@ static void __vc4_hvs_stop_channel(struc + if (!drm_dev_enter(drm, &idx)) + return; + +- if (HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE) ++ if (!(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE)) + goto out; + +- HVS_WRITE(SCALER_DISPCTRLX(chan), +- HVS_READ(SCALER_DISPCTRLX(chan)) | SCALER_DISPCTRLX_RESET); +- HVS_WRITE(SCALER_DISPCTRLX(chan), +- HVS_READ(SCALER_DISPCTRLX(chan)) & ~SCALER_DISPCTRLX_ENABLE); ++ HVS_WRITE(SCALER_DISPCTRLX(chan), SCALER_DISPCTRLX_RESET); ++ HVS_WRITE(SCALER_DISPCTRLX(chan), 0); + + /* Once we leave, the scaler should be disabled and its fifo empty. */ + WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET); +@@ -1026,7 +1024,7 @@ static void __vc6_hvs_stop_channel(struc + if (!drm_dev_enter(drm, &idx)) + return; + +- if (HVS_READ(SCALER6_DISPX_CTRL0(chan)) & SCALER6_DISPX_CTRL0_ENB) ++ if (!(HVS_READ(SCALER6_DISPX_CTRL0(chan)) & SCALER6_DISPX_CTRL0_ENB)) + goto out; + + HVS_WRITE(SCALER6_DISPX_CTRL0(chan), diff --git a/target/linux/bcm27xx/patches-6.1/950-1068-drm-vc4-Drop-WARN-for-HVS-FIFOs-not-being-empty.patch b/target/linux/bcm27xx/patches-6.1/950-1068-drm-vc4-Drop-WARN-for-HVS-FIFOs-not-being-empty.patch new file mode 100644 index 0000000000..627f22c845 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1068-drm-vc4-Drop-WARN-for-HVS-FIFOs-not-being-empty.patch @@ -0,0 +1,30 @@ +From 31c4c359aa2dbb1a7c095f0a6ef4e13cd46cfd14 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 26 Oct 2023 18:05:09 +0100 +Subject: [PATCH] drm/vc4: Drop WARN for HVS FIFOs not being empty + +The reset condition for the EMPTY flag in DISPSTATx is 0, +so seeing as we've just reset the pipeline there is no +guarantee that the flag will denote empty if it hasn't been +enabled. + +Drop the WARN. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -1005,10 +1005,6 @@ static void __vc4_hvs_stop_channel(struc + SCALER_DISPSTATX_MODE) != + SCALER_DISPSTATX_MODE_DISABLED); + +- WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) & +- (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) != +- SCALER_DISPSTATX_EMPTY); +- + out: + drm_dev_exit(idx); + } diff --git a/target/linux/bcm27xx/patches-6.1/950-1069-drm-vc4-Free-all-stale-dlists-if-channel-is-disabled.patch b/target/linux/bcm27xx/patches-6.1/950-1069-drm-vc4-Free-all-stale-dlists-if-channel-is-disabled.patch new file mode 100644 index 0000000000..ce03224c39 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1069-drm-vc4-Free-all-stale-dlists-if-channel-is-disabled.patch @@ -0,0 +1,85 @@ +From 8b7078d1bbd8bb548cc97d5214adb828e9f0037c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 26 Oct 2023 18:23:31 +0100 +Subject: [PATCH] drm/vc4: Free all stale dlists if channel is disabled + +The code handling freeing stale dlists had 2 issues: +- it disabled the interrupt as soon as the first EOF interrupt + occurred, even if it didn't clear all stale allocations, thus + leading to stale entries +- It didn't free stale entries from disabled channels, so eg + "kmstest -c 0" could leave a stale alloc on channel 1 floating + around. + +Keep the interrupt enabled whilst there are any outstanding +allocs, and discard those on disabled channels. This second +channel does require us to call vc4_hvs_stop_channel from +vc4_crtc_atomic_disable so that the channel actually gets stopped. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 2 ++ + drivers/gpu/drm/vc4/vc4_hvs.c | 27 +++++++++++++++++++++++++-- + 2 files changed, 27 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -660,6 +660,8 @@ static void vc4_crtc_atomic_disable(stru + + vc4_crtc_disable(crtc, encoder, state, old_vc4_state->assigned_channel); + ++ vc4_hvs_atomic_disable(crtc, state); ++ + /* + * Make sure we issue a vblank event after disabling the CRTC if + * someone was waiting it. +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -697,7 +697,8 @@ static void vc4_hvs_schedule_dlist_sweep + if (!list_empty(&hvs->stale_dlist_entries)) + queue_work(system_unbound_wq, &hvs->free_dlist_work); + +- vc4_hvs_irq_clear_eof(hvs, channel); ++ if (list_empty(&hvs->stale_dlist_entries)) ++ vc4_hvs_irq_clear_eof(hvs, channel); + + spin_unlock_irqrestore(&hvs->mm_lock, flags); + } +@@ -712,6 +713,27 @@ static bool vc4_hvs_frcnt_lte(u8 cnt1, u + return (s8)((cnt1 << 2) - (cnt2 << 2)) <= 0; + } + ++bool vc4_hvs_check_channel_active(struct vc4_hvs *hvs, unsigned int fifo) ++{ ++ struct vc4_dev *vc4 = hvs->vc4; ++ struct drm_device *drm = &vc4->base; ++ bool enabled = false; ++ int idx; ++ ++ WARN_ON_ONCE(vc4->gen > VC4_GEN_6); ++ ++ if (!drm_dev_enter(drm, &idx)) ++ return 0; ++ ++ if (vc4->gen >= VC4_GEN_6) ++ enabled = HVS_READ(SCALER6_DISPX_CTRL0(fifo)) & SCALER6_DISPX_CTRL0_ENB; ++ else ++ enabled = HVS_READ(SCALER_DISPCTRLX(fifo)) & SCALER_DISPCTRLX_ENABLE; ++ ++ drm_dev_exit(idx); ++ return enabled; ++} ++ + /* + * Some atomic commits (legacy cursor updates, mostly) will not wait for + * the next vblank and will just return once the commit has been pushed +@@ -746,7 +768,8 @@ static void vc4_hvs_dlist_free_work(stru + u8 frcnt; + + frcnt = vc4_hvs_get_fifo_frame_count(hvs, cur->channel); +- if (!vc4_hvs_frcnt_lte(cur->target_frame_count, frcnt)) ++ if (vc4_hvs_check_channel_active(hvs, cur->channel) && ++ !vc4_hvs_frcnt_lte(cur->target_frame_count, frcnt)) + continue; + + vc4_hvs_free_dlist_entry_locked(hvs, cur); diff --git a/target/linux/bcm27xx/patches-6.1/950-1070-drm-vc4-Add-hvs_dlist_allocs-debugfs-function.patch b/target/linux/bcm27xx/patches-6.1/950-1070-drm-vc4-Add-hvs_dlist_allocs-debugfs-function.patch new file mode 100644 index 0000000000..b16489a12d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1070-drm-vc4-Add-hvs_dlist_allocs-debugfs-function.patch @@ -0,0 +1,64 @@ +From 665e9810340abc37769b317445907bac1843dd64 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 27 Oct 2023 16:46:04 +0100 +Subject: [PATCH] drm/vc4: Add hvs_dlist_allocs debugfs function. + +Users are reporting running out of DLIST memory. Add a +debugfs file to dump out all the allocations. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -347,6 +347,36 @@ static int vc5_hvs_debugfs_gamma(struct + return 0; + } + ++static int vc4_hvs_debugfs_dlist_allocs(struct seq_file *m, void *data) ++{ ++ struct drm_info_node *node = m->private; ++ struct drm_device *dev = node->minor->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct drm_printer p = drm_seq_file_printer(m); ++ struct vc4_hvs_dlist_allocation *cur, *next; ++ struct drm_mm_node *mm_node; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&hvs->mm_lock, flags); ++ ++ drm_printf(&p, "Allocated nodes:\n"); ++ list_for_each_entry(mm_node, drm_mm_nodes(&hvs->dlist_mm), node_list) { ++ drm_printf(&p, "node [%08llx + %08llx]\n", mm_node->start, mm_node->size); ++ } ++ ++ drm_printf(&p, "Stale nodes:\n"); ++ list_for_each_entry_safe(cur, next, &hvs->stale_dlist_entries, node) { ++ drm_printf(&p, "node [%08llx + %08llx] channel %u frcnt %u\n", ++ cur->mm_node.start, cur->mm_node.size, cur->channel, ++ cur->target_frame_count); ++ } ++ ++ spin_unlock_irqrestore(&hvs->mm_lock, flags); ++ ++ return 0; ++} ++ + /* The filter kernel is composed of dwords each containing 3 9-bit + * signed integers packed next to each other. + */ +@@ -1602,6 +1632,11 @@ int vc4_hvs_debugfs_init(struct drm_mino + if (ret) + return ret; + ++ ret = vc4_debugfs_add_file(minor, "hvs_dlist_allocs", ++ vc4_hvs_debugfs_dlist_allocs, NULL); ++ if (ret) ++ return ret; ++ + ret = vc4_debugfs_add_regset32(minor, "hvs_regs", + &hvs->regset); + if (ret) diff --git a/target/linux/bcm27xx/patches-6.1/950-1071-drm-vc4-Log-the-size-of-the-dlist-allocation-that-wa.patch b/target/linux/bcm27xx/patches-6.1/950-1071-drm-vc4-Log-the-size-of-the-dlist-allocation-that-wa.patch new file mode 100644 index 0000000000..aa38b182ba --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1071-drm-vc4-Log-the-size-of-the-dlist-allocation-that-wa.patch @@ -0,0 +1,23 @@ +From 23ea21ef5f6efb3082c184843b35a2f8f2e4374c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 31 Oct 2023 11:15:38 +0000 +Subject: [PATCH] drm/vc4: Log the size of the dlist allocation that was + attempted + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -659,7 +659,8 @@ vc4_hvs_alloc_dlist_entry(struct vc4_hvs + dlist_count); + spin_unlock_irqrestore(&hvs->mm_lock, flags); + if (ret) { +- drm_err(dev, "Failed to allocate DLIST entry: %d\n", ret); ++ drm_err(dev, "Failed to allocate DLIST entry. Requested size=%zu. ret=%d\n", ++ dlist_count, ret); + return ERR_PTR(ret); + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-1072-drm-vc4-crtc-Support-odd-horizontal-timings-on-BCM27.patch b/target/linux/bcm27xx/patches-6.1/950-1072-drm-vc4-crtc-Support-odd-horizontal-timings-on-BCM27.patch new file mode 100644 index 0000000000..a72e3b8e5b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1072-drm-vc4-crtc-Support-odd-horizontal-timings-on-BCM27.patch @@ -0,0 +1,104 @@ +From f9f480b04f1dc280bd4411477f5ee7336361367b Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Tue, 24 Oct 2023 16:20:42 +0100 +Subject: [PATCH] drm/vc4: crtc: Support odd horizontal timings on BCM2712 + +BCM2711 runs pixelvalve at two pixels per clock cycle which results +in an unfortunate limitation that odd horizontal timings are not +possible. This is apparent on the standard DMT mode of 1366x768@60 +which cannot be driven with correct timing. + +BCM2712 defaults to the same behaviour, but has a mode to support +odd timings. While internally it still runs at two pixels per clock, +setting the PV_VCONTROL_ODD_TIMING bit makes it appear externally +to behave as it is one pixel per clock. + +Switching to this mode fixes 1366x768@60 mode, and other custom +resultions with odd horizontal timings. + +Signed-off-by: Dom Cobley +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 12 ++++-------- + drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++-- + drivers/gpu/drm/vc4/vc4_regs.h | 1 + + 3 files changed, 7 insertions(+), 10 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -398,12 +398,6 @@ static void vc4_crtc_config_pv(struct dr + + vc4_crtc_pixelvalve_reset(crtc); + +- /* +- * NOTE: The BCM2712 has a H_OTE (Horizontal Odd Timing Enable) +- * bit that, when set, will allow to specify the timings in +- * pixels instead of cycles, thus allowing to specify odd +- * timings. +- */ + CRTC_WRITE(PV_HORZA, + VC4_SET_FIELD((mode->htotal - mode->hsync_end) * pixel_rep / ppc, + PV_HORZA_HBP) | +@@ -448,6 +442,7 @@ static void vc4_crtc_config_pv(struct dr + */ + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | ++ (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) | + (is_dsi ? PV_VCONTROL_DSI : 0) | + PV_VCONTROL_INTERLACE | + (odd_field_first +@@ -459,6 +454,7 @@ static void vc4_crtc_config_pv(struct dr + } else { + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | ++ (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) | + (is_dsi ? PV_VCONTROL_DSI : 0)); + CRTC_WRITE(PV_VSYNCD_EVEN, 0); + } +@@ -1334,7 +1330,7 @@ const struct vc4_pv_data bcm2712_pv0_dat + .hvs_output = 0, + }, + .fifo_depth = 64, +- .pixels_per_clock = 2, ++ .pixels_per_clock = 1, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_HDMI0, + }, +@@ -1347,7 +1343,7 @@ const struct vc4_pv_data bcm2712_pv1_dat + .hvs_output = 1, + }, + .fifo_depth = 64, +- .pixels_per_clock = 2, ++ .pixels_per_clock = 1, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_HDMI1, + }, +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -3958,7 +3958,7 @@ static const struct vc4_hdmi_variant bcm + PHY_LANE_2, + PHY_LANE_CK, + }, +- .unsupported_odd_h_timings = true, ++ .unsupported_odd_h_timings = false, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, +@@ -3985,7 +3985,7 @@ static const struct vc4_hdmi_variant bcm + PHY_LANE_2, + PHY_LANE_CK, + }, +- .unsupported_odd_h_timings = true, ++ .unsupported_odd_h_timings = false, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -155,6 +155,7 @@ + # define PV_CONTROL_EN BIT(0) + + #define PV_V_CONTROL 0x04 ++# define PV_VCONTROL_ODD_TIMING BIT(29) + # define PV_VCONTROL_ODD_DELAY_MASK VC4_MASK(22, 6) + # define PV_VCONTROL_ODD_DELAY_SHIFT 6 + # define PV_VCONTROL_ODD_FIRST BIT(5) diff --git a/target/linux/bcm27xx/patches-6.1/950-1073-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch b/target/linux/bcm27xx/patches-6.1/950-1073-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch new file mode 100644 index 0000000000..caf8b1a462 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1073-spi-dw-dma-Get-the-last-DMA-scoop-out-of-the-FIFO.patch @@ -0,0 +1,41 @@ +From 686fe776309fba5cad642c40177d39bf1fb320b2 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 7 Nov 2023 14:49:47 +0000 +Subject: [PATCH] spi: dw-dma: Get the last DMA scoop out of the FIFO + +With a DMA FIFO threshold greater than 1 (encoded as 0), it is possible +for data in the FIFO to be inaccessible, causing the transfer to fail +after a timeout. If the transfer includes a transmission, reduce the +RX threshold when the TX completes, otherwise use 1 for the whole +transfer (inefficient, but not catastrophic at SPI data rates). + +See: https://github.com/raspberrypi/linux/issues/5696 + +Signed-off-by: Phil Elwell +--- + drivers/spi/spi-dw-dma.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-dw-dma.c ++++ b/drivers/spi/spi-dw-dma.c +@@ -275,8 +275,10 @@ static void dw_spi_dma_tx_done(void *arg + struct dw_spi *dws = arg; + + clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy); +- if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) ++ if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) { ++ dw_writel(dws, DW_SPI_DMARDLR, 0); + return; ++ } + + complete(&dws->dma_completion); + } +@@ -602,6 +604,8 @@ static int dw_spi_dma_transfer(struct dw + + nents = max(xfer->tx_sg.nents, xfer->rx_sg.nents); + ++ dw_writel(dws, DW_SPI_DMARDLR, xfer->tx_buf ? (dws->rxburst - 1) : 0); ++ + /* + * Execute normal DMA-based transfer (which submits the Rx and Tx SG + * lists directly to the DMA engine at once) if either full hardware diff --git a/target/linux/bcm27xx/patches-6.1/950-1075-drivers-mmc-sdhci-add-SPURIOUS_INT_RESP-quirk.patch b/target/linux/bcm27xx/patches-6.1/950-1075-drivers-mmc-sdhci-add-SPURIOUS_INT_RESP-quirk.patch new file mode 100644 index 0000000000..2ab224df05 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1075-drivers-mmc-sdhci-add-SPURIOUS_INT_RESP-quirk.patch @@ -0,0 +1,62 @@ +From 4d2261fe86ce08bbee3c000718000e9f86593d88 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 8 Nov 2023 11:52:16 +0000 +Subject: [PATCH] drivers: mmc: sdhci: add SPURIOUS_INT_RESP quirk + +Certain controllers (dwc-mshc) generate timeout conditions separately to +command-completion conditions, where the end result is interrupts are +separated in time depending on the current SDCLK frequency. + +This causes spurious interrupts if SDCLK is slow compared to the CPU's +ability to process and return from interrupt. This occurs during card +probe with an empty slot where all commands that would generate a +response time out. + +Add a quirk to squelch command response interrupts when a command +timeout interrupt is received. + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/host/sdhci.c | 11 +++++++++++ + drivers/mmc/host/sdhci.h | 3 +++ + 2 files changed, 14 insertions(+) + +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -1728,6 +1728,12 @@ static bool sdhci_send_command(struct sd + if (host->use_external_dma) + sdhci_external_dma_pre_transfer(host, cmd); + ++ if (host->quirks2 & SDHCI_QUIRK2_SPURIOUS_INT_RESP) { ++ host->ier |= SDHCI_INT_RESPONSE; ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ } ++ + sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); + + return true; +@@ -3330,6 +3336,11 @@ static void sdhci_cmd_irq(struct sdhci_h + if (intmask & SDHCI_INT_TIMEOUT) { + host->cmd->error = -ETIMEDOUT; + sdhci_err_stats_inc(host, CMD_TIMEOUT); ++ if (host->quirks2 & SDHCI_QUIRK2_SPURIOUS_INT_RESP) { ++ host->ier &= ~SDHCI_INT_RESPONSE; ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ } + } else { + host->cmd->error = -EILSEQ; + if (!mmc_op_tuning(host->cmd->opcode)) +--- a/drivers/mmc/host/sdhci.h ++++ b/drivers/mmc/host/sdhci.h +@@ -486,6 +486,9 @@ struct sdhci_host { + #define SDHCI_QUIRK2_NO_SDR50 (1<<20) + #define SDHCI_QUIRK2_NO_SDR104 (1<<21) + ++/* Command timeouts may generate a trailing INT_RESPONSE later */ ++#define SDHCI_QUIRK2_SPURIOUS_INT_RESP (1<<31) ++ + int irq; /* Device IRQ */ + void __iomem *ioaddr; /* Mapped address */ + phys_addr_t mapbase; /* physical address base */ diff --git a/target/linux/bcm27xx/patches-6.1/950-1076-dt-bindings-mmc-sdhci-of-dwcmhsc-Add-Raspberry-Pi-RP.patch b/target/linux/bcm27xx/patches-6.1/950-1076-dt-bindings-mmc-sdhci-of-dwcmhsc-Add-Raspberry-Pi-RP.patch new file mode 100644 index 0000000000..ffdc1b1c5d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1076-dt-bindings-mmc-sdhci-of-dwcmhsc-Add-Raspberry-Pi-RP.patch @@ -0,0 +1,42 @@ +From ebe13d0d4314255d226ba740e37a14172a8b9091 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 8 Nov 2023 16:10:13 +0000 +Subject: [PATCH] dt-bindings: mmc: sdhci-of-dwcmhsc: Add Raspberry Pi RP1 + support + +The DWC MSHC controller on RP1 needs differentiating from the generic +version. + +Signed-off-by: Jonathan Bell +--- + .../devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml ++++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +@@ -16,6 +16,7 @@ allOf: + properties: + compatible: + enum: ++ - raspberrypi,rp1-dwcmshc + - rockchip,rk3568-dwcmshc + - rockchip,rk3588-dwcmshc + - snps,dwcmshc-sdhci +@@ -34,6 +35,8 @@ properties: + - description: axi clock for rockchip specified + - description: block clock for rockchip specified + - description: timer clock for rockchip specified ++ - description: timeout clock for rp1 specified ++ - description: sdio clock generator for rp1 specified + + + clock-names: +@@ -44,6 +47,8 @@ properties: + - const: axi + - const: block + - const: timer ++ - const: timeout ++ - const: sdio + + rockchip,txclk-tapnum: + description: Specify the number of delay for tx sampling. diff --git a/target/linux/bcm27xx/patches-6.1/950-1077-drivers-mmc-sdhci-of-dwcmshc-add-RP1-dt-ID-and-quirk.patch b/target/linux/bcm27xx/patches-6.1/950-1077-drivers-mmc-sdhci-of-dwcmshc-add-RP1-dt-ID-and-quirk.patch new file mode 100644 index 0000000000..54b719c6ec --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1077-drivers-mmc-sdhci-of-dwcmshc-add-RP1-dt-ID-and-quirk.patch @@ -0,0 +1,41 @@ +From 80dd8795ca631ac692fd3079487aea6d934a829c Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 8 Nov 2023 16:12:59 +0000 +Subject: [PATCH] drivers: mmc: sdhci-of-dwcmshc: add RP1 dt ID and quirks + +Differentiate the RP1 variant of the Designware MSHC controller(s). + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -373,6 +373,15 @@ static const struct sdhci_pltfm_data sdh + }; + #endif + ++static const struct sdhci_pltfm_data sdhci_dwcmshc_rp1_pdata = { ++ .ops = &sdhci_dwcmshc_ops, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | ++ SDHCI_QUIRK_BROKEN_CARD_DETECTION, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_BROKEN_HS200 | ++ SDHCI_QUIRK2_SPURIOUS_INT_RESP, ++}; ++ + static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { + .ops = &sdhci_dwcmshc_rk35xx_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +@@ -441,6 +450,10 @@ static void dwcmshc_rk35xx_postinit(stru + + static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { + { ++ .compatible = "raspberrypi,rp1-dwcmshc", ++ .data = &sdhci_dwcmshc_rp1_pdata, ++ }, ++ { + .compatible = "rockchip,rk3588-dwcmshc", + .data = &sdhci_dwcmshc_rk35xx_pdata, + }, diff --git a/target/linux/bcm27xx/patches-6.1/950-1078-arm-dts-change-RP1-SDHCI-controller-compatible-strin.patch b/target/linux/bcm27xx/patches-6.1/950-1078-arm-dts-change-RP1-SDHCI-controller-compatible-strin.patch new file mode 100644 index 0000000000..c708bf1f71 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1078-arm-dts-change-RP1-SDHCI-controller-compatible-strin.patch @@ -0,0 +1,104 @@ +From 51cdff455e3c3df29764f71bc0c9dd0e099945d6 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 8 Nov 2023 16:14:25 +0000 +Subject: [PATCH] arm: dts: change RP1 SDHCI controller compatible string + +Also add a sdio-pi5 overlay which enables mmc0 on GPIOs 22-27, as was +possible with earlier models of Pi. + +Signed-off-by: Jonathan Bell +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 7 ++++++ + arch/arm/boot/dts/overlays/overlay_map.dts | 4 ++++ + .../boot/dts/overlays/sdio-pi5-overlay.dts | 24 +++++++++++++++++++ + arch/arm/boot/dts/rp1.dtsi | 4 ++-- + 5 files changed, 38 insertions(+), 2 deletions(-) + create mode 100644 arch/arm/boot/dts/overlays/sdio-pi5-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -225,6 +225,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + sc16is752-spi1.dtbo \ + sdhost.dtbo \ + sdio.dtbo \ ++ sdio-pi5.dtbo \ + seeed-can-fd-hat-v1.dtbo \ + seeed-can-fd-hat-v2.dtbo \ + sh1106-spi.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -3932,6 +3932,13 @@ Info: This overlay is now deprecated. + Load: + + ++Name: sdio-pi5 ++Info: Selects the rp1_mmc0 interface and enables it on GPIOs 22-27. ++ Pi 5 only. ++Load: dtoverlay=sdio-pi5 ++Params: ++ ++ + Name: sdtweak + Info: This overlay is now deprecated. Use the sd_* dtparams in the + base DTB, e.g. "dtoverlay=sdtweak,poll_once" becomes +--- a/arch/arm/boot/dts/overlays/overlay_map.dts ++++ b/arch/arm/boot/dts/overlays/overlay_map.dts +@@ -250,6 +250,10 @@ + deprecated = "use sdio,bus_width=1,gpios_22_25"; + }; + ++ sdio-pi5 { ++ bcm2712; ++ }; ++ + sdtweak { + deprecated = "use 'dtparam=sd_poll_once' etc."; + }; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/sdio-pi5-overlay.dts +@@ -0,0 +1,24 @@ ++/dts-v1/; ++/plugin/; ++ ++/* SDIO/SD/MMC on RP1 bank 0 */ ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&rp1_mmc0>; ++ frag0: __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&rp1_sdio0_22_27>; ++ pinctrl-names = "default"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&rp1_sdio_clk0>; ++ frag1: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +--- a/arch/arm/boot/dts/rp1.dtsi ++++ b/arch/arm/boot/dts/rp1.dtsi +@@ -962,7 +962,7 @@ + + rp1_mmc0: mmc@180000 { + reg = <0xc0 0x40180000 0x0 0x100>; +- compatible = "snps,dwcmshc-sdhci"; ++ compatible = "raspberrypi,rp1-dwcmshc"; + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core + &rp1_clocks RP1_CLK_SDIO_TIMER +@@ -978,7 +978,7 @@ + + rp1_mmc1: mmc@184000 { + reg = <0xc0 0x40184000 0x0 0x100>; +- compatible = "snps,dwcmshc-sdhci"; ++ compatible = "raspberrypi,rp1-dwcmshc"; + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core + &rp1_clocks RP1_CLK_SDIO_TIMER diff --git a/target/linux/bcm27xx/patches-6.1/950-1079-ASoC-bcm-audioinjector_octo-Add-soundcard-owner.patch b/target/linux/bcm27xx/patches-6.1/950-1079-ASoC-bcm-audioinjector_octo-Add-soundcard-owner.patch new file mode 100644 index 0000000000..aa025125e7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1079-ASoC-bcm-audioinjector_octo-Add-soundcard-owner.patch @@ -0,0 +1,22 @@ +From 020ee5029ab0b11e47696f538418105ccfdb44de Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 8 Nov 2023 19:17:33 +0000 +Subject: [PATCH] ASoC: bcm: audioinjector_octo: Add soundcard "owner" + +See: https://github.com/raspberrypi/linux/issues/5697 + +Signed-off-by: Phil Elwell +--- + sound/soc/bcm/audioinjector-octo-soundcard.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/soc/bcm/audioinjector-octo-soundcard.c ++++ b/sound/soc/bcm/audioinjector-octo-soundcard.c +@@ -252,6 +252,7 @@ static const struct snd_soc_dapm_route a + + static struct snd_soc_card snd_soc_audioinjector_octo = { + .name = "audioinjector-octo-soundcard", ++ .owner = THIS_MODULE, + .dai_link = audioinjector_octo_dai, + .num_links = ARRAY_SIZE(audioinjector_octo_dai), + diff --git a/target/linux/bcm27xx/patches-6.1/950-1080-drivers-media-imx708-Adjust-broken-line-correction-p.patch b/target/linux/bcm27xx/patches-6.1/950-1080-drivers-media-imx708-Adjust-broken-line-correction-p.patch new file mode 100644 index 0000000000..60f489c6c0 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1080-drivers-media-imx708-Adjust-broken-line-correction-p.patch @@ -0,0 +1,139 @@ +From f364e0eb8f973e1aa24a3c451d18e84247a8efcd Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Wed, 8 Nov 2023 10:57:45 +0000 +Subject: [PATCH] drivers: media: imx708: Adjust broken line correction + parameter + +In full-resolution mode, the LPF_INTENSITY_EN and LPF_INTENSITY +registers control Quad Bayer Re-mosaic broken line correction. +Expose this as a module parameter "qbc_adjust": zero disables +the correction and values in the range 2 to 5 set its strength. + +There is a trade-off between coloured and monochrome patterns. +The previous fixed value 4 could produce ladder/spots artefacts +in coloured textures. The new default value 2 may suit a wider +range of scenes. + +Signed-off-by: Nick Hollinghurst +--- + drivers/media/i2c/imx708.c | 50 ++++++++++++++++++++++++++++++++------ + 1 file changed, 42 insertions(+), 8 deletions(-) + +--- a/drivers/media/i2c/imx708.c ++++ b/drivers/media/i2c/imx708.c +@@ -20,6 +20,14 @@ + #include + #include + ++/* ++ * Parameter to adjust Quad Bayer re-mosaic broken line correction ++ * strength, used in full-resolution mode only. Set zero to disable. ++ */ ++static int qbc_adjust = 2; ++module_param(qbc_adjust, int, 0644); ++MODULE_PARM_DESC(qbc_adjust, "Quad Bayer broken line correction strength [0,2-5]"); ++ + #define IMX708_REG_VALUE_08BIT 1 + #define IMX708_REG_VALUE_16BIT 2 + +@@ -99,11 +107,17 @@ + + /* HDR exposure ratio (long:med == med:short) */ + #define IMX708_HDR_EXPOSURE_RATIO 4 +-#define IMX708_REG_MID_EXPOSURE 0x3116 +-#define IMX708_REG_SHT_EXPOSURE 0x0224 ++#define IMX708_REG_MID_EXPOSURE 0x3116 ++#define IMX708_REG_SHT_EXPOSURE 0x0224 + #define IMX708_REG_MID_ANALOG_GAIN 0x3118 + #define IMX708_REG_SHT_ANALOG_GAIN 0x0216 + ++/* QBC Re-mosaic broken line correction registers */ ++#define IMX708_LPF_INTENSITY_EN 0xC428 ++#define IMX708_LPF_INTENSITY_ENABLED 0x00 ++#define IMX708_LPF_INTENSITY_DISABLED 0x01 ++#define IMX708_LPF_INTENSITY 0xC429 ++ + /* + * Metadata buffer holds a variety of data, all sent with the same VC/DT (0x12). + * It comprises two scanlines (of up to 5760 bytes each, for 4608 pixels) +@@ -171,6 +185,9 @@ struct imx708_mode { + + /* HDR flag, used for checking if the current mode is HDR */ + bool hdr; ++ ++ /* Quad Bayer Re-mosaic flag */ ++ bool remosaic; + }; + + /* Default PDAF pixel correction gains */ +@@ -363,8 +380,6 @@ static const struct imx708_reg mode_4608 + {0x341f, 0x20}, + {0x3420, 0x00}, + {0x3421, 0xd8}, +- {0xC428, 0x00}, +- {0xC429, 0x04}, + {0x3366, 0x00}, + {0x3367, 0x00}, + {0x3368, 0x00}, +@@ -677,7 +692,8 @@ static const struct imx708_mode supporte + .pixel_rate = 595200000, + .exposure_lines_min = 8, + .exposure_lines_step = 1, +- .hdr = false ++ .hdr = false, ++ .remosaic = true + }, + { + /* regular 2x2 binned. */ +@@ -699,7 +715,8 @@ static const struct imx708_mode supporte + .pixel_rate = 585600000, + .exposure_lines_min = 4, + .exposure_lines_step = 2, +- .hdr = false ++ .hdr = false, ++ .remosaic = false + }, + { + /* 2x2 binned and cropped for 720p. */ +@@ -721,7 +738,8 @@ static const struct imx708_mode supporte + .pixel_rate = 566400000, + .exposure_lines_min = 4, + .exposure_lines_step = 2, +- .hdr = false ++ .hdr = false, ++ .remosaic = false + }, + }; + +@@ -746,7 +764,8 @@ static const struct imx708_mode supporte + .pixel_rate = 777600000, + .exposure_lines_min = 8 * IMX708_HDR_EXPOSURE_RATIO * IMX708_HDR_EXPOSURE_RATIO, + .exposure_lines_step = 2 * IMX708_HDR_EXPOSURE_RATIO * IMX708_HDR_EXPOSURE_RATIO, +- .hdr = true ++ .hdr = true, ++ .remosaic = false + } + }; + +@@ -1515,6 +1534,21 @@ static int imx708_start_streaming(struct + return ret; + } + ++ /* Quad Bayer re-mosaic adjustments (for full-resolution mode only) */ ++ if (imx708->mode->remosaic && qbc_adjust > 0) { ++ imx708_write_reg(imx708, IMX708_LPF_INTENSITY, ++ IMX708_REG_VALUE_08BIT, qbc_adjust); ++ imx708_write_reg(imx708, ++ IMX708_LPF_INTENSITY_EN, ++ IMX708_REG_VALUE_08BIT, ++ IMX708_LPF_INTENSITY_ENABLED); ++ } else { ++ imx708_write_reg(imx708, ++ IMX708_LPF_INTENSITY_EN, ++ IMX708_REG_VALUE_08BIT, ++ IMX708_LPF_INTENSITY_DISABLED); ++ } ++ + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(imx708->sd.ctrl_handler); + if (ret) diff --git a/target/linux/bcm27xx/patches-6.1/950-1082-drivers-media-cfe-Don-t-confuse-MHz-and-Mbps.patch b/target/linux/bcm27xx/patches-6.1/950-1082-drivers-media-cfe-Don-t-confuse-MHz-and-Mbps.patch new file mode 100644 index 0000000000..ea0ea396ba --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1082-drivers-media-cfe-Don-t-confuse-MHz-and-Mbps.patch @@ -0,0 +1,96 @@ +From 65407c54fb4119e528b70b329448269657e0941e Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 8 Nov 2023 10:05:05 +0000 +Subject: [PATCH] drivers: media: cfe: Don't confuse MHz and Mbps + +The driver was interchaning these units when talking about link rate. +Fix this to avoid confusion. Apart from the logging message change, +there is no function change in this commit. + +Signed-off-by: Naushir Patuck +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 8 ++++---- + drivers/media/platform/raspberrypi/rp1_cfe/dphy.c | 10 +++++----- + drivers/media/platform/raspberrypi/rp1_cfe/dphy.h | 2 +- + 3 files changed, 10 insertions(+), 10 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -983,7 +983,7 @@ static void cfe_buffer_queue(struct vb2_ + spin_unlock_irqrestore(&cfe->state_lock, flags); + } + +-static u64 sensor_link_frequency(struct cfe_device *cfe) ++static u64 sensor_link_rate(struct cfe_device *cfe) + { + struct v4l2_mbus_framefmt *source_fmt; + struct v4l2_subdev_state *state; +@@ -1028,11 +1028,11 @@ static u64 sensor_link_frequency(struct + + /* x2 for DDR. */ + link_freq *= 2; +- cfe_info("Using a link frequency of %lld Hz\n", link_freq); ++ cfe_info("Using a link rate of %lld Mbps\n", link_freq / (1000 * 1000)); + return link_freq; + + err: +- cfe_err("Unable to determine sensor link frequency, using 999 MHz\n"); ++ cfe_err("Unable to determine sensor link rate, using 999 Mbps\n"); + return 999 * 1000000UL; + } + +@@ -1104,7 +1104,7 @@ static int cfe_start_streaming(struct vb + } + + cfe_dbg("Configuring CSI-2 block\n"); +- cfe->csi2.dphy.dphy_freq = sensor_link_frequency(cfe) / 1000000UL; ++ cfe->csi2.dphy.dphy_rate = sensor_link_rate(cfe) / 1000000UL; + csi2_open_rx(&cfe->csi2); + + cfe_dbg("Starting sensor streaming\n"); +--- a/drivers/media/platform/raspberrypi/rp1_cfe/dphy.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/dphy.c +@@ -96,7 +96,7 @@ static uint8_t dphy_transaction(struct d + return get_tstdout(dphy); + } + +-static void dphy_set_hsfreqrange(struct dphy_data *dphy, uint32_t freq_mhz) ++static void dphy_set_hsfreqrange(struct dphy_data *dphy, uint32_t mbps) + { + /* See Table 5-1 on page 65 of dphy databook */ + static const u16 hsfreqrange_table[][2] = { +@@ -116,11 +116,11 @@ static void dphy_set_hsfreqrange(struct + }; + unsigned int i; + +- if (freq_mhz < 80 || freq_mhz > 1500) +- dphy_err("DPHY: Frequency %u MHz out of range\n", freq_mhz); ++ if (mbps < 80 || mbps > 1500) ++ dphy_err("DPHY: Datarate %u Mbps out of range\n", mbps); + + for (i = 0; i < ARRAY_SIZE(hsfreqrange_table) - 1; i++) { +- if (freq_mhz <= hsfreqrange_table[i][0]) ++ if (mbps <= hsfreqrange_table[i][0]) + break; + } + +@@ -139,7 +139,7 @@ static void dphy_init(struct dphy_data * + set_tstclr(dphy, 0); + usleep_range(15, 20); + +- dphy_set_hsfreqrange(dphy, dphy->dphy_freq); ++ dphy_set_hsfreqrange(dphy, dphy->dphy_rate); + + usleep_range(5, 10); + dw_csi2_host_write(dphy, PHY_SHUTDOWNZ, 1); +--- a/drivers/media/platform/raspberrypi/rp1_cfe/dphy.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/dphy.h +@@ -15,7 +15,7 @@ struct dphy_data { + + void __iomem *base; + +- u32 dphy_freq; ++ u32 dphy_rate; + u32 num_lanes; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1083-overlays-imx296-Fix-cam-port-override-for-regulators.patch b/target/linux/bcm27xx/patches-6.1/950-1083-overlays-imx296-Fix-cam-port-override-for-regulators.patch new file mode 100644 index 0000000000..1b6d2041f1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1083-overlays-imx296-Fix-cam-port-override-for-regulators.patch @@ -0,0 +1,25 @@ +From 6137fb168c08bd8c41c8421bf26f09ed29479f08 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 15 Nov 2023 08:25:11 +0000 +Subject: [PATCH] overlays: imx296: Fix cam port override for regulators + +The override was missing/incorrect for the regulator labels. + +Signed-off-by: Naushir Patuck +--- + arch/arm/boot/dts/overlays/imx296-overlay.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/imx296-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx296-overlay.dts +@@ -97,8 +97,9 @@ + cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, ++ <®_frag>, "target:0=",<&cam0_reg>, + <&imx296>, "clocks:0=",<&cam0_clk>, +- <&imx296>, "VANA-supply:0=",<&cam0_reg>; ++ <&imx296>, "avdd-supply:0=",<&cam0_reg>; + clock-frequency = <&clk_over>, "clock-frequency:0"; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-1148-overlays-ov5647-Regularise-vcm-node-label-name.patch b/target/linux/bcm27xx/patches-6.1/950-1148-overlays-ov5647-Regularise-vcm-node-label-name.patch new file mode 100644 index 0000000000..28017989a9 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1148-overlays-ov5647-Regularise-vcm-node-label-name.patch @@ -0,0 +1,32 @@ +From 7443b602cb503b42dd0ae8e957e26decb420d632 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 20 Nov 2023 10:15:15 +0000 +Subject: [PATCH] overlays: ov5647: Regularise vcm node label name + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/ov5647-overlay.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts +@@ -15,7 +15,7 @@ + + #include "ov5647.dtsi" + +- vcm: ad5398@c { ++ vcm_node: ad5398@c { + compatible = "adi,ad5398"; + reg = <0x0c>; + status = "disabled"; +@@ -78,8 +78,8 @@ + <&clk_frag>, "target:0=",<&cam0_clk>, + <&cam_node>, "clocks:0=",<&cam0_clk>, + <&cam_node>, "avdd-supply:0=",<&cam0_reg>; +- vcm = <&vcm>, "status=okay", +- <&cam_node>,"lens-focus:0=", <&vcm>; ++ vcm = <&vcm_node>, "status=okay", ++ <&cam_node>,"lens-focus:0=", <&vcm_node>; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1149-overlays-ov5647-cam0-mode-should-use-cam0_reg.patch b/target/linux/bcm27xx/patches-6.1/950-1149-overlays-ov5647-cam0-mode-should-use-cam0_reg.patch new file mode 100644 index 0000000000..f079756133 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1149-overlays-ov5647-cam0-mode-should-use-cam0_reg.patch @@ -0,0 +1,27 @@ +From d484bef133af9c87d64899fc1e1d0be2a7c7785b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 20 Nov 2023 10:16:10 +0000 +Subject: [PATCH] overlays: ov5647: cam0 mode should use cam0_reg + +When the cam0 parameter is used, the vcm should be updated to refer to +the cam0 regulator. + +See: https://github.com/raspberrypi/linux/issues/5722 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/ov5647-overlay.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts +@@ -77,7 +77,8 @@ + <®_frag>, "target:0=",<&cam0_reg>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&cam_node>, "clocks:0=",<&cam0_clk>, +- <&cam_node>, "avdd-supply:0=",<&cam0_reg>; ++ <&cam_node>, "avdd-supply:0=",<&cam0_reg>, ++ <&vcm_node>, "VANA-supply:0=",<&cam0_reg>; + vcm = <&vcm_node>, "status=okay", + <&cam_node>,"lens-focus:0=", <&vcm_node>; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-1150-w1-Disable-kernel-log-spam.patch b/target/linux/bcm27xx/patches-6.1/950-1150-w1-Disable-kernel-log-spam.patch new file mode 100644 index 0000000000..457a0e9ec5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1150-w1-Disable-kernel-log-spam.patch @@ -0,0 +1,25 @@ +From 0924b74687bd195b98f223814ff88b4227654e85 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 20 Nov 2023 14:46:14 +0000 +Subject: [PATCH] w1: Disable kernel log spam + +See: https://forums.raspberrypi.com/viewtopic.php?p=2159344 + +Signed-off-by: Phil Elwell +--- + drivers/w1/w1.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/w1/w1.c ++++ b/drivers/w1/w1.c +@@ -742,8 +742,10 @@ int w1_attach_slave_device(struct w1_mas + atomic_set(&sl->refcnt, 1); + atomic_inc(&sl->master->refcnt); + dev->slave_count++; ++#if 0 + dev_info(&dev->dev, "Attaching one wire slave %02x.%012llx crc %02x\n", + rn->family, (unsigned long long)rn->id, rn->crc); ++#endif + + /* slave modules need to be loaded in a context with unlocked mutex */ + mutex_unlock(&dev->mutex); diff --git a/target/linux/bcm27xx/patches-6.1/950-1151-include-uapi-mbus-Add-a-media-bus-format-enum-for-16.patch b/target/linux/bcm27xx/patches-6.1/950-1151-include-uapi-mbus-Add-a-media-bus-format-enum-for-16.patch new file mode 100644 index 0000000000..b8933bcbb6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1151-include-uapi-mbus-Add-a-media-bus-format-enum-for-16.patch @@ -0,0 +1,21 @@ +From be8ca764e0530ec8ac18ca03c49e3cda13562d3a Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 16 Nov 2023 14:21:05 +0000 +Subject: [PATCH] include: uapi: mbus: Add a media bus format enum for 16-bit + mono output + +Signed-off-by: Naushir Patuck +--- + include/uapi/linux/media-bus-format.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/uapi/linux/media-bus-format.h ++++ b/include/uapi/linux/media-bus-format.h +@@ -95,6 +95,7 @@ + #define MEDIA_BUS_FMT_YUYV12_2X12 0x201e + #define MEDIA_BUS_FMT_YVYU12_2X12 0x201f + #define MEDIA_BUS_FMT_Y14_1X14 0x202d ++#define MEDIA_BUS_FMT_Y16_1X16 0x202e + #define MEDIA_BUS_FMT_UYVY8_1X16 0x200f + #define MEDIA_BUS_FMT_VYUY8_1X16 0x2010 + #define MEDIA_BUS_FMT_YUYV8_1X16 0x2011 diff --git a/target/linux/bcm27xx/patches-6.1/950-1152-include-uapi-v4l2-Add-additional-pixel-formats-for-u.patch b/target/linux/bcm27xx/patches-6.1/950-1152-include-uapi-v4l2-Add-additional-pixel-formats-for-u.patch new file mode 100644 index 0000000000..56855184be --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1152-include-uapi-v4l2-Add-additional-pixel-formats-for-u.patch @@ -0,0 +1,73 @@ +From 9abab2e8e5cfbeae6e1b33cc3a5ed773e4e31774 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 16 Nov 2023 14:25:39 +0000 +Subject: [PATCH] include: uapi: v4l2: Add additional pixel formats for use + with PiSP + +Add the following formats: + +- V4L2_PIX_FMT_RGB48/V4L2_PIX_FMT_BGR48 + 48-bit RGB where each colour sample is 16-bits. + +- V4L2_PIX_FMT_PISP_COMP1_MONO/V4L2_PIX_FMT_PISP_COMP2_MONO + 16-bit to 8-bit pisp compressed monochrome pixel format. + +Signed-off-by: Naushir Patuck +--- + drivers/media/v4l2-core/v4l2-ioctl.c | 8 ++++++-- + include/uapi/linux/videodev2.h | 6 ++++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1304,6 +1304,8 @@ static void v4l_fill_fmtdesc(struct v4l2 + case V4L2_PIX_FMT_BGRX32: descr = "32-bit XBGR 8-8-8-8"; break; + case V4L2_PIX_FMT_RGBA32: descr = "32-bit RGBA 8-8-8-8"; break; + case V4L2_PIX_FMT_RGBX32: descr = "32-bit RGBX 8-8-8-8"; break; ++ case V4L2_PIX_FMT_BGR48: descr = "48-bit BGR 16-16-16"; break; ++ case V4L2_PIX_FMT_RGB48: descr = "48-bit RGB 16-16-16"; break; + case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break; + case V4L2_PIX_FMT_Y4: descr = "4-bit Greyscale"; break; + case V4L2_PIX_FMT_Y6: descr = "6-bit Greyscale"; break; +@@ -1510,11 +1512,13 @@ static void v4l_fill_fmtdesc(struct v4l2 + case V4L2_PIX_FMT_PISP_COMP1_RGGB: + case V4L2_PIX_FMT_PISP_COMP1_GRBG: + case V4L2_PIX_FMT_PISP_COMP1_GBRG: +- case V4L2_PIX_FMT_PISP_COMP1_BGGR: descr = "PiSP Bayer Comp 1"; break; ++ case V4L2_PIX_FMT_PISP_COMP1_BGGR: ++ case V4L2_PIX_FMT_PISP_COMP1_MONO: descr = "PiSP Bayer Comp 1"; break; + case V4L2_PIX_FMT_PISP_COMP2_RGGB: + case V4L2_PIX_FMT_PISP_COMP2_GRBG: + case V4L2_PIX_FMT_PISP_COMP2_GBRG: +- case V4L2_PIX_FMT_PISP_COMP2_BGGR: descr = "PiSP Bayer Comp 2"; break; ++ case V4L2_PIX_FMT_PISP_COMP2_BGGR: ++ case V4L2_PIX_FMT_PISP_COMP2_MONO: descr = "PiSP Bayer Comp 2"; break; + default: + if (fmt->description[0]) + return; +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -582,6 +582,10 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_ARGB32 v4l2_fourcc('B', 'A', '2', '4') /* 32 ARGB-8-8-8-8 */ + #define V4L2_PIX_FMT_XRGB32 v4l2_fourcc('B', 'X', '2', '4') /* 32 XRGB-8-8-8-8 */ + ++/* RGB formats (6 bytes per pixel) */ ++#define V4L2_PIX_FMT_BGR48 v4l2_fourcc('B', 'G', 'R', '6') /* 16 BGR-16-16-16 */ ++#define V4L2_PIX_FMT_RGB48 v4l2_fourcc('R', 'G', 'B', '6') /* 16 RGB-16-16-16 */ ++ + /* Grey formats */ + #define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ + #define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */ +@@ -799,10 +803,12 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_PISP_COMP1_GRBG v4l2_fourcc('P', 'C', '1', 'G') + #define V4L2_PIX_FMT_PISP_COMP1_GBRG v4l2_fourcc('P', 'C', '1', 'g') + #define V4L2_PIX_FMT_PISP_COMP1_BGGR v4l2_fourcc('P', 'C', '1', 'B') ++#define V4L2_PIX_FMT_PISP_COMP1_MONO v4l2_fourcc('P', 'C', '1', 'M') + #define V4L2_PIX_FMT_PISP_COMP2_RGGB v4l2_fourcc('P', 'C', '2', 'R') + #define V4L2_PIX_FMT_PISP_COMP2_GRBG v4l2_fourcc('P', 'C', '2', 'G') + #define V4L2_PIX_FMT_PISP_COMP2_GBRG v4l2_fourcc('P', 'C', '2', 'g') + #define V4L2_PIX_FMT_PISP_COMP2_BGGR v4l2_fourcc('P', 'C', '2', 'B') ++#define V4L2_PIX_FMT_PISP_COMP2_MONO v4l2_fourcc('P', 'C', '2', 'M') + + /* SDR formats - used only for Software Defined Radio devices */ + #define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */ diff --git a/target/linux/bcm27xx/patches-6.1/950-1153-drivers-media-cfe-Add-16-bit-and-compressed-mono-for.patch b/target/linux/bcm27xx/patches-6.1/950-1153-drivers-media-cfe-Add-16-bit-and-compressed-mono-for.patch new file mode 100644 index 0000000000..607f23eeb3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1153-drivers-media-cfe-Add-16-bit-and-compressed-mono-for.patch @@ -0,0 +1,52 @@ +From 88d06a674009ad5b77234537527a800e6e0e88a3 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 16 Nov 2023 14:28:55 +0000 +Subject: [PATCH] drivers: media: cfe: Add 16-bit and compressed mono format + support + +Signed-off-by: Naushir Patuck +--- + .../media/platform/raspberrypi/rp1_cfe/cfe_fmts.h | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h +@@ -249,28 +249,34 @@ static const struct cfe_fmt formats[] = + .code = MEDIA_BUS_FMT_Y10_1X10, + .depth = 10, + .csi_dt = 0x2b, +- .remap = { V4L2_PIX_FMT_Y16 }, ++ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y12P, + .code = MEDIA_BUS_FMT_Y12_1X12, + .depth = 12, + .csi_dt = 0x2c, +- .remap = { V4L2_PIX_FMT_Y16 }, ++ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y14P, + .code = MEDIA_BUS_FMT_Y14_1X14, + .depth = 14, + .csi_dt = 0x2d, +- .remap = { V4L2_PIX_FMT_Y16 }, ++ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y16, ++ .code = MEDIA_BUS_FMT_Y16_1X16, + .depth = 16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, +- ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_MONO, ++ .code = MEDIA_BUS_FMT_Y16_1X16, ++ .depth = 8, ++ .flags = CFE_FORMAT_FLAG_FE_OUT, ++ }, + /* Embedded data format */ + { + .fourcc = V4L2_META_FMT_SENSOR_DATA, diff --git a/target/linux/bcm27xx/patches-6.1/950-1154-drivers-media-pisp_be-Add-mono-and-48-bit-RGB-pixel-.patch b/target/linux/bcm27xx/patches-6.1/950-1154-drivers-media-pisp_be-Add-mono-and-48-bit-RGB-pixel-.patch new file mode 100644 index 0000000000..2ea4abd112 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1154-drivers-media-pisp_be-Add-mono-and-48-bit-RGB-pixel-.patch @@ -0,0 +1,72 @@ +From 2affda8d2b172aa0fd22778983d983fc9522e621 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 16 Nov 2023 14:29:47 +0000 +Subject: [PATCH] drivers: media: pisp_be: Add mono and 48-bit RGB pixel format + support + +Signed-off-by: Naushir Patuck +--- + .../raspberrypi/pisp_be/pisp_be_formats.h | 45 +++++++++++++++++++ + 1 file changed, 45 insertions(+) + +--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h +@@ -234,6 +234,24 @@ static const struct pisp_be_format suppo + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SRGB, + }, ++ { ++ .fourcc = V4L2_PIX_FMT_RGB48, ++ .align = 64, ++ .bit_depth = 48, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_BGR48, ++ .align = 64, ++ .bit_depth = 48, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SRGB, ++ }, + /* Bayer formats - 8-bit */ + { + .fourcc = V4L2_PIX_FMT_SRGGB8, +@@ -457,6 +475,33 @@ static const struct pisp_be_format suppo + .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, + .colorspace_default = V4L2_COLORSPACE_RAW, + }, ++ /* Greyscale Formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .bit_depth = 8, ++ .align = 32, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_Y16, ++ .bit_depth = 16, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_PISP_COMP1_MONO, ++ .bit_depth = 8, ++ .align = 32, ++ .plane_factor = { P3(1.0) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, ++ .colorspace_default = V4L2_COLORSPACE_RAW, ++ }, + /* Opaque BE format for HW verification. */ + { + .fourcc = V4L2_PIX_FMT_RPI_BE, diff --git a/target/linux/bcm27xx/patches-6.1/950-1155-ASoC-dwc-Remove-check-in-set_bclk_ratio-handling.patch b/target/linux/bcm27xx/patches-6.1/950-1155-ASoC-dwc-Remove-check-in-set_bclk_ratio-handling.patch new file mode 100644 index 0000000000..88bb61a4c3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1155-ASoC-dwc-Remove-check-in-set_bclk_ratio-handling.patch @@ -0,0 +1,32 @@ +From 52545628c07be2fd1c9df598a17130d92f12da23 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 20 Nov 2023 15:17:34 +0000 +Subject: [PATCH] ASoC: dwc: Remove check in set_bclk_ratio handling + +A check added to dw_i2s_set_bclk_ratio that the data format is +consistent with the ratio seems reasonable but breaks when the +ratio is changed before the format. Remove the check - it is +unnecessary. + +See: https://github.com/raspberrypi/linux/issues/5724 +Fixes: 9c6694c24f26 ("ASOC: dwc: Fix 16-bit audio handling") + +Signed-off-by: Phil Elwell +--- + sound/soc/dwc/dwc-i2s.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -427,11 +427,8 @@ static int dw_i2s_set_bclk_ratio(struct + unsigned int ratio) + { + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); +- struct i2s_clk_config_data *config = &dev->config; + + dev_dbg(dev->dev, "%s(%d)\n", __func__, ratio); +- if (ratio < config->data_width * 2) +- return -EINVAL; + + switch (ratio) { + case 32: diff --git a/target/linux/bcm27xx/patches-6.1/950-1159-overlays-README-Fix-cut-and-paste-errors.patch b/target/linux/bcm27xx/patches-6.1/950-1159-overlays-README-Fix-cut-and-paste-errors.patch new file mode 100644 index 0000000000..30cc82b0cd --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1159-overlays-README-Fix-cut-and-paste-errors.patch @@ -0,0 +1,39 @@ +From 5a0aa24b8ff58ceaf98c62670156bef7f48ed32b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 21 Nov 2023 15:08:38 +0000 +Subject: [PATCH] overlays: README: Fix cut-and-paste errors + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1673,7 +1673,7 @@ Params: 24db_digital_gain Allow ga + responsibility of the user to ensure that + the Digital volume control is set to a value + that does not result in clipping/distortion!) +- slave Force DAC+ Pro into slave mode, using Pi as ++ slave Force AMP100 into slave mode, using Pi as + master for bit clock and frame clock. + leds_off If set to 'true' the onboard indicator LEDs + are switched off at all times. +@@ -1713,7 +1713,7 @@ Params: 24db_digital_gain Allow ga + responsibility of the user to ensure that + the Digital volume control is set to a value + that does not result in clipping/distortion!) +- slave Force DAC+ Pro into slave mode, using Pi as ++ slave Force DAC+ into slave mode, using Pi as + master for bit clock and frame clock. + leds_off If set to 'true' the onboard indicator LEDs + are switched off at all times. +@@ -1736,7 +1736,7 @@ Params: 24db_digital_gain Allow ga + responsibility of the user to ensure that + the Digital volume control is set to a value + that does not result in clipping/distortion!) +- slave Force DAC+ Pro into slave mode, using Pi as ++ slave Force DAC+ADC into slave mode, using Pi as + master for bit clock and frame clock. + leds_off If set to 'true' the onboard indicator LEDs + are switched off at all times. diff --git a/target/linux/bcm27xx/patches-6.1/950-1160-media-i2c-ov7251-Switch-from-V4L2_CID_GAIN-to-V4L2_C.patch b/target/linux/bcm27xx/patches-6.1/950-1160-media-i2c-ov7251-Switch-from-V4L2_CID_GAIN-to-V4L2_C.patch new file mode 100644 index 0000000000..36565bf2d6 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1160-media-i2c-ov7251-Switch-from-V4L2_CID_GAIN-to-V4L2_C.patch @@ -0,0 +1,38 @@ +From e60fbc34aa98b3ba2c9338ad628fc8d8137e9065 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 14 Nov 2023 18:36:19 +0000 +Subject: [PATCH] media/i2c: ov7251: Switch from V4L2_CID_GAIN to + V4L2_CID_ANALOGUE_GAIN + +The mainline driver has implemented analogue gain using the control +V4L2_CID_GAIN instead of V4L2_CID_ANALOGUE_GAIN. + +libcamera requires V4L2_CID_ANALOGUE_GAIN, and therefore fails. + +Update the driver to use V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1063,7 +1063,7 @@ static int ov7251_s_ctrl(struct v4l2_ctr + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1588,7 +1588,7 @@ static int ov7251_init_ctrls(struct ov72 + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, diff --git a/target/linux/bcm27xx/patches-6.1/950-1161-drm-vc4-Drop-planes-that-are-completely-off-screen.patch b/target/linux/bcm27xx/patches-6.1/950-1161-drm-vc4-Drop-planes-that-are-completely-off-screen.patch new file mode 100644 index 0000000000..8cdbb51d55 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1161-drm-vc4-Drop-planes-that-are-completely-off-screen.patch @@ -0,0 +1,63 @@ +From 444884f7b62bfe5ef313dd1d47f81a40e695ab0b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 17 Nov 2023 14:43:44 +0000 +Subject: [PATCH] drm/vc4: Drop planes that are completely off-screen + +It is permitted for a plane to be configured such that none +of it is on-screen via either negative dest rectangle X,Y +offset, or just an offset that is greater than the crtc +dimensions. + +These planes were resized via drm_atomic_helper_check_plane_state +such that the source rectangle had a zero width or height, but +they still created a dlist entry even though they contributed +no pixels. In the case of vc6_plane_mode_set, that it could result +in negative values being written into registers, which caused +incorrect behaviour. + +Drop planes that result in a source width or height of 0 pixels +to avoid the incorrect rendering. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_plane.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1108,6 +1108,12 @@ static int vc4_plane_mode_set(struct drm + width = vc4_state->src_w[0] >> 16; + height = vc4_state->src_h[0] >> 16; + ++ if (!width || !height) { ++ /* 0 source size probably means the plane is offscreen */ ++ vc4_state->dlist_initialized = 1; ++ return 0; ++ } ++ + /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB + * and 4:4:4, scl1 should be set to scl0 so both channels of + * the scaler do the same thing. For YUV, the Y plane needs +@@ -1623,6 +1629,12 @@ static int vc6_plane_mode_set(struct drm + width = vc4_state->src_w[0] >> 16; + height = vc4_state->src_h[0] >> 16; + ++ if (!width || !height) { ++ /* 0 source size probably means the plane is offscreen */ ++ vc4_state->dlist_initialized = 1; ++ return 0; ++ } ++ + /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB + * and 4:4:4, scl1 should be set to scl0 so both channels of + * the scaler do the same thing. For YUV, the Y plane needs +@@ -1994,6 +2006,9 @@ int vc4_plane_atomic_check(struct drm_pl + if (ret) + return ret; + ++ if (!vc4_state->src_w[0] || !vc4_state->src_h[0]) ++ return 0; ++ + ret = vc4_plane_allocate_lbm(new_plane_state); + if (ret) + return ret; diff --git a/target/linux/bcm27xx/patches-6.1/950-1162-drm-bridge-display-connector-Select-DRM_KMS_HELPER.patch b/target/linux/bcm27xx/patches-6.1/950-1162-drm-bridge-display-connector-Select-DRM_KMS_HELPER.patch new file mode 100644 index 0000000000..270975e587 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1162-drm-bridge-display-connector-Select-DRM_KMS_HELPER.patch @@ -0,0 +1,29 @@ +From 91ad217f93232fb3a0b52487fec67860fb29e93a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 17 Nov 2023 14:50:11 +0000 +Subject: [PATCH] drm/bridge: display-connector: Select DRM_KMS_HELPER + +Commit 7cd70656d128 ("drm/bridge: display-connector: implement +bus fmts callbacks") added use of drm_atomic_helper_bridge_* +functions, but didn't select the dependency of DRM_KMS_HELPER. +If nothing else selected that dependency it resulted in a +build failure. + +Select the missing dependency. + +Fixes: 7cd70656d128 ("drm/bridge: display-connector: implement bus fmts callbacks") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/bridge/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -67,6 +67,7 @@ config DRM_CROS_EC_ANX7688 + config DRM_DISPLAY_CONNECTOR + tristate "Display connector support" + depends on OF ++ select DRM_KMS_HELPER + help + Driver for display connectors with support for DDC and hot-plug + detection. Most display controllers handle display connectors diff --git a/target/linux/bcm27xx/patches-6.1/950-1163-drm-vc4-Free-the-dlist-alloc-immediately-if-it-never.patch b/target/linux/bcm27xx/patches-6.1/950-1163-drm-vc4-Free-the-dlist-alloc-immediately-if-it-never.patch new file mode 100644 index 0000000000..49359362fe --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1163-drm-vc4-Free-the-dlist-alloc-immediately-if-it-never.patch @@ -0,0 +1,56 @@ +From 51712a6493bf8824419f51ca7950e7d88f48b699 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 22 Nov 2023 18:36:54 +0000 +Subject: [PATCH] drm: vc4: Free the dlist alloc immediately if it never hit + the hw + +atomic_check creates a state, and allocates the dlist memory for +it such that atomic_flush can not fail. + +On destroy that dlist allocation was being put in the stale list, +even though it had never been programmed into the hardware, +therefore doing lots of atomic_checks could consume all the dlist +memory and fail. + +If the dlist has never been programmed into the hardware, then +free it immediately. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_hvs.c | 6 +++++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -696,6 +696,7 @@ struct vc4_hvs_dlist_allocation { + struct drm_mm_node mm_node; + unsigned int channel; + u8 target_frame_count; ++ bool dlist_programmed; + }; + + struct vc4_crtc_state { +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -697,8 +697,11 @@ void vc4_hvs_mark_dlist_entry_stale(stru + * Kunit tests run with a mock device and we consider any hardware + * access a test failure. Let's free the dlist allocation right away if + * we're running under kunit, we won't risk a dlist corruption anyway. ++ * ++ * Likewise if the allocation was only checked and never programmed, we ++ * can destroy the allocation immediately. + */ +- if (kunit_get_current_test()) { ++ if (kunit_get_current_test() || !alloc->dlist_programmed) { + spin_lock_irqsave(&hvs->mm_lock, flags); + vc4_hvs_free_dlist_entry_locked(hvs, alloc); + spin_unlock_irqrestore(&hvs->mm_lock, flags); +@@ -1201,6 +1204,7 @@ static void vc4_hvs_install_dlist(struct + return; + + WARN_ON(!vc4_state->mm); ++ vc4_state->mm->dlist_programmed = true; + + if (vc4->gen >= VC4_GEN_6) + HVS_WRITE(SCALER6_DISPX_LPTRS(vc4_state->assigned_channel), diff --git a/target/linux/bcm27xx/patches-6.1/950-1164-input-edt-ft5x06-Include-I2C-details-in-names-for-th.patch b/target/linux/bcm27xx/patches-6.1/950-1164-input-edt-ft5x06-Include-I2C-details-in-names-for-th.patch new file mode 100644 index 0000000000..131e502406 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1164-input-edt-ft5x06-Include-I2C-details-in-names-for-th.patch @@ -0,0 +1,48 @@ +From 2a6c3115f4142e23ca10c984d7f65ac8fb901cc2 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 8 Nov 2023 15:50:39 +0000 +Subject: [PATCH] input: edt-ft5x06: Include I2C details in names for the + devices + +libinput uses the input device name alone. If you have two +identical input devices, then there is no way to differentiate +between them, and in the case of touchscreens that means no +way to associate them with the appropriate display device. + +Add the I2C bus and address to the start of the input device +name so that the name is always unique within the system. + +Signed-off-by: Dave Stevenson +--- + drivers/input/touchscreen/edt-ft5x06.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/input/touchscreen/edt-ft5x06.c ++++ b/drivers/input/touchscreen/edt-ft5x06.c +@@ -67,6 +67,7 @@ + #define TOUCH_EVENT_RESERVED 0x03 + + #define EDT_NAME_LEN 23 ++#define EDT_NAME_PREFIX_LEN 8 + #define EDT_SWITCH_MODE_RETRIES 10 + #define EDT_SWITCH_MODE_DELAY 5 /* msec */ + #define EDT_RAW_DATA_RETRIES 100 +@@ -134,7 +135,7 @@ struct edt_ft5x06_ts_data { + int max_support_points; + unsigned int known_ids; + +- char name[EDT_NAME_LEN]; ++ char name[EDT_NAME_PREFIX_LEN + EDT_NAME_LEN]; + char fw_version[EDT_NAME_LEN]; + int init_td_status; + +@@ -965,6 +966,9 @@ static int edt_ft5x06_ts_identify(struct + char *model_name = tsdata->name; + char *fw_version = tsdata->fw_version; + ++ snprintf(model_name, EDT_NAME_PREFIX_LEN, "%s ", dev_name(&client->dev)); ++ model_name += strlen(model_name); ++ + /* see what we find if we assume it is a M06 * + * if we get less than EDT_NAME_LEN, we don't want + * to have garbage in there diff --git a/target/linux/bcm27xx/patches-6.1/950-1165-input-goodix-Include-I2C-details-in-names-for-the-de.patch b/target/linux/bcm27xx/patches-6.1/950-1165-input-goodix-Include-I2C-details-in-names-for-the-de.patch new file mode 100644 index 0000000000..4b529e66f5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1165-input-goodix-Include-I2C-details-in-names-for-the-de.patch @@ -0,0 +1,52 @@ +From a420bbde05f8a6691b0c3e0830092e443365aaa7 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 8 Nov 2023 16:20:27 +0000 +Subject: [PATCH] input: goodix: Include I2C details in names for the devices + +libinput uses the input device name alone. If you have two +identical input devices, then there is no way to differentiate +between them, and in the case of touchscreens that means no +way to associate them with the appropriate display device. + +Add the I2C bus and address to the start of the input device +name so that the name is always unique within the system. + +Signed-off-by: Dave Stevenson +--- + drivers/input/touchscreen/goodix.c | 5 ++++- + drivers/input/touchscreen/goodix.h | 3 +++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/input/touchscreen/goodix.c ++++ b/drivers/input/touchscreen/goodix.c +@@ -1211,7 +1211,10 @@ static int goodix_configure_dev(struct g + return -ENOMEM; + } + +- ts->input_dev->name = "Goodix Capacitive TouchScreen"; ++ snprintf(ts->name, GOODIX_NAME_MAX_LEN, "%s Goodix Capacitive TouchScreen", ++ dev_name(&ts->client->dev)); ++ ++ ts->input_dev->name = ts->name; + ts->input_dev->phys = "input/ts"; + ts->input_dev->id.bustype = BUS_I2C; + ts->input_dev->id.vendor = 0x0416; +--- a/drivers/input/touchscreen/goodix.h ++++ b/drivers/input/touchscreen/goodix.h +@@ -57,6 +57,8 @@ + #define GOODIX_CONFIG_MAX_LENGTH 240 + #define GOODIX_MAX_KEYS 7 + ++#define GOODIX_NAME_MAX_LEN 38 ++ + enum goodix_irq_pin_access_method { + IRQ_PIN_ACCESS_NONE, + IRQ_PIN_ACCESS_GPIO, +@@ -91,6 +93,7 @@ struct goodix_ts_data { + enum gpiod_flags gpiod_rst_flags; + char id[GOODIX_ID_MAX_LEN + 1]; + char cfg_name[64]; ++ char name[GOODIX_NAME_MAX_LEN]; + u16 version; + bool reset_controller_at_probe; + bool load_cfg_from_disk; diff --git a/target/linux/bcm27xx/patches-6.1/950-1166-drm-vc4-Block-swiotlb-bounce-buffers-being-imported-.patch b/target/linux/bcm27xx/patches-6.1/950-1166-drm-vc4-Block-swiotlb-bounce-buffers-being-imported-.patch new file mode 100644 index 0000000000..c40b77c957 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1166-drm-vc4-Block-swiotlb-bounce-buffers-being-imported-.patch @@ -0,0 +1,84 @@ +From a984fda6b2c24dbf1ca21924f99c8f9418f5765e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 22 Nov 2023 19:17:44 +0000 +Subject: [PATCH] drm: vc4: Block swiotlb bounce buffers being imported as + dmabuf + +The dmabuf import already checks that the backing buffer is contiguous +and rejects it if it isn't. vc4 also requires that the buffer is +in the bottom 1GB of RAM, and this is all correctly defined via +dma-ranges. + +However the kernel silently uses swiotlb to bounce dma buffers +around if they are in the wrong region. This relies on dma sync +functions to be called in order to copy the data to/from the +bounce buffer. + +DRM is based on all memory allocations being coherent with the +GPU so that any updates to a framebuffer will be acted on without +the need for any additional update. This is fairly fundamentally +incompatible with needing to call dma_sync_ to handle the bounce +buffer copies, and therefore we have to detect and reject mappings +that use bounce buffers. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_drv.c | 26 ++++++++++++++++++++++++-- + 1 file changed, 24 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -175,6 +176,19 @@ static void vc4_close(struct drm_device + kfree(vc4file); + } + ++struct drm_gem_object * ++vc4_prime_import_sg_table(struct drm_device *dev, ++ struct dma_buf_attachment *attach, ++ struct sg_table *sgt) ++{ ++ phys_addr_t phys = dma_to_phys(dev->dev, sg_dma_address(sgt->sgl)); ++ ++ if (is_swiotlb_buffer(dev->dev, phys)) ++ return ERR_PTR(-EINVAL); ++ ++ return drm_gem_dma_prime_import_sg_table(dev, attach, sgt); ++} ++ + DEFINE_DRM_GEM_FOPS(vc4_drm_fops); + + static const struct drm_ioctl_desc vc4_drm_ioctls[] = { +@@ -211,7 +225,11 @@ const struct drm_driver vc4_drm_driver = + + .gem_create_object = vc4_create_object, + +- DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc4_bo_dumb_create), ++ .dumb_create = vc4_bo_dumb_create, ++ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, ++ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, ++ .gem_prime_import_sg_table = vc4_prime_import_sg_table, ++ .gem_prime_mmap = drm_gem_prime_mmap, + + .ioctls = vc4_drm_ioctls, + .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls), +@@ -234,7 +252,11 @@ const struct drm_driver vc5_drm_driver = + .debugfs_init = vc4_debugfs_init, + #endif + +- DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc5_dumb_create), ++ .dumb_create = vc5_dumb_create, ++ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, ++ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, ++ .gem_prime_import_sg_table = vc4_prime_import_sg_table, ++ .gem_prime_mmap = drm_gem_prime_mmap, + + .fops = &vc4_drm_fops, + diff --git a/target/linux/bcm27xx/patches-6.1/950-1167-overlays-i2c-sensor-Add-adt7410-support.patch b/target/linux/bcm27xx/patches-6.1/950-1167-overlays-i2c-sensor-Add-adt7410-support.patch new file mode 100644 index 0000000000..c7c9daba3f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1167-overlays-i2c-sensor-Add-adt7410-support.patch @@ -0,0 +1,75 @@ +From 77a01f7da77446277139d8e9ce63f078cbe1ecfe Mon Sep 17 00:00:00 2001 +From: Kenny +Date: Wed, 22 Nov 2023 16:22:37 -0800 +Subject: [PATCH] overlays: i2c-sensor: Add adt7410 support + +See https://github.com/raspberrypi/linux/pull/5738 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 12 ++++++++---- + .../boot/dts/overlays/i2c-sensor-common.dtsi | 18 +++++++++++++++++- + 2 files changed, 25 insertions(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2144,10 +2144,14 @@ Name: i2c-sensor + Info: Adds support for a number of I2C barometric pressure, temperature, + light level and chemical sensors on i2c_arm + Load: dtoverlay=i2c-sensor,= +-Params: addr Set the address for the BH1750, BME280, BME680, +- BMP280, BMP380, CCS811, DS1621, HDC100X, JC42, +- LM75, MCP980x, MPU6050, MPU9250, MS5637, MS5803, +- MS5805, MS5837, MS8607, SHT3x or TMP102 ++Params: addr Set the address for the ADT7410, BH1750, BME280, ++ BME680, BMP280, BMP380, CCS811, DS1621, HDC100X, ++ JC42, LM75, MCP980x, MPU6050, MPU9250, MS5637, ++ MS5803, MS5805, MS5837, MS8607, SHT3x or TMP102 ++ ++ adt7410 Select the Analog Devices ADT7410 and ADT7420 ++ temperature sensors ++ Valid address 0x48-0x4b, default 0x48 + + aht10 Select the Aosong AHT10 temperature and humidity + sensor +--- a/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi ++++ b/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi +@@ -508,6 +508,21 @@ + }; + }; + ++ fragment@34 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ adt7410: adt7410@48 { ++ compatible = "adi,adt7410", "adi,adt7420"; ++ reg = <0x48>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ + __overrides__ { + bme280 = <0>,"+0"; + bmp085 = <0>,"+1"; +@@ -543,6 +558,7 @@ + mpu9250 = <0>,"+29"; + bno055 = <0>,"+31"; + sht4x = <0>,"+32"; ++ adt7410 = <0>,"+34"; + + addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0", + <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0", +@@ -552,7 +568,7 @@ + <&ms5837>,"reg:0", <&ms8607>,"reg:0", + <&mpu6050>,"reg:0", <&mpu9250>,"reg:0", + <&bno055>,"reg:0", <&sht4x>,"reg:0", +- <&bmp380>,"reg:0"; ++ <&bmp380>,"reg:0", <&adt7410>,"reg:0"; + int_pin = <&max30102>, "interrupts:0", + <&mpu6050>, "interrupts:0", + <&mpu9250>, "interrupts:0"; diff --git a/target/linux/bcm27xx/patches-6.1/950-1168-overlays-hat_map-Add-pisound-mapping.patch b/target/linux/bcm27xx/patches-6.1/950-1168-overlays-hat_map-Add-pisound-mapping.patch new file mode 100644 index 0000000000..2620a598f7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1168-overlays-hat_map-Add-pisound-mapping.patch @@ -0,0 +1,26 @@ +From 7c185b18a1c6a6cd6ab8805fef03a4a8c9931656 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 24 Nov 2023 13:57:09 +0000 +Subject: [PATCH] overlays: hat_map: Add pisound mapping + +See: https://github.com/raspberrypi/linux/issues/5741 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/hat_map.dts | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/arm/boot/dts/overlays/hat_map.dts ++++ b/arch/arm/boot/dts/overlays/hat_map.dts +@@ -6,6 +6,11 @@ + overlay = "iqaudio-codec"; + }; + ++ pisound { ++ uuid = [ a7ee5d28 da03 41f5 bbd7 20438a4bec5d ]; ++ overlay = "pisound"; ++ }; ++ + recalbox-rgbdual { + uuid = [ 1c955808 681f 4bbc a2ef b7ea47cd388e ]; + overlay = "recalboxrgbdual"; diff --git a/target/linux/bcm27xx/patches-6.1/950-1169-drm-vc4-Set-TV-margins-on-the-composite-connector-st.patch b/target/linux/bcm27xx/patches-6.1/950-1169-drm-vc4-Set-TV-margins-on-the-composite-connector-st.patch new file mode 100644 index 0000000000..05da5d38c5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1169-drm-vc4-Set-TV-margins-on-the-composite-connector-st.patch @@ -0,0 +1,47 @@ +From bc76ab2e772242d0d92d38b2a5648485ee1a1b44 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20B=C3=BCchler?= +Date: Sun, 19 Nov 2023 01:22:20 +0100 +Subject: [PATCH] drm/vc4: Set TV margins on the composite connector state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Raspberry Pi bootloader can pass a set of margin values to the +kernel cmdline as part of the video= option. These should result in +black borders on the output to compensate for TVs where the visible area +on the screen is smaller than the full extents of the video image. + +With the VC4 driver this currently works on an HDMI connector, but not +on a composite video connector. + +The TV margins from the kernel cmdline are available in the +drm_cmdline_mode structure of the composite video connector. Apply them +to the connector state in the connector reset function. This is how it +is implemented for the VC4 HDMI connector. + +Signed-off-by: Michael Büchler +--- + drivers/gpu/drm/vc4/vc4_vec.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_vec.c ++++ b/drivers/gpu/drm/vc4/vc4_vec.c +@@ -436,6 +436,9 @@ static void vc4_vec_connector_reset(stru + /* preserve TV standard */ + if (connector->state) + connector->state->tv.mode = vc4_vec_get_default_mode(connector); ++ ++ /* apply TV margins from the cmdline_mode */ ++ drm_atomic_helper_connector_tv_reset(connector); + } + + static int vc4_vec_connector_atomic_check(struct drm_connector *conn, +@@ -483,6 +486,8 @@ static int vc4_vec_connector_init(struct + + drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs); + ++ drm_connector_attach_tv_margin_properties(connector); ++ + drm_object_attach_property(&connector->base, + dev->mode_config.tv_mode_property, + vc4_vec_get_default_mode(connector)); diff --git a/target/linux/bcm27xx/patches-6.1/950-1170-drm-panel-jdi-lt070me05000-Add-prepare_upstream_firs.patch b/target/linux/bcm27xx/patches-6.1/950-1170-drm-panel-jdi-lt070me05000-Add-prepare_upstream_firs.patch new file mode 100644 index 0000000000..62e408b514 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1170-drm-panel-jdi-lt070me05000-Add-prepare_upstream_firs.patch @@ -0,0 +1,26 @@ +From 63d8c0f5185169058384142547655fc038aae0bf Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 9 Aug 2023 21:04:40 +0100 +Subject: [PATCH] drm: panel: jdi-lt070me05000: Add prepare_upstream_first flag + +The panel driver wants to send DCS commands from the prepare +hook, therefore the DSI host wants to be pre_enabled first. +Set the flag to achieve this. + +https://forums.raspberrypi.com/viewtopic.php?t=354708 + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/panel/panel-jdi-lt070me05000.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c ++++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +@@ -437,6 +437,7 @@ static int jdi_panel_add(struct jdi_pane + return ret; + } + ++ jdi->base.prepare_upstream_first = true; + drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + diff --git a/target/linux/bcm27xx/patches-6.1/950-1172-drivers-media-cfe-Find-the-source-pads-on-the-sensor.patch b/target/linux/bcm27xx/patches-6.1/950-1172-drivers-media-cfe-Find-the-source-pads-on-the-sensor.patch new file mode 100644 index 0000000000..e1f16d0171 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1172-drivers-media-cfe-Find-the-source-pads-on-the-sensor.patch @@ -0,0 +1,55 @@ +From 76b1bbf3ec3be0afdc768863ab7e9bbd2734b97b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 24 Nov 2023 14:29:57 +0000 +Subject: [PATCH] drivers: media: cfe: Find the source pads on the sensor + entity + +The driver was assuming that pad 0 on the sensor entity was the +appropriate source pad, but this isn't necessarily the case. +With video-mux, it has the sink pads first, and then the source +pad as the last one. + +Iterate through the sensor pads to find the relevant source pads. + +Signed-off-by: Dave Stevenson +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -1826,7 +1826,7 @@ static void cfe_unregister_nodes(struct + + static int cfe_link_node_pads(struct cfe_device *cfe) + { +- unsigned int i; ++ unsigned int i, source_pad = 0; + int ret; + + for (i = 0; i < CSI2_NUM_CHANNELS; i++) { +@@ -1835,14 +1835,23 @@ static int cfe_link_node_pads(struct cfe + if (!check_state(cfe, NODE_REGISTERED, i)) + continue; + +- if (i < cfe->sensor->entity.num_pads) { ++ /* Find next source pad */ ++ while (source_pad < cfe->sensor->entity.num_pads && ++ !(cfe->sensor->entity.pads[source_pad].flags & ++ MEDIA_PAD_FL_SOURCE)) ++ source_pad++; ++ ++ if (source_pad < cfe->sensor->entity.num_pads) { + /* Sensor -> CSI2 */ +- ret = media_create_pad_link(&cfe->sensor->entity, i, ++ ret = media_create_pad_link(&cfe->sensor->entity, source_pad, + &cfe->csi2.sd.entity, i, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; ++ ++ /* Dealt with that source_pad, look at the next one next time */ ++ source_pad++; + } + + /* CSI2 channel # -> /dev/video# */ diff --git a/target/linux/bcm27xx/patches-6.1/950-1173-dtoverlays-Add-option-for-cam0-to-camera-mux-Nport-o.patch b/target/linux/bcm27xx/patches-6.1/950-1173-dtoverlays-Add-option-for-cam0-to-camera-mux-Nport-o.patch new file mode 100644 index 0000000000..09cdcc7928 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1173-dtoverlays-Add-option-for-cam0-to-camera-mux-Nport-o.patch @@ -0,0 +1,101 @@ +From 08c5904ad00ffc54d37058ead19814f8a85f6f39 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 27 Nov 2023 14:50:58 +0000 +Subject: [PATCH] dtoverlays: Add option for cam0 to camera-mux-Nport overlays + +Seeing as the mux can be connected to either CAM/DISP1 or +CAM/DISP0 on a Pi5, add a cam0 override to allow configuration +of which is used. Default (as with all camera overlays) is CAM/DISP1. + +The overlay does NOT update the camera regulator used by all the +sensors as doing so would be a nightmare. The Arducam mulitplexer +boards these overlays are initially supporting seem to tie the +regulator GPIO for all the sensors high anyway. +If it was viewed as necessary, then creating an additional +regulator that listed cam[01]_reg as the parent should work. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/README | 4 ++++ + arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts | 7 +++++-- + arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts | 7 +++++-- + 3 files changed, 14 insertions(+), 4 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -823,6 +823,8 @@ Params: cam0-arducam-64mp Select A + cam1-ov9281 Select OV9281 for camera on port 1 + cam1-imx290-clk-freq Set clock frequency for an IMX290 on port 1 + ++ cam0 Connect the mux to CAM0 port (default is CAM1) ++ + + Name: camera-mux-4port + Info: Configures a 4 port camera multiplexer +@@ -878,6 +880,8 @@ Params: cam0-arducam-64mp Select A + cam3-ov9281 Select OV9281 for camera on port 3 + cam3-imx290-clk-freq Set clock frequency for an IMX290 on port 3 + ++ cam0 Connect the mux to CAM0 port (default is CAM1) ++ + + Name: cap1106 + Info: Enables the ability to use the cap1106 touch sensor as a keyboard +--- a/arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts ++++ b/arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts +@@ -77,7 +77,7 @@ + }; + + /* Mux define */ +- fragment@200 { ++ i2c_frag: fragment@200 { + target = <&i2c_csi_dsi>; + __overlay__ { + #address-cells = <1>; +@@ -294,7 +294,7 @@ + }; + }; + +- fragment@201 { ++ csi_frag: fragment@201 { + target = <&csi1>; + __overlay__ { + status = "okay"; +@@ -501,5 +501,8 @@ + <&imx290_0>,"clock-frequency:0"; + cam1-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", + <&imx290_1>,"clock-frequency:0"; ++ ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>; + }; + }; +--- a/arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts ++++ b/arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts +@@ -135,7 +135,7 @@ + }; + + /* Mux define */ +- fragment@200 { ++ i2c_frag: fragment@200 { + target = <&i2c_csi_dsi>; + __overlay__ { + #address-cells = <1>; +@@ -552,7 +552,7 @@ + }; + }; + +- fragment@201 { ++ csi_frag: fragment@201 { + target = <&csi1>; + __overlay__ { + status = "okay"; +@@ -872,5 +872,8 @@ + <&imx290_2>,"clock-frequency:0"; + cam3-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", + <&imx290_3>,"clock-frequency:0"; ++ ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-1174-ASoC-dwc-Permit-sample-rates-up-to-384kHz.patch b/target/linux/bcm27xx/patches-6.1/950-1174-ASoC-dwc-Permit-sample-rates-up-to-384kHz.patch new file mode 100644 index 0000000000..258b9de01c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1174-ASoC-dwc-Permit-sample-rates-up-to-384kHz.patch @@ -0,0 +1,26 @@ +From 6fac5d5ed6d023733ef7304afc88c8d89467a204 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 27 Nov 2023 12:16:04 +0000 +Subject: [PATCH] ASoC: dwc: Permit sample rates up to 384kHz + +The BCM2835 I2S block advertises clock rates up to 384kHz, and there's +no reason why RP1's DWC I2S block shouldn't do the same. + +See: https://github.com/raspberrypi/linux/issues/5748 + +Signed-off-by: Phil Elwell +--- + sound/soc/dwc/dwc-i2s.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -667,7 +667,7 @@ static int dw_configure_dai_by_dt(struct + if (WARN_ON(idx >= ARRAY_SIZE(bus_widths))) + return -EINVAL; + +- ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000); ++ ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_384000); + if (ret < 0) + return ret; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1176-ASoC-dwc-Fix-full-duplex-mode.patch b/target/linux/bcm27xx/patches-6.1/950-1176-ASoC-dwc-Fix-full-duplex-mode.patch new file mode 100644 index 0000000000..f4b7098fae --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1176-ASoC-dwc-Fix-full-duplex-mode.patch @@ -0,0 +1,63 @@ +From cbc65d9c95088d1437a5a84c7d6628b8d27a86f1 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 28 Nov 2023 12:14:03 +0000 +Subject: [PATCH] ASoC: dwc: Fix full-duplex mode + +Configuration of the DMA register was carelessly zeroing bits that may +used by a stream in the other direction. Preserve them instead. + +See: https://github.com/raspberrypi/linux/issues/5741 + +Signed-off-by: Phil Elwell +--- + sound/soc/dwc/dwc-i2s.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -189,10 +189,17 @@ static void dw_i2s_config(struct dw_i2s_ + { + struct i2s_clk_config_data *config = &dev->config; + u32 ch_reg; +- u32 dmacr = 0; ++ u32 dmacr; + + i2s_disable_channels(dev, stream); + ++ dmacr = i2s_read_reg(dev->i2s_base, DMACR); ++ ++ if (stream == SNDRV_PCM_STREAM_PLAYBACK) ++ dmacr &= ~(DMACR_DMAEN_TXCH0 * 0xf); ++ else ++ dmacr &= ~(DMACR_DMAEN_RXCH0 * 0xf); ++ + for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + i2s_write_reg(dev->i2s_base, TCR(ch_reg), +@@ -210,10 +217,6 @@ static void dw_i2s_config(struct dw_i2s_ + dmacr |= (DMACR_DMAEN_RXCH0 << ch_reg); + } + } +- if (stream == SNDRV_PCM_STREAM_PLAYBACK) +- dmacr |= DMACR_DMAEN_TX; +- else if (stream == SNDRV_PCM_STREAM_CAPTURE) +- dmacr |= DMACR_DMAEN_RX; + + i2s_write_reg(dev->i2s_base, DMACR, dmacr); + } +@@ -319,10 +322,13 @@ static int dw_i2s_startup(struct snd_pcm + + dw_i2s_config(dev, substream->stream); + dmacr = i2s_read_reg(dev->i2s_base, DMACR); +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dma_data = &dev->play_dma_data; +- else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ dmacr |= DMACR_DMAEN_TX; ++ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + dma_data = &dev->capture_dma_data; ++ dmacr |= DMACR_DMAEN_RX; ++ } + + snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data); + i2s_write_reg(dev->i2s_base, DMACR, dmacr); diff --git a/target/linux/bcm27xx/patches-6.1/950-1179-ASoC-pcm512x-Adds-bindings-for-TAS575x-devices.patch b/target/linux/bcm27xx/patches-6.1/950-1179-ASoC-pcm512x-Adds-bindings-for-TAS575x-devices.patch new file mode 100644 index 0000000000..8472c3e9e1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1179-ASoC-pcm512x-Adds-bindings-for-TAS575x-devices.patch @@ -0,0 +1,45 @@ +From a7ac27fbac1aa3fb8316cf1ff6dd2f81109d46d2 Mon Sep 17 00:00:00 2001 +From: Joerg Schambacher +Date: Fri, 29 Sep 2023 17:05:55 +0200 +Subject: [PATCH] ASoC: pcm512x: Adds bindings for TAS575x devices + +commit 736b884a7b68c4eeb66dbf75b97c8ec9b9eeff7f upstream. + +The TAS5754/6 power amplifiers use the same pcm512x driver with +only minor restictions described in the bindings document. + +Signed-off-by: Joerg Schambacher +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20230929150555.405388-1-joerg.hifiberry@gmail.com +Signed-off-by: Mark Brown +--- + Documentation/devicetree/bindings/sound/pcm512x.txt | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/Documentation/devicetree/bindings/sound/pcm512x.txt ++++ b/Documentation/devicetree/bindings/sound/pcm512x.txt +@@ -1,12 +1,12 @@ +-PCM512x audio CODECs ++PCM512x and TAS575x audio CODECs/amplifiers + + These devices support both I2C and SPI (configured with pin strapping +-on the board). ++on the board). The TAS575x devices only support I2C. + + Required properties: + +- - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141" or +- "ti,pcm5142" ++ - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141", ++ "ti,pcm5142", "ti,tas5754" or "ti,tas5756" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. +@@ -25,6 +25,7 @@ Optional properties: + through <6>. The device will be configured for clock input on the + given pll-in pin and PLL output on the given pll-out pin. An + external connection from the pll-out pin to the SCLK pin is assumed. ++ Caution: the TAS-desvices only support gpios 1,2 and 3 + + Examples: + diff --git a/target/linux/bcm27xx/patches-6.1/950-1180-ASoC-Adds-support-for-TAS575x-to-the-pcm512x-driver.patch b/target/linux/bcm27xx/patches-6.1/950-1180-ASoC-Adds-support-for-TAS575x-to-the-pcm512x-driver.patch new file mode 100644 index 0000000000..5009b225a3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1180-ASoC-Adds-support-for-TAS575x-to-the-pcm512x-driver.patch @@ -0,0 +1,102 @@ +From a535dd07aff73f3a6eb40174ab5dc413d05f36a1 Mon Sep 17 00:00:00 2001 +From: Joerg Schambacher +Date: Fri, 29 Sep 2023 17:07:20 +0200 +Subject: [PATCH] ASoC: Adds support for TAS575x to the pcm512x driver + +commit 1f817805262c2c34142291da376d4932d3c493bc upstream. + +Enables the existing pcm512x driver to control the almost +compatible TAS5754 and -76 amplifers. Both amplifiers support +only an I2C interface and the internal PLL must be always +on to provide necessary clocks to the amplifier section. +Tested on TAS5756 with support from Andreas Arbesser-Krasser +from Texas Instruments + +Signed-off-by: Joerg Schambacher +Link: https://lore.kernel.org/r/20230929150722.405415-1-joerg.hifiberry@gmail.com +Signed-off-by: Mark Brown +--- + sound/soc/codecs/pcm512x-i2c.c | 4 ++++ + sound/soc/codecs/pcm512x.c | 36 +++++++++++++++++++++++++++++++--- + 2 files changed, 37 insertions(+), 3 deletions(-) + +--- a/sound/soc/codecs/pcm512x-i2c.c ++++ b/sound/soc/codecs/pcm512x-i2c.c +@@ -39,6 +39,8 @@ static const struct i2c_device_id pcm512 + { "pcm5122", }, + { "pcm5141", }, + { "pcm5142", }, ++ { "tas5754", }, ++ { "tas5756", }, + { } + }; + MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); +@@ -49,6 +51,8 @@ static const struct of_device_id pcm512x + { .compatible = "ti,pcm5122", }, + { .compatible = "ti,pcm5141", }, + { .compatible = "ti,pcm5142", }, ++ { .compatible = "ti,tas5754", }, ++ { .compatible = "ti,tas5756", }, + { } + }; + MODULE_DEVICE_TABLE(of, pcm512x_of_match); +--- a/sound/soc/codecs/pcm512x.c ++++ b/sound/soc/codecs/pcm512x.c +@@ -48,6 +48,7 @@ struct pcm512x_priv { + int mute; + struct mutex mutex; + unsigned int bclk_ratio; ++ int force_pll_on; + }; + + /* +@@ -1258,10 +1259,34 @@ static int pcm512x_hw_params(struct snd_ + return ret; + } + +- ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN, +- PCM512x_PLLE, 0); ++ if (!pcm512x->force_pll_on) { ++ ret = regmap_update_bits(pcm512x->regmap, ++ PCM512x_PLL_EN, PCM512x_PLLE, 0); ++ } else { ++ /* provide minimum PLL config for TAS575x clocking ++ * and leave PLL enabled ++ */ ++ ret = regmap_write(pcm512x->regmap, ++ PCM512x_PLL_COEFF_0, 0x01); ++ if (ret != 0) { ++ dev_err(component->dev, ++ "Failed to set pll coefficient: %d\n", ret); ++ return ret; ++ } ++ ret = regmap_write(pcm512x->regmap, ++ PCM512x_PLL_COEFF_1, 0x04); ++ if (ret != 0) { ++ dev_err(component->dev, ++ "Failed to set pll coefficient: %d\n", ret); ++ return ret; ++ } ++ ret = regmap_write(pcm512x->regmap, ++ PCM512x_PLL_EN, 0x01); ++ dev_dbg(component->dev, "Enabling PLL for TAS575x\n"); ++ } ++ + if (ret != 0) { +- dev_err(component->dev, "Failed to disable pll: %d\n", ret); ++ dev_err(component->dev, "Failed to set pll mode: %d\n", ret); + return ret; + } + } +@@ -1659,6 +1684,11 @@ int pcm512x_probe(struct device *dev, st + ret = -EINVAL; + goto err_pm; + } ++ ++ if (!strcmp(np->name, "tas5756") || ++ !strcmp(np->name, "tas5754")) ++ pcm512x->force_pll_on = 1; ++ dev_dbg(dev, "Device ID: %s\n", np->name); + } + #endif + diff --git a/target/linux/bcm27xx/patches-6.1/950-1182-drm-panel-add-panel-dsi.patch b/target/linux/bcm27xx/patches-6.1/950-1182-drm-panel-add-panel-dsi.patch new file mode 100644 index 0000000000..d914ab6d04 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1182-drm-panel-add-panel-dsi.patch @@ -0,0 +1,176 @@ +From 0a0084b8621682ad96d001e798aa239b11a3cf00 Mon Sep 17 00:00:00 2001 +From: Timon Skerutsch +Date: Mon, 13 Nov 2023 22:53:12 +0100 +Subject: [PATCH] drm/panel: add panel-dsi + +Equivalent to panel-dpi for configuring a simple DSI panel with +device tree side timings and bus settings. +Motiviation is the same as for panel-dpi of wanting to support +new simple panels without needing to patch the kernel. + +Signed-off-by: Timon Skerutsch +--- + drivers/gpu/drm/panel/panel-simple.c | 123 ++++++++++++++++++++++++++- + 1 file changed, 122 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + + /** + * struct panel_desc - Describes a simple panel. +@@ -4660,6 +4661,9 @@ static const struct panel_desc_dsi osd10 + .lanes = 4, + }; + ++// for panels using generic panel-dsi binding ++static struct panel_desc_dsi panel_dsi; ++ + static const struct of_device_id dsi_of_match[] = { + { + .compatible = "auo,b080uan01", +@@ -4683,14 +4687,118 @@ static const struct of_device_id dsi_of_ + .compatible = "osddisplays,osd101t2045-53ts", + .data = &osd101t2045_53ts + }, { ++ /* Must be the last entry */ ++ .compatible = "panel-dsi", ++ .data = &panel_dsi, ++ }, { + /* sentinel */ + } + }; + MODULE_DEVICE_TABLE(of, dsi_of_match); + ++ ++/* Checks for DSI panel definition in device-tree, analog to panel_dpi */ ++static int panel_dsi_dt_probe(struct device *dev, ++ struct panel_desc_dsi *desc_dsi) ++{ ++ struct panel_desc *desc; ++ struct display_timing *timing; ++ const struct device_node *np; ++ const char *dsi_color_format; ++ const char *dsi_mode_flags; ++ struct property *prop; ++ int dsi_lanes, ret; ++ ++ np = dev->of_node; ++ ++ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); ++ if (!desc) ++ return -ENOMEM; ++ ++ timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); ++ if (!timing) ++ return -ENOMEM; ++ ++ ret = of_get_display_timing(np, "panel-timing", timing); ++ if (ret < 0) { ++ dev_err(dev, "%pOF: no panel-timing node found for \"panel-dsi\" binding\n", ++ np); ++ return ret; ++ } ++ ++ desc->timings = timing; ++ desc->num_timings = 1; ++ ++ of_property_read_u32(np, "width-mm", &desc->size.width); ++ of_property_read_u32(np, "height-mm", &desc->size.height); ++ ++ dsi_lanes = drm_of_get_data_lanes_count_ep(np, 0, 0, 1, 4); ++ ++ if (dsi_lanes < 0) { ++ dev_err(dev, "%pOF: no or too many data-lanes defined", np); ++ return dsi_lanes; ++ } ++ ++ desc_dsi->lanes = dsi_lanes; ++ ++ of_property_read_string(np, "dsi-color-format", &dsi_color_format); ++ if (!strcmp(dsi_color_format, "RGB888")) { ++ desc_dsi->format = MIPI_DSI_FMT_RGB888; ++ desc->bpc = 8; ++ } else if (!strcmp(dsi_color_format, "RGB565")) { ++ desc_dsi->format = MIPI_DSI_FMT_RGB565; ++ desc->bpc = 6; ++ } else if (!strcmp(dsi_color_format, "RGB666")) { ++ desc_dsi->format = MIPI_DSI_FMT_RGB666; ++ desc->bpc = 6; ++ } else if (!strcmp(dsi_color_format, "RGB666_PACKED")) { ++ desc_dsi->format = MIPI_DSI_FMT_RGB666_PACKED; ++ desc->bpc = 6; ++ } else { ++ dev_err(dev, "%pOF: no valid dsi-color-format defined", np); ++ return -EINVAL; ++ } ++ ++ ++ of_property_for_each_string(np, "mode", prop, dsi_mode_flags) { ++ if (!strcmp(dsi_mode_flags, "MODE_VIDEO")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_BURST")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_BURST; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_SYNC_PULSE")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_AUTO_VERT")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_AUTO_VERT; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_HSE")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_HSE; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HFP")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HFP; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HBP")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HBP; ++ else if (!strcmp(dsi_mode_flags, "MODE_VIDEO_NO_HSA")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VIDEO_NO_HSA; ++ else if (!strcmp(dsi_mode_flags, "MODE_VSYNC_FLUSH")) ++ desc_dsi->flags |= MIPI_DSI_MODE_VSYNC_FLUSH; ++ else if (!strcmp(dsi_mode_flags, "MODE_NO_EOT_PACKET")) ++ desc_dsi->flags |= MIPI_DSI_MODE_NO_EOT_PACKET; ++ else if (!strcmp(dsi_mode_flags, "CLOCK_NON_CONTINUOUS")) ++ desc_dsi->flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; ++ else if (!strcmp(dsi_mode_flags, "MODE_LPM")) ++ desc_dsi->flags |= MIPI_DSI_MODE_LPM; ++ else if (!strcmp(dsi_mode_flags, "HS_PKT_END_ALIGNED")) ++ desc_dsi->flags |= MIPI_DSI_HS_PKT_END_ALIGNED; ++ } ++ ++ desc->connector_type = DRM_MODE_CONNECTOR_DSI; ++ desc_dsi->desc = *desc; ++ ++ return 0; ++} ++ + static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi) + { + const struct panel_desc_dsi *desc; ++ struct panel_desc_dsi *dt_desc; + const struct of_device_id *id; + int err; + +@@ -4698,7 +4806,20 @@ static int panel_simple_dsi_probe(struct + if (!id) + return -ENODEV; + +- desc = id->data; ++ if (id->data == &panel_dsi) { ++ /* Handle the generic panel-dsi binding */ ++ dt_desc = devm_kzalloc(&dsi->dev, sizeof(*dt_desc), GFP_KERNEL); ++ if (!dt_desc) ++ return -ENOMEM; ++ ++ err = panel_dsi_dt_probe(&dsi->dev, dt_desc); ++ if (err < 0) ++ return err; ++ ++ desc = dt_desc; ++ } else { ++ desc = id->data; ++ } + + err = panel_simple_probe(&dsi->dev, &desc->desc); + if (err < 0) diff --git a/target/linux/bcm27xx/patches-6.1/950-1183-dt-bindings-display-panel-dsi-bindings.patch b/target/linux/bcm27xx/patches-6.1/950-1183-dt-bindings-display-panel-dsi-bindings.patch new file mode 100644 index 0000000000..c75ca8e8ac --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1183-dt-bindings-display-panel-dsi-bindings.patch @@ -0,0 +1,136 @@ +From e14ceeadfa5b9d8a41e73edfa416bbe92dd5b20d Mon Sep 17 00:00:00 2001 +From: Timon Skerutsch +Date: Mon, 13 Nov 2023 22:53:22 +0100 +Subject: [PATCH] dt-bindings: display: panel-dsi bindings + +Bindings for the panel-dsi specific additions to panel-simple. +Allow for DSI specific bus settings and panel timing +to be define in devicetree. Very similar to panel-dpi. + +Signed-off-by: Timon Skerutsch +--- + .../bindings/display/panel/panel-dsi.yaml | 118 ++++++++++++++++++ + 1 file changed, 118 insertions(+) + create mode 100644 Documentation/devicetree/bindings/display/panel/panel-dsi.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/panel/panel-dsi.yaml +@@ -0,0 +1,118 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/panel/panel-dsi.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Generic MIPI DSI Panel ++ ++maintainers: ++ - Timon Skerutsch ++ ++allOf: ++ - $ref: panel-common.yaml# ++ ++properties: ++ compatible: ++ description: ++ Shall contain a panel specific compatible and "panel-dsi" ++ in that order. ++ items: ++ - {} ++ - const: panel-dsi ++ ++ dsi-color-format: ++ description: | ++ The color format used by the panel. Only DSI supported formats are allowed. ++ enum: ++ - RGB888 ++ - RGB666 ++ - RGB666_PACKED ++ - RGB565 ++ ++ port: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ unevaluatedProperties: false ++ description: ++ Panel MIPI DSI input ++ ++ properties: ++ endpoint: ++ $ref: /schemas/media/video-interfaces.yaml# ++ unevaluatedProperties: false ++ ++ properties: ++ data-lanes: true ++ ++ required: ++ - data-lanes ++ ++ mode: ++ description: | ++ DSI mode flags. See DSI Specs for details. ++ These are driver independent features of the DSI bus. ++ items: ++ - const: MODE_VIDEO ++ - const: MODE_VIDEO_BURST ++ - const: MODE_VIDEO_SYNC_PULSE ++ - const: MODE_VIDEO_AUTO_VERT ++ - const: MODE_VIDEO_HSE ++ - const: MODE_VIDEO_NO_HFP ++ - const: MODE_VIDEO_NO_HBP ++ - const: MODE_VIDEO_NO_HSA ++ - const: MODE_VSYNC_FLUSH ++ - const: MODE_NO_EOT_PACKET ++ - const: CLOCK_NON_CONTINUOUS ++ - const: MODE_LPM ++ - const: HS_PKT_END_ALIGNED ++ ++ reg: true ++ backlight: true ++ enable-gpios: true ++ width-mm: true ++ height-mm: true ++ panel-timing: true ++ power-supply: true ++ reset-gpios: true ++ ddc-i2c-bus: true ++ ++required: ++ - panel-timing ++ - reg ++ - power-supply ++ - dsi-color-format ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ panel { ++ compatible = "panel-mfgr,generic-dsi-panel","panel-dsi"; ++ power-supply = <&vcc_supply>; ++ backlight = <&backlight>; ++ dsi-color-format = "RGB888"; ++ reg = <0>; ++ mode = "MODE_VIDEO", "MODE_VIDEO_BURST", "MODE_NO_EOT_PACKET"; ++ ++ port { ++ panel_dsi_port: endpoint { ++ data-lanes = <1 2>; ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ ++ panel-timing { ++ clock-frequency = <9200000>; ++ hactive = <800>; ++ vactive = <480>; ++ hfront-porch = <8>; ++ hback-porch = <4>; ++ hsync-len = <41>; ++ vback-porch = <2>; ++ vfront-porch = <4>; ++ vsync-len = <10>; ++ }; ++ }; ++ ++... diff --git a/target/linux/bcm27xx/patches-6.1/950-1184-overlays-example-overlay-for-using-panel-dsi-on-RPi.patch b/target/linux/bcm27xx/patches-6.1/950-1184-overlays-example-overlay-for-using-panel-dsi-on-RPi.patch new file mode 100644 index 0000000000..28a82d596d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1184-overlays-example-overlay-for-using-panel-dsi-on-RPi.patch @@ -0,0 +1,176 @@ +From ccf75f2a6f4045484c4539f7d47264f8f6b8453c Mon Sep 17 00:00:00 2001 +From: Timon Skerutsch +Date: Mon, 13 Nov 2023 22:52:35 +0100 +Subject: [PATCH] overlays: example overlay for using panel-dsi on RPi + +Analog to the generic panel-dpi overlay to use panel-dsi with dtparam +to not require a panel specific overlay for simple use cases that +do not require setting more niche DSI modes. + +Signed-off-by: Timon Skerutsch +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 31 +++++ + .../overlays/vc4-kms-dsi-generic-overlay.dts | 106 ++++++++++++++++++ + 3 files changed, 138 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-generic-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -293,6 +293,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + vc4-kms-dpi-hyperpixel4sq.dtbo \ + vc4-kms-dpi-panel.dtbo \ + vc4-kms-dsi-7inch.dtbo \ ++ vc4-kms-dsi-generic.dtbo \ + vc4-kms-dsi-lt070me05000.dtbo \ + vc4-kms-dsi-lt070me05000-v2.dtbo \ + vc4-kms-dsi-waveshare-panel.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -4785,6 +4785,37 @@ Params: sizex Touchscr + the default DSI1 and i2c_csi_dsi). + + ++Name: vc4-kms-dsi-generic ++Info: Enable a generic DSI display under KMS. ++ Default timings are for a 840x480 RGB888 panel. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dsi-generic,= ++Params: clock-frequency Display clock frequency (Hz) ++ hactive Horizontal active pixels ++ hfp Horizontal front porch ++ hsync Horizontal sync pulse width ++ hbp Horizontal back porch ++ vactive Vertical active lines ++ vfp Vertical front porch ++ vsync Vertical sync pulse width ++ vbp Vertical back porch ++ width-mm Define the screen width in mm ++ height-mm Define the screen height in mm ++ rgb565 Change to RGB565 output ++ rgb666 Change to RGB666 output ++ rgb666p Change to RGB666 output with pixel packing ++ rgb888 Change to RGB888 output, this is the default ++ one-lane Use one DSI lane for data transmission ++ This is the default ++ two-lane Use two DSI lanes for data transmission ++ three-lane Use three DSI lanes for data transmission ++ Only supported on Pi5 and CM ++ four-lane Use four DSI lanes for data transmission ++ Only supported on Pi5 and CM ++ dsi0 Switch DSI port to DSI0 ++ Only supported on Pi5 and CM ++ ++ + Name: vc4-kms-dsi-lt070me05000 + Info: Enable a JDI LT070ME05000 DSI display on DSI1. + Note that this is a 4 lane DSI device, so it will only work on a Compute +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-generic-overlay.dts +@@ -0,0 +1,106 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ dsi_frag: fragment@0 { ++ target = <&dsi1>; ++ __overlay__{ ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port { ++ dsi_out:endpoint { ++ remote-endpoint = <&panel_dsi_port>; ++ }; ++ }; ++ panel: panel-dsi-generic@0 { ++ // See panel-dsi.yaml binding ++ // Using dummy name for panel model ++ compatible = "Generic,panel-dsi","panel-dsi"; ++ reg = <0>; ++ power-supply = <0>; ++ backlight = <0>; ++ dsi-color-format = "RGB888"; ++ mode = "MODE_VIDEO"; ++ width-mm = <0>; ++ height-mm = <0>; ++ ++ port { ++ panel_dsi_port: endpoint { ++ data-lanes = <1>; ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ ++ timing: panel-timing { ++ clock-frequency = <30000000>; ++ hactive = <840>; ++ vactive = <480>; ++ hback-porch = <44>; ++ hfront-porch = <46>; ++ hsync-len = <2>; ++ vback-porch = <18>; ++ vfront-porch = <16>; ++ vsync-len = <2>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&panel_dsi_port>; ++ __dormant__ { ++ data-lanes = <1>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&panel_dsi_port>; ++ __dormant__ { ++ data-lanes = <1 2>; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&panel_dsi_port>; ++ __dormant__ { ++ data-lanes = <1 2 3>; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&panel_dsi_port>; ++ __dormant__ { ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ ++ __overrides__ { ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>; ++ ++ clock-frequency = <&timing>, "clock-frequency:0"; ++ hactive = <&timing>, "hactive:0"; ++ hfp = <&timing>, "hfront-porch:0"; ++ hsync = <&timing>, "hsync-len:0"; ++ hbp = <&timing>, "hback-porch:0"; ++ vactive = <&timing>, "vactive:0"; ++ vfp = <&timing>, "vfront-porch:0"; ++ vsync = <&timing>, "vsync-len:0"; ++ vbp = <&timing>, "vback-porch:0"; ++ ++ width-mm = <&panel>, "width-mm:0"; ++ height-mm = <&panel>, "height-mm:0"; ++ ++ rgb565 = <&panel>, "dsi-color-format=RGB565"; ++ rgb666p = <&panel>, "dsi-color-format=RGB666_PACKED"; ++ rgb666 = <&panel>, "dsi-color-format=RGB666"; ++ rgb888 = <&panel>, "dsi-color-format=RGB888"; ++ one-lane = <0>,"+1"; ++ two-lane = <0>,"+2"; ++ three-lane = <0>,"+3"; ++ four-lane = <0>,"+4"; ++ }; ++ ++}; diff --git a/target/linux/bcm27xx/patches-6.1/950-1185-overlays-ADS1115-allow-specification-of-the-i2c-bus.patch b/target/linux/bcm27xx/patches-6.1/950-1185-overlays-ADS1115-allow-specification-of-the-i2c-bus.patch new file mode 100644 index 0000000000..ef9328bd6f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1185-overlays-ADS1115-allow-specification-of-the-i2c-bus.patch @@ -0,0 +1,159 @@ +From a477a6351575aa173f9f82857f5797e384fbc704 Mon Sep 17 00:00:00 2001 +From: JinShil +Date: Tue, 28 Nov 2023 17:05:44 +0900 +Subject: [PATCH] overlays: ADS1115: allow specification of the i2c bus + +--- + arch/arm/boot/dts/overlays/README | 10 +++ + .../arm/boot/dts/overlays/ads1115-overlay.dts | 80 +++++++++++++------ + 2 files changed, 66 insertions(+), 24 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -489,6 +489,16 @@ Params: addr I2C bus + cha_gain Set the gain of the Programmable Gain + Amplifier for this channel. (Default 1 sets the + full scale of the channel to 4.096 Volts) ++ i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ i2c_csi_dsi Choose the I2C0 bus on GPIOs 44&45 ++ i2c3 Choose the I2C3 bus (configure with the i2c3 ++ overlay - BCM2711 only) ++ i2c4 Choose the I2C4 bus (configure with the i2c4 ++ overlay - BCM2711 only) ++ i2c5 Choose the I2C5 bus (configure with the i2c5 ++ overlay - BCM2711 only) ++ i2c6 Choose the I2C6 bus (configure with the i2c6 ++ overlay - BCM2711 only) + + Channel parameters can be set for each enabled channel. + A maximum of 4 channels can be enabled (letters a thru d). +--- a/arch/arm/boot/dts/overlays/ads1115-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ads1115-overlay.dts +@@ -9,23 +9,6 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target = <&i2c_arm>; +- __overlay__ { +- #address-cells = <1>; +- #size-cells = <0>; +- status = "okay"; +- +- ads1115: ads1115@48 { +- compatible = "ti,ads1115"; +- status = "okay"; +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x48>; +- }; +- }; +- }; +- +- fragment@1 { + target = <&ads1115>; + __dormant__ { + #address-cells = <1>; +@@ -39,7 +22,7 @@ + }; + }; + +- fragment@2 { ++ fragment@1 { + target = <&ads1115>; + __dormant__ { + #address-cells = <1>; +@@ -53,7 +36,7 @@ + }; + }; + +- fragment@3 { ++ fragment@2 { + target = <&ads1115>; + __dormant__ { + #address-cells = <1>; +@@ -67,7 +50,7 @@ + }; + }; + +- fragment@4 { ++ fragment@3 { + target = <&ads1115>; + __dormant__ { + #address-cells = <1>; +@@ -81,23 +64,72 @@ + }; + }; + ++ fragment@4 { ++ target = <&i2cbus>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ads1115: ads1115@48 { ++ compatible = "ti,ads1115"; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x48>; ++ }; ++ }; ++ }; ++ ++ frag100: fragment@100 { ++ target = <&i2c1>; ++ i2cbus: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@101 { ++ target = <&i2c0if>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&i2c0mux>; ++ __dormant__ { ++ status = "okay"; ++ }; ++ }; ++ + __overrides__ { + addr = <&ads1115>,"reg:0"; +- cha_enable = <0>,"=1"; ++ cha_enable = <0>,"=0"; + cha_cfg = <&channel_a>,"reg:0"; + cha_gain = <&channel_a>,"ti,gain:0"; + cha_datarate = <&channel_a>,"ti,datarate:0"; +- chb_enable = <0>,"=2"; ++ chb_enable = <0>,"=1"; + chb_cfg = <&channel_b>,"reg:0"; + chb_gain = <&channel_b>,"ti,gain:0"; + chb_datarate = <&channel_b>,"ti,datarate:0"; +- chc_enable = <0>,"=3"; ++ chc_enable = <0>,"=2"; + chc_cfg = <&channel_c>,"reg:0"; + chc_gain = <&channel_c>,"ti,gain:0"; + chc_datarate = <&channel_c>,"ti,datarate:0"; +- chd_enable = <0>,"=4"; ++ chd_enable = <0>,"=3"; + chd_cfg = <&channel_d>,"reg:0"; + chd_gain = <&channel_d>,"ti,gain:0"; + chd_datarate = <&channel_d>,"ti,datarate:0"; ++ i2c0 = <&frag100>, "target:0=",<&i2c0>; ++ i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, ++ <0>,"+101+102"; ++ i2c3 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c3"; ++ i2c4 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c4"; ++ i2c5 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c5"; ++ i2c6 = <&frag100>, "target?=0", ++ <&frag100>, "target-path=i2c6"; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-1186-dts-bcm2712-put-usb-under-axi-not-soc.patch b/target/linux/bcm27xx/patches-6.1/950-1186-dts-bcm2712-put-usb-under-axi-not-soc.patch new file mode 100644 index 0000000000..b66265f5a1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1186-dts-bcm2712-put-usb-under-axi-not-soc.patch @@ -0,0 +1,59 @@ +From 82069a7a02632aa60fa5c69415bf891ede7d6fd4 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 5 Dec 2023 16:55:17 +0000 +Subject: [PATCH] dts: bcm2712: put usb under /axi not /soc + +On 2712, the DWC USB controller is no longer attached to the Videocore +30-bit bus with its associated aliases, and can see the bottom 4GB of +RAM directly. + +Ideally it should make use of IOMMU6 but for now software bounce buffers +get it working. + +Signed-off-by: Jonathan Bell +--- + arch/arm/boot/dts/bcm2712.dtsi | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +--- a/arch/arm/boot/dts/bcm2712.dtsi ++++ b/arch/arm/boot/dts/bcm2712.dtsi +@@ -133,19 +133,6 @@ + status = "disabled"; + }; + +- usb: usb@7c480000 { +- compatible = "brcm,bcm2835-usb"; +- reg = <0x7c480000 0x10000>; +- interrupts = ; +- #address-cells = <1>; +- #size-cells = <0>; +- clocks = <&clk_usb>; +- clock-names = "otg"; +- phys = <&usbphy>; +- phy-names = "usb2-phy"; +- status = "disabled"; +- }; +- + mop: mop@7c500000 { + compatible = "brcm,bcm2712-mop"; + reg = <0x7c500000 0x20>; +@@ -1145,6 +1132,19 @@ + reg = <0x10 0x00400018 0x0 0x18>; + }; + ++ usb: usb@480000 { ++ compatible = "brcm,bcm2835-usb"; ++ reg = <0x10 0x00480000 0x0 0x10000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk_usb>; ++ clock-names = "otg"; ++ phys = <&usbphy>; ++ phy-names = "usb2-phy"; ++ status = "disabled"; ++ }; ++ + rpivid: codec@800000 { + compatible = "raspberrypi,rpivid-vid-decoder"; + reg = <0x10 0x00800000 0x0 0x10000>, /* HEVC */ diff --git a/target/linux/bcm27xx/patches-6.1/950-1187-drm-vc4-Correct-HVS-muxing-setup-for-the-moplet.patch b/target/linux/bcm27xx/patches-6.1/950-1187-drm-vc4-Correct-HVS-muxing-setup-for-the-moplet.patch new file mode 100644 index 0000000000..be02fd27fa --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1187-drm-vc4-Correct-HVS-muxing-setup-for-the-moplet.patch @@ -0,0 +1,26 @@ +From 01139e4e9141d031c6f4f00371e5eb52fa78839e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 5 Dec 2023 18:28:19 +0000 +Subject: [PATCH] drm/vc4: Correct HVS muxing setup for the moplet + +The moplet registers as VC4_ENCODER_TYPE_TXP1 and can be +fed from mux output 2 of HVS channel 1. + +Correct the option which checked for VC4_ENCODER_TYPE_TXP0 + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_kms.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -365,7 +365,7 @@ static void vc6_hvs_pv_muxing_commit(str + mux = 0; + break; + +- case VC4_ENCODER_TYPE_TXP0: ++ case VC4_ENCODER_TYPE_TXP1: + mux = 2; + break; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1188-drm-vc4-Mop-and-moplet-have-different-register-offse.patch b/target/linux/bcm27xx/patches-6.1/950-1188-drm-vc4-Mop-and-moplet-have-different-register-offse.patch new file mode 100644 index 0000000000..f1bb26a26b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1188-drm-vc4-Mop-and-moplet-have-different-register-offse.patch @@ -0,0 +1,68 @@ +From cc948130d3e1c70ef21ae9963b56e0d500cef70b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 5 Dec 2023 18:29:34 +0000 +Subject: [PATCH] drm/vc4: Mop and moplet have different register offsets for + high addr + +MOP uses register offset 0x24 for the high bits of the address, +whilst Moplet uses 0x1c. + +Handle this difference between the block types. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_txp.c | 8 ++++++-- + 2 files changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -564,6 +564,7 @@ struct vc4_crtc_data { + struct vc4_txp_data { + struct vc4_crtc_data base; + enum vc4_encoder_type encoder_type; ++ unsigned int high_addr_ptr_reg; + unsigned int has_byte_enable:1; + unsigned int size_minus_one:1; + unsigned int supports_40bit_addresses:1; +--- a/drivers/gpu/drm/vc4/vc4_txp.c ++++ b/drivers/gpu/drm/vc4/vc4_txp.c +@@ -145,7 +145,8 @@ + /* Number of lines received and committed to memory. */ + #define TXP_PROGRESS 0x10 + +-#define TXP_DST_PTR_HIGH 0x1c ++#define TXP_DST_PTR_HIGH_MOPLET 0x1c ++#define TXP_DST_PTR_HIGH_MOP 0x24 + + #define TXP_READ(offset) \ + ({ \ +@@ -338,10 +339,11 @@ static void vc4_txp_connector_atomic_com + + gem = drm_fb_dma_get_gem_obj(fb, 0); + addr = gem->dma_addr + fb->offsets[0]; ++ + TXP_WRITE(TXP_DST_PTR, lower_32_bits(addr)); + + if (txp_data->supports_40bit_addresses) +- TXP_WRITE(TXP_DST_PTR_HIGH, upper_32_bits(addr) & 0xff); ++ TXP_WRITE(txp_data->high_addr_ptr_reg, upper_32_bits(addr) & 0xff); + + TXP_WRITE(TXP_DST_PITCH, fb->pitches[0]); + +@@ -520,6 +522,7 @@ const struct vc4_txp_data bcm2712_mop_da + .hvs_output = 2, + }, + .encoder_type = VC4_ENCODER_TYPE_TXP0, ++ .high_addr_ptr_reg = TXP_DST_PTR_HIGH_MOP, + .has_byte_enable = true, + .size_minus_one = true, + .supports_40bit_addresses = true, +@@ -533,6 +536,7 @@ const struct vc4_txp_data bcm2712_moplet + .hvs_output = 4, + }, + .encoder_type = VC4_ENCODER_TYPE_TXP1, ++ .high_addr_ptr_reg = TXP_DST_PTR_HIGH_MOPLET, + .size_minus_one = true, + .supports_40bit_addresses = true, + }; diff --git a/target/linux/bcm27xx/patches-6.1/950-1189-arm-dt-bcm2712-Correct-the-size-of-the-register-rang.patch b/target/linux/bcm27xx/patches-6.1/950-1189-arm-dt-bcm2712-Correct-the-size-of-the-register-rang.patch new file mode 100644 index 0000000000..ece5c716e7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1189-arm-dt-bcm2712-Correct-the-size-of-the-register-rang.patch @@ -0,0 +1,25 @@ +From 36593e2e27769d635ef18301f25b5e219a23949a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 5 Dec 2023 18:31:25 +0000 +Subject: [PATCH] arm: dt: bcm2712: Correct the size of the register range for + MOP + +The Mop covers 0x28 bytes of registers, so ensure the range is +defined appropriately. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2712.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2712.dtsi ++++ b/arch/arm/boot/dts/bcm2712.dtsi +@@ -135,7 +135,7 @@ + + mop: mop@7c500000 { + compatible = "brcm,bcm2712-mop"; +- reg = <0x7c500000 0x20>; ++ reg = <0x7c500000 0x28>; + interrupt-parent = <&disp_intr>; + interrupts = <1>; + status = "disabled"; diff --git a/target/linux/bcm27xx/patches-6.1/950-1192-media-Add-MIPI-CCI-register-access-helper-functions.patch b/target/linux/bcm27xx/patches-6.1/950-1192-media-Add-MIPI-CCI-register-access-helper-functions.patch new file mode 100644 index 0000000000..3305e66986 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1192-media-Add-MIPI-CCI-register-access-helper-functions.patch @@ -0,0 +1,388 @@ +From ae0e1b70f675f6ac7966e427f0d8f57812dbc312 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 27 Jun 2023 14:51:04 +0200 +Subject: [PATCH] media: Add MIPI CCI register access helper functions + +The CSI2 specification specifies a standard method to access camera sensor +registers called "Camera Control Interface (CCI)". + +This uses either 8 or 16 bit (big-endian wire order) register addresses +and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths. + +Currently a lot of Linux camera sensor drivers all have their own custom +helpers for this, often copy and pasted from other drivers. + +Add a set of generic helpers for this so that all sensor drivers can +switch to a single common implementation. + +These helpers take an extra optional "int *err" function parameter, +this can be used to chain a bunch of register accesses together with +only a single error check at the end, rather than needing to error +check each individual register access. The first failing call will +set the contents of err to a non 0 value and all other calls will +then become no-ops. + +Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@redhat.com/ + +Reviewed-by: Andy Shevchenko +Tested-by: Tommaso Merciai +Reviewed-by: Tommaso Merciai +Signed-off-by: Hans de Goede +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 613cbb91e9cee7cf5a61f0816d2acab7bc117407) +--- + Documentation/driver-api/media/v4l2-cci.rst | 5 + + Documentation/driver-api/media/v4l2-core.rst | 1 + + drivers/media/v4l2-core/Kconfig | 9 + + drivers/media/v4l2-core/Makefile | 1 + + drivers/media/v4l2-core/v4l2-cci.c | 166 +++++++++++++++++++ + include/media/v4l2-cci.h | 125 ++++++++++++++ + 6 files changed, 307 insertions(+) + create mode 100644 Documentation/driver-api/media/v4l2-cci.rst + create mode 100644 drivers/media/v4l2-core/v4l2-cci.c + create mode 100644 include/media/v4l2-cci.h + +--- /dev/null ++++ b/Documentation/driver-api/media/v4l2-cci.rst +@@ -0,0 +1,5 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++V4L2 CCI kAPI ++^^^^^^^^^^^^^ ++.. kernel-doc:: include/media/v4l2-cci.h +--- a/Documentation/driver-api/media/v4l2-core.rst ++++ b/Documentation/driver-api/media/v4l2-core.rst +@@ -22,6 +22,7 @@ Video4Linux devices + v4l2-mem2mem + v4l2-async + v4l2-fwnode ++ v4l2-cci + v4l2-rect + v4l2-tuner + v4l2-common +--- a/drivers/media/v4l2-core/Kconfig ++++ b/drivers/media/v4l2-core/Kconfig +@@ -74,6 +74,15 @@ config V4L2_FWNODE + config V4L2_ASYNC + tristate + ++config V4L2_CCI ++ tristate ++ ++config V4L2_CCI_I2C ++ tristate ++ depends on I2C ++ select REGMAP_I2C ++ select V4L2_CCI ++ + # Used by drivers that need Videobuf modules + config VIDEOBUF_GEN + tristate +--- a/drivers/media/v4l2-core/Makefile ++++ b/drivers/media/v4l2-core/Makefile +@@ -25,6 +25,7 @@ videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l + # (e. g. LC_ALL=C sort Makefile) + + obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o ++obj-$(CONFIG_V4L2_CCI) += v4l2-cci.o + obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o + obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o + obj-$(CONFIG_V4L2_H264) += v4l2-h264.o +--- /dev/null ++++ b/drivers/media/v4l2-core/v4l2-cci.c +@@ -0,0 +1,166 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * MIPI Camera Control Interface (CCI) register access helpers. ++ * ++ * Copyright (C) 2023 Hans de Goede ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++int cci_read(struct regmap *map, u32 reg, u64 *val, int *err) ++{ ++ unsigned int len; ++ u8 buf[8]; ++ int ret; ++ ++ if (err && *err) ++ return *err; ++ ++ len = FIELD_GET(CCI_REG_WIDTH_MASK, reg); ++ reg = FIELD_GET(CCI_REG_ADDR_MASK, reg); ++ ++ ret = regmap_bulk_read(map, reg, buf, len); ++ if (ret) { ++ dev_err(regmap_get_device(map), "Error reading reg 0x%4x: %d\n", ++ reg, ret); ++ goto out; ++ } ++ ++ switch (len) { ++ case 1: ++ *val = buf[0]; ++ break; ++ case 2: ++ *val = get_unaligned_be16(buf); ++ break; ++ case 3: ++ *val = get_unaligned_be24(buf); ++ break; ++ case 4: ++ *val = get_unaligned_be32(buf); ++ break; ++ case 8: ++ *val = get_unaligned_be64(buf); ++ break; ++ default: ++ dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n", ++ len, reg); ++ ret = -EINVAL; ++ break; ++ } ++ ++out: ++ if (ret && err) ++ *err = ret; ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(cci_read); ++ ++int cci_write(struct regmap *map, u32 reg, u64 val, int *err) ++{ ++ unsigned int len; ++ u8 buf[8]; ++ int ret; ++ ++ if (err && *err) ++ return *err; ++ ++ len = FIELD_GET(CCI_REG_WIDTH_MASK, reg); ++ reg = FIELD_GET(CCI_REG_ADDR_MASK, reg); ++ ++ switch (len) { ++ case 1: ++ buf[0] = val; ++ break; ++ case 2: ++ put_unaligned_be16(val, buf); ++ break; ++ case 3: ++ put_unaligned_be24(val, buf); ++ break; ++ case 4: ++ put_unaligned_be32(val, buf); ++ break; ++ case 8: ++ put_unaligned_be64(val, buf); ++ break; ++ default: ++ dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n", ++ len, reg); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ ret = regmap_bulk_write(map, reg, buf, len); ++ if (ret) ++ dev_err(regmap_get_device(map), "Error writing reg 0x%4x: %d\n", ++ reg, ret); ++ ++out: ++ if (ret && err) ++ *err = ret; ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(cci_write); ++ ++int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err) ++{ ++ u64 readval; ++ int ret; ++ ++ ret = cci_read(map, reg, &readval, err); ++ if (ret) ++ return ret; ++ ++ val = (readval & ~mask) | (val & mask); ++ ++ return cci_write(map, reg, val, err); ++} ++EXPORT_SYMBOL_GPL(cci_update_bits); ++ ++int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs, ++ unsigned int num_regs, int *err) ++{ ++ unsigned int i; ++ int ret; ++ ++ for (i = 0; i < num_regs; i++) { ++ ret = cci_write(map, regs[i].reg, regs[i].val, err); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(cci_multi_reg_write); ++ ++#if IS_ENABLED(CONFIG_V4L2_CCI_I2C) ++struct regmap *devm_cci_regmap_init_i2c(struct i2c_client *client, ++ int reg_addr_bits) ++{ ++ struct regmap_config config = { ++ .reg_bits = reg_addr_bits, ++ .val_bits = 8, ++ .reg_format_endian = REGMAP_ENDIAN_BIG, ++ .disable_locking = true, ++ }; ++ ++ return devm_regmap_init_i2c(client, &config); ++} ++EXPORT_SYMBOL_GPL(devm_cci_regmap_init_i2c); ++#endif ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Hans de Goede "); ++MODULE_DESCRIPTION("MIPI Camera Control Interface (CCI) support"); +--- /dev/null ++++ b/include/media/v4l2-cci.h +@@ -0,0 +1,125 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * MIPI Camera Control Interface (CCI) register access helpers. ++ * ++ * Copyright (C) 2023 Hans de Goede ++ */ ++#ifndef _V4L2_CCI_H ++#define _V4L2_CCI_H ++ ++#include ++ ++struct i2c_client; ++struct regmap; ++ ++/** ++ * struct cci_reg_sequence - An individual write from a sequence of CCI writes ++ * ++ * @reg: Register address, use CCI_REG#() macros to encode reg width ++ * @val: Register value ++ * ++ * Register/value pairs for sequences of writes. ++ */ ++struct cci_reg_sequence { ++ u32 reg; ++ u64 val; ++}; ++ ++/* ++ * Macros to define register address with the register width encoded ++ * into the higher bits. ++ */ ++#define CCI_REG_ADDR_MASK GENMASK(15, 0) ++#define CCI_REG_WIDTH_SHIFT 16 ++#define CCI_REG_WIDTH_MASK GENMASK(19, 16) ++ ++#define CCI_REG8(x) ((1 << CCI_REG_WIDTH_SHIFT) | (x)) ++#define CCI_REG16(x) ((2 << CCI_REG_WIDTH_SHIFT) | (x)) ++#define CCI_REG24(x) ((3 << CCI_REG_WIDTH_SHIFT) | (x)) ++#define CCI_REG32(x) ((4 << CCI_REG_WIDTH_SHIFT) | (x)) ++#define CCI_REG64(x) ((8 << CCI_REG_WIDTH_SHIFT) | (x)) ++ ++/** ++ * cci_read() - Read a value from a single CCI register ++ * ++ * @map: Register map to read from ++ * @reg: Register address to read, use CCI_REG#() macros to encode reg width ++ * @val: Pointer to store read value ++ * @err: Optional pointer to store errors, if a previous error is set ++ * then the read will be skipped ++ * ++ * Return: %0 on success or a negative error code on failure. ++ */ ++int cci_read(struct regmap *map, u32 reg, u64 *val, int *err); ++ ++/** ++ * cci_write() - Write a value to a single CCI register ++ * ++ * @map: Register map to write to ++ * @reg: Register address to write, use CCI_REG#() macros to encode reg width ++ * @val: Value to be written ++ * @err: Optional pointer to store errors, if a previous error is set ++ * then the write will be skipped ++ * ++ * Return: %0 on success or a negative error code on failure. ++ */ ++int cci_write(struct regmap *map, u32 reg, u64 val, int *err); ++ ++/** ++ * cci_update_bits() - Perform a read/modify/write cycle on ++ * a single CCI register ++ * ++ * @map: Register map to update ++ * @reg: Register address to update, use CCI_REG#() macros to encode reg width ++ * @mask: Bitmask to change ++ * @val: New value for bitmask ++ * @err: Optional pointer to store errors, if a previous error is set ++ * then the update will be skipped ++ * ++ * Note this uses read-modify-write to update the bits, atomicity with regards ++ * to other cci_*() register access functions is NOT guaranteed. ++ * ++ * Return: %0 on success or a negative error code on failure. ++ */ ++int cci_update_bits(struct regmap *map, u32 reg, u64 mask, u64 val, int *err); ++ ++/** ++ * cci_multi_reg_write() - Write multiple registers to the device ++ * ++ * @map: Register map to write to ++ * @regs: Array of structures containing register-address, -value pairs to be ++ * written, register-addresses use CCI_REG#() macros to encode reg width ++ * @num_regs: Number of registers to write ++ * @err: Optional pointer to store errors, if a previous error is set ++ * then the write will be skipped ++ * ++ * Write multiple registers to the device where the set of register, value ++ * pairs are supplied in any order, possibly not all in a single range. ++ * ++ * Use of the CCI_REG#() macros to encode reg width is mandatory. ++ * ++ * For raw lists of register-address, -value pairs with only 8 bit ++ * wide writes regmap_multi_reg_write() can be used instead. ++ * ++ * Return: %0 on success or a negative error code on failure. ++ */ ++int cci_multi_reg_write(struct regmap *map, const struct cci_reg_sequence *regs, ++ unsigned int num_regs, int *err); ++ ++#if IS_ENABLED(CONFIG_V4L2_CCI_I2C) ++/** ++ * devm_cci_regmap_init_i2c() - Create regmap to use with cci_*() register ++ * access functions ++ * ++ * @client: i2c_client to create the regmap for ++ * @reg_addr_bits: register address width to use (8 or 16) ++ * ++ * Note the memory for the created regmap is devm() managed, tied to the client. ++ * ++ * Return: %0 on success or a negative error code on failure. ++ */ ++struct regmap *devm_cci_regmap_init_i2c(struct i2c_client *client, ++ int reg_addr_bits); ++#endif ++ ++#endif diff --git a/target/linux/bcm27xx/patches-6.1/950-1193-media-dt-bindings-Add-OmniVision-OV64A40.patch b/target/linux/bcm27xx/patches-6.1/950-1193-media-dt-bindings-Add-OmniVision-OV64A40.patch new file mode 100644 index 0000000000..649e8bc393 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1193-media-dt-bindings-Add-OmniVision-OV64A40.patch @@ -0,0 +1,114 @@ +From 3d108604ca669b83bb4918c4f5f0a02ddef84972 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Sun, 1 Oct 2023 13:20:12 +0200 +Subject: [PATCH] media: dt-bindings: Add OmniVision OV64A40 + +Add bindings for OmniVision OV64A40. + +Signed-off-by: Jacopo Mondi +--- + .../bindings/media/i2c/ovti,ov64a40.yaml | 98 +++++++++++++++++++ + 1 file changed, 98 insertions(+) + create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml +@@ -0,0 +1,98 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/ovti,ov64a40.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: OmniVision OV64A40 Image Sensor ++ ++maintainers: ++ - Jacopo Mondi ++ ++allOf: ++ - $ref: /schemas/media/video-interface-devices.yaml# ++ ++properties: ++ compatible: ++ const: ovti,ov64a40 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ avdd-supply: ++ description: Analog voltage supply, 2.8 volts ++ ++ dvdd-supply: ++ description: Digital core voltage supply, 1.1 volts ++ ++ dovdd-supply: ++ description: Digital I/O voltage supply, 1.8 volts ++ ++ powerdown-gpios: ++ maxItems: 1 ++ ++ reset-gpios: ++ maxItems: 1 ++ ++ port: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ additionalProperties: false ++ ++ properties: ++ endpoint: ++ $ref: /schemas/media/video-interfaces.yaml# ++ additionalProperties: false ++ ++ properties: ++ bus-type: ++ enum: ++ - 1 # MIPI CSI-2 C-PHY ++ - 4 # MIPI CSI-2 D-PHY ++ data-lanes: true ++ link-frequencies: true ++ clock-noncontinuous: true ++ remote-endpoint: true ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - port ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ #include ++ ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ camera@36 { ++ compatible = "ovti,ov64a40"; ++ reg = <0x36>; ++ clocks = <&camera_clk>; ++ dovdd-supply = <&vgen4_reg>; ++ avdd-supply = <&vgen3_reg>; ++ dvdd-supply = <&vgen2_reg>; ++ powerdown-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ endpoint { ++ remote-endpoint = <&mipi_csi2_in>; ++ bus-type = <4>; ++ data-lanes = <1 2 3 4>; ++ link-frequencies = /bits/ 64 <456000000>; ++ }; ++ }; ++ }; ++ }; ++ ++... diff --git a/target/linux/bcm27xx/patches-6.1/950-1194-media-dt-bindings-i2c-Add-Rohm-BU64754-bindings.patch b/target/linux/bcm27xx/patches-6.1/950-1194-media-dt-bindings-i2c-Add-Rohm-BU64754-bindings.patch new file mode 100644 index 0000000000..82eda14173 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1194-media-dt-bindings-i2c-Add-Rohm-BU64754-bindings.patch @@ -0,0 +1,83 @@ +From 31c2999e543c245f7b96af3e73cd18e1036bfe7b Mon Sep 17 00:00:00 2001 +From: Kieran Bingham +Date: Thu, 14 Sep 2023 17:03:24 +0100 +Subject: [PATCH] media: dt-bindings: i2c: Add Rohm BU64754 bindings + +Add YAML device tree bindings for the ROHM BU64754 VCM Motor Driver for +Camera Autofocus. + +Signed-off-by: Kieran Bingham +Signed-off-by: Jacopo Mondi +--- + .../bindings/media/i2c/rohm,bu64754.yaml | 48 +++++++++++++++++++ + MAINTAINERS | 7 +++ + 2 files changed, 55 insertions(+) + create mode 100644 Documentation/devicetree/bindings/media/i2c/rohm,bu64754.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/rohm,bu64754.yaml +@@ -0,0 +1,48 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++# Copyright (C) 2023 Ideas on Board Oy. ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/rohm,bu64754.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: ROHM BU64754 Actuator Driver for Camera Autofocus ++ ++maintainers: ++ - Kieran Bingham ++ ++description: | ++ The BU64754GWZ is an actuator driver IC which can control the actuator ++ position precisely using an internal Hall Sensor. ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - rohm,bu64754 ++ ++ reg: ++ maxItems: 1 ++ ++ vdd-supply: ++ description: ++ Definition of the regulator used as VDD power supply to the driver. ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ lens@76 { ++ compatible = "rohm,bu64754"; ++ reg = <0x76>; ++ vdd-supply = <&cam1_reg>; ++ }; ++ }; ++... +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -17895,6 +17895,13 @@ S: Maintained + F: Documentation/devicetree/bindings/iio/light/bh1750.yaml + F: drivers/iio/light/bh1750.c + ++ROHM BU64754 MOTOR DRIVER FOR CAMERA AUTOFOCUS ++M: Kieran Bingham ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/rohm,bu64754.yaml ++ + ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS + M: Marek Vasut + L: linux-kernel@vger.kernel.org diff --git a/target/linux/bcm27xx/patches-6.1/950-1195-media-i2c-Add-driver-for-OmniVision-OV64A40.patch b/target/linux/bcm27xx/patches-6.1/950-1195-media-i2c-Add-driver-for-OmniVision-OV64A40.patch new file mode 100644 index 0000000000..2f3ea4b072 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1195-media-i2c-Add-driver-for-OmniVision-OV64A40.patch @@ -0,0 +1,3763 @@ +From 87e3fcaad3017bdc91a7a79d2d1c874422ef87b0 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Thu, 20 Jul 2023 11:44:40 +0200 +Subject: [PATCH] media: i2c: Add driver for OmniVision OV64A40 + +Add a driver for the OmniVision OV64A40 image sensor. + +Signed-off-by: Jacopo Mondi +--- + MAINTAINERS | 8 + + drivers/media/i2c/Kconfig | 14 + + drivers/media/i2c/Makefile | 1 + + drivers/media/i2c/ov64a40.c | 3694 +++++++++++++++++++++++++++++++++++ + 4 files changed, 3717 insertions(+) + create mode 100644 drivers/media/i2c/ov64a40.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15321,6 +15321,14 @@ S: Maintained + T: git git://linuxtv.org/media_tree.git + F: drivers/media/i2c/ov5695.c + ++OMNIVISION OV64A40 SENSOR DRIVER ++M: Jacopo Mondi ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml ++F: drivers/media/i2c/ov64a40.c ++ + OMNIVISION OV7670 SENSOR DRIVER + L: linux-media@vger.kernel.org + S: Orphan +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -631,6 +631,20 @@ config VIDEO_OV5695 + To compile this driver as a module, choose M here: the + module will be called ov5695. + ++config VIDEO_OV64A40 ++ tristate "OmniVision OV64A40 sensor support" ++ depends on I2C && VIDEO_DEV ++ select MEDIA_CONTROLLER ++ select VIDEO_V4L2_SUBDEV_API ++ select V4L2_FWNODE ++ select V4L2_CCI_I2C ++ help ++ This is a Video4Linux2 sensor driver for the OmniVision ++ OV64A40 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ov64a40. ++ + config VIDEO_OV6650 + tristate "OmniVision OV6650 sensor support" + depends on I2C && VIDEO_DEV +--- a/drivers/media/i2c/Makefile ++++ b/drivers/media/i2c/Makefile +@@ -96,6 +96,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o + obj-$(CONFIG_VIDEO_OV5675) += ov5675.o + obj-$(CONFIG_VIDEO_OV5693) += ov5693.o + obj-$(CONFIG_VIDEO_OV5695) += ov5695.o ++obj-$(CONFIG_VIDEO_OV64A40) += ov64a40.o + obj-$(CONFIG_VIDEO_OV6650) += ov6650.o + obj-$(CONFIG_VIDEO_OV7251) += ov7251.o + obj-$(CONFIG_VIDEO_OV7640) += ov7640.o +--- /dev/null ++++ b/drivers/media/i2c/ov64a40.c +@@ -0,0 +1,3694 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * V4L2 sensor driver for OmniVision OV64A40 ++ * ++ * Copyright (C) 2023 Ideas On Board Oy ++ * Copyright (C) 2023 Arducam ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define OV64A40_XCLK_FREQ 24000000 ++ ++#define OV64A40_NATIVE_WIDTH 9286 ++#define OV64A40_NATIVE_HEIGHT 6976 ++#define OV64A40_PIXEL_ARRAY_TOP 0 ++#define OV64A40_PIXEL_ARRAY_LEFT 0 ++#define OV64A40_PIXEL_ARRAY_WIDTH 9248 ++#define OV64A40_PIXEL_ARRAY_HEIGHT 6944 ++ ++#define OV64A40_PIXEL_RATE 300000000 ++ ++#define OV64A40_LINK_FREQ_360M 360000000 ++#define OV64A40_LINK_FREQ_456M 456000000 ++ ++#define OV64A40_PLL1_PRE_DIV0 CCI_REG8(0x0301) ++#define OV64A40_PLL1_PRE_DIV CCI_REG8(0x0303) ++#define OV64A40_PLL1_MULTIPLIER CCI_REG16(0x0304) ++#define OV64A40_PLL1_M_DIV CCI_REG8(0x0307) ++#define OV64A40_PLL2_SEL_BAK_SA1 CCI_REG8(0x0320) ++#define OV64A40_PLL2_PRE_DIV CCI_REG8(0x0323) ++#define OV64A40_PLL2_MULTIPLIER CCI_REG16(0x0324) ++#define OV64A40_PLL2_PRE_DIV0 CCI_REG8(0x0326) ++#define OV64A40_PLL2_DIVDAC CCI_REG8(0x0329) ++#define OV64A40_PLL2_DIVSP CCI_REG8(0x032d) ++#define OV64A40_PLL2_DACPREDIV CCI_REG8(0x032e) ++ ++/* TODO: validate vblank_min, it's not characterized in the datasheet. */ ++#define OV64A40_VBLANK_MIN 128 ++#define OV64A40_VTS_MAX 0xffffff ++ ++#define OV64A40_REG_MEC_LONG_EXPO CCI_REG24(0x3500) ++#define OV64A40_EXPOSURE_MIN 16 ++#define OV64A40_EXPOSURE_MARGIN 32 ++ ++#define OV64A40_REG_MEC_LONG_GAIN CCI_REG16(0x3508) ++#define OV64A40_ANA_GAIN_MIN 0x80 ++#define OV64A40_ANA_GAIN_MAX 0x7ff ++#define OV64A40_ANA_GAIN_DEFAULT 0x80 ++ ++#define OV64A40_REG_TIMING_CTRL0 CCI_REG16(0x3800) ++#define OV64A40_REG_TIMING_CTRL2 CCI_REG16(0x3802) ++#define OV64A40_REG_TIMING_CTRL4 CCI_REG16(0x3804) ++#define OV64A40_REG_TIMING_CTRL6 CCI_REG16(0x3806) ++#define OV64A40_REG_TIMING_CTRL8 CCI_REG16(0x3808) ++#define OV64A40_REG_TIMING_CTRLA CCI_REG16(0x380a) ++#define OV64A40_REG_TIMING_CTRLC CCI_REG16(0x380c) ++#define OV64A40_REG_TIMING_CTRLE CCI_REG16(0x380e) ++#define OV64A40_REG_TIMING_CTRL10 CCI_REG16(0x3810) ++#define OV64A40_REG_TIMING_CTRL12 CCI_REG16(0x3812) ++ ++/* ++ * Careful: a typo in the datasheet calls this register ++ * OV64A40_REG_TIMING_CTRL20. ++ */ ++#define OV64A40_REG_TIMING_CTRL14 CCI_REG8(0x3814) ++#define OV64A40_REG_TIMING_CTRL15 CCI_REG8(0x3815) ++#define OV64A40_ODD_INC_SHIFT 4 ++#define OV64A40_SKIPPING_CONFIG(_odd, _even) \ ++ (((_odd) << OV64A40_ODD_INC_SHIFT) | (_even)) ++ ++#define OV64A40_REG_TIMING_CTRL_20 CCI_REG8(0x3820) ++#define OV64A40_TIMING_CTRL_20_VFLIP BIT(2) ++#define OV64A40_TIMING_CTRL_20_VBIN BIT(1) ++ ++#define OV64A40_REG_TIMING_CTRL_21 CCI_REG8(0x3821) ++#define OV64A40_TIMING_CTRL_21_HBIN BIT(4) ++#define OV64A40_TIMING_CTRL_21_HFLIP BIT(2) ++#define OV64A40_TIMING_CTRL_21_DSPEED BIT(0) ++#define OV64A40_TIMING_CTRL_21_HBIN_CONF \ ++ (OV64A40_TIMING_CTRL_21_HBIN | \ ++ OV64A40_TIMING_CTRL_21_DSPEED) ++ ++#define OV64A40_REG_TIMINGS_VTS_HIGH CCI_REG8(0x3840) ++#define OV64A40_REG_TIMINGS_VTS_MID CCI_REG8(0x380e) ++#define OV64A40_REG_TIMINGS_VTS_LOW CCI_REG8(0x380f) ++ ++/* The test pattern control is weirdly named PRE_ISP_2325_D2V2_TOP_1 in TRM. */ ++#define OV64A40_REG_TEST_PATTERN CCI_REG8(0x50c1) ++#define OV64A40_TEST_PATTERN_DISABLED 0x00 ++#define OV64A40_TEST_PATTERN_TYPE1 BIT(0) ++#define OV64A40_TEST_PATTERN_TYPE2 (BIT(4) | BIT(0)) ++#define OV64A40_TEST_PATTERN_TYPE3 (BIT(5) | BIT(0)) ++#define OV64A40_TEST_PATTERN_TYPE4 (BIT(5) | BIT(4) | BIT(0)) ++ ++#define OV64A40_REG_CHIP_ID CCI_REG24(0x300a) ++#define OV64A40_CHIP_ID 0x566441 ++ ++#define OV64A40_REG_SMIA CCI_REG8(0x0100) ++#define OV64A40_REG_SMIA_STREAMING BIT(0) ++ ++enum ov64a40_link_freq_ids { ++ OV64A40_LINK_FREQ_456M_ID, ++ OV64A40_LINK_FREQ_360M_ID, ++ OV64A40_NUM_LINK_FREQ, ++}; ++ ++static const char * const ov64a40_supply_names[] = { ++ /* Supplies can be enabled in any order */ ++ "avdd", /* Analog (2.8V) supply */ ++ "dovdd", /* Digital Core (1.8V) supply */ ++ "dvdd", /* IF (1.1V) supply */ ++}; ++ ++static const char * const ov64a40_test_pattern_menu[] = { ++ "Disabled", ++ "Type1", ++ "Type2", ++ "Type3", ++ "Type4", ++}; ++ ++static const int ov64a40_test_pattern_val[] = { ++ OV64A40_TEST_PATTERN_DISABLED, ++ OV64A40_TEST_PATTERN_TYPE1, ++ OV64A40_TEST_PATTERN_TYPE2, ++ OV64A40_TEST_PATTERN_TYPE3, ++ OV64A40_TEST_PATTERN_TYPE4, ++}; ++ ++static const unsigned int ov64a40_mbus_codes[] = { ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SRGGB10_1X10, ++}; ++ ++static const struct cci_reg_sequence ov64a40_init[] = { ++ { CCI_REG8(0x0103), 0x01 }, { CCI_REG8(0x0301), 0x88 }, ++ { CCI_REG8(0x0304), 0x00 }, { CCI_REG8(0x0305), 0x96 }, ++ { CCI_REG8(0x0306), 0x03 }, { CCI_REG8(0x0307), 0x00 }, ++ { CCI_REG8(0x0345), 0x2c }, { CCI_REG8(0x034a), 0x02 }, ++ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x0350), 0xc0 }, ++ { CCI_REG8(0x0360), 0x09 }, { CCI_REG8(0x3012), 0x31 }, ++ { CCI_REG8(0x3015), 0xf0 }, { CCI_REG8(0x3017), 0xf0 }, ++ { CCI_REG8(0x301d), 0xf6 }, { CCI_REG8(0x301e), 0xf1 }, ++ { CCI_REG8(0x3022), 0xf0 }, { CCI_REG8(0x3400), 0x08 }, ++ { CCI_REG8(0x3608), 0x41 }, { CCI_REG8(0x3421), 0x02 }, ++ { CCI_REG8(0x3500), 0x00 }, { CCI_REG8(0x3501), 0x00 }, ++ { CCI_REG8(0x3502), 0x18 }, { CCI_REG8(0x3504), 0x0c }, ++ { CCI_REG8(0x3508), 0x01 }, { CCI_REG8(0x3509), 0x00 }, ++ { CCI_REG8(0x350a), 0x01 }, { CCI_REG8(0x350b), 0x00 }, ++ { CCI_REG8(0x350b), 0x00 }, { CCI_REG8(0x3540), 0x00 }, ++ { CCI_REG8(0x3541), 0x00 }, { CCI_REG8(0x3542), 0x08 }, ++ { CCI_REG8(0x3548), 0x01 }, { CCI_REG8(0x3549), 0xa0 }, ++ { CCI_REG8(0x3549), 0x00 }, { CCI_REG8(0x3549), 0x00 }, ++ { CCI_REG8(0x3549), 0x00 }, { CCI_REG8(0x3580), 0x00 }, ++ { CCI_REG8(0x3581), 0x00 }, { CCI_REG8(0x3582), 0x04 }, ++ { CCI_REG8(0x3588), 0x01 }, { CCI_REG8(0x3589), 0xf0 }, ++ { CCI_REG8(0x3589), 0x00 }, { CCI_REG8(0x3589), 0x00 }, ++ { CCI_REG8(0x3589), 0x00 }, { CCI_REG8(0x360d), 0x83 }, ++ { CCI_REG8(0x3616), 0xa0 }, { CCI_REG8(0x3617), 0x31 }, ++ { CCI_REG8(0x3623), 0x10 }, { CCI_REG8(0x3633), 0x03 }, ++ { CCI_REG8(0x3634), 0x03 }, { CCI_REG8(0x3635), 0x77 }, ++ { CCI_REG8(0x3640), 0x19 }, { CCI_REG8(0x3641), 0x80 }, ++ { CCI_REG8(0x364d), 0x0f }, { CCI_REG8(0x3680), 0x80 }, ++ { CCI_REG8(0x3682), 0x00 }, { CCI_REG8(0x3683), 0x00 }, ++ { CCI_REG8(0x3684), 0x07 }, { CCI_REG8(0x3688), 0x01 }, ++ { CCI_REG8(0x3689), 0x08 }, { CCI_REG8(0x368a), 0x26 }, ++ { CCI_REG8(0x368b), 0xc8 }, { CCI_REG8(0x368e), 0x70 }, ++ { CCI_REG8(0x368f), 0x00 }, { CCI_REG8(0x3692), 0x04 }, ++ { CCI_REG8(0x3693), 0x00 }, { CCI_REG8(0x3696), 0xd1 }, ++ { CCI_REG8(0x3697), 0xe0 }, { CCI_REG8(0x3698), 0x80 }, ++ { CCI_REG8(0x3699), 0x2b }, { CCI_REG8(0x369a), 0x00 }, ++ { CCI_REG8(0x369d), 0x00 }, { CCI_REG8(0x369e), 0x14 }, ++ { CCI_REG8(0x369f), 0x20 }, { CCI_REG8(0x36a5), 0x80 }, ++ { CCI_REG8(0x36a6), 0x00 }, { CCI_REG8(0x36a7), 0x00 }, ++ { CCI_REG8(0x36a8), 0x00 }, { CCI_REG8(0x36b5), 0x17 }, ++ { CCI_REG8(0x3701), 0x30 }, { CCI_REG8(0x3706), 0x2b }, ++ { CCI_REG8(0x3709), 0x8d }, { CCI_REG8(0x370b), 0x4f }, ++ { CCI_REG8(0x3711), 0x00 }, { CCI_REG8(0x3712), 0x01 }, ++ { CCI_REG8(0x3713), 0x00 }, { CCI_REG8(0x3720), 0x08 }, ++ { CCI_REG8(0x3727), 0x22 }, { CCI_REG8(0x3728), 0x01 }, ++ { CCI_REG8(0x375e), 0x00 }, { CCI_REG8(0x3760), 0x08 }, ++ { CCI_REG8(0x3761), 0x10 }, { CCI_REG8(0x3762), 0x08 }, ++ { CCI_REG8(0x3765), 0x10 }, { CCI_REG8(0x3766), 0x18 }, ++ { CCI_REG8(0x376a), 0x08 }, { CCI_REG8(0x376b), 0x00 }, ++ { CCI_REG8(0x376d), 0x1b }, { CCI_REG8(0x3791), 0x2b }, ++ { CCI_REG8(0x3793), 0x2b }, { CCI_REG8(0x3795), 0x2b }, ++ { CCI_REG8(0x3797), 0x4f }, { CCI_REG8(0x3799), 0x4f }, ++ { CCI_REG8(0x379b), 0x4f }, { CCI_REG8(0x37a0), 0x22 }, ++ { CCI_REG8(0x37da), 0x04 }, { CCI_REG8(0x37f9), 0x02 }, ++ { CCI_REG8(0x37fa), 0x02 }, { CCI_REG8(0x37fb), 0x02 }, ++ { CCI_REG8(0x3814), 0x11 }, { CCI_REG8(0x3815), 0x11 }, ++ { CCI_REG8(0x3820), 0x40 }, { CCI_REG8(0x3821), 0x04 }, ++ { CCI_REG8(0x3822), 0x00 }, { CCI_REG8(0x3823), 0x04 }, ++ { CCI_REG8(0x3827), 0x08 }, { CCI_REG8(0x3828), 0x00 }, ++ { CCI_REG8(0x382a), 0x81 }, { CCI_REG8(0x382e), 0x70 }, ++ { CCI_REG8(0x3837), 0x10 }, { CCI_REG8(0x3839), 0x00 }, ++ { CCI_REG8(0x383b), 0x00 }, { CCI_REG8(0x383c), 0x00 }, ++ { CCI_REG8(0x383d), 0x10 }, { CCI_REG8(0x383f), 0x00 }, ++ { CCI_REG8(0x384c), 0x02 }, { CCI_REG8(0x384d), 0x8c }, ++ { CCI_REG8(0x3852), 0x00 }, { CCI_REG8(0x3856), 0x10 }, ++ { CCI_REG8(0x3857), 0x10 }, { CCI_REG8(0x3858), 0x20 }, ++ { CCI_REG8(0x3859), 0x20 }, { CCI_REG8(0x3894), 0x00 }, ++ { CCI_REG8(0x3895), 0x00 }, { CCI_REG8(0x3896), 0x00 }, ++ { CCI_REG8(0x3897), 0x00 }, { CCI_REG8(0x3900), 0x40 }, ++ { CCI_REG8(0x3aed), 0x6e }, { CCI_REG8(0x3af1), 0x73 }, ++ { CCI_REG8(0x3d86), 0x12 }, { CCI_REG8(0x3d87), 0x30 }, ++ { CCI_REG8(0x3d8c), 0xab }, { CCI_REG8(0x3d8d), 0xb0 }, ++ { CCI_REG8(0x3f00), 0x12 }, { CCI_REG8(0x3f00), 0x12 }, ++ { CCI_REG8(0x3f00), 0x12 }, { CCI_REG8(0x3f01), 0x03 }, ++ { CCI_REG8(0x4009), 0x01 }, { CCI_REG8(0x400e), 0xc6 }, ++ { CCI_REG8(0x400f), 0x00 }, { CCI_REG8(0x4010), 0x28 }, ++ { CCI_REG8(0x4011), 0x01 }, { CCI_REG8(0x4012), 0x0c }, ++ { CCI_REG8(0x4015), 0x00 }, { CCI_REG8(0x4016), 0x1f }, ++ { CCI_REG8(0x4017), 0x00 }, { CCI_REG8(0x4018), 0x07 }, ++ { CCI_REG8(0x401a), 0x40 }, { CCI_REG8(0x4028), 0x01 }, ++ { CCI_REG8(0x4504), 0x00 }, { CCI_REG8(0x4506), 0x01 }, ++ { CCI_REG8(0x4508), 0x00 }, { CCI_REG8(0x4509), 0x35 }, ++ { CCI_REG8(0x450a), 0x08 }, { CCI_REG8(0x450c), 0x00 }, ++ { CCI_REG8(0x450d), 0x20 }, { CCI_REG8(0x450e), 0x00 }, ++ { CCI_REG8(0x450f), 0x20 }, { CCI_REG8(0x451e), 0x00 }, ++ { CCI_REG8(0x451f), 0x00 }, { CCI_REG8(0x4523), 0x00 }, ++ { CCI_REG8(0x4526), 0x00 }, { CCI_REG8(0x4527), 0x18 }, ++ { CCI_REG8(0x4580), 0x01 }, { CCI_REG8(0x4583), 0x00 }, ++ { CCI_REG8(0x4584), 0x00 }, { CCI_REG8(0x45c0), 0xa1 }, ++ { CCI_REG8(0x4602), 0x08 }, { CCI_REG8(0x4603), 0x05 }, ++ { CCI_REG8(0x4606), 0x12 }, { CCI_REG8(0x4607), 0x30 }, ++ { CCI_REG8(0x460b), 0x00 }, { CCI_REG8(0x460d), 0x00 }, ++ { CCI_REG8(0x4640), 0x00 }, { CCI_REG8(0x4641), 0x24 }, ++ { CCI_REG8(0x4643), 0x08 }, { CCI_REG8(0x4645), 0x14 }, ++ { CCI_REG8(0x4648), 0x0a }, { CCI_REG8(0x4649), 0x06 }, ++ { CCI_REG8(0x464a), 0x00 }, { CCI_REG8(0x464b), 0x30 }, ++ { CCI_REG8(0x4800), 0x04 }, { CCI_REG8(0x4802), 0x02 }, ++ { CCI_REG8(0x480b), 0x10 }, { CCI_REG8(0x480c), 0x80 }, ++ { CCI_REG8(0x480e), 0x04 }, { CCI_REG8(0x480f), 0x32 }, ++ { CCI_REG8(0x481b), 0x12 }, { CCI_REG8(0x4833), 0x30 }, ++ { CCI_REG8(0x4837), 0x08 }, { CCI_REG8(0x484b), 0x27 }, ++ { CCI_REG8(0x4850), 0x42 }, { CCI_REG8(0x4851), 0xaa }, ++ { CCI_REG8(0x4860), 0x01 }, { CCI_REG8(0x4861), 0xec }, ++ { CCI_REG8(0x4862), 0x25 }, { CCI_REG8(0x4888), 0x00 }, ++ { CCI_REG8(0x4889), 0x03 }, { CCI_REG8(0x488c), 0x60 }, ++ { CCI_REG8(0x4910), 0x28 }, { CCI_REG8(0x4911), 0x01 }, ++ { CCI_REG8(0x4912), 0x0c }, { CCI_REG8(0x491a), 0x40 }, ++ { CCI_REG8(0x4915), 0x00 }, { CCI_REG8(0x4916), 0x0f }, ++ { CCI_REG8(0x4917), 0x00 }, { CCI_REG8(0x4918), 0x07 }, ++ { CCI_REG8(0x4a10), 0x28 }, { CCI_REG8(0x4a11), 0x01 }, ++ { CCI_REG8(0x4a12), 0x0c }, { CCI_REG8(0x4a1a), 0x40 }, ++ { CCI_REG8(0x4a15), 0x00 }, { CCI_REG8(0x4a16), 0x0f }, ++ { CCI_REG8(0x4a17), 0x00 }, { CCI_REG8(0x4a18), 0x07 }, ++ { CCI_REG8(0x4d00), 0x04 }, { CCI_REG8(0x4d01), 0x5a }, ++ { CCI_REG8(0x4d02), 0xbb }, { CCI_REG8(0x4d03), 0x84 }, ++ { CCI_REG8(0x4d04), 0xd1 }, { CCI_REG8(0x4d05), 0x68 }, ++ { CCI_REG8(0xc4fa), 0x10 }, { CCI_REG8(0x3b56), 0x0a }, ++ { CCI_REG8(0x3b57), 0x0a }, { CCI_REG8(0x3b58), 0x0c }, ++ { CCI_REG8(0x3b59), 0x10 }, { CCI_REG8(0x3a1d), 0x30 }, ++ { CCI_REG8(0x3a1e), 0x30 }, { CCI_REG8(0x3a21), 0x30 }, ++ { CCI_REG8(0x3a22), 0x30 }, { CCI_REG8(0x3992), 0x02 }, ++ { CCI_REG8(0x399e), 0x02 }, { CCI_REG8(0x39fb), 0x30 }, ++ { CCI_REG8(0x39fc), 0x30 }, { CCI_REG8(0x39fd), 0x30 }, ++ { CCI_REG8(0x39fe), 0x30 }, { CCI_REG8(0x3a6d), 0x83 }, ++ { CCI_REG8(0x3a5e), 0x83 }, { CCI_REG8(0xc500), 0x12 }, ++ { CCI_REG8(0xc501), 0x12 }, { CCI_REG8(0xc502), 0x12 }, ++ { CCI_REG8(0xc503), 0x12 }, { CCI_REG8(0xc505), 0x12 }, ++ { CCI_REG8(0xc506), 0x12 }, { CCI_REG8(0xc507), 0x12 }, ++ { CCI_REG8(0xc508), 0x12 }, { CCI_REG8(0x3a77), 0x12 }, ++ { CCI_REG8(0x3a73), 0x12 }, { CCI_REG8(0x3a7b), 0x12 }, ++ { CCI_REG8(0x3a7f), 0x12 }, { CCI_REG8(0x3b2e), 0x13 }, ++ { CCI_REG8(0x3b29), 0x13 }, { CCI_REG8(0xc439), 0x13 }, ++ { CCI_REG8(0xc469), 0x13 }, { CCI_REG8(0xc41c), 0x89 }, ++ { CCI_REG8(0x3618), 0x80 }, { CCI_REG8(0xc514), 0x51 }, ++ { CCI_REG8(0xc515), 0x2c }, { CCI_REG8(0xc516), 0x16 }, ++ { CCI_REG8(0xc517), 0x0d }, { CCI_REG8(0x3615), 0x7f }, ++ { CCI_REG8(0x3632), 0x99 }, { CCI_REG8(0x3642), 0x00 }, ++ { CCI_REG8(0x3645), 0x80 }, { CCI_REG8(0x3702), 0x2a }, ++ { CCI_REG8(0x3703), 0x2a }, { CCI_REG8(0x3708), 0x2f }, ++ { CCI_REG8(0x3721), 0x15 }, { CCI_REG8(0x3744), 0x28 }, ++ { CCI_REG8(0x3991), 0x0c }, { CCI_REG8(0x371d), 0x24 }, ++ { CCI_REG8(0x371f), 0x0c }, { CCI_REG8(0x374b), 0x03 }, ++ { CCI_REG8(0x37d0), 0x00 }, { CCI_REG8(0x391d), 0x55 }, ++ { CCI_REG8(0x391e), 0x52 }, { CCI_REG8(0x399d), 0x0c }, ++ { CCI_REG8(0x3a2f), 0x01 }, { CCI_REG8(0x3a30), 0x01 }, ++ { CCI_REG8(0x3a31), 0x01 }, { CCI_REG8(0x3a32), 0x01 }, ++ { CCI_REG8(0x3a34), 0x01 }, { CCI_REG8(0x3a35), 0x01 }, ++ { CCI_REG8(0x3a36), 0x01 }, { CCI_REG8(0x3a37), 0x01 }, ++ { CCI_REG8(0x3a43), 0x01 }, { CCI_REG8(0x3a44), 0x01 }, ++ { CCI_REG8(0x3a45), 0x01 }, { CCI_REG8(0x3a46), 0x01 }, ++ { CCI_REG8(0x3a48), 0x01 }, { CCI_REG8(0x3a49), 0x01 }, ++ { CCI_REG8(0x3a4a), 0x01 }, { CCI_REG8(0x3a4b), 0x01 }, ++ { CCI_REG8(0x3a50), 0x14 }, { CCI_REG8(0x3a54), 0x14 }, ++ { CCI_REG8(0x3a60), 0x20 }, { CCI_REG8(0x3a6f), 0x20 }, ++ { CCI_REG8(0x3ac5), 0x01 }, { CCI_REG8(0x3ac6), 0x01 }, ++ { CCI_REG8(0x3ac7), 0x01 }, { CCI_REG8(0x3ac8), 0x01 }, ++ { CCI_REG8(0x3ac9), 0x01 }, { CCI_REG8(0x3aca), 0x01 }, ++ { CCI_REG8(0x3acb), 0x01 }, { CCI_REG8(0x3acc), 0x01 }, ++ { CCI_REG8(0x3acd), 0x01 }, { CCI_REG8(0x3ace), 0x01 }, ++ { CCI_REG8(0x3acf), 0x01 }, { CCI_REG8(0x3ad0), 0x01 }, ++ { CCI_REG8(0x3ad1), 0x01 }, { CCI_REG8(0x3ad2), 0x01 }, ++ { CCI_REG8(0x3ad3), 0x01 }, { CCI_REG8(0x3ad4), 0x01 }, ++ { CCI_REG8(0x3add), 0x1f }, { CCI_REG8(0x3adf), 0x24 }, ++ { CCI_REG8(0x3aef), 0x1f }, { CCI_REG8(0x3af0), 0x24 }, ++ { CCI_REG8(0x3b92), 0x08 }, { CCI_REG8(0x3b93), 0x08 }, ++ { CCI_REG8(0x3b94), 0x08 }, { CCI_REG8(0x3b95), 0x08 }, ++ { CCI_REG8(0x3be7), 0x1e }, { CCI_REG8(0x3be8), 0x26 }, ++ { CCI_REG8(0xc44a), 0x20 }, { CCI_REG8(0xc44c), 0x20 }, ++ { CCI_REG8(0xc483), 0x00 }, { CCI_REG8(0xc484), 0x00 }, ++ { CCI_REG8(0xc485), 0x00 }, { CCI_REG8(0xc486), 0x00 }, ++ { CCI_REG8(0xc487), 0x01 }, { CCI_REG8(0xc488), 0x01 }, ++ { CCI_REG8(0xc489), 0x01 }, { CCI_REG8(0xc48a), 0x01 }, ++ { CCI_REG8(0xc4c1), 0x00 }, { CCI_REG8(0xc4c2), 0x00 }, ++ { CCI_REG8(0xc4c3), 0x00 }, { CCI_REG8(0xc4c4), 0x00 }, ++ { CCI_REG8(0xc4c6), 0x10 }, { CCI_REG8(0xc4c7), 0x10 }, ++ { CCI_REG8(0xc4c8), 0x10 }, { CCI_REG8(0xc4c9), 0x10 }, ++ { CCI_REG8(0xc4ca), 0x10 }, { CCI_REG8(0xc4cb), 0x10 }, ++ { CCI_REG8(0xc4cc), 0x10 }, { CCI_REG8(0xc4cd), 0x10 }, ++ { CCI_REG8(0xc4ea), 0x07 }, { CCI_REG8(0xc4eb), 0x07 }, ++ { CCI_REG8(0xc4ec), 0x07 }, { CCI_REG8(0xc4ed), 0x07 }, ++ { CCI_REG8(0xc4ee), 0x07 }, { CCI_REG8(0xc4f6), 0x10 }, ++ { CCI_REG8(0xc4f7), 0x10 }, { CCI_REG8(0xc4f8), 0x10 }, ++ { CCI_REG8(0xc4f9), 0x10 }, { CCI_REG8(0xc518), 0x0e }, ++ { CCI_REG8(0xc519), 0x0e }, { CCI_REG8(0xc51a), 0x0e }, ++ { CCI_REG8(0xc51b), 0x0e }, { CCI_REG8(0xc51c), 0x0e }, ++ { CCI_REG8(0xc51d), 0x0e }, { CCI_REG8(0xc51e), 0x0e }, ++ { CCI_REG8(0xc51f), 0x0e }, { CCI_REG8(0xc520), 0x0e }, ++ { CCI_REG8(0xc521), 0x0e }, { CCI_REG8(0xc522), 0x0e }, ++ { CCI_REG8(0xc523), 0x0e }, { CCI_REG8(0xc524), 0x0e }, ++ { CCI_REG8(0xc525), 0x0e }, { CCI_REG8(0xc526), 0x0e }, ++ { CCI_REG8(0xc527), 0x0e }, { CCI_REG8(0xc528), 0x0e }, ++ { CCI_REG8(0xc529), 0x0e }, { CCI_REG8(0xc52a), 0x0e }, ++ { CCI_REG8(0xc52b), 0x0e }, { CCI_REG8(0xc52c), 0x0e }, ++ { CCI_REG8(0xc52d), 0x0e }, { CCI_REG8(0xc52e), 0x0e }, ++ { CCI_REG8(0xc52f), 0x0e }, { CCI_REG8(0xc530), 0x0e }, ++ { CCI_REG8(0xc531), 0x0e }, { CCI_REG8(0xc532), 0x0e }, ++ { CCI_REG8(0xc533), 0x0e }, { CCI_REG8(0xc534), 0x0e }, ++ { CCI_REG8(0xc535), 0x0e }, { CCI_REG8(0xc536), 0x0e }, ++ { CCI_REG8(0xc537), 0x0e }, { CCI_REG8(0xc538), 0x0e }, ++ { CCI_REG8(0xc539), 0x0e }, { CCI_REG8(0xc53a), 0x0e }, ++ { CCI_REG8(0xc53b), 0x0e }, { CCI_REG8(0xc53c), 0x0e }, ++ { CCI_REG8(0xc53d), 0x0e }, { CCI_REG8(0xc53e), 0x0e }, ++ { CCI_REG8(0xc53f), 0x0e }, { CCI_REG8(0xc540), 0x0e }, ++ { CCI_REG8(0xc541), 0x0e }, { CCI_REG8(0xc542), 0x0e }, ++ { CCI_REG8(0xc543), 0x0e }, { CCI_REG8(0xc544), 0x0e }, ++ { CCI_REG8(0xc545), 0x0e }, { CCI_REG8(0xc546), 0x0e }, ++ { CCI_REG8(0xc547), 0x0e }, { CCI_REG8(0xc548), 0x0e }, ++ { CCI_REG8(0xc549), 0x0e }, { CCI_REG8(0xc57f), 0x22 }, ++ { CCI_REG8(0xc580), 0x22 }, { CCI_REG8(0xc581), 0x22 }, ++ { CCI_REG8(0xc582), 0x22 }, { CCI_REG8(0xc583), 0x22 }, ++ { CCI_REG8(0xc584), 0x22 }, { CCI_REG8(0xc585), 0x22 }, ++ { CCI_REG8(0xc586), 0x22 }, { CCI_REG8(0xc587), 0x22 }, ++ { CCI_REG8(0xc588), 0x22 }, { CCI_REG8(0xc589), 0x22 }, ++ { CCI_REG8(0xc58a), 0x22 }, { CCI_REG8(0xc58b), 0x22 }, ++ { CCI_REG8(0xc58c), 0x22 }, { CCI_REG8(0xc58d), 0x22 }, ++ { CCI_REG8(0xc58e), 0x22 }, { CCI_REG8(0xc58f), 0x22 }, ++ { CCI_REG8(0xc590), 0x22 }, { CCI_REG8(0xc591), 0x22 }, ++ { CCI_REG8(0xc592), 0x22 }, { CCI_REG8(0xc598), 0x22 }, ++ { CCI_REG8(0xc599), 0x22 }, { CCI_REG8(0xc59a), 0x22 }, ++ { CCI_REG8(0xc59b), 0x22 }, { CCI_REG8(0xc59c), 0x22 }, ++ { CCI_REG8(0xc59d), 0x22 }, { CCI_REG8(0xc59e), 0x22 }, ++ { CCI_REG8(0xc59f), 0x22 }, { CCI_REG8(0xc5a0), 0x22 }, ++ { CCI_REG8(0xc5a1), 0x22 }, { CCI_REG8(0xc5a2), 0x22 }, ++ { CCI_REG8(0xc5a3), 0x22 }, { CCI_REG8(0xc5a4), 0x22 }, ++ { CCI_REG8(0xc5a5), 0x22 }, { CCI_REG8(0xc5a6), 0x22 }, ++ { CCI_REG8(0xc5a7), 0x22 }, { CCI_REG8(0xc5a8), 0x22 }, ++ { CCI_REG8(0xc5a9), 0x22 }, { CCI_REG8(0xc5aa), 0x22 }, ++ { CCI_REG8(0xc5ab), 0x22 }, { CCI_REG8(0xc5b1), 0x2a }, ++ { CCI_REG8(0xc5b2), 0x2a }, { CCI_REG8(0xc5b3), 0x2a }, ++ { CCI_REG8(0xc5b4), 0x2a }, { CCI_REG8(0xc5b5), 0x2a }, ++ { CCI_REG8(0xc5b6), 0x2a }, { CCI_REG8(0xc5b7), 0x2a }, ++ { CCI_REG8(0xc5b8), 0x2a }, { CCI_REG8(0xc5b9), 0x2a }, ++ { CCI_REG8(0xc5ba), 0x2a }, { CCI_REG8(0xc5bb), 0x2a }, ++ { CCI_REG8(0xc5bc), 0x2a }, { CCI_REG8(0xc5bd), 0x2a }, ++ { CCI_REG8(0xc5be), 0x2a }, { CCI_REG8(0xc5bf), 0x2a }, ++ { CCI_REG8(0xc5c0), 0x2a }, { CCI_REG8(0xc5c1), 0x2a }, ++ { CCI_REG8(0xc5c2), 0x2a }, { CCI_REG8(0xc5c3), 0x2a }, ++ { CCI_REG8(0xc5c4), 0x2a }, { CCI_REG8(0xc5ca), 0x2a }, ++ { CCI_REG8(0xc5cb), 0x2a }, { CCI_REG8(0xc5cc), 0x2a }, ++ { CCI_REG8(0xc5cd), 0x2a }, { CCI_REG8(0xc5ce), 0x2a }, ++ { CCI_REG8(0xc5cf), 0x2a }, { CCI_REG8(0xc5d0), 0x2a }, ++ { CCI_REG8(0xc5d1), 0x2a }, { CCI_REG8(0xc5d2), 0x2a }, ++ { CCI_REG8(0xc5d3), 0x2a }, { CCI_REG8(0xc5d4), 0x2a }, ++ { CCI_REG8(0xc5d5), 0x2a }, { CCI_REG8(0xc5d6), 0x2a }, ++ { CCI_REG8(0xc5d7), 0x2a }, { CCI_REG8(0xc5d8), 0x2a }, ++ { CCI_REG8(0xc5d9), 0x2a }, { CCI_REG8(0xc5da), 0x2a }, ++ { CCI_REG8(0xc5db), 0x2a }, { CCI_REG8(0xc5dc), 0x2a }, ++ { CCI_REG8(0xc5dd), 0x2a }, { CCI_REG8(0xc5e8), 0x22 }, ++ { CCI_REG8(0xc5ea), 0x22 }, { CCI_REG8(0x4540), 0x12 }, ++ { CCI_REG8(0x4541), 0x30 }, { CCI_REG8(0x3d86), 0x12 }, ++ { CCI_REG8(0x3d87), 0x30 }, { CCI_REG8(0x4606), 0x12 }, ++ { CCI_REG8(0x4607), 0x30 }, { CCI_REG8(0x4648), 0x0a }, ++ { CCI_REG8(0x4649), 0x06 }, { CCI_REG8(0x3220), 0x12 }, ++ { CCI_REG8(0x3221), 0x30 }, { CCI_REG8(0x40c2), 0x12 }, ++ { CCI_REG8(0x49c2), 0x12 }, { CCI_REG8(0x4ac2), 0x12 }, ++ { CCI_REG8(0x40c3), 0x30 }, { CCI_REG8(0x49c3), 0x30 }, ++ { CCI_REG8(0x4ac3), 0x30 }, { CCI_REG8(0x36b0), 0x12 }, ++ { CCI_REG8(0x36b1), 0x30 }, { CCI_REG8(0x45cb), 0x12 }, ++ { CCI_REG8(0x45cc), 0x30 }, { CCI_REG8(0x4585), 0x12 }, ++ { CCI_REG8(0x4586), 0x30 }, { CCI_REG8(0x36b2), 0x12 }, ++ { CCI_REG8(0x36b3), 0x30 }, { CCI_REG8(0x5a40), 0x75 }, ++ { CCI_REG8(0x5a41), 0x75 }, { CCI_REG8(0x5a42), 0x75 }, ++ { CCI_REG8(0x5a43), 0x75 }, { CCI_REG8(0x5a44), 0x75 }, ++ { CCI_REG8(0x5a45), 0x75 }, { CCI_REG8(0x5a46), 0x75 }, ++ { CCI_REG8(0x5a47), 0x75 }, { CCI_REG8(0x5a48), 0x75 }, ++ { CCI_REG8(0x5a49), 0x75 }, { CCI_REG8(0x5a4a), 0x75 }, ++ { CCI_REG8(0x5a4b), 0x75 }, { CCI_REG8(0x5a4c), 0x75 }, ++ { CCI_REG8(0x5a4d), 0x75 }, { CCI_REG8(0x5a4e), 0x75 }, ++ { CCI_REG8(0x5a4f), 0x75 }, { CCI_REG8(0x5a50), 0x75 }, ++ { CCI_REG8(0x5a51), 0x75 }, { CCI_REG8(0x5a52), 0x75 }, ++ { CCI_REG8(0x5a53), 0x75 }, { CCI_REG8(0x5a54), 0x75 }, ++ { CCI_REG8(0x5a55), 0x75 }, { CCI_REG8(0x5a56), 0x75 }, ++ { CCI_REG8(0x5a57), 0x75 }, { CCI_REG8(0x5a58), 0x75 }, ++ { CCI_REG8(0x5a59), 0x75 }, { CCI_REG8(0x5a5a), 0x75 }, ++ { CCI_REG8(0x5a5b), 0x75 }, { CCI_REG8(0x5a5c), 0x75 }, ++ { CCI_REG8(0x5a5d), 0x75 }, { CCI_REG8(0x5a5e), 0x75 }, ++ { CCI_REG8(0x5a5f), 0x75 }, { CCI_REG8(0x5a60), 0x75 }, ++ { CCI_REG8(0x5a61), 0x75 }, { CCI_REG8(0x5a62), 0x75 }, ++ { CCI_REG8(0x5a63), 0x75 }, { CCI_REG8(0x5a64), 0x75 }, ++ { CCI_REG8(0x5a65), 0x75 }, { CCI_REG8(0x5a66), 0x75 }, ++ { CCI_REG8(0x5a67), 0x75 }, { CCI_REG8(0x5a68), 0x75 }, ++ { CCI_REG8(0x5a69), 0x75 }, { CCI_REG8(0x5a6a), 0x75 }, ++ { CCI_REG8(0x5a6b), 0x75 }, { CCI_REG8(0x5a6c), 0x75 }, ++ { CCI_REG8(0x5a6d), 0x75 }, { CCI_REG8(0x5a6e), 0x75 }, ++ { CCI_REG8(0x5a6f), 0x75 }, { CCI_REG8(0x5a70), 0x75 }, ++ { CCI_REG8(0x5a71), 0x75 }, { CCI_REG8(0x5a72), 0x75 }, ++ { CCI_REG8(0x5a73), 0x75 }, { CCI_REG8(0x5a74), 0x75 }, ++ { CCI_REG8(0x5a75), 0x75 }, { CCI_REG8(0x5a76), 0x75 }, ++ { CCI_REG8(0x5a77), 0x75 }, { CCI_REG8(0x5a78), 0x75 }, ++ { CCI_REG8(0x5a79), 0x75 }, { CCI_REG8(0x5a7a), 0x75 }, ++ { CCI_REG8(0x5a7b), 0x75 }, { CCI_REG8(0x5a7c), 0x75 }, ++ { CCI_REG8(0x5a7d), 0x75 }, { CCI_REG8(0x5a7e), 0x75 }, ++ { CCI_REG8(0x5a7f), 0x75 }, { CCI_REG8(0x5a80), 0x75 }, ++ { CCI_REG8(0x5a81), 0x75 }, { CCI_REG8(0x5a82), 0x75 }, ++ { CCI_REG8(0x5a83), 0x75 }, { CCI_REG8(0x5a84), 0x75 }, ++ { CCI_REG8(0x5a85), 0x75 }, { CCI_REG8(0x5a86), 0x75 }, ++ { CCI_REG8(0x5a87), 0x75 }, { CCI_REG8(0x5a88), 0x75 }, ++ { CCI_REG8(0x5a89), 0x75 }, { CCI_REG8(0x5a8a), 0x75 }, ++ { CCI_REG8(0x5a8b), 0x75 }, { CCI_REG8(0x5a8c), 0x75 }, ++ { CCI_REG8(0x5a8d), 0x75 }, { CCI_REG8(0x5a8e), 0x75 }, ++ { CCI_REG8(0x5a8f), 0x75 }, { CCI_REG8(0x5a90), 0x75 }, ++ { CCI_REG8(0x5a91), 0x75 }, { CCI_REG8(0x5a92), 0x75 }, ++ { CCI_REG8(0x5a93), 0x75 }, { CCI_REG8(0x5a94), 0x75 }, ++ { CCI_REG8(0x5a95), 0x75 }, { CCI_REG8(0x5a96), 0x75 }, ++ { CCI_REG8(0x5a97), 0x75 }, { CCI_REG8(0x5a98), 0x75 }, ++ { CCI_REG8(0x5a99), 0x75 }, { CCI_REG8(0x5a9a), 0x75 }, ++ { CCI_REG8(0x5a9b), 0x75 }, { CCI_REG8(0x5a9c), 0x75 }, ++ { CCI_REG8(0x5a9d), 0x75 }, { CCI_REG8(0x5a9e), 0x75 }, ++ { CCI_REG8(0x5a9f), 0x75 }, { CCI_REG8(0x5aa0), 0x75 }, ++ { CCI_REG8(0x5aa1), 0x75 }, { CCI_REG8(0x5aa2), 0x75 }, ++ { CCI_REG8(0x5aa3), 0x75 }, { CCI_REG8(0x5aa4), 0x75 }, ++ { CCI_REG8(0x5aa5), 0x75 }, { CCI_REG8(0x5aa6), 0x75 }, ++ { CCI_REG8(0x5aa7), 0x75 }, { CCI_REG8(0x5aa8), 0x75 }, ++ { CCI_REG8(0x5aa9), 0x75 }, { CCI_REG8(0x5aaa), 0x75 }, ++ { CCI_REG8(0x5aab), 0x75 }, { CCI_REG8(0x5aac), 0x75 }, ++ { CCI_REG8(0x5aad), 0x75 }, { CCI_REG8(0x5aae), 0x75 }, ++ { CCI_REG8(0x5aaf), 0x75 }, { CCI_REG8(0x5ab0), 0x75 }, ++ { CCI_REG8(0x5ab1), 0x75 }, { CCI_REG8(0x5ab2), 0x75 }, ++ { CCI_REG8(0x5ab3), 0x75 }, { CCI_REG8(0x5ab4), 0x75 }, ++ { CCI_REG8(0x5ab5), 0x75 }, { CCI_REG8(0x5ab6), 0x75 }, ++ { CCI_REG8(0x5ab7), 0x75 }, { CCI_REG8(0x5ab8), 0x75 }, ++ { CCI_REG8(0x5ab9), 0x75 }, { CCI_REG8(0x5aba), 0x75 }, ++ { CCI_REG8(0x5abb), 0x75 }, { CCI_REG8(0x5abc), 0x75 }, ++ { CCI_REG8(0x5abd), 0x75 }, { CCI_REG8(0x5abe), 0x75 }, ++ { CCI_REG8(0x5abf), 0x75 }, { CCI_REG8(0x5ac0), 0x75 }, ++ { CCI_REG8(0x5ac1), 0x75 }, { CCI_REG8(0x5ac2), 0x75 }, ++ { CCI_REG8(0x5ac3), 0x75 }, { CCI_REG8(0x5ac4), 0x75 }, ++ { CCI_REG8(0x5ac5), 0x75 }, { CCI_REG8(0x5ac6), 0x75 }, ++ { CCI_REG8(0x5ac7), 0x75 }, { CCI_REG8(0x5ac8), 0x75 }, ++ { CCI_REG8(0x5ac9), 0x75 }, { CCI_REG8(0x5aca), 0x75 }, ++ { CCI_REG8(0x5acb), 0x75 }, { CCI_REG8(0x5acc), 0x75 }, ++ { CCI_REG8(0x5acd), 0x75 }, { CCI_REG8(0x5ace), 0x75 }, ++ { CCI_REG8(0x5acf), 0x75 }, { CCI_REG8(0x5ad0), 0x75 }, ++ { CCI_REG8(0x5ad1), 0x75 }, { CCI_REG8(0x5ad2), 0x75 }, ++ { CCI_REG8(0x5ad3), 0x75 }, { CCI_REG8(0x5ad4), 0x75 }, ++ { CCI_REG8(0x5ad5), 0x75 }, { CCI_REG8(0x5ad6), 0x75 }, ++ { CCI_REG8(0x5ad7), 0x75 }, { CCI_REG8(0x5ad8), 0x75 }, ++ { CCI_REG8(0x5ad9), 0x75 }, { CCI_REG8(0x5ada), 0x75 }, ++ { CCI_REG8(0x5adb), 0x75 }, { CCI_REG8(0x5adc), 0x75 }, ++ { CCI_REG8(0x5add), 0x75 }, { CCI_REG8(0x5ade), 0x75 }, ++ { CCI_REG8(0x5adf), 0x75 }, { CCI_REG8(0x5ae0), 0x75 }, ++ { CCI_REG8(0x5ae1), 0x75 }, { CCI_REG8(0x5ae2), 0x75 }, ++ { CCI_REG8(0x5ae3), 0x75 }, { CCI_REG8(0x5ae4), 0x75 }, ++ { CCI_REG8(0x5ae5), 0x75 }, { CCI_REG8(0x5ae6), 0x75 }, ++ { CCI_REG8(0x5ae7), 0x75 }, { CCI_REG8(0x5ae8), 0x75 }, ++ { CCI_REG8(0x5ae9), 0x75 }, { CCI_REG8(0x5aea), 0x75 }, ++ { CCI_REG8(0x5aeb), 0x75 }, { CCI_REG8(0x5aec), 0x75 }, ++ { CCI_REG8(0x5aed), 0x75 }, { CCI_REG8(0x5aee), 0x75 }, ++ { CCI_REG8(0x5aef), 0x75 }, { CCI_REG8(0x5af0), 0x75 }, ++ { CCI_REG8(0x5af1), 0x75 }, { CCI_REG8(0x5af2), 0x75 }, ++ { CCI_REG8(0x5af3), 0x75 }, { CCI_REG8(0x5af4), 0x75 }, ++ { CCI_REG8(0x5af5), 0x75 }, { CCI_REG8(0x5af6), 0x75 }, ++ { CCI_REG8(0x5af7), 0x75 }, { CCI_REG8(0x5af8), 0x75 }, ++ { CCI_REG8(0x5af9), 0x75 }, { CCI_REG8(0x5afa), 0x75 }, ++ { CCI_REG8(0x5afb), 0x75 }, { CCI_REG8(0x5afc), 0x75 }, ++ { CCI_REG8(0x5afd), 0x75 }, { CCI_REG8(0x5afe), 0x75 }, ++ { CCI_REG8(0x5aff), 0x75 }, { CCI_REG8(0x5b00), 0x75 }, ++ { CCI_REG8(0x5b01), 0x75 }, { CCI_REG8(0x5b02), 0x75 }, ++ { CCI_REG8(0x5b03), 0x75 }, { CCI_REG8(0x5b04), 0x75 }, ++ { CCI_REG8(0x5b05), 0x75 }, { CCI_REG8(0x5b06), 0x75 }, ++ { CCI_REG8(0x5b07), 0x75 }, { CCI_REG8(0x5b08), 0x75 }, ++ { CCI_REG8(0x5b09), 0x75 }, { CCI_REG8(0x5b0a), 0x75 }, ++ { CCI_REG8(0x5b0b), 0x75 }, { CCI_REG8(0x5b0c), 0x75 }, ++ { CCI_REG8(0x5b0d), 0x75 }, { CCI_REG8(0x5b0e), 0x75 }, ++ { CCI_REG8(0x5b0f), 0x75 }, { CCI_REG8(0x5b10), 0x75 }, ++ { CCI_REG8(0x5b11), 0x75 }, { CCI_REG8(0x5b12), 0x75 }, ++ { CCI_REG8(0x5b13), 0x75 }, { CCI_REG8(0x5b14), 0x75 }, ++ { CCI_REG8(0x5b15), 0x75 }, { CCI_REG8(0x5b16), 0x75 }, ++ { CCI_REG8(0x5b17), 0x75 }, { CCI_REG8(0x5b18), 0x75 }, ++ { CCI_REG8(0x5b19), 0x75 }, { CCI_REG8(0x5b1a), 0x75 }, ++ { CCI_REG8(0x5b1b), 0x75 }, { CCI_REG8(0x5b1c), 0x75 }, ++ { CCI_REG8(0x5b1d), 0x75 }, { CCI_REG8(0x5b1e), 0x75 }, ++ { CCI_REG8(0x5b1f), 0x75 }, { CCI_REG8(0x5b20), 0x75 }, ++ { CCI_REG8(0x5b21), 0x75 }, { CCI_REG8(0x5b22), 0x75 }, ++ { CCI_REG8(0x5b23), 0x75 }, { CCI_REG8(0x5b24), 0x75 }, ++ { CCI_REG8(0x5b25), 0x75 }, { CCI_REG8(0x5b26), 0x75 }, ++ { CCI_REG8(0x5b27), 0x75 }, { CCI_REG8(0x5b28), 0x75 }, ++ { CCI_REG8(0x5b29), 0x75 }, { CCI_REG8(0x5b2a), 0x75 }, ++ { CCI_REG8(0x5b2b), 0x75 }, { CCI_REG8(0x5b2c), 0x75 }, ++ { CCI_REG8(0x5b2d), 0x75 }, { CCI_REG8(0x5b2e), 0x75 }, ++ { CCI_REG8(0x5b2f), 0x75 }, { CCI_REG8(0x5b30), 0x75 }, ++ { CCI_REG8(0x5b31), 0x75 }, { CCI_REG8(0x5b32), 0x75 }, ++ { CCI_REG8(0x5b33), 0x75 }, { CCI_REG8(0x5b34), 0x75 }, ++ { CCI_REG8(0x5b35), 0x75 }, { CCI_REG8(0x5b36), 0x75 }, ++ { CCI_REG8(0x5b37), 0x75 }, { CCI_REG8(0x5b38), 0x75 }, ++ { CCI_REG8(0x5b39), 0x75 }, { CCI_REG8(0x5b3a), 0x75 }, ++ { CCI_REG8(0x5b3b), 0x75 }, { CCI_REG8(0x5b3c), 0x75 }, ++ { CCI_REG8(0x5b3d), 0x75 }, { CCI_REG8(0x5b3e), 0x75 }, ++ { CCI_REG8(0x5b3f), 0x75 }, { CCI_REG8(0x5b40), 0x75 }, ++ { CCI_REG8(0x5b41), 0x75 }, { CCI_REG8(0x5b42), 0x75 }, ++ { CCI_REG8(0x5b43), 0x75 }, { CCI_REG8(0x5b44), 0x75 }, ++ { CCI_REG8(0x5b45), 0x75 }, { CCI_REG8(0x5b46), 0x75 }, ++ { CCI_REG8(0x5b47), 0x75 }, { CCI_REG8(0x5b48), 0x75 }, ++ { CCI_REG8(0x5b49), 0x75 }, { CCI_REG8(0x5b4a), 0x75 }, ++ { CCI_REG8(0x5b4b), 0x75 }, { CCI_REG8(0x5b4c), 0x75 }, ++ { CCI_REG8(0x5b4d), 0x75 }, { CCI_REG8(0x5b4e), 0x75 }, ++ { CCI_REG8(0x5b4f), 0x75 }, { CCI_REG8(0x5b50), 0x75 }, ++ { CCI_REG8(0x5b51), 0x75 }, { CCI_REG8(0x5b52), 0x75 }, ++ { CCI_REG8(0x5b53), 0x75 }, { CCI_REG8(0x5b54), 0x75 }, ++ { CCI_REG8(0x5b55), 0x75 }, { CCI_REG8(0x5b56), 0x75 }, ++ { CCI_REG8(0x5b57), 0x75 }, { CCI_REG8(0x5b58), 0x75 }, ++ { CCI_REG8(0x5b59), 0x75 }, { CCI_REG8(0x5b5a), 0x75 }, ++ { CCI_REG8(0x5b5b), 0x75 }, { CCI_REG8(0x5b5c), 0x75 }, ++ { CCI_REG8(0x5b5d), 0x75 }, { CCI_REG8(0x5b5e), 0x75 }, ++ { CCI_REG8(0x5b5f), 0x75 }, { CCI_REG8(0x5b80), 0x75 }, ++ { CCI_REG8(0x5b81), 0x75 }, { CCI_REG8(0x5b82), 0x75 }, ++ { CCI_REG8(0x5b83), 0x75 }, { CCI_REG8(0x5b84), 0x75 }, ++ { CCI_REG8(0x5b85), 0x75 }, { CCI_REG8(0x5b86), 0x75 }, ++ { CCI_REG8(0x5b87), 0x75 }, { CCI_REG8(0x5b88), 0x75 }, ++ { CCI_REG8(0x5b89), 0x75 }, { CCI_REG8(0x5b8a), 0x75 }, ++ { CCI_REG8(0x5b8b), 0x75 }, { CCI_REG8(0x5b8c), 0x75 }, ++ { CCI_REG8(0x5b8d), 0x75 }, { CCI_REG8(0x5b8e), 0x75 }, ++ { CCI_REG8(0x5b8f), 0x75 }, { CCI_REG8(0x5b90), 0x75 }, ++ { CCI_REG8(0x5b91), 0x75 }, { CCI_REG8(0x5b92), 0x75 }, ++ { CCI_REG8(0x5b93), 0x75 }, { CCI_REG8(0x5b94), 0x75 }, ++ { CCI_REG8(0x5b95), 0x75 }, { CCI_REG8(0x5b96), 0x75 }, ++ { CCI_REG8(0x5b97), 0x75 }, { CCI_REG8(0x5b98), 0x75 }, ++ { CCI_REG8(0x5b99), 0x75 }, { CCI_REG8(0x5b9a), 0x75 }, ++ { CCI_REG8(0x5b9b), 0x75 }, { CCI_REG8(0x5b9c), 0x75 }, ++ { CCI_REG8(0x5b9d), 0x75 }, { CCI_REG8(0x5b9e), 0x75 }, ++ { CCI_REG8(0x5b9f), 0x75 }, { CCI_REG8(0x5ba0), 0x75 }, ++ { CCI_REG8(0x5ba1), 0x75 }, { CCI_REG8(0x5ba2), 0x75 }, ++ { CCI_REG8(0x5ba3), 0x75 }, { CCI_REG8(0x5ba4), 0x75 }, ++ { CCI_REG8(0x5ba5), 0x75 }, { CCI_REG8(0x5ba6), 0x75 }, ++ { CCI_REG8(0x5ba7), 0x75 }, { CCI_REG8(0x5ba8), 0x75 }, ++ { CCI_REG8(0x5ba9), 0x75 }, { CCI_REG8(0x5baa), 0x75 }, ++ { CCI_REG8(0x5bab), 0x75 }, { CCI_REG8(0x5bac), 0x75 }, ++ { CCI_REG8(0x5bad), 0x75 }, { CCI_REG8(0x5bae), 0x75 }, ++ { CCI_REG8(0x5baf), 0x75 }, { CCI_REG8(0x5bb0), 0x75 }, ++ { CCI_REG8(0x5bb1), 0x75 }, { CCI_REG8(0x5bb2), 0x75 }, ++ { CCI_REG8(0x5bb3), 0x75 }, { CCI_REG8(0x5bb4), 0x75 }, ++ { CCI_REG8(0x5bb5), 0x75 }, { CCI_REG8(0x5bb6), 0x75 }, ++ { CCI_REG8(0x5bb7), 0x75 }, { CCI_REG8(0x5bb8), 0x75 }, ++ { CCI_REG8(0x5bb9), 0x75 }, { CCI_REG8(0x5bba), 0x75 }, ++ { CCI_REG8(0x5bbb), 0x75 }, { CCI_REG8(0x5bbc), 0x75 }, ++ { CCI_REG8(0x5bbd), 0x75 }, { CCI_REG8(0x5bbe), 0x75 }, ++ { CCI_REG8(0x5bbf), 0x75 }, { CCI_REG8(0x5bc0), 0x75 }, ++ { CCI_REG8(0x5bc1), 0x75 }, { CCI_REG8(0x5bc2), 0x75 }, ++ { CCI_REG8(0x5bc3), 0x75 }, { CCI_REG8(0x5bc4), 0x75 }, ++ { CCI_REG8(0x5bc5), 0x75 }, { CCI_REG8(0x5bc6), 0x75 }, ++ { CCI_REG8(0x5bc7), 0x75 }, { CCI_REG8(0x5bc8), 0x75 }, ++ { CCI_REG8(0x5bc9), 0x75 }, { CCI_REG8(0x5bca), 0x75 }, ++ { CCI_REG8(0x5bcb), 0x75 }, { CCI_REG8(0x5bcc), 0x75 }, ++ { CCI_REG8(0x5bcd), 0x75 }, { CCI_REG8(0x5bce), 0x75 }, ++ { CCI_REG8(0x5bcf), 0x75 }, { CCI_REG8(0x5bd0), 0x75 }, ++ { CCI_REG8(0x5bd1), 0x75 }, { CCI_REG8(0x5bd2), 0x75 }, ++ { CCI_REG8(0x5bd3), 0x75 }, { CCI_REG8(0x5bd4), 0x75 }, ++ { CCI_REG8(0x5bd5), 0x75 }, { CCI_REG8(0x5bd6), 0x75 }, ++ { CCI_REG8(0x5bd7), 0x75 }, { CCI_REG8(0x5bd8), 0x75 }, ++ { CCI_REG8(0x5bd9), 0x75 }, { CCI_REG8(0x5bda), 0x75 }, ++ { CCI_REG8(0x5bdb), 0x75 }, { CCI_REG8(0x5bdc), 0x75 }, ++ { CCI_REG8(0x5bdd), 0x75 }, { CCI_REG8(0x5bde), 0x75 }, ++ { CCI_REG8(0x5bdf), 0x75 }, { CCI_REG8(0x5be0), 0x75 }, ++ { CCI_REG8(0x5be1), 0x75 }, { CCI_REG8(0x5be2), 0x75 }, ++ { CCI_REG8(0x5be3), 0x75 }, { CCI_REG8(0x5be4), 0x75 }, ++ { CCI_REG8(0x5be5), 0x75 }, { CCI_REG8(0x5be6), 0x75 }, ++ { CCI_REG8(0x5be7), 0x75 }, { CCI_REG8(0x5be8), 0x75 }, ++ { CCI_REG8(0x5be9), 0x75 }, { CCI_REG8(0x5bea), 0x75 }, ++ { CCI_REG8(0x5beb), 0x75 }, { CCI_REG8(0x5bec), 0x75 }, ++ { CCI_REG8(0x5bed), 0x75 }, { CCI_REG8(0x5bee), 0x75 }, ++ { CCI_REG8(0x5bef), 0x75 }, { CCI_REG8(0x5bf0), 0x75 }, ++ { CCI_REG8(0x5bf1), 0x75 }, { CCI_REG8(0x5bf2), 0x75 }, ++ { CCI_REG8(0x5bf3), 0x75 }, { CCI_REG8(0x5bf4), 0x75 }, ++ { CCI_REG8(0x5bf5), 0x75 }, { CCI_REG8(0x5bf6), 0x75 }, ++ { CCI_REG8(0x5bf7), 0x75 }, { CCI_REG8(0x5bf8), 0x75 }, ++ { CCI_REG8(0x5bf9), 0x75 }, { CCI_REG8(0x5bfa), 0x75 }, ++ { CCI_REG8(0x5bfb), 0x75 }, { CCI_REG8(0x5bfc), 0x75 }, ++ { CCI_REG8(0x5bfd), 0x75 }, { CCI_REG8(0x5bfe), 0x75 }, ++ { CCI_REG8(0x5bff), 0x75 }, { CCI_REG8(0x5c00), 0x75 }, ++ { CCI_REG8(0x5c01), 0x75 }, { CCI_REG8(0x5c02), 0x75 }, ++ { CCI_REG8(0x5c03), 0x75 }, { CCI_REG8(0x5c04), 0x75 }, ++ { CCI_REG8(0x5c05), 0x75 }, { CCI_REG8(0x5c06), 0x75 }, ++ { CCI_REG8(0x5c07), 0x75 }, { CCI_REG8(0x5c08), 0x75 }, ++ { CCI_REG8(0x5c09), 0x75 }, { CCI_REG8(0x5c0a), 0x75 }, ++ { CCI_REG8(0x5c0b), 0x75 }, { CCI_REG8(0x5c0c), 0x75 }, ++ { CCI_REG8(0x5c0d), 0x75 }, { CCI_REG8(0x5c0e), 0x75 }, ++ { CCI_REG8(0x5c0f), 0x75 }, { CCI_REG8(0x5c10), 0x75 }, ++ { CCI_REG8(0x5c11), 0x75 }, { CCI_REG8(0x5c12), 0x75 }, ++ { CCI_REG8(0x5c13), 0x75 }, { CCI_REG8(0x5c14), 0x75 }, ++ { CCI_REG8(0x5c15), 0x75 }, { CCI_REG8(0x5c16), 0x75 }, ++ { CCI_REG8(0x5c17), 0x75 }, { CCI_REG8(0x5c18), 0x75 }, ++ { CCI_REG8(0x5c19), 0x75 }, { CCI_REG8(0x5c1a), 0x75 }, ++ { CCI_REG8(0x5c1b), 0x75 }, { CCI_REG8(0x5c1c), 0x75 }, ++ { CCI_REG8(0x5c1d), 0x75 }, { CCI_REG8(0x5c1e), 0x75 }, ++ { CCI_REG8(0x5c1f), 0x75 }, { CCI_REG8(0x5c20), 0x75 }, ++ { CCI_REG8(0x5c21), 0x75 }, { CCI_REG8(0x5c22), 0x75 }, ++ { CCI_REG8(0x5c23), 0x75 }, { CCI_REG8(0x5c24), 0x75 }, ++ { CCI_REG8(0x5c25), 0x75 }, { CCI_REG8(0x5c26), 0x75 }, ++ { CCI_REG8(0x5c27), 0x75 }, { CCI_REG8(0x5c28), 0x75 }, ++ { CCI_REG8(0x5c29), 0x75 }, { CCI_REG8(0x5c2a), 0x75 }, ++ { CCI_REG8(0x5c2b), 0x75 }, { CCI_REG8(0x5c2c), 0x75 }, ++ { CCI_REG8(0x5c2d), 0x75 }, { CCI_REG8(0x5c2e), 0x75 }, ++ { CCI_REG8(0x5c2f), 0x75 }, { CCI_REG8(0x5c30), 0x75 }, ++ { CCI_REG8(0x5c31), 0x75 }, { CCI_REG8(0x5c32), 0x75 }, ++ { CCI_REG8(0x5c33), 0x75 }, { CCI_REG8(0x5c34), 0x75 }, ++ { CCI_REG8(0x5c35), 0x75 }, { CCI_REG8(0x5c36), 0x75 }, ++ { CCI_REG8(0x5c37), 0x75 }, { CCI_REG8(0x5c38), 0x75 }, ++ { CCI_REG8(0x5c39), 0x75 }, { CCI_REG8(0x5c3a), 0x75 }, ++ { CCI_REG8(0x5c3b), 0x75 }, { CCI_REG8(0x5c3c), 0x75 }, ++ { CCI_REG8(0x5c3d), 0x75 }, { CCI_REG8(0x5c3e), 0x75 }, ++ { CCI_REG8(0x5c3f), 0x75 }, { CCI_REG8(0x5c40), 0x75 }, ++ { CCI_REG8(0x5c41), 0x75 }, { CCI_REG8(0x5c42), 0x75 }, ++ { CCI_REG8(0x5c43), 0x75 }, { CCI_REG8(0x5c44), 0x75 }, ++ { CCI_REG8(0x5c45), 0x75 }, { CCI_REG8(0x5c46), 0x75 }, ++ { CCI_REG8(0x5c47), 0x75 }, { CCI_REG8(0x5c48), 0x75 }, ++ { CCI_REG8(0x5c49), 0x75 }, { CCI_REG8(0x5c4a), 0x75 }, ++ { CCI_REG8(0x5c4b), 0x75 }, { CCI_REG8(0x5c4c), 0x75 }, ++ { CCI_REG8(0x5c4d), 0x75 }, { CCI_REG8(0x5c4e), 0x75 }, ++ { CCI_REG8(0x5c4f), 0x75 }, { CCI_REG8(0x5c50), 0x75 }, ++ { CCI_REG8(0x5c51), 0x75 }, { CCI_REG8(0x5c52), 0x75 }, ++ { CCI_REG8(0x5c53), 0x75 }, { CCI_REG8(0x5c54), 0x75 }, ++ { CCI_REG8(0x5c55), 0x75 }, { CCI_REG8(0x5c56), 0x75 }, ++ { CCI_REG8(0x5c57), 0x75 }, { CCI_REG8(0x5c58), 0x75 }, ++ { CCI_REG8(0x5c59), 0x75 }, { CCI_REG8(0x5c5a), 0x75 }, ++ { CCI_REG8(0x5c5b), 0x75 }, { CCI_REG8(0x5c5c), 0x75 }, ++ { CCI_REG8(0x5c5d), 0x75 }, { CCI_REG8(0x5c5e), 0x75 }, ++ { CCI_REG8(0x5c5f), 0x75 }, { CCI_REG8(0x5c60), 0x75 }, ++ { CCI_REG8(0x5c61), 0x75 }, { CCI_REG8(0x5c62), 0x75 }, ++ { CCI_REG8(0x5c63), 0x75 }, { CCI_REG8(0x5c64), 0x75 }, ++ { CCI_REG8(0x5c65), 0x75 }, { CCI_REG8(0x5c66), 0x75 }, ++ { CCI_REG8(0x5c67), 0x75 }, { CCI_REG8(0x5c68), 0x75 }, ++ { CCI_REG8(0x5c69), 0x75 }, { CCI_REG8(0x5c6a), 0x75 }, ++ { CCI_REG8(0x5c6b), 0x75 }, { CCI_REG8(0x5c6c), 0x75 }, ++ { CCI_REG8(0x5c6d), 0x75 }, { CCI_REG8(0x5c6e), 0x75 }, ++ { CCI_REG8(0x5c6f), 0x75 }, { CCI_REG8(0x5c70), 0x75 }, ++ { CCI_REG8(0x5c71), 0x75 }, { CCI_REG8(0x5c72), 0x75 }, ++ { CCI_REG8(0x5c73), 0x75 }, { CCI_REG8(0x5c74), 0x75 }, ++ { CCI_REG8(0x5c75), 0x75 }, { CCI_REG8(0x5c76), 0x75 }, ++ { CCI_REG8(0x5c77), 0x75 }, { CCI_REG8(0x5c78), 0x75 }, ++ { CCI_REG8(0x5c79), 0x75 }, { CCI_REG8(0x5c7a), 0x75 }, ++ { CCI_REG8(0x5c7b), 0x75 }, { CCI_REG8(0x5c7c), 0x75 }, ++ { CCI_REG8(0x5c7d), 0x75 }, { CCI_REG8(0x5c7e), 0x75 }, ++ { CCI_REG8(0x5c7f), 0x75 }, { CCI_REG8(0x5c80), 0x75 }, ++ { CCI_REG8(0x5c81), 0x75 }, { CCI_REG8(0x5c82), 0x75 }, ++ { CCI_REG8(0x5c83), 0x75 }, { CCI_REG8(0x5c84), 0x75 }, ++ { CCI_REG8(0x5c85), 0x75 }, { CCI_REG8(0x5c86), 0x75 }, ++ { CCI_REG8(0x5c87), 0x75 }, { CCI_REG8(0x5c88), 0x75 }, ++ { CCI_REG8(0x5c89), 0x75 }, { CCI_REG8(0x5c8a), 0x75 }, ++ { CCI_REG8(0x5c8b), 0x75 }, { CCI_REG8(0x5c8c), 0x75 }, ++ { CCI_REG8(0x5c8d), 0x75 }, { CCI_REG8(0x5c8e), 0x75 }, ++ { CCI_REG8(0x5c8f), 0x75 }, { CCI_REG8(0x5c90), 0x75 }, ++ { CCI_REG8(0x5c91), 0x75 }, { CCI_REG8(0x5c92), 0x75 }, ++ { CCI_REG8(0x5c93), 0x75 }, { CCI_REG8(0x5c94), 0x75 }, ++ { CCI_REG8(0x5c95), 0x75 }, { CCI_REG8(0x5c96), 0x75 }, ++ { CCI_REG8(0x5c97), 0x75 }, { CCI_REG8(0x5c98), 0x75 }, ++ { CCI_REG8(0x5c99), 0x75 }, { CCI_REG8(0x5c9a), 0x75 }, ++ { CCI_REG8(0x5c9b), 0x75 }, { CCI_REG8(0x5c9c), 0x75 }, ++ { CCI_REG8(0x5c9d), 0x75 }, { CCI_REG8(0x5c9e), 0x75 }, ++ { CCI_REG8(0x5c9f), 0x75 }, { CCI_REG8(0x5ca0), 0x75 }, ++ { CCI_REG8(0x5ca1), 0x75 }, { CCI_REG8(0x5ca2), 0x75 }, ++ { CCI_REG8(0x5ca3), 0x75 }, { CCI_REG8(0x5ca4), 0x75 }, ++ { CCI_REG8(0x5ca5), 0x75 }, { CCI_REG8(0x5ca6), 0x75 }, ++ { CCI_REG8(0x5ca7), 0x75 }, { CCI_REG8(0x5ca8), 0x75 }, ++ { CCI_REG8(0x5ca9), 0x75 }, { CCI_REG8(0x5caa), 0x75 }, ++ { CCI_REG8(0x5cab), 0x75 }, { CCI_REG8(0x5cac), 0x75 }, ++ { CCI_REG8(0x5cad), 0x75 }, { CCI_REG8(0x5cae), 0x75 }, ++ { CCI_REG8(0x5caf), 0x75 }, { CCI_REG8(0x5cb0), 0x75 }, ++ { CCI_REG8(0x5cb1), 0x75 }, { CCI_REG8(0x5cb2), 0x75 }, ++ { CCI_REG8(0x5cb3), 0x75 }, { CCI_REG8(0x5cb4), 0x75 }, ++ { CCI_REG8(0x5cb5), 0x75 }, { CCI_REG8(0x5cb6), 0x75 }, ++ { CCI_REG8(0x5cb7), 0x75 }, { CCI_REG8(0x5cb8), 0x75 }, ++ { CCI_REG8(0x5cb9), 0x75 }, { CCI_REG8(0x5cba), 0x75 }, ++ { CCI_REG8(0x5cbb), 0x75 }, { CCI_REG8(0x5cbc), 0x75 }, ++ { CCI_REG8(0x5cbd), 0x75 }, { CCI_REG8(0x5cbe), 0x75 }, ++ { CCI_REG8(0x5cbf), 0x75 }, { CCI_REG8(0x5cc0), 0x75 }, ++ { CCI_REG8(0x5cc1), 0x75 }, { CCI_REG8(0x5cc2), 0x75 }, ++ { CCI_REG8(0x5cc3), 0x75 }, { CCI_REG8(0x5cc4), 0x75 }, ++ { CCI_REG8(0x5cc5), 0x75 }, { CCI_REG8(0x5cc6), 0x75 }, ++ { CCI_REG8(0x5cc7), 0x75 }, { CCI_REG8(0x5cc8), 0x75 }, ++ { CCI_REG8(0x5cc9), 0x75 }, { CCI_REG8(0x5cca), 0x75 }, ++ { CCI_REG8(0x5ccb), 0x75 }, { CCI_REG8(0x5ccc), 0x75 }, ++ { CCI_REG8(0x5ccd), 0x75 }, { CCI_REG8(0x5cce), 0x75 }, ++ { CCI_REG8(0x5ccf), 0x75 }, { CCI_REG8(0x5cd0), 0x75 }, ++ { CCI_REG8(0x5cd1), 0x75 }, { CCI_REG8(0x5cd2), 0x75 }, ++ { CCI_REG8(0x5cd3), 0x75 }, { CCI_REG8(0x5cd4), 0x75 }, ++ { CCI_REG8(0x5cd5), 0x75 }, { CCI_REG8(0x5cd6), 0x75 }, ++ { CCI_REG8(0x5cd7), 0x75 }, { CCI_REG8(0x5cd8), 0x75 }, ++ { CCI_REG8(0x5cd9), 0x75 }, { CCI_REG8(0x5cda), 0x75 }, ++ { CCI_REG8(0x5cdb), 0x75 }, { CCI_REG8(0x5cdc), 0x75 }, ++ { CCI_REG8(0x5cdd), 0x75 }, { CCI_REG8(0x5cde), 0x75 }, ++ { CCI_REG8(0x5cdf), 0x75 }, { CCI_REG8(0x5ce0), 0x75 }, ++ { CCI_REG8(0x5ce1), 0x75 }, { CCI_REG8(0x5ce2), 0x75 }, ++ { CCI_REG8(0x5ce3), 0x75 }, { CCI_REG8(0x5ce4), 0x75 }, ++ { CCI_REG8(0x5ce5), 0x75 }, { CCI_REG8(0x5ce6), 0x75 }, ++ { CCI_REG8(0x5ce7), 0x75 }, { CCI_REG8(0x5ce8), 0x75 }, ++ { CCI_REG8(0x5ce9), 0x75 }, { CCI_REG8(0x5cea), 0x75 }, ++ { CCI_REG8(0x5ceb), 0x75 }, { CCI_REG8(0x5cec), 0x75 }, ++ { CCI_REG8(0x5ced), 0x75 }, { CCI_REG8(0x5cee), 0x75 }, ++ { CCI_REG8(0x5cef), 0x75 }, { CCI_REG8(0x5cf0), 0x75 }, ++ { CCI_REG8(0x5cf1), 0x75 }, { CCI_REG8(0x5cf2), 0x75 }, ++ { CCI_REG8(0x5cf3), 0x75 }, { CCI_REG8(0x5cf4), 0x75 }, ++ { CCI_REG8(0x5cf5), 0x75 }, { CCI_REG8(0x5cf6), 0x75 }, ++ { CCI_REG8(0x5cf7), 0x75 }, { CCI_REG8(0x5cf8), 0x75 }, ++ { CCI_REG8(0x5cf9), 0x75 }, { CCI_REG8(0x5cfa), 0x75 }, ++ { CCI_REG8(0x5cfb), 0x75 }, { CCI_REG8(0x5cfc), 0x75 }, ++ { CCI_REG8(0x5cfd), 0x75 }, { CCI_REG8(0x5cfe), 0x75 }, ++ { CCI_REG8(0x5cff), 0x75 }, { CCI_REG8(0x5d00), 0x75 }, ++ { CCI_REG8(0x5d01), 0x75 }, { CCI_REG8(0x5d02), 0x75 }, ++ { CCI_REG8(0x5d03), 0x75 }, { CCI_REG8(0x5d04), 0x75 }, ++ { CCI_REG8(0x5d05), 0x75 }, { CCI_REG8(0x5d06), 0x75 }, ++ { CCI_REG8(0x5d07), 0x75 }, { CCI_REG8(0x5d08), 0x75 }, ++ { CCI_REG8(0x5d09), 0x75 }, { CCI_REG8(0x5d0a), 0x75 }, ++ { CCI_REG8(0x5d0b), 0x75 }, { CCI_REG8(0x5d0c), 0x75 }, ++ { CCI_REG8(0x5d0d), 0x75 }, { CCI_REG8(0x5d0e), 0x75 }, ++ { CCI_REG8(0x5d0f), 0x75 }, { CCI_REG8(0x5d10), 0x75 }, ++ { CCI_REG8(0x5d11), 0x75 }, { CCI_REG8(0x5d12), 0x75 }, ++ { CCI_REG8(0x5d13), 0x75 }, { CCI_REG8(0x5d14), 0x75 }, ++ { CCI_REG8(0x5d15), 0x75 }, { CCI_REG8(0x5d16), 0x75 }, ++ { CCI_REG8(0x5d17), 0x75 }, { CCI_REG8(0x5d18), 0x75 }, ++ { CCI_REG8(0x5d19), 0x75 }, { CCI_REG8(0x5d1a), 0x75 }, ++ { CCI_REG8(0x5d1b), 0x75 }, { CCI_REG8(0x5d1c), 0x75 }, ++ { CCI_REG8(0x5d1d), 0x75 }, { CCI_REG8(0x5d1e), 0x75 }, ++ { CCI_REG8(0x5d1f), 0x75 }, { CCI_REG8(0x5d20), 0x75 }, ++ { CCI_REG8(0x5d21), 0x75 }, { CCI_REG8(0x5d22), 0x75 }, ++ { CCI_REG8(0x5d23), 0x75 }, { CCI_REG8(0x5d24), 0x75 }, ++ { CCI_REG8(0x5d25), 0x75 }, { CCI_REG8(0x5d26), 0x75 }, ++ { CCI_REG8(0x5d27), 0x75 }, { CCI_REG8(0x5d28), 0x75 }, ++ { CCI_REG8(0x5d29), 0x75 }, { CCI_REG8(0x5d2a), 0x75 }, ++ { CCI_REG8(0x5d2b), 0x75 }, { CCI_REG8(0x5d2c), 0x75 }, ++ { CCI_REG8(0x5d2d), 0x75 }, { CCI_REG8(0x5d2e), 0x75 }, ++ { CCI_REG8(0x5d2f), 0x75 }, { CCI_REG8(0x5d30), 0x75 }, ++ { CCI_REG8(0x5d31), 0x75 }, { CCI_REG8(0x5d32), 0x75 }, ++ { CCI_REG8(0x5d33), 0x75 }, { CCI_REG8(0x5d34), 0x75 }, ++ { CCI_REG8(0x5d35), 0x75 }, { CCI_REG8(0x5d36), 0x75 }, ++ { CCI_REG8(0x5d37), 0x75 }, { CCI_REG8(0x5d38), 0x75 }, ++ { CCI_REG8(0x5d39), 0x75 }, { CCI_REG8(0x5d3a), 0x75 }, ++ { CCI_REG8(0x5d3b), 0x75 }, { CCI_REG8(0x5d3c), 0x75 }, ++ { CCI_REG8(0x5d3d), 0x75 }, { CCI_REG8(0x5d3e), 0x75 }, ++ { CCI_REG8(0x5d3f), 0x75 }, { CCI_REG8(0x5d40), 0x75 }, ++ { CCI_REG8(0x5d41), 0x75 }, { CCI_REG8(0x5d42), 0x75 }, ++ { CCI_REG8(0x5d43), 0x75 }, { CCI_REG8(0x5d44), 0x75 }, ++ { CCI_REG8(0x5d45), 0x75 }, { CCI_REG8(0x5d46), 0x75 }, ++ { CCI_REG8(0x5d47), 0x75 }, { CCI_REG8(0x5d48), 0x75 }, ++ { CCI_REG8(0x5d49), 0x75 }, { CCI_REG8(0x5d4a), 0x75 }, ++ { CCI_REG8(0x5d4b), 0x75 }, { CCI_REG8(0x5d4c), 0x75 }, ++ { CCI_REG8(0x5d4d), 0x75 }, { CCI_REG8(0x5d4e), 0x75 }, ++ { CCI_REG8(0x5d4f), 0x75 }, { CCI_REG8(0x5d50), 0x75 }, ++ { CCI_REG8(0x5d51), 0x75 }, { CCI_REG8(0x5d52), 0x75 }, ++ { CCI_REG8(0x5d53), 0x75 }, { CCI_REG8(0x5d54), 0x75 }, ++ { CCI_REG8(0x5d55), 0x75 }, { CCI_REG8(0x5d56), 0x75 }, ++ { CCI_REG8(0x5d57), 0x75 }, { CCI_REG8(0x5d58), 0x75 }, ++ { CCI_REG8(0x5d59), 0x75 }, { CCI_REG8(0x5d5a), 0x75 }, ++ { CCI_REG8(0x5d5b), 0x75 }, { CCI_REG8(0x5d5c), 0x75 }, ++ { CCI_REG8(0x5d5d), 0x75 }, { CCI_REG8(0x5d5e), 0x75 }, ++ { CCI_REG8(0x5d5f), 0x75 }, { CCI_REG8(0x5d60), 0x75 }, ++ { CCI_REG8(0x5d61), 0x75 }, { CCI_REG8(0x5d62), 0x75 }, ++ { CCI_REG8(0x5d63), 0x75 }, { CCI_REG8(0x5d64), 0x75 }, ++ { CCI_REG8(0x5d65), 0x75 }, { CCI_REG8(0x5d66), 0x75 }, ++ { CCI_REG8(0x5d67), 0x75 }, { CCI_REG8(0x5d68), 0x75 }, ++ { CCI_REG8(0x5d69), 0x75 }, { CCI_REG8(0x5d6a), 0x75 }, ++ { CCI_REG8(0x5d6b), 0x75 }, { CCI_REG8(0x5d6c), 0x75 }, ++ { CCI_REG8(0x5d6d), 0x75 }, { CCI_REG8(0x5d6e), 0x75 }, ++ { CCI_REG8(0x5d6f), 0x75 }, { CCI_REG8(0x5d70), 0x75 }, ++ { CCI_REG8(0x5d71), 0x75 }, { CCI_REG8(0x5d72), 0x75 }, ++ { CCI_REG8(0x5d73), 0x75 }, { CCI_REG8(0x5d74), 0x75 }, ++ { CCI_REG8(0x5d75), 0x75 }, { CCI_REG8(0x5d76), 0x75 }, ++ { CCI_REG8(0x5d77), 0x75 }, { CCI_REG8(0x5d78), 0x75 }, ++ { CCI_REG8(0x5d79), 0x75 }, { CCI_REG8(0x5d7a), 0x75 }, ++ { CCI_REG8(0x5d7b), 0x75 }, { CCI_REG8(0x5d7c), 0x75 }, ++ { CCI_REG8(0x5d7d), 0x75 }, { CCI_REG8(0x5d7e), 0x75 }, ++ { CCI_REG8(0x5d7f), 0x75 }, { CCI_REG8(0x5d80), 0x75 }, ++ { CCI_REG8(0x5d81), 0x75 }, { CCI_REG8(0x5d82), 0x75 }, ++ { CCI_REG8(0x5d83), 0x75 }, { CCI_REG8(0x5d84), 0x75 }, ++ { CCI_REG8(0x5d85), 0x75 }, { CCI_REG8(0x5d86), 0x75 }, ++ { CCI_REG8(0x5d87), 0x75 }, { CCI_REG8(0x5d88), 0x75 }, ++ { CCI_REG8(0x5d89), 0x75 }, { CCI_REG8(0x5d8a), 0x75 }, ++ { CCI_REG8(0x5d8b), 0x75 }, { CCI_REG8(0x5d8c), 0x75 }, ++ { CCI_REG8(0x5d8d), 0x75 }, { CCI_REG8(0x5d8e), 0x75 }, ++ { CCI_REG8(0x5d8f), 0x75 }, { CCI_REG8(0x5d90), 0x75 }, ++ { CCI_REG8(0x5d91), 0x75 }, { CCI_REG8(0x5d92), 0x75 }, ++ { CCI_REG8(0x5d93), 0x75 }, { CCI_REG8(0x5d94), 0x75 }, ++ { CCI_REG8(0x5d95), 0x75 }, { CCI_REG8(0x5d96), 0x75 }, ++ { CCI_REG8(0x5d97), 0x75 }, { CCI_REG8(0x5d98), 0x75 }, ++ { CCI_REG8(0x5d99), 0x75 }, { CCI_REG8(0x5d9a), 0x75 }, ++ { CCI_REG8(0x5d9b), 0x75 }, { CCI_REG8(0x5d9c), 0x75 }, ++ { CCI_REG8(0x5d9d), 0x75 }, { CCI_REG8(0x5d9e), 0x75 }, ++ { CCI_REG8(0x5d9f), 0x75 }, { CCI_REG8(0x5da0), 0x75 }, ++ { CCI_REG8(0x5da1), 0x75 }, { CCI_REG8(0x5da2), 0x75 }, ++ { CCI_REG8(0x5da3), 0x75 }, { CCI_REG8(0x5da4), 0x75 }, ++ { CCI_REG8(0x5da5), 0x75 }, { CCI_REG8(0x5da6), 0x75 }, ++ { CCI_REG8(0x5da7), 0x75 }, { CCI_REG8(0x5da8), 0x75 }, ++ { CCI_REG8(0x5da9), 0x75 }, { CCI_REG8(0x5daa), 0x75 }, ++ { CCI_REG8(0x5dab), 0x75 }, { CCI_REG8(0x5dac), 0x75 }, ++ { CCI_REG8(0x5dad), 0x75 }, { CCI_REG8(0x5dae), 0x75 }, ++ { CCI_REG8(0x5daf), 0x75 }, { CCI_REG8(0x5db0), 0x75 }, ++ { CCI_REG8(0x5db1), 0x75 }, { CCI_REG8(0x5db2), 0x75 }, ++ { CCI_REG8(0x5db3), 0x75 }, { CCI_REG8(0x5db4), 0x75 }, ++ { CCI_REG8(0x5db5), 0x75 }, { CCI_REG8(0x5db6), 0x75 }, ++ { CCI_REG8(0x5db7), 0x75 }, { CCI_REG8(0x5db8), 0x75 }, ++ { CCI_REG8(0x5db9), 0x75 }, { CCI_REG8(0x5dba), 0x75 }, ++ { CCI_REG8(0x5dbb), 0x75 }, { CCI_REG8(0x5dbc), 0x75 }, ++ { CCI_REG8(0x5dbd), 0x75 }, { CCI_REG8(0x5dbe), 0x75 }, ++ { CCI_REG8(0x5dbf), 0x75 }, { CCI_REG8(0x5dc0), 0x75 }, ++ { CCI_REG8(0x5dc1), 0x75 }, { CCI_REG8(0x5dc2), 0x75 }, ++ { CCI_REG8(0x5dc3), 0x75 }, { CCI_REG8(0x5dc4), 0x75 }, ++ { CCI_REG8(0x5dc5), 0x75 }, { CCI_REG8(0x5dc6), 0x75 }, ++ { CCI_REG8(0x5dc7), 0x75 }, { CCI_REG8(0x5dc8), 0x75 }, ++ { CCI_REG8(0x5dc9), 0x75 }, { CCI_REG8(0x5dca), 0x75 }, ++ { CCI_REG8(0x5dcb), 0x75 }, { CCI_REG8(0x5dcc), 0x75 }, ++ { CCI_REG8(0x5dcd), 0x75 }, { CCI_REG8(0x5dce), 0x75 }, ++ { CCI_REG8(0x5dcf), 0x75 }, { CCI_REG8(0x5dd0), 0x75 }, ++ { CCI_REG8(0x5dd1), 0x75 }, { CCI_REG8(0x5dd2), 0x75 }, ++ { CCI_REG8(0x5dd3), 0x75 }, { CCI_REG8(0x5dd4), 0x75 }, ++ { CCI_REG8(0x5dd5), 0x75 }, { CCI_REG8(0x5dd6), 0x75 }, ++ { CCI_REG8(0x5dd7), 0x75 }, { CCI_REG8(0x5dd8), 0x75 }, ++ { CCI_REG8(0x5dd9), 0x75 }, { CCI_REG8(0x5dda), 0x75 }, ++ { CCI_REG8(0x5ddb), 0x75 }, { CCI_REG8(0x5ddc), 0x75 }, ++ { CCI_REG8(0x5ddd), 0x75 }, { CCI_REG8(0x5dde), 0x75 }, ++ { CCI_REG8(0x5ddf), 0x75 }, { CCI_REG8(0x5de0), 0x75 }, ++ { CCI_REG8(0x5de1), 0x75 }, { CCI_REG8(0x5de2), 0x75 }, ++ { CCI_REG8(0x5de3), 0x75 }, { CCI_REG8(0x5de4), 0x75 }, ++ { CCI_REG8(0x5de5), 0x75 }, { CCI_REG8(0x5de6), 0x75 }, ++ { CCI_REG8(0x5de7), 0x75 }, { CCI_REG8(0x5de8), 0x75 }, ++ { CCI_REG8(0x5de9), 0x75 }, { CCI_REG8(0x5dea), 0x75 }, ++ { CCI_REG8(0x5deb), 0x75 }, { CCI_REG8(0x5dec), 0x75 }, ++ { CCI_REG8(0x5ded), 0x75 }, { CCI_REG8(0x5dee), 0x75 }, ++ { CCI_REG8(0x5def), 0x75 }, { CCI_REG8(0x5df0), 0x75 }, ++ { CCI_REG8(0x5df1), 0x75 }, { CCI_REG8(0x5df2), 0x75 }, ++ { CCI_REG8(0x5df3), 0x75 }, { CCI_REG8(0x5df4), 0x75 }, ++ { CCI_REG8(0x5df5), 0x75 }, { CCI_REG8(0x5df6), 0x75 }, ++ { CCI_REG8(0x5df7), 0x75 }, { CCI_REG8(0x5df8), 0x75 }, ++ { CCI_REG8(0x5df9), 0x75 }, { CCI_REG8(0x5dfa), 0x75 }, ++ { CCI_REG8(0x5dfb), 0x75 }, { CCI_REG8(0x5dfc), 0x75 }, ++ { CCI_REG8(0x5dfd), 0x75 }, { CCI_REG8(0x5dfe), 0x75 }, ++ { CCI_REG8(0x5dff), 0x75 }, { CCI_REG8(0x5e00), 0x75 }, ++ { CCI_REG8(0x5e01), 0x75 }, { CCI_REG8(0x5e02), 0x75 }, ++ { CCI_REG8(0x5e03), 0x75 }, { CCI_REG8(0x5e04), 0x75 }, ++ { CCI_REG8(0x5e05), 0x75 }, { CCI_REG8(0x5e06), 0x75 }, ++ { CCI_REG8(0x5e07), 0x75 }, { CCI_REG8(0x5e08), 0x75 }, ++ { CCI_REG8(0x5e09), 0x75 }, { CCI_REG8(0x5e0a), 0x75 }, ++ { CCI_REG8(0x5e0b), 0x75 }, { CCI_REG8(0x5e0c), 0x75 }, ++ { CCI_REG8(0x5e0d), 0x75 }, { CCI_REG8(0x5e0e), 0x75 }, ++ { CCI_REG8(0x5e0f), 0x75 }, { CCI_REG8(0x5e10), 0x75 }, ++ { CCI_REG8(0x5e11), 0x75 }, { CCI_REG8(0x5e12), 0x75 }, ++ { CCI_REG8(0x5e13), 0x75 }, { CCI_REG8(0x5e14), 0x75 }, ++ { CCI_REG8(0x5e15), 0x75 }, { CCI_REG8(0x5e16), 0x75 }, ++ { CCI_REG8(0x5e17), 0x75 }, { CCI_REG8(0x5e18), 0x75 }, ++ { CCI_REG8(0x5e19), 0x75 }, { CCI_REG8(0x5e1a), 0x75 }, ++ { CCI_REG8(0x5e1b), 0x75 }, { CCI_REG8(0x5e1c), 0x75 }, ++ { CCI_REG8(0x5e1d), 0x75 }, { CCI_REG8(0x5e1e), 0x75 }, ++ { CCI_REG8(0x5e1f), 0x75 }, { CCI_REG8(0x5e20), 0x75 }, ++ { CCI_REG8(0x5e21), 0x75 }, { CCI_REG8(0x5e22), 0x75 }, ++ { CCI_REG8(0x5e23), 0x75 }, { CCI_REG8(0x5e24), 0x75 }, ++ { CCI_REG8(0x5e25), 0x75 }, { CCI_REG8(0x5e26), 0x75 }, ++ { CCI_REG8(0x5e27), 0x75 }, { CCI_REG8(0x5e28), 0x75 }, ++ { CCI_REG8(0x5e29), 0x75 }, { CCI_REG8(0x5e2a), 0x75 }, ++ { CCI_REG8(0x5e2b), 0x75 }, { CCI_REG8(0x5e2c), 0x75 }, ++ { CCI_REG8(0x5e2d), 0x75 }, { CCI_REG8(0x5e2e), 0x75 }, ++ { CCI_REG8(0x5e2f), 0x75 }, { CCI_REG8(0x5e30), 0x75 }, ++ { CCI_REG8(0x5e31), 0x75 }, { CCI_REG8(0x5e32), 0x75 }, ++ { CCI_REG8(0x5e33), 0x75 }, { CCI_REG8(0x5e34), 0x75 }, ++ { CCI_REG8(0x5e35), 0x75 }, { CCI_REG8(0x5e36), 0x75 }, ++ { CCI_REG8(0x5e37), 0x75 }, { CCI_REG8(0x5e38), 0x75 }, ++ { CCI_REG8(0x5e39), 0x75 }, { CCI_REG8(0x5e3a), 0x75 }, ++ { CCI_REG8(0x5e3b), 0x75 }, { CCI_REG8(0x5e3c), 0x75 }, ++ { CCI_REG8(0x5e3d), 0x75 }, { CCI_REG8(0x5e3e), 0x75 }, ++ { CCI_REG8(0x5e3f), 0x75 }, { CCI_REG8(0x5e40), 0x75 }, ++ { CCI_REG8(0x5e41), 0x75 }, { CCI_REG8(0x5e42), 0x75 }, ++ { CCI_REG8(0x5e43), 0x75 }, { CCI_REG8(0x5e44), 0x75 }, ++ { CCI_REG8(0x5e45), 0x75 }, { CCI_REG8(0x5e46), 0x75 }, ++ { CCI_REG8(0x5e47), 0x75 }, { CCI_REG8(0x5e48), 0x75 }, ++ { CCI_REG8(0x5e49), 0x75 }, { CCI_REG8(0x5e4a), 0x75 }, ++ { CCI_REG8(0x5e4b), 0x75 }, { CCI_REG8(0x5e4c), 0x75 }, ++ { CCI_REG8(0x5e4d), 0x75 }, { CCI_REG8(0x5e4e), 0x75 }, ++ { CCI_REG8(0x5e4f), 0x75 }, { CCI_REG8(0x5e50), 0x75 }, ++ { CCI_REG8(0x5e51), 0x75 }, { CCI_REG8(0x5e52), 0x75 }, ++ { CCI_REG8(0x5e53), 0x75 }, { CCI_REG8(0x5e54), 0x75 }, ++ { CCI_REG8(0x5e55), 0x75 }, { CCI_REG8(0x5e56), 0x75 }, ++ { CCI_REG8(0x5e57), 0x75 }, { CCI_REG8(0x5e58), 0x75 }, ++ { CCI_REG8(0x5e59), 0x75 }, { CCI_REG8(0x5e5a), 0x75 }, ++ { CCI_REG8(0x5e5b), 0x75 }, { CCI_REG8(0x5e5c), 0x75 }, ++ { CCI_REG8(0x5e5d), 0x75 }, { CCI_REG8(0x5e5e), 0x75 }, ++ { CCI_REG8(0x5e5f), 0x75 }, { CCI_REG8(0x5e60), 0x75 }, ++ { CCI_REG8(0x5e61), 0x75 }, { CCI_REG8(0x5e62), 0x75 }, ++ { CCI_REG8(0x5e63), 0x75 }, { CCI_REG8(0x5e64), 0x75 }, ++ { CCI_REG8(0x5e65), 0x75 }, { CCI_REG8(0x5e66), 0x75 }, ++ { CCI_REG8(0x5e67), 0x75 }, { CCI_REG8(0x5e68), 0x75 }, ++ { CCI_REG8(0x5e69), 0x75 }, { CCI_REG8(0x5e6a), 0x75 }, ++ { CCI_REG8(0x5e6b), 0x75 }, { CCI_REG8(0x5e6c), 0x75 }, ++ { CCI_REG8(0x5e6d), 0x75 }, { CCI_REG8(0x5e6e), 0x75 }, ++ { CCI_REG8(0x5e6f), 0x75 }, { CCI_REG8(0x5e70), 0x75 }, ++ { CCI_REG8(0x5e71), 0x75 }, { CCI_REG8(0x5e72), 0x75 }, ++ { CCI_REG8(0x5e73), 0x75 }, { CCI_REG8(0x5e74), 0x75 }, ++ { CCI_REG8(0x5e75), 0x75 }, { CCI_REG8(0x5e76), 0x75 }, ++ { CCI_REG8(0x5e77), 0x75 }, { CCI_REG8(0x5e78), 0x75 }, ++ { CCI_REG8(0x5e79), 0x75 }, { CCI_REG8(0x5e7a), 0x75 }, ++ { CCI_REG8(0x5e7b), 0x75 }, { CCI_REG8(0x5e7c), 0x75 }, ++ { CCI_REG8(0x5e7d), 0x75 }, { CCI_REG8(0x5e7e), 0x75 }, ++ { CCI_REG8(0x5e7f), 0x75 }, { CCI_REG8(0x5e80), 0x75 }, ++ { CCI_REG8(0x5e81), 0x75 }, { CCI_REG8(0x5e82), 0x75 }, ++ { CCI_REG8(0x5e83), 0x75 }, { CCI_REG8(0x5e84), 0x75 }, ++ { CCI_REG8(0x5e85), 0x75 }, { CCI_REG8(0x5e86), 0x75 }, ++ { CCI_REG8(0x5e87), 0x75 }, { CCI_REG8(0x5e88), 0x75 }, ++ { CCI_REG8(0x5e89), 0x75 }, { CCI_REG8(0x5e8a), 0x75 }, ++ { CCI_REG8(0x5e8b), 0x75 }, { CCI_REG8(0x5e8c), 0x75 }, ++ { CCI_REG8(0x5e8d), 0x75 }, { CCI_REG8(0x5e8e), 0x75 }, ++ { CCI_REG8(0x5e8f), 0x75 }, { CCI_REG8(0x5e90), 0x75 }, ++ { CCI_REG8(0x5e91), 0x75 }, { CCI_REG8(0x5e92), 0x75 }, ++ { CCI_REG8(0x5e93), 0x75 }, { CCI_REG8(0x5e94), 0x75 }, ++ { CCI_REG8(0x5e95), 0x75 }, { CCI_REG8(0x5e96), 0x75 }, ++ { CCI_REG8(0x5e97), 0x75 }, { CCI_REG8(0x5e98), 0x75 }, ++ { CCI_REG8(0x5e99), 0x75 }, { CCI_REG8(0x5e9a), 0x75 }, ++ { CCI_REG8(0x5e9b), 0x75 }, { CCI_REG8(0x5e9c), 0x75 }, ++ { CCI_REG8(0x5e9d), 0x75 }, { CCI_REG8(0x5e9e), 0x75 }, ++ { CCI_REG8(0x5e9f), 0x75 }, { CCI_REG8(0x5ea0), 0x75 }, ++ { CCI_REG8(0x5ea1), 0x75 }, { CCI_REG8(0x5ea2), 0x75 }, ++ { CCI_REG8(0x5ea3), 0x75 }, { CCI_REG8(0x5ea4), 0x75 }, ++ { CCI_REG8(0x5ea5), 0x75 }, { CCI_REG8(0x5ea6), 0x75 }, ++ { CCI_REG8(0x5ea7), 0x75 }, { CCI_REG8(0x5ea8), 0x75 }, ++ { CCI_REG8(0x5ea9), 0x75 }, { CCI_REG8(0x5eaa), 0x75 }, ++ { CCI_REG8(0x5eab), 0x75 }, { CCI_REG8(0x5eac), 0x75 }, ++ { CCI_REG8(0x5ead), 0x75 }, { CCI_REG8(0x5eae), 0x75 }, ++ { CCI_REG8(0x5eaf), 0x75 }, { CCI_REG8(0x5eb0), 0x75 }, ++ { CCI_REG8(0x5eb1), 0x75 }, { CCI_REG8(0x5eb2), 0x75 }, ++ { CCI_REG8(0x5eb3), 0x75 }, { CCI_REG8(0x5eb4), 0x75 }, ++ { CCI_REG8(0x5eb5), 0x75 }, { CCI_REG8(0x5eb6), 0x75 }, ++ { CCI_REG8(0x5eb7), 0x75 }, { CCI_REG8(0x5eb8), 0x75 }, ++ { CCI_REG8(0x5eb9), 0x75 }, { CCI_REG8(0x5eba), 0x75 }, ++ { CCI_REG8(0x5ebb), 0x75 }, { CCI_REG8(0x5ebc), 0x75 }, ++ { CCI_REG8(0x5ebd), 0x75 }, { CCI_REG8(0x5ebe), 0x75 }, ++ { CCI_REG8(0x5ebf), 0x75 }, { CCI_REG8(0x5ec0), 0x75 }, ++ { CCI_REG8(0x5ec1), 0x75 }, { CCI_REG8(0x5ec2), 0x75 }, ++ { CCI_REG8(0x5ec3), 0x75 }, { CCI_REG8(0x5ec4), 0x75 }, ++ { CCI_REG8(0x5ec5), 0x75 }, { CCI_REG8(0x5ec6), 0x75 }, ++ { CCI_REG8(0x5ec7), 0x75 }, { CCI_REG8(0x5ec8), 0x75 }, ++ { CCI_REG8(0x5ec9), 0x75 }, { CCI_REG8(0x5eca), 0x75 }, ++ { CCI_REG8(0x5ecb), 0x75 }, { CCI_REG8(0x5ecc), 0x75 }, ++ { CCI_REG8(0x5ecd), 0x75 }, { CCI_REG8(0x5ece), 0x75 }, ++ { CCI_REG8(0x5ecf), 0x75 }, { CCI_REG8(0x5ed0), 0x75 }, ++ { CCI_REG8(0x5ed1), 0x75 }, { CCI_REG8(0x5ed2), 0x75 }, ++ { CCI_REG8(0x5ed3), 0x75 }, { CCI_REG8(0x5ed4), 0x75 }, ++ { CCI_REG8(0x5ed5), 0x75 }, { CCI_REG8(0x5ed6), 0x75 }, ++ { CCI_REG8(0x5ed7), 0x75 }, { CCI_REG8(0x5ed8), 0x75 }, ++ { CCI_REG8(0x5ed9), 0x75 }, { CCI_REG8(0x5eda), 0x75 }, ++ { CCI_REG8(0x5edb), 0x75 }, { CCI_REG8(0x5edc), 0x75 }, ++ { CCI_REG8(0x5edd), 0x75 }, { CCI_REG8(0x5ede), 0x75 }, ++ { CCI_REG8(0x5edf), 0x75 }, { CCI_REG8(0xfff9), 0x08 }, ++ { CCI_REG8(0x1570), 0x00 }, { CCI_REG8(0x15d0), 0x00 }, ++ { CCI_REG8(0x15a0), 0x02 }, { CCI_REG8(0x15a1), 0x00 }, ++ { CCI_REG8(0x15a2), 0x02 }, { CCI_REG8(0x15a3), 0x76 }, ++ { CCI_REG8(0x15a4), 0x03 }, { CCI_REG8(0x15a5), 0x08 }, ++ { CCI_REG8(0x15a6), 0x00 }, { CCI_REG8(0x15a7), 0x60 }, ++ { CCI_REG8(0x15a8), 0x01 }, { CCI_REG8(0x15a9), 0x00 }, ++ { CCI_REG8(0x15aa), 0x02 }, { CCI_REG8(0x15ab), 0x00 }, ++ { CCI_REG8(0x1600), 0x02 }, { CCI_REG8(0x1601), 0x00 }, ++ { CCI_REG8(0x1602), 0x02 }, { CCI_REG8(0x1603), 0x76 }, ++ { CCI_REG8(0x1604), 0x03 }, { CCI_REG8(0x1605), 0x08 }, ++ { CCI_REG8(0x1606), 0x00 }, { CCI_REG8(0x1607), 0x60 }, ++ { CCI_REG8(0x1608), 0x01 }, { CCI_REG8(0x1609), 0x00 }, ++ { CCI_REG8(0x160a), 0x02 }, { CCI_REG8(0x160b), 0x00 }, ++ { CCI_REG8(0x1633), 0x03 }, { CCI_REG8(0x1634), 0x01 }, ++ { CCI_REG8(0x163c), 0x3a }, { CCI_REG8(0x163d), 0x01 }, ++ { CCI_REG8(0x1648), 0x32 }, { CCI_REG8(0x1658), 0x01 }, ++ { CCI_REG8(0x1659), 0x01 }, { CCI_REG8(0x165f), 0x01 }, ++ { CCI_REG8(0x1677), 0x01 }, { CCI_REG8(0x1690), 0x08 }, ++ { CCI_REG8(0x1691), 0x00 }, { CCI_REG8(0x1692), 0x20 }, ++ { CCI_REG8(0x1693), 0x00 }, { CCI_REG8(0x1694), 0x10 }, ++ { CCI_REG8(0x1695), 0x14 }, { CCI_REG8(0x1696), 0x10 }, ++ { CCI_REG8(0x1697), 0x0e }, { CCI_REG8(0x1730), 0x01 }, ++ { CCI_REG8(0x1732), 0x00 }, { CCI_REG8(0x1733), 0x10 }, ++ { CCI_REG8(0x1734), 0x01 }, { CCI_REG8(0x1735), 0x00 }, ++ { CCI_REG8(0x1748), 0x01 }, { CCI_REG8(0xfff9), 0x06 }, ++ { CCI_REG8(0x5000), 0xff }, { CCI_REG8(0x5001), 0x3d }, ++ { CCI_REG8(0x5002), 0xf5 }, { CCI_REG8(0x5004), 0x80 }, ++ { CCI_REG8(0x5006), 0x04 }, { CCI_REG8(0x5061), 0x20 }, ++ { CCI_REG8(0x5063), 0x20 }, { CCI_REG8(0x5064), 0x24 }, ++ { CCI_REG8(0x5065), 0x00 }, { CCI_REG8(0x5066), 0x1b }, ++ { CCI_REG8(0x5067), 0x00 }, { CCI_REG8(0x5068), 0x03 }, ++ { CCI_REG8(0x5069), 0x10 }, { CCI_REG8(0x506a), 0x20 }, ++ { CCI_REG8(0x506b), 0x04 }, { CCI_REG8(0x506c), 0x04 }, ++ { CCI_REG8(0x506d), 0x0c }, { CCI_REG8(0x506e), 0x0c }, ++ { CCI_REG8(0x506f), 0x04 }, { CCI_REG8(0x5070), 0x0c }, ++ { CCI_REG8(0x5071), 0x14 }, { CCI_REG8(0x5072), 0x1c }, ++ { CCI_REG8(0x5073), 0x01 }, { CCI_REG8(0x5074), 0x01 }, ++ { CCI_REG8(0x5075), 0xbe }, { CCI_REG8(0x5083), 0x00 }, ++ { CCI_REG8(0x5114), 0x03 }, { CCI_REG8(0x51b0), 0x00 }, ++ { CCI_REG8(0x51b3), 0x0e }, { CCI_REG8(0x51b5), 0x02 }, ++ { CCI_REG8(0x51b6), 0x00 }, { CCI_REG8(0x51b7), 0x00 }, ++ { CCI_REG8(0x51b8), 0x00 }, { CCI_REG8(0x51b9), 0x70 }, ++ { CCI_REG8(0x51ba), 0x00 }, { CCI_REG8(0x51bb), 0x10 }, ++ { CCI_REG8(0x51bc), 0x00 }, { CCI_REG8(0x51bd), 0x00 }, ++ { CCI_REG8(0x51d2), 0xff }, { CCI_REG8(0x51d3), 0x1c }, ++ { CCI_REG8(0x5250), 0x34 }, { CCI_REG8(0x5251), 0x00 }, ++ { CCI_REG8(0x525b), 0x00 }, { CCI_REG8(0x525d), 0x00 }, ++ { CCI_REG8(0x527a), 0x00 }, { CCI_REG8(0x527b), 0x38 }, ++ { CCI_REG8(0x527c), 0x00 }, { CCI_REG8(0x527d), 0x4b }, ++ { CCI_REG8(0x5286), 0x1b }, { CCI_REG8(0x5287), 0x40 }, ++ { CCI_REG8(0x5290), 0x00 }, { CCI_REG8(0x5291), 0x50 }, ++ { CCI_REG8(0x5292), 0x00 }, { CCI_REG8(0x5293), 0x50 }, ++ { CCI_REG8(0x5294), 0x00 }, { CCI_REG8(0x5295), 0x50 }, ++ { CCI_REG8(0x5296), 0x00 }, { CCI_REG8(0x5297), 0x50 }, ++ { CCI_REG8(0x5298), 0x00 }, { CCI_REG8(0x5299), 0x50 }, ++ { CCI_REG8(0x529a), 0x01 }, { CCI_REG8(0x529b), 0x00 }, ++ { CCI_REG8(0x529c), 0x01 }, { CCI_REG8(0x529d), 0x00 }, ++ { CCI_REG8(0x529e), 0x00 }, { CCI_REG8(0x529f), 0x50 }, ++ { CCI_REG8(0x52a0), 0x00 }, { CCI_REG8(0x52a1), 0x50 }, ++ { CCI_REG8(0x52a2), 0x01 }, { CCI_REG8(0x52a3), 0x00 }, ++ { CCI_REG8(0x52a4), 0x01 }, { CCI_REG8(0x52a5), 0x00 }, ++ { CCI_REG8(0x52a6), 0x00 }, { CCI_REG8(0x52a7), 0x50 }, ++ { CCI_REG8(0x52a8), 0x00 }, { CCI_REG8(0x52a9), 0x50 }, ++ { CCI_REG8(0x52aa), 0x00 }, { CCI_REG8(0x52ab), 0x50 }, ++ { CCI_REG8(0x52ac), 0x00 }, { CCI_REG8(0x52ad), 0x50 }, ++ { CCI_REG8(0x52ae), 0x00 }, { CCI_REG8(0x52af), 0x50 }, ++ { CCI_REG8(0x52b0), 0x00 }, { CCI_REG8(0x52b1), 0x50 }, ++ { CCI_REG8(0x52b2), 0x00 }, { CCI_REG8(0x52b3), 0x50 }, ++ { CCI_REG8(0x52b4), 0x00 }, { CCI_REG8(0x52b5), 0x50 }, ++ { CCI_REG8(0x52b6), 0x00 }, { CCI_REG8(0x52b7), 0x50 }, ++ { CCI_REG8(0x52b8), 0x00 }, { CCI_REG8(0x52b9), 0x50 }, ++ { CCI_REG8(0x52ba), 0x01 }, { CCI_REG8(0x52bb), 0x00 }, ++ { CCI_REG8(0x52bc), 0x01 }, { CCI_REG8(0x52bd), 0x00 }, ++ { CCI_REG8(0x52be), 0x00 }, { CCI_REG8(0x52bf), 0x50 }, ++ { CCI_REG8(0x52c0), 0x00 }, { CCI_REG8(0x52c1), 0x50 }, ++ { CCI_REG8(0x52c2), 0x01 }, { CCI_REG8(0x52c3), 0x00 }, ++ { CCI_REG8(0x52c4), 0x01 }, { CCI_REG8(0x52c5), 0x00 }, ++ { CCI_REG8(0x52c6), 0x00 }, { CCI_REG8(0x52c7), 0x50 }, ++ { CCI_REG8(0x52c8), 0x00 }, { CCI_REG8(0x52c9), 0x50 }, ++ { CCI_REG8(0x52ca), 0x00 }, { CCI_REG8(0x52cb), 0x50 }, ++ { CCI_REG8(0x52cc), 0x00 }, { CCI_REG8(0x52cd), 0x50 }, ++ { CCI_REG8(0x52ce), 0x00 }, { CCI_REG8(0x52cf), 0x50 }, ++ { CCI_REG8(0x52f0), 0x04 }, { CCI_REG8(0x52f1), 0x03 }, ++ { CCI_REG8(0x52f2), 0x02 }, { CCI_REG8(0x52f3), 0x01 }, ++ { CCI_REG8(0x52f4), 0x08 }, { CCI_REG8(0x52f5), 0x07 }, ++ { CCI_REG8(0x52f6), 0x06 }, { CCI_REG8(0x52f7), 0x05 }, ++ { CCI_REG8(0x52f8), 0x0c }, { CCI_REG8(0x52f9), 0x0b }, ++ { CCI_REG8(0x52fa), 0x0a }, { CCI_REG8(0x52fb), 0x09 }, ++ { CCI_REG8(0x52fc), 0x10 }, { CCI_REG8(0x52fd), 0x0f }, ++ { CCI_REG8(0x52fe), 0x0e }, { CCI_REG8(0x52ff), 0x0d }, ++ { CCI_REG8(0x5300), 0x14 }, { CCI_REG8(0x5301), 0x13 }, ++ { CCI_REG8(0x5302), 0x12 }, { CCI_REG8(0x5303), 0x11 }, ++ { CCI_REG8(0x5304), 0x18 }, { CCI_REG8(0x5305), 0x17 }, ++ { CCI_REG8(0x5306), 0x16 }, { CCI_REG8(0x5307), 0x15 }, ++ { CCI_REG8(0x5308), 0x1c }, { CCI_REG8(0x5309), 0x1b }, ++ { CCI_REG8(0x530a), 0x1a }, { CCI_REG8(0x530b), 0x19 }, ++ { CCI_REG8(0x530c), 0x20 }, { CCI_REG8(0x530d), 0x1f }, ++ { CCI_REG8(0x530e), 0x1e }, { CCI_REG8(0x530f), 0x1d }, ++ { CCI_REG8(0x5310), 0x03 }, { CCI_REG8(0x5311), 0xe8 }, ++ { CCI_REG8(0x5331), 0x0a }, { CCI_REG8(0x5332), 0x43 }, ++ { CCI_REG8(0x5333), 0x45 }, { CCI_REG8(0x5353), 0x09 }, ++ { CCI_REG8(0x5354), 0x00 }, { CCI_REG8(0x5414), 0x03 }, ++ { CCI_REG8(0x54b0), 0x10 }, { CCI_REG8(0x54b3), 0x0e }, ++ { CCI_REG8(0x54b5), 0x02 }, { CCI_REG8(0x54b6), 0x00 }, ++ { CCI_REG8(0x54b7), 0x00 }, { CCI_REG8(0x54b8), 0x00 }, ++ { CCI_REG8(0x54b9), 0x70 }, { CCI_REG8(0x54ba), 0x00 }, ++ { CCI_REG8(0x54bb), 0x10 }, { CCI_REG8(0x54bc), 0x00 }, ++ { CCI_REG8(0x54bd), 0x00 }, { CCI_REG8(0x54d2), 0xff }, ++ { CCI_REG8(0x54d3), 0x1c }, { CCI_REG8(0x5510), 0x03 }, ++ { CCI_REG8(0x5511), 0xe8 }, { CCI_REG8(0x5550), 0x6c }, ++ { CCI_REG8(0x5551), 0x00 }, { CCI_REG8(0x557a), 0x00 }, ++ { CCI_REG8(0x557b), 0x38 }, { CCI_REG8(0x557c), 0x00 }, ++ { CCI_REG8(0x557d), 0x4b }, { CCI_REG8(0x5590), 0x00 }, ++ { CCI_REG8(0x5591), 0x50 }, { CCI_REG8(0x5592), 0x00 }, ++ { CCI_REG8(0x5593), 0x50 }, { CCI_REG8(0x5594), 0x00 }, ++ { CCI_REG8(0x5595), 0x50 }, { CCI_REG8(0x5596), 0x00 }, ++ { CCI_REG8(0x5597), 0x50 }, { CCI_REG8(0x5598), 0x00 }, ++ { CCI_REG8(0x5599), 0x50 }, { CCI_REG8(0x559a), 0x01 }, ++ { CCI_REG8(0x559b), 0x00 }, { CCI_REG8(0x559c), 0x01 }, ++ { CCI_REG8(0x559d), 0x00 }, { CCI_REG8(0x559e), 0x00 }, ++ { CCI_REG8(0x559f), 0x50 }, { CCI_REG8(0x55a0), 0x00 }, ++ { CCI_REG8(0x55a1), 0x50 }, { CCI_REG8(0x55a2), 0x01 }, ++ { CCI_REG8(0x55a3), 0x00 }, { CCI_REG8(0x55a4), 0x01 }, ++ { CCI_REG8(0x55a5), 0x00 }, { CCI_REG8(0x55a6), 0x00 }, ++ { CCI_REG8(0x55a7), 0x50 }, { CCI_REG8(0x55a8), 0x00 }, ++ { CCI_REG8(0x55a9), 0x50 }, { CCI_REG8(0x55aa), 0x00 }, ++ { CCI_REG8(0x55ab), 0x50 }, { CCI_REG8(0x55ac), 0x00 }, ++ { CCI_REG8(0x55ad), 0x50 }, { CCI_REG8(0x55ae), 0x00 }, ++ { CCI_REG8(0x55af), 0x50 }, { CCI_REG8(0x55b0), 0x00 }, ++ { CCI_REG8(0x55b1), 0x50 }, { CCI_REG8(0x55b2), 0x00 }, ++ { CCI_REG8(0x55b3), 0x50 }, { CCI_REG8(0x55b4), 0x00 }, ++ { CCI_REG8(0x55b5), 0x50 }, { CCI_REG8(0x55b6), 0x00 }, ++ { CCI_REG8(0x55b7), 0x50 }, { CCI_REG8(0x55b8), 0x00 }, ++ { CCI_REG8(0x55b9), 0x50 }, { CCI_REG8(0x55ba), 0x01 }, ++ { CCI_REG8(0x55bb), 0x00 }, { CCI_REG8(0x55bc), 0x01 }, ++ { CCI_REG8(0x55bd), 0x00 }, { CCI_REG8(0x55be), 0x00 }, ++ { CCI_REG8(0x55bf), 0x50 }, { CCI_REG8(0x55c0), 0x00 }, ++ { CCI_REG8(0x55c1), 0x50 }, { CCI_REG8(0x55c2), 0x01 }, ++ { CCI_REG8(0x55c3), 0x00 }, { CCI_REG8(0x55c4), 0x01 }, ++ { CCI_REG8(0x55c5), 0x00 }, { CCI_REG8(0x55c6), 0x00 }, ++ { CCI_REG8(0x55c7), 0x50 }, { CCI_REG8(0x55c8), 0x00 }, ++ { CCI_REG8(0x55c9), 0x50 }, { CCI_REG8(0x55ca), 0x00 }, ++ { CCI_REG8(0x55cb), 0x50 }, { CCI_REG8(0x55cc), 0x00 }, ++ { CCI_REG8(0x55cd), 0x50 }, { CCI_REG8(0x55ce), 0x00 }, ++ { CCI_REG8(0x55cf), 0x50 }, { CCI_REG8(0x55f0), 0x04 }, ++ { CCI_REG8(0x55f1), 0x03 }, { CCI_REG8(0x55f2), 0x02 }, ++ { CCI_REG8(0x55f3), 0x01 }, { CCI_REG8(0x55f4), 0x08 }, ++ { CCI_REG8(0x55f5), 0x07 }, { CCI_REG8(0x55f6), 0x06 }, ++ { CCI_REG8(0x55f7), 0x05 }, { CCI_REG8(0x55f8), 0x0c }, ++ { CCI_REG8(0x55f9), 0x0b }, { CCI_REG8(0x55fa), 0x0a }, ++ { CCI_REG8(0x55fb), 0x09 }, { CCI_REG8(0x55fc), 0x10 }, ++ { CCI_REG8(0x55fd), 0x0f }, { CCI_REG8(0x55fe), 0x0e }, ++ { CCI_REG8(0x55ff), 0x0d }, { CCI_REG8(0x5600), 0x14 }, ++ { CCI_REG8(0x5601), 0x13 }, { CCI_REG8(0x5602), 0x12 }, ++ { CCI_REG8(0x5603), 0x11 }, { CCI_REG8(0x5604), 0x18 }, ++ { CCI_REG8(0x5605), 0x17 }, { CCI_REG8(0x5606), 0x16 }, ++ { CCI_REG8(0x5607), 0x15 }, { CCI_REG8(0x5608), 0x1c }, ++ { CCI_REG8(0x5609), 0x1b }, { CCI_REG8(0x560a), 0x1a }, ++ { CCI_REG8(0x560b), 0x19 }, { CCI_REG8(0x560c), 0x20 }, ++ { CCI_REG8(0x560d), 0x1f }, { CCI_REG8(0x560e), 0x1e }, ++ { CCI_REG8(0x560f), 0x1d }, { CCI_REG8(0x5631), 0x02 }, ++ { CCI_REG8(0x5632), 0x42 }, { CCI_REG8(0x5633), 0x24 }, ++ { CCI_REG8(0x5653), 0x09 }, { CCI_REG8(0x5654), 0x00 }, ++ { CCI_REG8(0x5714), 0x03 }, { CCI_REG8(0x57b0), 0x10 }, ++ { CCI_REG8(0x57b3), 0x0e }, { CCI_REG8(0x57b5), 0x02 }, ++ { CCI_REG8(0x57b6), 0x00 }, { CCI_REG8(0x57b7), 0x00 }, ++ { CCI_REG8(0x57b8), 0x00 }, { CCI_REG8(0x57b9), 0x70 }, ++ { CCI_REG8(0x57ba), 0x00 }, { CCI_REG8(0x57bb), 0x10 }, ++ { CCI_REG8(0x57bc), 0x00 }, { CCI_REG8(0x57bd), 0x00 }, ++ { CCI_REG8(0x57d2), 0xff }, { CCI_REG8(0x57d3), 0x1c }, ++ { CCI_REG8(0x5810), 0x03 }, { CCI_REG8(0x5811), 0xe8 }, ++ { CCI_REG8(0x5850), 0x6c }, { CCI_REG8(0x5851), 0x00 }, ++ { CCI_REG8(0x587a), 0x00 }, { CCI_REG8(0x587b), 0x38 }, ++ { CCI_REG8(0x587c), 0x00 }, { CCI_REG8(0x587d), 0x4b }, ++ { CCI_REG8(0x5890), 0x00 }, { CCI_REG8(0x5891), 0x50 }, ++ { CCI_REG8(0x5892), 0x00 }, { CCI_REG8(0x5893), 0x50 }, ++ { CCI_REG8(0x5894), 0x00 }, { CCI_REG8(0x5895), 0x50 }, ++ { CCI_REG8(0x5896), 0x00 }, { CCI_REG8(0x5897), 0x50 }, ++ { CCI_REG8(0x5898), 0x00 }, { CCI_REG8(0x5899), 0x50 }, ++ { CCI_REG8(0x589a), 0x01 }, { CCI_REG8(0x589b), 0x00 }, ++ { CCI_REG8(0x589c), 0x01 }, { CCI_REG8(0x589d), 0x00 }, ++ { CCI_REG8(0x589e), 0x00 }, { CCI_REG8(0x589f), 0x50 }, ++ { CCI_REG8(0x58a0), 0x00 }, { CCI_REG8(0x58a1), 0x50 }, ++ { CCI_REG8(0x58a2), 0x01 }, { CCI_REG8(0x58a3), 0x00 }, ++ { CCI_REG8(0x58a4), 0x01 }, { CCI_REG8(0x58a5), 0x00 }, ++ { CCI_REG8(0x58a6), 0x00 }, { CCI_REG8(0x58a7), 0x50 }, ++ { CCI_REG8(0x58a8), 0x00 }, { CCI_REG8(0x58a9), 0x50 }, ++ { CCI_REG8(0x58aa), 0x00 }, { CCI_REG8(0x58ab), 0x50 }, ++ { CCI_REG8(0x58ac), 0x00 }, { CCI_REG8(0x58ad), 0x50 }, ++ { CCI_REG8(0x58ae), 0x00 }, { CCI_REG8(0x58af), 0x50 }, ++ { CCI_REG8(0x58b0), 0x00 }, { CCI_REG8(0x58b1), 0x50 }, ++ { CCI_REG8(0x58b2), 0x00 }, { CCI_REG8(0x58b3), 0x50 }, ++ { CCI_REG8(0x58b4), 0x00 }, { CCI_REG8(0x58b5), 0x50 }, ++ { CCI_REG8(0x58b6), 0x00 }, { CCI_REG8(0x58b7), 0x50 }, ++ { CCI_REG8(0x58b8), 0x00 }, { CCI_REG8(0x58b9), 0x50 }, ++ { CCI_REG8(0x58ba), 0x01 }, { CCI_REG8(0x58bb), 0x00 }, ++ { CCI_REG8(0x58bc), 0x01 }, { CCI_REG8(0x58bd), 0x00 }, ++ { CCI_REG8(0x58be), 0x00 }, { CCI_REG8(0x58bf), 0x50 }, ++ { CCI_REG8(0x58c0), 0x00 }, { CCI_REG8(0x58c1), 0x50 }, ++ { CCI_REG8(0x58c2), 0x01 }, { CCI_REG8(0x58c3), 0x00 }, ++ { CCI_REG8(0x58c4), 0x01 }, { CCI_REG8(0x58c5), 0x00 }, ++ { CCI_REG8(0x58c6), 0x00 }, { CCI_REG8(0x58c7), 0x50 }, ++ { CCI_REG8(0x58c8), 0x00 }, { CCI_REG8(0x58c9), 0x50 }, ++ { CCI_REG8(0x58ca), 0x00 }, { CCI_REG8(0x58cb), 0x50 }, ++ { CCI_REG8(0x58cc), 0x00 }, { CCI_REG8(0x58cd), 0x50 }, ++ { CCI_REG8(0x58ce), 0x00 }, { CCI_REG8(0x58cf), 0x50 }, ++ { CCI_REG8(0x58f0), 0x04 }, { CCI_REG8(0x58f1), 0x03 }, ++ { CCI_REG8(0x58f2), 0x02 }, { CCI_REG8(0x58f3), 0x01 }, ++ { CCI_REG8(0x58f4), 0x08 }, { CCI_REG8(0x58f5), 0x07 }, ++ { CCI_REG8(0x58f6), 0x06 }, { CCI_REG8(0x58f7), 0x05 }, ++ { CCI_REG8(0x58f8), 0x0c }, { CCI_REG8(0x58f9), 0x0b }, ++ { CCI_REG8(0x58fa), 0x0a }, { CCI_REG8(0x58fb), 0x09 }, ++ { CCI_REG8(0x58fc), 0x10 }, { CCI_REG8(0x58fd), 0x0f }, ++ { CCI_REG8(0x58fe), 0x0e }, { CCI_REG8(0x58ff), 0x0d }, ++ { CCI_REG8(0x5900), 0x14 }, { CCI_REG8(0x5901), 0x13 }, ++ { CCI_REG8(0x5902), 0x12 }, { CCI_REG8(0x5903), 0x11 }, ++ { CCI_REG8(0x5904), 0x18 }, { CCI_REG8(0x5905), 0x17 }, ++ { CCI_REG8(0x5906), 0x16 }, { CCI_REG8(0x5907), 0x15 }, ++ { CCI_REG8(0x5908), 0x1c }, { CCI_REG8(0x5909), 0x1b }, ++ { CCI_REG8(0x590a), 0x1a }, { CCI_REG8(0x590b), 0x19 }, ++ { CCI_REG8(0x590c), 0x20 }, { CCI_REG8(0x590d), 0x1f }, ++ { CCI_REG8(0x590e), 0x1e }, { CCI_REG8(0x590f), 0x1d }, ++ { CCI_REG8(0x5931), 0x02 }, { CCI_REG8(0x5932), 0x42 }, ++ { CCI_REG8(0x5933), 0x24 }, { CCI_REG8(0x5953), 0x09 }, ++ { CCI_REG8(0x5954), 0x00 }, { CCI_REG8(0x5989), 0x84 }, ++ { CCI_REG8(0x59c3), 0x04 }, { CCI_REG8(0x59c4), 0x24 }, ++ { CCI_REG8(0x59c5), 0x40 }, { CCI_REG8(0x59c6), 0x1b }, ++ { CCI_REG8(0x59c7), 0x40 }, { CCI_REG8(0x5a02), 0x0f }, ++ { CCI_REG8(0x5f00), 0x29 }, { CCI_REG8(0x5f2d), 0x28 }, ++ { CCI_REG8(0x5f2e), 0x28 }, { CCI_REG8(0x6801), 0x11 }, ++ { CCI_REG8(0x6802), 0x3f }, { CCI_REG8(0x6803), 0xe7 }, ++ { CCI_REG8(0x6825), 0x0f }, { CCI_REG8(0x6826), 0x20 }, ++ { CCI_REG8(0x6827), 0x00 }, { CCI_REG8(0x6829), 0x16 }, ++ { CCI_REG8(0x682b), 0xb3 }, { CCI_REG8(0x682c), 0x01 }, ++ { CCI_REG8(0x6832), 0xff }, { CCI_REG8(0x6833), 0xff }, ++ { CCI_REG8(0x6898), 0x80 }, { CCI_REG8(0x6899), 0x80 }, ++ { CCI_REG8(0x689b), 0x40 }, { CCI_REG8(0x689c), 0x20 }, ++ { CCI_REG8(0x689d), 0x20 }, { CCI_REG8(0x689e), 0x80 }, ++ { CCI_REG8(0x689f), 0x60 }, { CCI_REG8(0x68a0), 0x40 }, ++ { CCI_REG8(0x68a4), 0x40 }, { CCI_REG8(0x68a5), 0x20 }, ++ { CCI_REG8(0x68a6), 0x00 }, { CCI_REG8(0x68b6), 0x80 }, ++ { CCI_REG8(0x68b7), 0x80 }, { CCI_REG8(0x68b8), 0x80 }, ++ { CCI_REG8(0x68bc), 0x80 }, { CCI_REG8(0x68bd), 0x80 }, ++ { CCI_REG8(0x68be), 0x80 }, { CCI_REG8(0x68bf), 0x40 }, ++ { CCI_REG8(0x68c2), 0x80 }, { CCI_REG8(0x68c3), 0x80 }, ++ { CCI_REG8(0x68c4), 0x60 }, { CCI_REG8(0x68c5), 0x30 }, ++ { CCI_REG8(0x6918), 0x80 }, { CCI_REG8(0x6919), 0x80 }, ++ { CCI_REG8(0x691b), 0x40 }, { CCI_REG8(0x691c), 0x20 }, ++ { CCI_REG8(0x691d), 0x20 }, { CCI_REG8(0x691e), 0x80 }, ++ { CCI_REG8(0x691f), 0x60 }, { CCI_REG8(0x6920), 0x40 }, ++ { CCI_REG8(0x6924), 0x40 }, { CCI_REG8(0x6925), 0x20 }, ++ { CCI_REG8(0x6926), 0x00 }, { CCI_REG8(0x6936), 0x40 }, ++ { CCI_REG8(0x6937), 0x40 }, { CCI_REG8(0x6938), 0x20 }, ++ { CCI_REG8(0x6939), 0x20 }, { CCI_REG8(0x693a), 0x10 }, ++ { CCI_REG8(0x693b), 0x10 }, { CCI_REG8(0x693c), 0x20 }, ++ { CCI_REG8(0x693d), 0x20 }, { CCI_REG8(0x693e), 0x10 }, ++ { CCI_REG8(0x693f), 0x10 }, { CCI_REG8(0x6940), 0x00 }, ++ { CCI_REG8(0x6941), 0x00 }, { CCI_REG8(0x6942), 0x08 }, ++ { CCI_REG8(0x6943), 0x08 }, { CCI_REG8(0x6944), 0x00 }, ++ { CCI_REG8(0x69c2), 0x07 }, { CCI_REG8(0x6a20), 0x01 }, ++ { CCI_REG8(0x6a23), 0x10 }, { CCI_REG8(0x6a26), 0x3d }, ++ { CCI_REG8(0x6a27), 0x3e }, { CCI_REG8(0x6a38), 0x02 }, ++ { CCI_REG8(0x6a39), 0x20 }, { CCI_REG8(0x6a3a), 0x02 }, ++ { CCI_REG8(0x6a3b), 0x84 }, { CCI_REG8(0x6a3e), 0x02 }, ++ { CCI_REG8(0x6a3f), 0x20 }, { CCI_REG8(0x6a47), 0x3b }, ++ { CCI_REG8(0x6a63), 0x04 }, { CCI_REG8(0x6a65), 0x00 }, ++ { CCI_REG8(0x6a67), 0x0f }, { CCI_REG8(0x6b22), 0x07 }, ++ { CCI_REG8(0x6b23), 0xc2 }, { CCI_REG8(0x6b2f), 0x00 }, ++ { CCI_REG8(0x6b60), 0x1f }, { CCI_REG8(0x6bd2), 0x5a }, ++ { CCI_REG8(0x6c20), 0x50 }, { CCI_REG8(0x6c60), 0x50 }, ++ { CCI_REG8(0x6c61), 0x06 }, { CCI_REG8(0x7318), 0x04 }, ++ { CCI_REG8(0x7319), 0x01 }, { CCI_REG8(0x731a), 0x04 }, ++ { CCI_REG8(0x731b), 0x01 }, { CCI_REG8(0x731c), 0x00 }, ++ { CCI_REG8(0x731d), 0x00 }, { CCI_REG8(0x731e), 0x04 }, ++ { CCI_REG8(0x731f), 0x01 }, { CCI_REG8(0x7320), 0x04 }, ++ { CCI_REG8(0x7321), 0x00 }, { CCI_REG8(0x7322), 0x04 }, ++ { CCI_REG8(0x7323), 0x00 }, { CCI_REG8(0x7324), 0x04 }, ++ { CCI_REG8(0x7325), 0x00 }, { CCI_REG8(0x7326), 0x04 }, ++ { CCI_REG8(0x7327), 0x00 }, { CCI_REG8(0x7600), 0x00 }, ++ { CCI_REG8(0x7601), 0x00 }, { CCI_REG8(0x7602), 0x10 }, ++ { CCI_REG8(0x7603), 0x00 }, { CCI_REG8(0x7604), 0x00 }, ++ { CCI_REG8(0x7605), 0x00 }, { CCI_REG8(0x7606), 0x10 }, ++ { CCI_REG8(0x7607), 0x00 }, { CCI_REG8(0x7608), 0x00 }, ++ { CCI_REG8(0x7609), 0x00 }, { CCI_REG8(0x760a), 0x10 }, ++ { CCI_REG8(0x760b), 0x00 }, { CCI_REG8(0x760c), 0x00 }, ++ { CCI_REG8(0x760d), 0x00 }, { CCI_REG8(0x760e), 0x10 }, ++ { CCI_REG8(0x760f), 0x00 }, { CCI_REG8(0x7610), 0x00 }, ++ { CCI_REG8(0x7611), 0x00 }, { CCI_REG8(0x7612), 0x10 }, ++ { CCI_REG8(0x7613), 0x00 }, { CCI_REG8(0x7614), 0x00 }, ++ { CCI_REG8(0x7615), 0x00 }, { CCI_REG8(0x7616), 0x10 }, ++ { CCI_REG8(0x7617), 0x00 }, { CCI_REG8(0x7618), 0x00 }, ++ { CCI_REG8(0x7619), 0x00 }, { CCI_REG8(0x761a), 0x10 }, ++ { CCI_REG8(0x761b), 0x00 }, { CCI_REG8(0x761c), 0x00 }, ++ { CCI_REG8(0x761d), 0x00 }, { CCI_REG8(0x761e), 0x10 }, ++ { CCI_REG8(0x761f), 0x00 }, { CCI_REG8(0x7620), 0x00 }, ++ { CCI_REG8(0x7621), 0x00 }, { CCI_REG8(0x7622), 0x10 }, ++ { CCI_REG8(0x7623), 0x00 }, { CCI_REG8(0x7624), 0x00 }, ++ { CCI_REG8(0x7625), 0x00 }, { CCI_REG8(0x7626), 0x10 }, ++ { CCI_REG8(0x7627), 0x00 }, { CCI_REG8(0x7628), 0x00 }, ++ { CCI_REG8(0x7629), 0x00 }, { CCI_REG8(0x762a), 0x10 }, ++ { CCI_REG8(0x762b), 0x00 }, { CCI_REG8(0x762c), 0x00 }, ++ { CCI_REG8(0x762d), 0x00 }, { CCI_REG8(0x762e), 0x10 }, ++ { CCI_REG8(0x762f), 0x00 }, { CCI_REG8(0x7630), 0x00 }, ++ { CCI_REG8(0x7631), 0x00 }, { CCI_REG8(0x7632), 0x10 }, ++ { CCI_REG8(0x7633), 0x00 }, { CCI_REG8(0x7634), 0x00 }, ++ { CCI_REG8(0x7635), 0x00 }, { CCI_REG8(0x7636), 0x10 }, ++ { CCI_REG8(0x7637), 0x00 }, { CCI_REG8(0x7638), 0x00 }, ++ { CCI_REG8(0x7639), 0x00 }, { CCI_REG8(0x763a), 0x10 }, ++ { CCI_REG8(0x763b), 0x00 }, { CCI_REG8(0x763c), 0x00 }, ++ { CCI_REG8(0x763d), 0x00 }, { CCI_REG8(0x763e), 0x10 }, ++ { CCI_REG8(0x763f), 0x00 }, { CCI_REG8(0x7640), 0x00 }, ++ { CCI_REG8(0x7641), 0x00 }, { CCI_REG8(0x7642), 0x10 }, ++ { CCI_REG8(0x7643), 0x00 }, { CCI_REG8(0x7644), 0x00 }, ++ { CCI_REG8(0x7645), 0x00 }, { CCI_REG8(0x7646), 0x10 }, ++ { CCI_REG8(0x7647), 0x00 }, { CCI_REG8(0x7648), 0x00 }, ++ { CCI_REG8(0x7649), 0x00 }, { CCI_REG8(0x764a), 0x10 }, ++ { CCI_REG8(0x764b), 0x00 }, { CCI_REG8(0x764c), 0x00 }, ++ { CCI_REG8(0x764d), 0x00 }, { CCI_REG8(0x764e), 0x10 }, ++ { CCI_REG8(0x764f), 0x00 }, { CCI_REG8(0x7650), 0x00 }, ++ { CCI_REG8(0x7651), 0x00 }, { CCI_REG8(0x7652), 0x10 }, ++ { CCI_REG8(0x7653), 0x00 }, { CCI_REG8(0x7654), 0x00 }, ++ { CCI_REG8(0x7655), 0x00 }, { CCI_REG8(0x7656), 0x10 }, ++ { CCI_REG8(0x7657), 0x00 }, { CCI_REG8(0x7658), 0x00 }, ++ { CCI_REG8(0x7659), 0x00 }, { CCI_REG8(0x765a), 0x10 }, ++ { CCI_REG8(0x765b), 0x00 }, { CCI_REG8(0x765c), 0x00 }, ++ { CCI_REG8(0x765d), 0x00 }, { CCI_REG8(0x765e), 0x10 }, ++ { CCI_REG8(0x765f), 0x00 }, { CCI_REG8(0x7660), 0x00 }, ++ { CCI_REG8(0x7661), 0x00 }, { CCI_REG8(0x7662), 0x10 }, ++ { CCI_REG8(0x7663), 0x00 }, { CCI_REG8(0x7664), 0x00 }, ++ { CCI_REG8(0x7665), 0x00 }, { CCI_REG8(0x7666), 0x10 }, ++ { CCI_REG8(0x7667), 0x00 }, { CCI_REG8(0x7668), 0x00 }, ++ { CCI_REG8(0x7669), 0x00 }, { CCI_REG8(0x766a), 0x10 }, ++ { CCI_REG8(0x766b), 0x00 }, { CCI_REG8(0x766c), 0x00 }, ++ { CCI_REG8(0x766d), 0x00 }, { CCI_REG8(0x766e), 0x10 }, ++ { CCI_REG8(0x766f), 0x00 }, { CCI_REG8(0x7670), 0x00 }, ++ { CCI_REG8(0x7671), 0x00 }, { CCI_REG8(0x7672), 0x10 }, ++ { CCI_REG8(0x7673), 0x00 }, { CCI_REG8(0x7674), 0x00 }, ++ { CCI_REG8(0x7675), 0x00 }, { CCI_REG8(0x7676), 0x10 }, ++ { CCI_REG8(0x7677), 0x00 }, { CCI_REG8(0x7678), 0x00 }, ++ { CCI_REG8(0x7679), 0x00 }, { CCI_REG8(0x767a), 0x10 }, ++ { CCI_REG8(0x767b), 0x00 }, { CCI_REG8(0x767c), 0x00 }, ++ { CCI_REG8(0x767d), 0x00 }, { CCI_REG8(0x767e), 0x10 }, ++ { CCI_REG8(0x767f), 0x00 }, { CCI_REG8(0x7680), 0x00 }, ++ { CCI_REG8(0x7681), 0x00 }, { CCI_REG8(0x7682), 0x10 }, ++ { CCI_REG8(0x7683), 0x00 }, { CCI_REG8(0x7684), 0x00 }, ++ { CCI_REG8(0x7685), 0x00 }, { CCI_REG8(0x7686), 0x10 }, ++ { CCI_REG8(0x7687), 0x00 }, { CCI_REG8(0x7688), 0x00 }, ++ { CCI_REG8(0x7689), 0x00 }, { CCI_REG8(0x768a), 0x10 }, ++ { CCI_REG8(0x768b), 0x00 }, { CCI_REG8(0x768c), 0x00 }, ++ { CCI_REG8(0x768d), 0x00 }, { CCI_REG8(0x768e), 0x10 }, ++ { CCI_REG8(0x768f), 0x00 }, { CCI_REG8(0x7690), 0x00 }, ++ { CCI_REG8(0x7691), 0x00 }, { CCI_REG8(0x7692), 0x10 }, ++ { CCI_REG8(0x7693), 0x00 }, { CCI_REG8(0x7694), 0x00 }, ++ { CCI_REG8(0x7695), 0x00 }, { CCI_REG8(0x7696), 0x10 }, ++ { CCI_REG8(0x7697), 0x00 }, { CCI_REG8(0x7698), 0x00 }, ++ { CCI_REG8(0x7699), 0x00 }, { CCI_REG8(0x769a), 0x10 }, ++ { CCI_REG8(0x769b), 0x00 }, { CCI_REG8(0x769c), 0x00 }, ++ { CCI_REG8(0x769d), 0x00 }, { CCI_REG8(0x769e), 0x10 }, ++ { CCI_REG8(0x769f), 0x00 }, { CCI_REG8(0x76a0), 0x00 }, ++ { CCI_REG8(0x76a1), 0x00 }, { CCI_REG8(0x76a2), 0x10 }, ++ { CCI_REG8(0x76a3), 0x00 }, { CCI_REG8(0x76a4), 0x00 }, ++ { CCI_REG8(0x76a5), 0x00 }, { CCI_REG8(0x76a6), 0x10 }, ++ { CCI_REG8(0x76a7), 0x00 }, { CCI_REG8(0x76a8), 0x00 }, ++ { CCI_REG8(0x76a9), 0x00 }, { CCI_REG8(0x76aa), 0x10 }, ++ { CCI_REG8(0x76ab), 0x00 }, { CCI_REG8(0x76ac), 0x00 }, ++ { CCI_REG8(0x76ad), 0x00 }, { CCI_REG8(0x76ae), 0x10 }, ++ { CCI_REG8(0x76af), 0x00 }, { CCI_REG8(0x76b0), 0x00 }, ++ { CCI_REG8(0x76b1), 0x00 }, { CCI_REG8(0x76b2), 0x10 }, ++ { CCI_REG8(0x76b3), 0x00 }, { CCI_REG8(0x76b4), 0x00 }, ++ { CCI_REG8(0x76b5), 0x00 }, { CCI_REG8(0x76b6), 0x10 }, ++ { CCI_REG8(0x76b7), 0x00 }, { CCI_REG8(0x76b8), 0x00 }, ++ { CCI_REG8(0x76b9), 0x00 }, { CCI_REG8(0x76ba), 0x10 }, ++ { CCI_REG8(0x76bb), 0x00 }, { CCI_REG8(0x76bc), 0x00 }, ++ { CCI_REG8(0x76bd), 0x00 }, { CCI_REG8(0x76be), 0x10 }, ++ { CCI_REG8(0x76bf), 0x00 }, { CCI_REG8(0x76c0), 0x00 }, ++ { CCI_REG8(0x76c1), 0x00 }, { CCI_REG8(0x76c2), 0x10 }, ++ { CCI_REG8(0x76c3), 0x00 }, { CCI_REG8(0x76c4), 0x00 }, ++ { CCI_REG8(0x76c5), 0x00 }, { CCI_REG8(0x76c6), 0x10 }, ++ { CCI_REG8(0x76c7), 0x00 }, { CCI_REG8(0x76c8), 0x00 }, ++ { CCI_REG8(0x76c9), 0x00 }, { CCI_REG8(0x76ca), 0x10 }, ++ { CCI_REG8(0x76cb), 0x00 }, { CCI_REG8(0x76cc), 0x00 }, ++ { CCI_REG8(0x76cd), 0x00 }, { CCI_REG8(0x76ce), 0x10 }, ++ { CCI_REG8(0x76cf), 0x00 }, { CCI_REG8(0x76d0), 0x00 }, ++ { CCI_REG8(0x76d1), 0x00 }, { CCI_REG8(0x76d2), 0x10 }, ++ { CCI_REG8(0x76d3), 0x00 }, { CCI_REG8(0x76d4), 0x00 }, ++ { CCI_REG8(0x76d5), 0x00 }, { CCI_REG8(0x76d6), 0x10 }, ++ { CCI_REG8(0x76d7), 0x00 }, { CCI_REG8(0x76d8), 0x00 }, ++ { CCI_REG8(0x76d9), 0x00 }, { CCI_REG8(0x76da), 0x10 }, ++ { CCI_REG8(0x76db), 0x00 }, { CCI_REG8(0x76dc), 0x00 }, ++ { CCI_REG8(0x76dd), 0x00 }, { CCI_REG8(0x76de), 0x10 }, ++ { CCI_REG8(0x76df), 0x00 }, { CCI_REG8(0x76e0), 0x00 }, ++ { CCI_REG8(0x76e1), 0x00 }, { CCI_REG8(0x76e2), 0x10 }, ++ { CCI_REG8(0x76e3), 0x00 }, { CCI_REG8(0x76e4), 0x00 }, ++ { CCI_REG8(0x76e5), 0x00 }, { CCI_REG8(0x76e6), 0x10 }, ++ { CCI_REG8(0x76e7), 0x00 }, { CCI_REG8(0x76e8), 0x00 }, ++ { CCI_REG8(0x76e9), 0x00 }, { CCI_REG8(0x76ea), 0x10 }, ++ { CCI_REG8(0x76eb), 0x00 }, { CCI_REG8(0x76ec), 0x00 }, ++ { CCI_REG8(0x76ed), 0x00 }, { CCI_REG8(0x76ee), 0x10 }, ++ { CCI_REG8(0x76ef), 0x00 }, { CCI_REG8(0x76f0), 0x00 }, ++ { CCI_REG8(0x76f1), 0x00 }, { CCI_REG8(0x76f2), 0x10 }, ++ { CCI_REG8(0x76f3), 0x00 }, { CCI_REG8(0x76f4), 0x00 }, ++ { CCI_REG8(0x76f5), 0x00 }, { CCI_REG8(0x76f6), 0x10 }, ++ { CCI_REG8(0x76f7), 0x00 }, { CCI_REG8(0x76f8), 0x00 }, ++ { CCI_REG8(0x76f9), 0x00 }, { CCI_REG8(0x76fa), 0x10 }, ++ { CCI_REG8(0x76fb), 0x00 }, { CCI_REG8(0x76fc), 0x00 }, ++ { CCI_REG8(0x76fd), 0x00 }, { CCI_REG8(0x76fe), 0x10 }, ++ { CCI_REG8(0x76ff), 0x00 }, { CCI_REG8(0x7700), 0x00 }, ++ { CCI_REG8(0x7701), 0x00 }, { CCI_REG8(0x7702), 0x10 }, ++ { CCI_REG8(0x7703), 0x00 }, { CCI_REG8(0x7704), 0x00 }, ++ { CCI_REG8(0x7705), 0x00 }, { CCI_REG8(0x7706), 0x10 }, ++ { CCI_REG8(0x7707), 0x00 }, { CCI_REG8(0x7708), 0x00 }, ++ { CCI_REG8(0x7709), 0x00 }, { CCI_REG8(0x770a), 0x10 }, ++ { CCI_REG8(0x770b), 0x00 }, { CCI_REG8(0x770c), 0x00 }, ++ { CCI_REG8(0x770d), 0x00 }, { CCI_REG8(0x770e), 0x10 }, ++ { CCI_REG8(0x770f), 0x00 }, { CCI_REG8(0x7710), 0x00 }, ++ { CCI_REG8(0x7711), 0x00 }, { CCI_REG8(0x7712), 0x10 }, ++ { CCI_REG8(0x7713), 0x00 }, { CCI_REG8(0x7714), 0x00 }, ++ { CCI_REG8(0x7715), 0x00 }, { CCI_REG8(0x7716), 0x10 }, ++ { CCI_REG8(0x7717), 0x00 }, { CCI_REG8(0x7718), 0x00 }, ++ { CCI_REG8(0x7719), 0x00 }, { CCI_REG8(0x771a), 0x10 }, ++ { CCI_REG8(0x771b), 0x00 }, { CCI_REG8(0x771c), 0x00 }, ++ { CCI_REG8(0x771d), 0x00 }, { CCI_REG8(0x771e), 0x10 }, ++ { CCI_REG8(0x771f), 0x00 }, { CCI_REG8(0x7720), 0x00 }, ++ { CCI_REG8(0x7721), 0x00 }, { CCI_REG8(0x7722), 0x10 }, ++ { CCI_REG8(0x7723), 0x00 }, { CCI_REG8(0x7724), 0x00 }, ++ { CCI_REG8(0x7725), 0x00 }, { CCI_REG8(0x7726), 0x10 }, ++ { CCI_REG8(0x7727), 0x00 }, { CCI_REG8(0x7728), 0x00 }, ++ { CCI_REG8(0x7729), 0x00 }, { CCI_REG8(0x772a), 0x10 }, ++ { CCI_REG8(0x772b), 0x00 }, { CCI_REG8(0x772c), 0x00 }, ++ { CCI_REG8(0x772d), 0x00 }, { CCI_REG8(0x772e), 0x10 }, ++ { CCI_REG8(0x772f), 0x00 }, { CCI_REG8(0x7730), 0x00 }, ++ { CCI_REG8(0x7731), 0x00 }, { CCI_REG8(0x7732), 0x10 }, ++ { CCI_REG8(0x7733), 0x00 }, { CCI_REG8(0x7734), 0x00 }, ++ { CCI_REG8(0x7735), 0x00 }, { CCI_REG8(0x7736), 0x10 }, ++ { CCI_REG8(0x7737), 0x00 }, { CCI_REG8(0x7738), 0x00 }, ++ { CCI_REG8(0x7739), 0x00 }, { CCI_REG8(0x773a), 0x10 }, ++ { CCI_REG8(0x773b), 0x00 }, { CCI_REG8(0x773c), 0x00 }, ++ { CCI_REG8(0x773d), 0x00 }, { CCI_REG8(0x773e), 0x10 }, ++ { CCI_REG8(0x773f), 0x00 }, { CCI_REG8(0x7740), 0x00 }, ++ { CCI_REG8(0x7741), 0x00 }, { CCI_REG8(0x7742), 0x10 }, ++ { CCI_REG8(0x7743), 0x00 }, { CCI_REG8(0x3421), 0x02 }, ++ { CCI_REG8(0x37d0), 0x00 }, { CCI_REG8(0x3632), 0x99 }, ++ { CCI_REG8(0xc518), 0x1f }, { CCI_REG8(0xc519), 0x1f }, ++ { CCI_REG8(0xc51a), 0x1f }, { CCI_REG8(0xc51b), 0x1f }, ++ { CCI_REG8(0xc51c), 0x1f }, { CCI_REG8(0xc51d), 0x1f }, ++ { CCI_REG8(0xc51e), 0x1f }, { CCI_REG8(0xc51f), 0x1f }, ++ { CCI_REG8(0xc520), 0x1f }, { CCI_REG8(0xc521), 0x1f }, ++ { CCI_REG8(0x3616), 0xa0 }, { CCI_REG8(0x3615), 0xc5 }, ++ { CCI_REG8(0xc4c1), 0x02 }, { CCI_REG8(0xc4c2), 0x02 }, ++ { CCI_REG8(0xc4c3), 0x03 }, { CCI_REG8(0xc4c4), 0x03 }, ++ { CCI_REG8(0xc4f6), 0x0a }, { CCI_REG8(0xc4f7), 0x0a }, ++ { CCI_REG8(0xc4f8), 0x0a }, { CCI_REG8(0xc4f9), 0x0a }, ++ { CCI_REG8(0xc4fa), 0x0a }, { CCI_REG8(0xc4c6), 0x0a }, ++ { CCI_REG8(0xc4c7), 0x0a }, { CCI_REG8(0xc4c8), 0x0a }, ++ { CCI_REG8(0xc4c9), 0x0a }, { CCI_REG8(0xc4ca), 0x14 }, ++ { CCI_REG8(0xc4cb), 0x14 }, { CCI_REG8(0xc4cc), 0x14 }, ++ { CCI_REG8(0xc4cd), 0x14 }, { CCI_REG8(0x3b92), 0x05 }, ++ { CCI_REG8(0x3b93), 0x05 }, { CCI_REG8(0x3b94), 0x05 }, ++ { CCI_REG8(0x3b95), 0x05 }, { CCI_REG8(0x3623), 0x10 }, ++ { CCI_REG8(0xc522), 0x18 }, { CCI_REG8(0xc523), 0x12 }, ++ { CCI_REG8(0xc524), 0x0e }, { CCI_REG8(0xc525), 0x0b }, ++ { CCI_REG8(0xc526), 0x18 }, { CCI_REG8(0xc527), 0x12 }, ++ { CCI_REG8(0xc528), 0x0c }, { CCI_REG8(0xc529), 0x08 }, ++ { CCI_REG8(0xc52a), 0x18 }, { CCI_REG8(0xc52b), 0x12 }, ++ { CCI_REG8(0xc52c), 0x0e }, { CCI_REG8(0xc52d), 0x0b }, ++ { CCI_REG8(0xc52e), 0x18 }, { CCI_REG8(0xc52f), 0x12 }, ++ { CCI_REG8(0xc530), 0x0e }, { CCI_REG8(0xc531), 0x0b }, ++ { CCI_REG8(0xc532), 0x18 }, { CCI_REG8(0xc533), 0x12 }, ++ { CCI_REG8(0xc534), 0x0e }, { CCI_REG8(0xc535), 0x0b }, ++ { CCI_REG8(0xc536), 0x18 }, { CCI_REG8(0xc537), 0x12 }, ++ { CCI_REG8(0xc538), 0x0e }, { CCI_REG8(0xc539), 0x0b }, ++ { CCI_REG8(0xc53a), 0x18 }, { CCI_REG8(0xc53b), 0x12 }, ++ { CCI_REG8(0xc53c), 0x0c }, { CCI_REG8(0xc53d), 0x08 }, ++ { CCI_REG8(0xc53e), 0x18 }, { CCI_REG8(0xc53f), 0x12 }, ++ { CCI_REG8(0xc540), 0x0e }, { CCI_REG8(0xc541), 0x0b }, ++ { CCI_REG8(0xc542), 0x18 }, { CCI_REG8(0xc543), 0x12 }, ++ { CCI_REG8(0xc544), 0x0e }, { CCI_REG8(0xc545), 0x0b }, ++ { CCI_REG8(0xc546), 0x18 }, { CCI_REG8(0xc547), 0x12 }, ++ { CCI_REG8(0xc548), 0x0e }, { CCI_REG8(0xc549), 0x0b }, ++ { CCI_REG8(0x3701), 0x18 }, { CCI_REG8(0x3702), 0x38 }, ++ { CCI_REG8(0x3703), 0x72 }, { CCI_REG8(0x3708), 0x26 }, ++ { CCI_REG8(0x3709), 0xe6 }, { CCI_REG8(0x3a1d), 0x18 }, ++ { CCI_REG8(0x3a1e), 0x18 }, { CCI_REG8(0x3a21), 0x18 }, ++ { CCI_REG8(0x3a22), 0x18 }, { CCI_REG8(0x39fb), 0x18 }, ++ { CCI_REG8(0x39fc), 0x18 }, { CCI_REG8(0x39fd), 0x18 }, ++ { CCI_REG8(0x39fe), 0x18 }, { CCI_REG8(0xc44a), 0x08 }, ++ { CCI_REG8(0xc44c), 0x08 }, { CCI_REG8(0xc5e8), 0x0a }, ++ { CCI_REG8(0xc5ea), 0x0a }, { CCI_REG8(0x391d), 0x54 }, ++ { CCI_REG8(0x391e), 0xca }, { CCI_REG8(0x3991), 0x0c }, ++ { CCI_REG8(0x399d), 0x0c }, { CCI_REG8(0x3744), 0x24 }, ++ { CCI_REG8(0x374b), 0x0c }, { CCI_REG8(0x3be7), 0x1e }, ++ { CCI_REG8(0x3be8), 0x26 }, { CCI_REG8(0x3a50), 0x14 }, ++ { CCI_REG8(0x3a54), 0x14 }, { CCI_REG8(0x3add), 0x1f }, ++ { CCI_REG8(0x3adf), 0x24 }, { CCI_REG8(0x3aef), 0x1f }, ++ { CCI_REG8(0x3af0), 0x24 }, { CCI_REG8(0xc57f), 0x30 }, ++ { CCI_REG8(0xc580), 0x30 }, { CCI_REG8(0xc581), 0x30 }, ++ { CCI_REG8(0xc582), 0x30 }, { CCI_REG8(0xc583), 0x30 }, ++ { CCI_REG8(0xc584), 0x30 }, { CCI_REG8(0xc585), 0x30 }, ++ { CCI_REG8(0xc586), 0x30 }, { CCI_REG8(0xc587), 0x30 }, ++ { CCI_REG8(0xc588), 0x30 }, { CCI_REG8(0xc589), 0x30 }, ++ { CCI_REG8(0xc58a), 0x30 }, { CCI_REG8(0xc58b), 0x30 }, ++ { CCI_REG8(0xc58c), 0x30 }, { CCI_REG8(0xc58d), 0x30 }, ++ { CCI_REG8(0xc58e), 0x30 }, { CCI_REG8(0xc58f), 0x30 }, ++ { CCI_REG8(0xc590), 0x30 }, { CCI_REG8(0xc591), 0x30 }, ++ { CCI_REG8(0xc592), 0x30 }, { CCI_REG8(0xc598), 0x30 }, ++ { CCI_REG8(0xc599), 0x30 }, { CCI_REG8(0xc59a), 0x30 }, ++ { CCI_REG8(0xc59b), 0x30 }, { CCI_REG8(0xc59c), 0x30 }, ++ { CCI_REG8(0xc59d), 0x30 }, { CCI_REG8(0xc59e), 0x30 }, ++ { CCI_REG8(0xc59f), 0x30 }, { CCI_REG8(0xc5a0), 0x30 }, ++ { CCI_REG8(0xc5a1), 0x30 }, { CCI_REG8(0xc5a2), 0x30 }, ++ { CCI_REG8(0xc5a3), 0x30 }, { CCI_REG8(0xc5a4), 0x30 }, ++ { CCI_REG8(0xc5a5), 0x30 }, { CCI_REG8(0xc5a6), 0x30 }, ++ { CCI_REG8(0xc5a7), 0x30 }, { CCI_REG8(0xc5a8), 0x30 }, ++ { CCI_REG8(0xc5a9), 0x30 }, { CCI_REG8(0xc5aa), 0x30 }, ++ { CCI_REG8(0xc5ab), 0x30 }, { CCI_REG8(0xc5b1), 0x38 }, ++ { CCI_REG8(0xc5b2), 0x38 }, { CCI_REG8(0xc5b3), 0x38 }, ++ { CCI_REG8(0xc5b4), 0x38 }, { CCI_REG8(0xc5b5), 0x38 }, ++ { CCI_REG8(0xc5b6), 0x38 }, { CCI_REG8(0xc5b7), 0x38 }, ++ { CCI_REG8(0xc5b8), 0x38 }, { CCI_REG8(0xc5b9), 0x38 }, ++ { CCI_REG8(0xc5ba), 0x38 }, { CCI_REG8(0xc5bb), 0x38 }, ++ { CCI_REG8(0xc5bc), 0x38 }, { CCI_REG8(0xc5bd), 0x38 }, ++ { CCI_REG8(0xc5be), 0x38 }, { CCI_REG8(0xc5bf), 0x38 }, ++ { CCI_REG8(0xc5c0), 0x38 }, { CCI_REG8(0xc5c1), 0x38 }, ++ { CCI_REG8(0xc5c2), 0x38 }, { CCI_REG8(0xc5c3), 0x38 }, ++ { CCI_REG8(0xc5c4), 0x38 }, { CCI_REG8(0xc5ca), 0x38 }, ++ { CCI_REG8(0xc5cb), 0x38 }, { CCI_REG8(0xc5cc), 0x38 }, ++ { CCI_REG8(0xc5cd), 0x38 }, { CCI_REG8(0xc5ce), 0x38 }, ++ { CCI_REG8(0xc5cf), 0x38 }, { CCI_REG8(0xc5d0), 0x38 }, ++ { CCI_REG8(0xc5d1), 0x38 }, { CCI_REG8(0xc5d2), 0x38 }, ++ { CCI_REG8(0xc5d3), 0x38 }, { CCI_REG8(0xc5d4), 0x38 }, ++ { CCI_REG8(0xc5d5), 0x38 }, { CCI_REG8(0xc5d6), 0x38 }, ++ { CCI_REG8(0xc5d7), 0x38 }, { CCI_REG8(0xc5d8), 0x38 }, ++ { CCI_REG8(0xc5d9), 0x38 }, { CCI_REG8(0xc5da), 0x38 }, ++ { CCI_REG8(0xc5db), 0x38 }, { CCI_REG8(0xc5dc), 0x38 }, ++ { CCI_REG8(0xc5dd), 0x38 }, { CCI_REG8(0x3a60), 0x68 }, ++ { CCI_REG8(0x3a6f), 0x68 }, { CCI_REG8(0x3a5e), 0xdc }, ++ { CCI_REG8(0x3a6d), 0xdc }, { CCI_REG8(0x3aed), 0x6e }, ++ { CCI_REG8(0x3af1), 0x73 }, { CCI_REG8(0x3992), 0x02 }, ++ { CCI_REG8(0x399e), 0x02 }, { CCI_REG8(0x371d), 0x17 }, ++ { CCI_REG8(0x371f), 0x08 }, { CCI_REG8(0x3721), 0xc9 }, ++ { CCI_REG8(0x401e), 0x00 }, { CCI_REG8(0x401f), 0xf8 }, ++ { CCI_REG8(0x3642), 0x00 }, { CCI_REG8(0x3641), 0x7f }, ++ { CCI_REG8(0x3ac5), 0x0c }, { CCI_REG8(0x3ac6), 0x09 }, ++ { CCI_REG8(0x3ac7), 0x06 }, { CCI_REG8(0x3ac8), 0x02 }, ++ { CCI_REG8(0x3ac9), 0x0c }, { CCI_REG8(0x3aca), 0x09 }, ++ { CCI_REG8(0x3acb), 0x06 }, { CCI_REG8(0x3acc), 0x02 }, ++ { CCI_REG8(0x3acd), 0x0c }, { CCI_REG8(0x3ace), 0x09 }, ++ { CCI_REG8(0x3acf), 0x07 }, { CCI_REG8(0x3ad0), 0x04 }, ++ { CCI_REG8(0x3ad1), 0x0c }, { CCI_REG8(0x3ad2), 0x09 }, ++ { CCI_REG8(0x3ad3), 0x07 }, { CCI_REG8(0x3ad4), 0x04 }, ++ { CCI_REG8(0xc483), 0x0c }, { CCI_REG8(0xc484), 0x0c }, ++ { CCI_REG8(0xc485), 0x0c }, { CCI_REG8(0xc486), 0x0c }, ++ { CCI_REG8(0x3a2f), 0x0c }, { CCI_REG8(0x3a30), 0x09 }, ++ { CCI_REG8(0x3a31), 0x06 }, { CCI_REG8(0x3a32), 0x02 }, ++ { CCI_REG8(0x3a34), 0x0c }, { CCI_REG8(0x3a35), 0x09 }, ++ { CCI_REG8(0x3a36), 0x07 }, { CCI_REG8(0x3a37), 0x04 }, ++ { CCI_REG8(0x3a43), 0x0c }, { CCI_REG8(0x3a44), 0x09 }, ++ { CCI_REG8(0x3a45), 0x06 }, { CCI_REG8(0x3a46), 0x02 }, ++ { CCI_REG8(0x3a48), 0x0c }, { CCI_REG8(0x3a49), 0x09 }, ++ { CCI_REG8(0x3a4a), 0x07 }, { CCI_REG8(0x3a4b), 0x04 }, ++ { CCI_REG8(0xc487), 0x0c }, { CCI_REG8(0xc488), 0x0c }, ++ { CCI_REG8(0xc489), 0x0c }, { CCI_REG8(0xc48a), 0x0c }, ++ { CCI_REG8(0x3645), 0xbd }, { CCI_REG8(0x373f), 0x00 }, ++ { CCI_REG8(0x374f), 0x10 }, { CCI_REG8(0x3743), 0xc6 }, ++ { CCI_REG8(0x3717), 0x82 }, { CCI_REG8(0x3732), 0x07 }, ++ { CCI_REG8(0x3731), 0x16 }, { CCI_REG8(0x3730), 0x16 }, ++ { CCI_REG8(0x3828), 0x07 }, { CCI_REG8(0x3714), 0x68 }, ++ { CCI_REG8(0x371d), 0x02 }, { CCI_REG8(0x371f), 0x02 }, ++ { CCI_REG8(0x37e0), 0x00 }, { CCI_REG8(0x37e1), 0x03 }, ++ { CCI_REG8(0x37e2), 0x07 }, { CCI_REG8(0x3734), 0x3e }, ++ { CCI_REG8(0x3736), 0x02 }, { CCI_REG8(0x37e4), 0x36 }, ++ { CCI_REG8(0x37e9), 0x1c }, { CCI_REG8(0x37ea), 0x01 }, ++ { CCI_REG8(0x37eb), 0x0a }, { CCI_REG8(0x37ec), 0x1c }, ++ { CCI_REG8(0x37ed), 0x01 }, { CCI_REG8(0x37ee), 0x36 }, ++ { CCI_REG8(0x373b), 0x1c }, { CCI_REG8(0x373c), 0x02 }, ++ { CCI_REG8(0x37bb), 0x1c }, { CCI_REG8(0x37bc), 0x02 }, ++ { CCI_REG8(0x37b8), 0x0c }, { CCI_REG8(0x371c), 0x01 }, ++ { CCI_REG8(0x371e), 0x11 }, { CCI_REG8(0x371d), 0x01 }, ++ { CCI_REG8(0x371f), 0x01 }, { CCI_REG8(0x3721), 0x01 }, ++ { CCI_REG8(0x3725), 0x12 }, { CCI_REG8(0x37e3), 0x06 }, ++ { CCI_REG8(0x37dd), 0x86 }, { CCI_REG8(0x37db), 0x0a }, ++ { CCI_REG8(0x37dc), 0x14 }, { CCI_REG8(0x3727), 0x20 }, ++ { CCI_REG8(0x37b2), 0x80 }, { CCI_REG8(0x37da), 0x04 }, ++ { CCI_REG8(0x37df), 0x01 }, { CCI_REG8(0x3731), 0x11 }, ++ { CCI_REG8(0x37dd), 0x86 }, { CCI_REG8(0x37df), 0x01 }, ++ { CCI_REG8(0x37da), 0x03 }, { CCI_REG8(0x37b2), 0x80 }, ++ { CCI_REG8(0x3727), 0x20 }, { CCI_REG8(0x4883), 0x26 }, ++ { CCI_REG8(0x488b), 0x88 }, { CCI_REG8(0x3d85), 0x1f }, ++ { CCI_REG8(0x3d81), 0x01 }, { CCI_REG8(0x3d84), 0x40 }, ++ { CCI_REG8(0x3d88), 0x00 }, { CCI_REG8(0x3d89), 0x00 }, ++ { CCI_REG8(0x3d8a), 0x0b }, { CCI_REG8(0x3d8b), 0xff }, ++ { CCI_REG8(0x4d00), 0x05 }, { CCI_REG8(0x4d01), 0xc4 }, ++ { CCI_REG8(0x4d02), 0xa3 }, { CCI_REG8(0x4d03), 0x8c }, ++ { CCI_REG8(0x4d04), 0xfb }, { CCI_REG8(0x4d05), 0xed }, ++ { CCI_REG8(0x4010), 0x28 }, { CCI_REG8(0x4030), 0x00 }, ++ { CCI_REG8(0x4031), 0x00 }, { CCI_REG8(0x4032), 0x00 }, ++ { CCI_REG8(0x4033), 0x00 }, { CCI_REG8(0x4034), 0x00 }, ++ { CCI_REG8(0x4035), 0x00 }, { CCI_REG8(0x4036), 0x00 }, ++ { CCI_REG8(0x4037), 0x00 }, { CCI_REG8(0x4040), 0x00 }, ++ { CCI_REG8(0x4041), 0x00 }, { CCI_REG8(0x4042), 0x00 }, ++ { CCI_REG8(0x4043), 0x00 }, { CCI_REG8(0x4044), 0x00 }, ++ { CCI_REG8(0x4045), 0x00 }, { CCI_REG8(0x4046), 0x00 }, ++ { CCI_REG8(0x4047), 0x00 }, { CCI_REG8(0x3400), 0x00 }, ++ { CCI_REG8(0x3421), 0x23 }, { CCI_REG8(0x3422), 0xfc }, ++ { CCI_REG8(0x3423), 0x07 }, { CCI_REG8(0x3424), 0x01 }, ++ { CCI_REG8(0x3425), 0x04 }, { CCI_REG8(0x3426), 0x50 }, ++ { CCI_REG8(0x3427), 0x55 }, { CCI_REG8(0x3428), 0x15 }, ++ { CCI_REG8(0x3429), 0x00 }, { CCI_REG8(0x3025), 0x03 }, ++ { CCI_REG8(0x3053), 0x00 }, { CCI_REG8(0x3054), 0x00 }, ++ { CCI_REG8(0x3055), 0x00 }, { CCI_REG8(0x3056), 0x00 }, ++ { CCI_REG8(0x3057), 0x00 }, { CCI_REG8(0x3058), 0x00 }, ++ { CCI_REG8(0x305c), 0x00 }, { CCI_REG8(0x340c), 0x1f }, ++ { CCI_REG8(0x340d), 0x00 }, { CCI_REG8(0x3501), 0x01 }, ++ { CCI_REG8(0x3542), 0x48 }, { CCI_REG8(0x3582), 0x24 }, ++ { CCI_REG8(0x3015), 0xf1 }, { CCI_REG8(0x3018), 0xf2 }, ++ { CCI_REG8(0x301c), 0xf2 }, { CCI_REG8(0x301d), 0xf6 }, ++ { CCI_REG8(0x301e), 0xf1 }, { CCI_REG8(0x0100), 0x01 }, ++ { CCI_REG8(0xfff9), 0x08 }, { CCI_REG8(0x3900), 0xcd }, ++ { CCI_REG8(0x3901), 0xcd }, { CCI_REG8(0x3902), 0xcd }, ++ { CCI_REG8(0x3903), 0xcd }, { CCI_REG8(0x3904), 0xcd }, ++ { CCI_REG8(0x3905), 0xcd }, { CCI_REG8(0x3906), 0xcd }, ++ { CCI_REG8(0x3907), 0xcd }, { CCI_REG8(0x3908), 0xcd }, ++ { CCI_REG8(0x3909), 0xcd }, { CCI_REG8(0x390a), 0xcd }, ++ { CCI_REG8(0x390b), 0xcd }, { CCI_REG8(0x390c), 0xcd }, ++ { CCI_REG8(0x390d), 0xcd }, { CCI_REG8(0x390e), 0xcd }, ++ { CCI_REG8(0x390f), 0xcd }, { CCI_REG8(0x3910), 0xcd }, ++ { CCI_REG8(0x3911), 0xcd }, { CCI_REG8(0x3912), 0xcd }, ++ { CCI_REG8(0x3913), 0xcd }, { CCI_REG8(0x3914), 0xcd }, ++ { CCI_REG8(0x3915), 0xcd }, { CCI_REG8(0x3916), 0xcd }, ++ { CCI_REG8(0x3917), 0xcd }, { CCI_REG8(0x3918), 0xcd }, ++ { CCI_REG8(0x3919), 0xcd }, { CCI_REG8(0x391a), 0xcd }, ++ { CCI_REG8(0x391b), 0xcd }, { CCI_REG8(0x391c), 0xcd }, ++ { CCI_REG8(0x391d), 0xcd }, { CCI_REG8(0x391e), 0xcd }, ++ { CCI_REG8(0x391f), 0xcd }, { CCI_REG8(0x3920), 0xcd }, ++ { CCI_REG8(0x3921), 0xcd }, { CCI_REG8(0x3922), 0xcd }, ++ { CCI_REG8(0x3923), 0xcd }, { CCI_REG8(0x3924), 0xcd }, ++ { CCI_REG8(0x3925), 0xcd }, { CCI_REG8(0x3926), 0xcd }, ++ { CCI_REG8(0x3927), 0xcd }, { CCI_REG8(0x3928), 0xcd }, ++ { CCI_REG8(0x3929), 0xcd }, { CCI_REG8(0x392a), 0xcd }, ++ { CCI_REG8(0x392b), 0xcd }, { CCI_REG8(0x392c), 0xcd }, ++ { CCI_REG8(0x392d), 0xcd }, { CCI_REG8(0x392e), 0xcd }, ++ { CCI_REG8(0x392f), 0xcd }, { CCI_REG8(0x3930), 0xcd }, ++ { CCI_REG8(0x3931), 0xcd }, { CCI_REG8(0x3932), 0xcd }, ++ { CCI_REG8(0x3933), 0xcd }, { CCI_REG8(0x3934), 0xcd }, ++ { CCI_REG8(0x3935), 0xcd }, { CCI_REG8(0x3936), 0xcd }, ++ { CCI_REG8(0x3937), 0xcd }, { CCI_REG8(0x3938), 0xcd }, ++ { CCI_REG8(0x3939), 0xcd }, { CCI_REG8(0x393a), 0xcd }, ++ { CCI_REG8(0x393b), 0xcd }, { CCI_REG8(0x393c), 0xcd }, ++ { CCI_REG8(0x393d), 0xcd }, { CCI_REG8(0x393e), 0xcd }, ++ { CCI_REG8(0x393f), 0xcd }, { CCI_REG8(0x3940), 0xcd }, ++ { CCI_REG8(0x3941), 0xcd }, { CCI_REG8(0x3942), 0xcd }, ++ { CCI_REG8(0x3943), 0xcd }, { CCI_REG8(0x3944), 0xcd }, ++ { CCI_REG8(0x3945), 0xcd }, { CCI_REG8(0x3946), 0xcd }, ++ { CCI_REG8(0x3947), 0xcd }, { CCI_REG8(0x3948), 0xcd }, ++ { CCI_REG8(0x3949), 0xcd }, { CCI_REG8(0x394a), 0xcd }, ++ { CCI_REG8(0x394b), 0xcd }, { CCI_REG8(0x394c), 0xcd }, ++ { CCI_REG8(0x394d), 0xcd }, { CCI_REG8(0x394e), 0xcd }, ++ { CCI_REG8(0x394f), 0xcd }, { CCI_REG8(0x3950), 0xcd }, ++ { CCI_REG8(0x3951), 0xcd }, { CCI_REG8(0x3952), 0xcd }, ++ { CCI_REG8(0x3953), 0xcd }, { CCI_REG8(0x3954), 0xcd }, ++ { CCI_REG8(0x3955), 0xcd }, { CCI_REG8(0x3956), 0xcd }, ++ { CCI_REG8(0x3957), 0xcd }, { CCI_REG8(0x3958), 0xcd }, ++ { CCI_REG8(0x3959), 0xcd }, { CCI_REG8(0x395a), 0xcd }, ++ { CCI_REG8(0x395b), 0xcd }, { CCI_REG8(0x395c), 0xcd }, ++ { CCI_REG8(0x395d), 0xcd }, { CCI_REG8(0x395e), 0xcd }, ++ { CCI_REG8(0x395f), 0xcd }, { CCI_REG8(0x3960), 0xcd }, ++ { CCI_REG8(0x3961), 0xcd }, { CCI_REG8(0x3962), 0xcd }, ++ { CCI_REG8(0x3963), 0xcd }, { CCI_REG8(0x3964), 0xcd }, ++ { CCI_REG8(0x3965), 0xcd }, { CCI_REG8(0x3966), 0xcd }, ++ { CCI_REG8(0x3967), 0xcd }, { CCI_REG8(0x3968), 0xcd }, ++ { CCI_REG8(0x3969), 0xcd }, { CCI_REG8(0x396a), 0xcd }, ++ { CCI_REG8(0x396b), 0xcd }, { CCI_REG8(0x396c), 0xcd }, ++ { CCI_REG8(0x396d), 0xcd }, { CCI_REG8(0x396e), 0xcd }, ++ { CCI_REG8(0x396f), 0xcd }, { CCI_REG8(0x3970), 0xcd }, ++ { CCI_REG8(0x3971), 0xcd }, { CCI_REG8(0x3972), 0xcd }, ++ { CCI_REG8(0x3973), 0xcd }, { CCI_REG8(0x3974), 0xcd }, ++ { CCI_REG8(0x3975), 0xcd }, { CCI_REG8(0x3976), 0xcd }, ++ { CCI_REG8(0x3977), 0xcd }, { CCI_REG8(0x3978), 0xcd }, ++ { CCI_REG8(0x3979), 0xcd }, { CCI_REG8(0x397a), 0xcd }, ++ { CCI_REG8(0x397b), 0xcd }, { CCI_REG8(0x397c), 0xcd }, ++ { CCI_REG8(0x397d), 0xcd }, { CCI_REG8(0x397e), 0xcd }, ++ { CCI_REG8(0x397f), 0xcd }, { CCI_REG8(0x3980), 0xcd }, ++ { CCI_REG8(0x3981), 0xcd }, { CCI_REG8(0x3982), 0xcd }, ++ { CCI_REG8(0x3983), 0xcd }, { CCI_REG8(0x3984), 0xcd }, ++ { CCI_REG8(0x3985), 0xcd }, { CCI_REG8(0x3986), 0xcd }, ++ { CCI_REG8(0x3987), 0xcd }, { CCI_REG8(0x3988), 0xcd }, ++ { CCI_REG8(0x3989), 0xcd }, { CCI_REG8(0x398a), 0xcd }, ++ { CCI_REG8(0x398b), 0xcd }, { CCI_REG8(0x398c), 0xcd }, ++ { CCI_REG8(0x398d), 0xcd }, { CCI_REG8(0x398e), 0xcd }, ++ { CCI_REG8(0x398f), 0xcd }, { CCI_REG8(0x3990), 0xcd }, ++ { CCI_REG8(0x3991), 0xcd }, { CCI_REG8(0x3992), 0xcd }, ++ { CCI_REG8(0x3993), 0xcd }, { CCI_REG8(0x3994), 0xcd }, ++ { CCI_REG8(0x3995), 0xcd }, { CCI_REG8(0x3996), 0xcd }, ++ { CCI_REG8(0x3997), 0xcd }, { CCI_REG8(0x3998), 0xcd }, ++ { CCI_REG8(0x3999), 0xcd }, { CCI_REG8(0x399a), 0xcd }, ++ { CCI_REG8(0x399b), 0xcd }, { CCI_REG8(0x399c), 0xcd }, ++ { CCI_REG8(0x399d), 0xcd }, { CCI_REG8(0x399e), 0xcd }, ++ { CCI_REG8(0x399f), 0xcd }, { CCI_REG8(0x39a0), 0xcd }, ++ { CCI_REG8(0x39a1), 0xcd }, { CCI_REG8(0x39a2), 0xcd }, ++ { CCI_REG8(0x39a3), 0xcd }, { CCI_REG8(0x39a4), 0xcd }, ++ { CCI_REG8(0x39a5), 0xcd }, { CCI_REG8(0x39a6), 0xcd }, ++ { CCI_REG8(0x39a7), 0xcd }, { CCI_REG8(0x39a8), 0xcd }, ++ { CCI_REG8(0x39a9), 0xcd }, { CCI_REG8(0x39aa), 0xcd }, ++ { CCI_REG8(0x39ab), 0xcd }, { CCI_REG8(0x39ac), 0xcd }, ++ { CCI_REG8(0x39ad), 0xcd }, { CCI_REG8(0x39ae), 0xcd }, ++ { CCI_REG8(0x39af), 0xcd }, { CCI_REG8(0x39b0), 0xcd }, ++ { CCI_REG8(0x39b1), 0xcd }, { CCI_REG8(0x39b2), 0xcd }, ++ { CCI_REG8(0x39b3), 0xcd }, { CCI_REG8(0x39b4), 0xcd }, ++ { CCI_REG8(0x39b5), 0xcd }, { CCI_REG8(0x39b6), 0xcd }, ++ { CCI_REG8(0x39b7), 0xcd }, { CCI_REG8(0x39b8), 0xcd }, ++ { CCI_REG8(0x39b9), 0xcd }, { CCI_REG8(0x39ba), 0xcd }, ++ { CCI_REG8(0x39bb), 0xcd }, { CCI_REG8(0x39bc), 0xcd }, ++ { CCI_REG8(0x39bd), 0xcd }, { CCI_REG8(0x39be), 0xcd }, ++ { CCI_REG8(0x39bf), 0xcd }, { CCI_REG8(0x39c0), 0xcd }, ++ { CCI_REG8(0x39c1), 0xcd }, { CCI_REG8(0x39c2), 0xcd }, ++ { CCI_REG8(0x39c3), 0xcd }, { CCI_REG8(0x39c4), 0xcd }, ++ { CCI_REG8(0x39c5), 0xcd }, { CCI_REG8(0x39c6), 0xcd }, ++ { CCI_REG8(0x39c7), 0xcd }, { CCI_REG8(0x39c8), 0xcd }, ++ { CCI_REG8(0x39c9), 0xcd }, { CCI_REG8(0x39ca), 0xcd }, ++ { CCI_REG8(0x39cb), 0xcd }, { CCI_REG8(0x39cc), 0xcd }, ++ { CCI_REG8(0x39cd), 0xcd }, { CCI_REG8(0x39ce), 0xcd }, ++ { CCI_REG8(0x39cf), 0xcd }, { CCI_REG8(0x39d0), 0xcd }, ++ { CCI_REG8(0x39d1), 0xcd }, { CCI_REG8(0x39d2), 0xcd }, ++ { CCI_REG8(0x39d3), 0xcd }, { CCI_REG8(0x39d4), 0xcd }, ++ { CCI_REG8(0x39d5), 0xcd }, { CCI_REG8(0x39d6), 0xcd }, ++ { CCI_REG8(0x39d7), 0xcd }, { CCI_REG8(0x39d8), 0xcd }, ++ { CCI_REG8(0x39d9), 0xcd }, { CCI_REG8(0x39da), 0xcd }, ++ { CCI_REG8(0x39db), 0xcd }, { CCI_REG8(0x39dc), 0xcd }, ++ { CCI_REG8(0x39dd), 0xcd }, { CCI_REG8(0x39de), 0xcd }, ++ { CCI_REG8(0x39df), 0xcd }, { CCI_REG8(0x39e0), 0xcd }, ++ { CCI_REG8(0x39e1), 0x40 }, { CCI_REG8(0x39e2), 0x40 }, ++ { CCI_REG8(0x39e3), 0x40 }, { CCI_REG8(0x39e4), 0x40 }, ++ { CCI_REG8(0x39e5), 0x40 }, { CCI_REG8(0x39e6), 0x40 }, ++ { CCI_REG8(0x39e7), 0x40 }, { CCI_REG8(0x39e8), 0x40 }, ++ { CCI_REG8(0x39e9), 0x40 }, { CCI_REG8(0x39ea), 0x40 }, ++ { CCI_REG8(0x39eb), 0x40 }, { CCI_REG8(0x39ec), 0x40 }, ++ { CCI_REG8(0x39ed), 0x40 }, { CCI_REG8(0x39ee), 0x40 }, ++ { CCI_REG8(0x39ef), 0x40 }, { CCI_REG8(0x39f0), 0x40 }, ++ { CCI_REG8(0x39f1), 0x40 }, { CCI_REG8(0x39f2), 0x40 }, ++ { CCI_REG8(0x39f3), 0x40 }, { CCI_REG8(0x39f4), 0x40 }, ++ { CCI_REG8(0x39f5), 0x40 }, { CCI_REG8(0x39f6), 0x40 }, ++ { CCI_REG8(0x39f7), 0x40 }, { CCI_REG8(0x39f8), 0x40 }, ++ { CCI_REG8(0x39f9), 0x40 }, { CCI_REG8(0x39fa), 0x40 }, ++ { CCI_REG8(0x39fb), 0x40 }, { CCI_REG8(0x39fc), 0x40 }, ++ { CCI_REG8(0x39fd), 0x40 }, { CCI_REG8(0x39fe), 0x40 }, ++ { CCI_REG8(0x39ff), 0x40 }, { CCI_REG8(0x3a00), 0x40 }, ++ { CCI_REG8(0x3a01), 0x40 }, { CCI_REG8(0x3a02), 0x40 }, ++ { CCI_REG8(0x3a03), 0x40 }, { CCI_REG8(0x3a04), 0x40 }, ++ { CCI_REG8(0x3a05), 0x40 }, { CCI_REG8(0x3a06), 0x40 }, ++ { CCI_REG8(0x3a07), 0x40 }, { CCI_REG8(0x3a08), 0x40 }, ++ { CCI_REG8(0x3a09), 0x40 }, { CCI_REG8(0x3a0a), 0x40 }, ++ { CCI_REG8(0x3a0b), 0x40 }, { CCI_REG8(0x3a0c), 0x40 }, ++ { CCI_REG8(0x3a0d), 0x40 }, { CCI_REG8(0x3a0e), 0x40 }, ++ { CCI_REG8(0x3a0f), 0x40 }, { CCI_REG8(0x3a10), 0x40 }, ++ { CCI_REG8(0x3a11), 0x40 }, { CCI_REG8(0x3a12), 0x40 }, ++ { CCI_REG8(0x3a13), 0x40 }, { CCI_REG8(0x3a14), 0x40 }, ++ { CCI_REG8(0x3a15), 0x40 }, { CCI_REG8(0x3a16), 0x40 }, ++ { CCI_REG8(0x3a17), 0x40 }, { CCI_REG8(0x3a18), 0x40 }, ++ { CCI_REG8(0x3a19), 0x40 }, { CCI_REG8(0x3a1a), 0x40 }, ++ { CCI_REG8(0x3a1b), 0x40 }, { CCI_REG8(0x3a1c), 0x40 }, ++ { CCI_REG8(0x3a1d), 0x40 }, { CCI_REG8(0x3a1e), 0x40 }, ++ { CCI_REG8(0x3a1f), 0x40 }, { CCI_REG8(0x3a20), 0x40 }, ++ { CCI_REG8(0x3a21), 0x40 }, { CCI_REG8(0x3a22), 0x40 }, ++ { CCI_REG8(0x3a23), 0x40 }, { CCI_REG8(0x3a24), 0x40 }, ++ { CCI_REG8(0x3a25), 0x40 }, { CCI_REG8(0x3a26), 0x40 }, ++ { CCI_REG8(0x3a27), 0x40 }, { CCI_REG8(0x3a28), 0x40 }, ++ { CCI_REG8(0x3a29), 0x40 }, { CCI_REG8(0x3a2a), 0x40 }, ++ { CCI_REG8(0x3a2b), 0x40 }, { CCI_REG8(0x3a2c), 0x40 }, ++ { CCI_REG8(0x3a2d), 0x40 }, { CCI_REG8(0x3a2e), 0x40 }, ++ { CCI_REG8(0x3a2f), 0x40 }, { CCI_REG8(0x3a30), 0x40 }, ++ { CCI_REG8(0x3a31), 0x40 }, { CCI_REG8(0x3a32), 0x40 }, ++ { CCI_REG8(0x3a33), 0x40 }, { CCI_REG8(0x3a34), 0x40 }, ++ { CCI_REG8(0x3a35), 0x40 }, { CCI_REG8(0x3a36), 0x40 }, ++ { CCI_REG8(0x3a37), 0x40 }, { CCI_REG8(0x3a38), 0x40 }, ++ { CCI_REG8(0x3a39), 0x40 }, { CCI_REG8(0x3a3a), 0x40 }, ++ { CCI_REG8(0x3a3b), 0xcd }, { CCI_REG8(0x3a3c), 0xcd }, ++ { CCI_REG8(0x3a3d), 0xcd }, { CCI_REG8(0x3a3e), 0xcd }, ++ { CCI_REG8(0x3a3f), 0xcd }, { CCI_REG8(0x3a40), 0xcd }, ++ { CCI_REG8(0x3a41), 0xcd }, { CCI_REG8(0x3a42), 0xcd }, ++ { CCI_REG8(0x3a43), 0xcd }, { CCI_REG8(0x3a44), 0xcd }, ++ { CCI_REG8(0x3a45), 0xcd }, { CCI_REG8(0x3a46), 0xcd }, ++ { CCI_REG8(0x3a47), 0xcd }, { CCI_REG8(0x3a48), 0xcd }, ++ { CCI_REG8(0x3a49), 0xcd }, { CCI_REG8(0x3a4a), 0xcd }, ++ { CCI_REG8(0x3a4b), 0xcd }, { CCI_REG8(0x3a4c), 0xcd }, ++ { CCI_REG8(0x3a4d), 0xcd }, { CCI_REG8(0x3a4e), 0xcd }, ++ { CCI_REG8(0x3a4f), 0xcd }, { CCI_REG8(0x3a50), 0xcd }, ++ { CCI_REG8(0x3a51), 0xcd }, { CCI_REG8(0x3a52), 0xcd }, ++ { CCI_REG8(0x3a53), 0xcd }, { CCI_REG8(0x3a54), 0xcd }, ++ { CCI_REG8(0x3a55), 0xcd }, { CCI_REG8(0x3a56), 0xcd }, ++ { CCI_REG8(0x3a57), 0xcd }, { CCI_REG8(0x3a58), 0xcd }, ++ { CCI_REG8(0x3a59), 0xcd }, { CCI_REG8(0x3a5a), 0xcd }, ++ { CCI_REG8(0x3a5b), 0xcd }, { CCI_REG8(0x3a5c), 0xcd }, ++ { CCI_REG8(0x3a5d), 0xcd }, { CCI_REG8(0x3a5e), 0xcd }, ++ { CCI_REG8(0x3a5f), 0xcd }, { CCI_REG8(0x3a60), 0xcd }, ++ { CCI_REG8(0x3a61), 0xcd }, { CCI_REG8(0x3a62), 0xcd }, ++ { CCI_REG8(0x3a63), 0xcd }, { CCI_REG8(0x3a64), 0xcd }, ++ { CCI_REG8(0x3a65), 0xcd }, { CCI_REG8(0x3a66), 0xcd }, ++ { CCI_REG8(0x3a67), 0xcd }, { CCI_REG8(0x3a68), 0xcd }, ++ { CCI_REG8(0x3a69), 0xcd }, { CCI_REG8(0x3a6a), 0xcd }, ++ { CCI_REG8(0x3a6b), 0xcd }, { CCI_REG8(0x3a6c), 0xcd }, ++ { CCI_REG8(0x3a6d), 0xcd }, { CCI_REG8(0x3a6e), 0xcd }, ++ { CCI_REG8(0x3a6f), 0xcd }, { CCI_REG8(0x3a70), 0xcd }, ++ { CCI_REG8(0x3a71), 0xcd }, { CCI_REG8(0x3a72), 0xcd }, ++ { CCI_REG8(0x3a73), 0xcd }, { CCI_REG8(0x3a74), 0xcd }, ++ { CCI_REG8(0x3a75), 0xcd }, { CCI_REG8(0x3a76), 0xcd }, ++ { CCI_REG8(0x3a77), 0xcd }, { CCI_REG8(0x3a78), 0xcd }, ++ { CCI_REG8(0x3a79), 0xcd }, { CCI_REG8(0x3a7a), 0xcd }, ++ { CCI_REG8(0x3a7b), 0xcd }, { CCI_REG8(0x3a7c), 0xcd }, ++ { CCI_REG8(0x3a7d), 0xcd }, { CCI_REG8(0x3a7e), 0xcd }, ++ { CCI_REG8(0x3a7f), 0xcd }, { CCI_REG8(0x3a80), 0xcd }, ++ { CCI_REG8(0x3a81), 0xcd }, { CCI_REG8(0x3a82), 0xcd }, ++ { CCI_REG8(0x3a83), 0xcd }, { CCI_REG8(0x3a84), 0xcd }, ++ { CCI_REG8(0x3a85), 0xcd }, { CCI_REG8(0x3a86), 0xcd }, ++ { CCI_REG8(0x3a87), 0xcd }, { CCI_REG8(0x3a88), 0xcd }, ++ { CCI_REG8(0x3a89), 0xcd }, { CCI_REG8(0x3a8a), 0xcd }, ++ { CCI_REG8(0x3a8b), 0xcd }, { CCI_REG8(0x3a8c), 0xcd }, ++ { CCI_REG8(0x3a8d), 0xcd }, { CCI_REG8(0x3a8e), 0xcd }, ++ { CCI_REG8(0x3a8f), 0xcd }, { CCI_REG8(0x3a90), 0xcd }, ++ { CCI_REG8(0x3a91), 0xcd }, { CCI_REG8(0x3a92), 0xcd }, ++ { CCI_REG8(0x3a93), 0xcd }, { CCI_REG8(0x3a94), 0xcd }, ++ { CCI_REG8(0x3a95), 0x40 }, { CCI_REG8(0x3a96), 0x40 }, ++ { CCI_REG8(0x3a97), 0x40 }, { CCI_REG8(0x3a98), 0x40 }, ++ { CCI_REG8(0x3a99), 0x40 }, { CCI_REG8(0x3a9a), 0x40 }, ++ { CCI_REG8(0x3a9b), 0x40 }, { CCI_REG8(0x3a9c), 0x40 }, ++ { CCI_REG8(0x3a9d), 0x40 }, { CCI_REG8(0x3a9e), 0x40 }, ++ { CCI_REG8(0x3a9f), 0x40 }, { CCI_REG8(0x3aa0), 0x40 }, ++ { CCI_REG8(0x3aa1), 0x40 }, { CCI_REG8(0x3aa2), 0x40 }, ++ { CCI_REG8(0x3aa3), 0x40 }, { CCI_REG8(0x3aa4), 0x40 }, ++ { CCI_REG8(0x3aa5), 0x40 }, { CCI_REG8(0x3aa6), 0x40 }, ++ { CCI_REG8(0x3aa7), 0x40 }, { CCI_REG8(0x3aa8), 0x40 }, ++ { CCI_REG8(0x3aa9), 0x40 }, { CCI_REG8(0x3aaa), 0x40 }, ++ { CCI_REG8(0x3aab), 0x40 }, { CCI_REG8(0x3aac), 0x40 }, ++ { CCI_REG8(0x3aad), 0x40 }, { CCI_REG8(0x3aae), 0x40 }, ++ { CCI_REG8(0x3aaf), 0x40 }, { CCI_REG8(0x3ab0), 0x40 }, ++ { CCI_REG8(0x3ab1), 0x40 }, { CCI_REG8(0x3ab2), 0x40 }, ++ { CCI_REG8(0x3ab3), 0x40 }, { CCI_REG8(0x3ab4), 0x40 }, ++ { CCI_REG8(0x3ab5), 0x40 }, { CCI_REG8(0x3ab6), 0x40 }, ++ { CCI_REG8(0x3ab7), 0x40 }, { CCI_REG8(0x3ab8), 0x40 }, ++ { CCI_REG8(0x3ab9), 0x40 }, { CCI_REG8(0x3aba), 0x40 }, ++ { CCI_REG8(0x3abb), 0x40 }, { CCI_REG8(0x3abc), 0x40 }, ++ { CCI_REG8(0x3abd), 0x40 }, { CCI_REG8(0x3abe), 0x40 }, ++ { CCI_REG8(0x3abf), 0x40 }, { CCI_REG8(0x3ac0), 0x40 }, ++ { CCI_REG8(0x3ac1), 0x40 }, { CCI_REG8(0x3ac2), 0x40 }, ++ { CCI_REG8(0x3ac3), 0x40 }, { CCI_REG8(0x3ac4), 0x40 }, ++ { CCI_REG8(0x3ac5), 0x40 }, { CCI_REG8(0x3ac6), 0x40 }, ++ { CCI_REG8(0x3ac7), 0x40 }, { CCI_REG8(0x3ac8), 0x40 }, ++ { CCI_REG8(0x3ac9), 0x40 }, { CCI_REG8(0x3aca), 0x40 }, ++ { CCI_REG8(0x3acb), 0x40 }, { CCI_REG8(0x3acc), 0x40 }, ++ { CCI_REG8(0x3acd), 0x40 }, { CCI_REG8(0x3ace), 0x40 }, ++ { CCI_REG8(0x3acf), 0x40 }, { CCI_REG8(0x3ad0), 0x40 }, ++ { CCI_REG8(0x3ad1), 0x40 }, { CCI_REG8(0x3ad2), 0x40 }, ++ { CCI_REG8(0x3ad3), 0x40 }, { CCI_REG8(0x3ad4), 0x40 }, ++ { CCI_REG8(0x3ad5), 0x40 }, { CCI_REG8(0x3ad6), 0x40 }, ++ { CCI_REG8(0x3ad7), 0x40 }, { CCI_REG8(0x3ad8), 0x40 }, ++ { CCI_REG8(0x3ad9), 0x40 }, { CCI_REG8(0x3ada), 0x40 }, ++ { CCI_REG8(0x3adb), 0x40 }, { CCI_REG8(0x3adc), 0x40 }, ++ { CCI_REG8(0x3add), 0x40 }, { CCI_REG8(0x3ade), 0x40 }, ++ { CCI_REG8(0x3adf), 0x40 }, { CCI_REG8(0x3ae0), 0x40 }, ++ { CCI_REG8(0x3ae1), 0x40 }, { CCI_REG8(0x3ae2), 0x40 }, ++ { CCI_REG8(0x3ae3), 0x40 }, { CCI_REG8(0x3ae4), 0x40 }, ++ { CCI_REG8(0x3ae5), 0x40 }, { CCI_REG8(0x3ae6), 0x40 }, ++ { CCI_REG8(0x3ae7), 0x40 }, { CCI_REG8(0x3ae8), 0x40 }, ++ { CCI_REG8(0x3ae9), 0x40 }, { CCI_REG8(0x3aea), 0x40 }, ++ { CCI_REG8(0x3aeb), 0x40 }, { CCI_REG8(0x3aec), 0x40 }, ++ { CCI_REG8(0x3aed), 0x40 }, { CCI_REG8(0x3aee), 0x40 }, ++ { CCI_REG8(0x3aef), 0xcd }, { CCI_REG8(0x3af0), 0xcd }, ++ { CCI_REG8(0x3af1), 0xcd }, { CCI_REG8(0x3af2), 0xcd }, ++ { CCI_REG8(0x3af3), 0xcd }, { CCI_REG8(0x3af4), 0xcd }, ++ { CCI_REG8(0x3af5), 0xcd }, { CCI_REG8(0x3af6), 0xcd }, ++ { CCI_REG8(0x3af7), 0xcd }, { CCI_REG8(0x3af8), 0xcd }, ++ { CCI_REG8(0x3af9), 0xcd }, { CCI_REG8(0x3afa), 0xcd }, ++ { CCI_REG8(0x3afb), 0xcd }, { CCI_REG8(0x3afc), 0xcd }, ++ { CCI_REG8(0x3afd), 0xcd }, { CCI_REG8(0x3afe), 0xcd }, ++ { CCI_REG8(0x3aff), 0xcd }, { CCI_REG8(0x3b00), 0xcd }, ++ { CCI_REG8(0x3b01), 0xcd }, { CCI_REG8(0x3b02), 0xcd }, ++ { CCI_REG8(0x3b03), 0xcd }, { CCI_REG8(0x3b04), 0xcd }, ++ { CCI_REG8(0x3b05), 0xcd }, { CCI_REG8(0x3b06), 0xcd }, ++ { CCI_REG8(0x3b07), 0xcd }, { CCI_REG8(0x3b08), 0xcd }, ++ { CCI_REG8(0x3b09), 0xcd }, { CCI_REG8(0x3b0a), 0xcd }, ++ { CCI_REG8(0x3b0b), 0xcd }, { CCI_REG8(0x3b0c), 0xcd }, ++ { CCI_REG8(0x3b0d), 0xcd }, { CCI_REG8(0x3b0e), 0xcd }, ++ { CCI_REG8(0x3b0f), 0xcd }, { CCI_REG8(0x3b10), 0xcd }, ++ { CCI_REG8(0x3b11), 0xcd }, { CCI_REG8(0x3b12), 0xcd }, ++ { CCI_REG8(0x3b13), 0xcd }, { CCI_REG8(0x3b14), 0xcd }, ++ { CCI_REG8(0x3b15), 0xcd }, { CCI_REG8(0x3b16), 0xcd }, ++ { CCI_REG8(0x3b17), 0xcd }, { CCI_REG8(0x3b18), 0xcd }, ++ { CCI_REG8(0x3b19), 0xcd }, { CCI_REG8(0x3b1a), 0xcd }, ++ { CCI_REG8(0x3b1b), 0xcd }, { CCI_REG8(0x3b1c), 0xcd }, ++ { CCI_REG8(0x3b1d), 0xcd }, { CCI_REG8(0x3b1e), 0xcd }, ++ { CCI_REG8(0x3b1f), 0xcd }, { CCI_REG8(0x3b20), 0xcd }, ++ { CCI_REG8(0x3b21), 0xcd }, { CCI_REG8(0x3b22), 0xcd }, ++ { CCI_REG8(0x3b23), 0xcd }, { CCI_REG8(0x3b24), 0xcd }, ++ { CCI_REG8(0x3b25), 0xcd }, { CCI_REG8(0x3b26), 0xcd }, ++ { CCI_REG8(0x3b27), 0xcd }, { CCI_REG8(0x3b28), 0xcd }, ++ { CCI_REG8(0x3b29), 0xcd }, { CCI_REG8(0x3b2a), 0xcd }, ++ { CCI_REG8(0x3b2b), 0xcd }, { CCI_REG8(0x3b2c), 0xcd }, ++ { CCI_REG8(0x3b2d), 0xcd }, { CCI_REG8(0x3b2e), 0xcd }, ++ { CCI_REG8(0x3b2f), 0xcd }, { CCI_REG8(0x3b30), 0xcd }, ++ { CCI_REG8(0x3b31), 0xcd }, { CCI_REG8(0x3b32), 0xcd }, ++ { CCI_REG8(0x3b33), 0xcd }, { CCI_REG8(0x3b34), 0xcd }, ++ { CCI_REG8(0x3b35), 0xcd }, { CCI_REG8(0x3b36), 0xcd }, ++ { CCI_REG8(0x3b37), 0xcd }, { CCI_REG8(0x3b38), 0xcd }, ++ { CCI_REG8(0x3b39), 0xcd }, { CCI_REG8(0x3b3a), 0xcd }, ++ { CCI_REG8(0x3b3b), 0xcd }, { CCI_REG8(0x3b3c), 0xcd }, ++ { CCI_REG8(0x3b3d), 0xcd }, { CCI_REG8(0x3b3e), 0xcd }, ++ { CCI_REG8(0x3b3f), 0xcd }, { CCI_REG8(0x3b40), 0xcd }, ++ { CCI_REG8(0x3b41), 0xcd }, { CCI_REG8(0x3b42), 0xcd }, ++ { CCI_REG8(0x3b43), 0xcd }, { CCI_REG8(0x3b44), 0xcd }, ++ { CCI_REG8(0x3b45), 0xcd }, { CCI_REG8(0x3b46), 0xcd }, ++ { CCI_REG8(0x3b47), 0xcd }, { CCI_REG8(0x3b48), 0xcd }, ++ { CCI_REG8(0x3b49), 0xcd }, { CCI_REG8(0x3b4a), 0xcd }, ++ { CCI_REG8(0x3b4b), 0xcd }, { CCI_REG8(0x3b4c), 0xcd }, ++ { CCI_REG8(0x3b4d), 0xcd }, { CCI_REG8(0x3b4e), 0xcd }, ++ { CCI_REG8(0x3b4f), 0xcd }, { CCI_REG8(0x3b50), 0xcd }, ++ { CCI_REG8(0x3b51), 0xcd }, { CCI_REG8(0x3b52), 0xcd }, ++ { CCI_REG8(0x3b53), 0xcd }, { CCI_REG8(0x3b54), 0xcd }, ++ { CCI_REG8(0x3b55), 0xcd }, { CCI_REG8(0x3b56), 0xcd }, ++ { CCI_REG8(0x3b57), 0xcd }, { CCI_REG8(0x3b58), 0xcd }, ++ { CCI_REG8(0x3b59), 0xcd }, { CCI_REG8(0x3b5a), 0xcd }, ++ { CCI_REG8(0x3b5b), 0xcd }, { CCI_REG8(0x3b5c), 0xcd }, ++ { CCI_REG8(0x3b5d), 0xcd }, { CCI_REG8(0x3b5e), 0xcd }, ++ { CCI_REG8(0x3b5f), 0xcd }, { CCI_REG8(0x3b60), 0xcd }, ++ { CCI_REG8(0x3b61), 0xcd }, { CCI_REG8(0x3b62), 0xcd }, ++ { CCI_REG8(0x3b63), 0xcd }, { CCI_REG8(0x3b64), 0xcd }, ++ { CCI_REG8(0x3b65), 0xcd }, { CCI_REG8(0x3b66), 0xcd }, ++ { CCI_REG8(0x3b67), 0xcd }, { CCI_REG8(0x3b68), 0xcd }, ++ { CCI_REG8(0x3b69), 0xcd }, { CCI_REG8(0x3b6a), 0xcd }, ++ { CCI_REG8(0x3b6b), 0xcd }, { CCI_REG8(0x3b6c), 0xcd }, ++ { CCI_REG8(0x3b6d), 0xcd }, { CCI_REG8(0x3b6e), 0xcd }, ++ { CCI_REG8(0x3b6f), 0xcd }, { CCI_REG8(0x3b70), 0xcd }, ++ { CCI_REG8(0x3b71), 0xcd }, { CCI_REG8(0x3b72), 0xcd }, ++ { CCI_REG8(0x3b73), 0xcd }, { CCI_REG8(0x3b74), 0xcd }, ++ { CCI_REG8(0x3b75), 0xcd }, { CCI_REG8(0x3b76), 0xcd }, ++ { CCI_REG8(0x3b77), 0xcd }, { CCI_REG8(0x3b78), 0xcd }, ++ { CCI_REG8(0x3b79), 0xcd }, { CCI_REG8(0x3b7a), 0xcd }, ++ { CCI_REG8(0x3b7b), 0xcd }, { CCI_REG8(0x3b7c), 0xcd }, ++ { CCI_REG8(0x3b7d), 0xcd }, { CCI_REG8(0x3b7e), 0xcd }, ++ { CCI_REG8(0x3b7f), 0xcd }, { CCI_REG8(0x3b80), 0xcd }, ++ { CCI_REG8(0x3b81), 0xcd }, { CCI_REG8(0x3b82), 0xcd }, ++ { CCI_REG8(0x3b83), 0xcd }, { CCI_REG8(0x3b84), 0xcd }, ++ { CCI_REG8(0x3b85), 0xcd }, { CCI_REG8(0x3b86), 0xcd }, ++ { CCI_REG8(0x3b87), 0xcd }, { CCI_REG8(0x3b88), 0xcd }, ++ { CCI_REG8(0x3b89), 0xcd }, { CCI_REG8(0x3b8a), 0xcd }, ++ { CCI_REG8(0x3b8b), 0xcd }, { CCI_REG8(0x3b8c), 0xcd }, ++ { CCI_REG8(0x3b8d), 0xcd }, { CCI_REG8(0x3b8e), 0xcd }, ++ { CCI_REG8(0x3b8f), 0xcd }, { CCI_REG8(0x3b90), 0xcd }, ++ { CCI_REG8(0x3b91), 0xcd }, { CCI_REG8(0x3b92), 0xcd }, ++ { CCI_REG8(0x3b93), 0xcd }, { CCI_REG8(0x3b94), 0xcd }, ++ { CCI_REG8(0x3b95), 0xcd }, { CCI_REG8(0x3b96), 0xcd }, ++ { CCI_REG8(0x3b97), 0xcd }, { CCI_REG8(0x3b98), 0xcd }, ++ { CCI_REG8(0x3b99), 0xcd }, { CCI_REG8(0x3b9a), 0xcd }, ++ { CCI_REG8(0x3b9b), 0xcd }, { CCI_REG8(0x3b9c), 0xcd }, ++ { CCI_REG8(0x3b9d), 0xcd }, { CCI_REG8(0x3b9e), 0xcd }, ++ { CCI_REG8(0x3b9f), 0xcd }, { CCI_REG8(0x3ba0), 0xcd }, ++ { CCI_REG8(0x3ba1), 0xcd }, { CCI_REG8(0x3ba2), 0xcd }, ++ { CCI_REG8(0x3ba3), 0xcd }, { CCI_REG8(0x3ba4), 0xcd }, ++ { CCI_REG8(0x3ba5), 0xcd }, { CCI_REG8(0x3ba6), 0xcd }, ++ { CCI_REG8(0x3ba7), 0xcd }, { CCI_REG8(0x3ba8), 0xcd }, ++ { CCI_REG8(0x3ba9), 0xcd }, { CCI_REG8(0x3baa), 0xcd }, ++ { CCI_REG8(0x3bab), 0xcd }, { CCI_REG8(0x3bac), 0xcd }, ++ { CCI_REG8(0x3bad), 0xcd }, { CCI_REG8(0x3bae), 0xcd }, ++ { CCI_REG8(0x3baf), 0xcd }, { CCI_REG8(0x3bb0), 0xcd }, ++ { CCI_REG8(0x3bb1), 0xcd }, { CCI_REG8(0x3bb2), 0xcd }, ++ { CCI_REG8(0x3bb3), 0xcd }, { CCI_REG8(0x3bb4), 0xcd }, ++ { CCI_REG8(0x3bb5), 0xcd }, { CCI_REG8(0x3bb6), 0xcd }, ++ { CCI_REG8(0x3bb7), 0xcd }, { CCI_REG8(0x3bb8), 0xcd }, ++ { CCI_REG8(0x3bb9), 0xcd }, { CCI_REG8(0x3bba), 0xcd }, ++ { CCI_REG8(0x3bbb), 0xcd }, { CCI_REG8(0x3bbc), 0xcd }, ++ { CCI_REG8(0x3bbd), 0xcd }, { CCI_REG8(0x3bbe), 0xcd }, ++ { CCI_REG8(0x3bbf), 0xcd }, { CCI_REG8(0x3bc0), 0xcd }, ++ { CCI_REG8(0x3bc1), 0xcd }, { CCI_REG8(0x3bc2), 0xcd }, ++ { CCI_REG8(0x3bc3), 0xcd }, { CCI_REG8(0x3bc4), 0xcd }, ++ { CCI_REG8(0x3bc5), 0xcd }, { CCI_REG8(0x3bc6), 0xcd }, ++ { CCI_REG8(0x3bc7), 0xcd }, { CCI_REG8(0x3bc8), 0xcd }, ++ { CCI_REG8(0x3bc9), 0xcd }, { CCI_REG8(0x3bca), 0xcd }, ++ { CCI_REG8(0x3bcb), 0xcd }, { CCI_REG8(0x3bcc), 0xcd }, ++ { CCI_REG8(0x3bcd), 0xcd }, { CCI_REG8(0x3bce), 0xcd }, ++ { CCI_REG8(0x3bcf), 0xcd }, { CCI_REG8(0x3bd0), 0xcd }, ++ { CCI_REG8(0x3bd1), 0xcd }, { CCI_REG8(0x3bd2), 0xcd }, ++ { CCI_REG8(0x3bd3), 0xcd }, { CCI_REG8(0x3bd4), 0xcd }, ++ { CCI_REG8(0x3bd5), 0xcd }, { CCI_REG8(0x3bd6), 0xcd }, ++ { CCI_REG8(0x3bd7), 0xcd }, { CCI_REG8(0x3bd8), 0xcd }, ++ { CCI_REG8(0x3bd9), 0xcd }, { CCI_REG8(0x3bda), 0xcd }, ++ { CCI_REG8(0x3bdb), 0xcd }, { CCI_REG8(0x3bdc), 0xcd }, ++ { CCI_REG8(0x3bdd), 0xcd }, { CCI_REG8(0x3bde), 0xcd }, ++ { CCI_REG8(0x3bdf), 0xcd }, { CCI_REG8(0x3be0), 0xcd }, ++ { CCI_REG8(0x3be1), 0xcd }, { CCI_REG8(0x3be2), 0xcd }, ++ { CCI_REG8(0x3be3), 0xcd }, { CCI_REG8(0x3be4), 0xcd }, ++ { CCI_REG8(0x3be5), 0xcd }, { CCI_REG8(0x3be6), 0xcd }, ++ { CCI_REG8(0x3be7), 0xcd }, { CCI_REG8(0x3be8), 0xcd }, ++ { CCI_REG8(0x3be9), 0xcd }, { CCI_REG8(0x3bea), 0xcd }, ++ { CCI_REG8(0x3beb), 0xcd }, { CCI_REG8(0x3bec), 0xcd }, ++ { CCI_REG8(0x3bed), 0xcd }, { CCI_REG8(0x3bee), 0xcd }, ++ { CCI_REG8(0x3bef), 0xcd }, { CCI_REG8(0x3bf0), 0xcd }, ++ { CCI_REG8(0x3bf1), 0xcd }, { CCI_REG8(0x3bf2), 0xcd }, ++ { CCI_REG8(0x3bf3), 0xcd }, { CCI_REG8(0x3bf4), 0xcd }, ++ { CCI_REG8(0x3bf5), 0xcd }, { CCI_REG8(0x3bf6), 0xcd }, ++ { CCI_REG8(0x3bf7), 0xcd }, { CCI_REG8(0x3bf8), 0xcd }, ++ { CCI_REG8(0x3bf9), 0xcd }, { CCI_REG8(0x3bfa), 0xcd }, ++ { CCI_REG8(0x3bfb), 0xcd }, { CCI_REG8(0x3bfc), 0xcd }, ++ { CCI_REG8(0x3bfd), 0xcd }, { CCI_REG8(0x3bfe), 0xcd }, ++ { CCI_REG8(0x3bff), 0xcd }, { CCI_REG8(0x3c00), 0xcd }, ++ { CCI_REG8(0x3c01), 0xcd }, { CCI_REG8(0x3c02), 0xcd }, ++ { CCI_REG8(0x3c03), 0xcd }, { CCI_REG8(0x3c04), 0xcd }, ++ { CCI_REG8(0x3c05), 0xcd }, { CCI_REG8(0x3c06), 0xcd }, ++ { CCI_REG8(0x3c07), 0xcd }, { CCI_REG8(0x3c08), 0xcd }, ++ { CCI_REG8(0x3c09), 0xcd }, { CCI_REG8(0x3c0a), 0xcd }, ++ { CCI_REG8(0x3c0b), 0xcd }, { CCI_REG8(0x3c0c), 0xcd }, ++ { CCI_REG8(0x3c0d), 0xcd }, { CCI_REG8(0x3c0e), 0xcd }, ++ { CCI_REG8(0x3c0f), 0xcd }, { CCI_REG8(0x3c10), 0xcd }, ++ { CCI_REG8(0x3c11), 0xcd }, { CCI_REG8(0x3c12), 0xcd }, ++ { CCI_REG8(0x3c13), 0xcd }, { CCI_REG8(0x3c14), 0xcd }, ++ { CCI_REG8(0x3c15), 0xcd }, { CCI_REG8(0x3c16), 0xcd }, ++ { CCI_REG8(0x3c17), 0xcd }, { CCI_REG8(0x3c18), 0xcd }, ++ { CCI_REG8(0x3c19), 0xcd }, { CCI_REG8(0x3c1a), 0xcd }, ++ { CCI_REG8(0x3c1b), 0xcd }, { CCI_REG8(0x3c1c), 0xcd }, ++ { CCI_REG8(0x3c1d), 0xcd }, { CCI_REG8(0x3c1e), 0xcd }, ++ { CCI_REG8(0x3c1f), 0xcd }, { CCI_REG8(0x3c20), 0xcd }, ++ { CCI_REG8(0x3c21), 0xcd }, { CCI_REG8(0x3c22), 0xcd }, ++ { CCI_REG8(0x3c23), 0xcd }, { CCI_REG8(0x3c24), 0xcd }, ++ { CCI_REG8(0x3c25), 0xcd }, { CCI_REG8(0x3c26), 0xcd }, ++ { CCI_REG8(0x3c27), 0xcd }, { CCI_REG8(0x3c28), 0xcd }, ++ { CCI_REG8(0x3c29), 0xcd }, { CCI_REG8(0x3c2a), 0xcd }, ++ { CCI_REG8(0x3c2b), 0xcd }, { CCI_REG8(0x3c2c), 0xcd }, ++ { CCI_REG8(0x3c2d), 0xcd }, { CCI_REG8(0x3c2e), 0xcd }, ++ { CCI_REG8(0x3c2f), 0xcd }, { CCI_REG8(0x3c30), 0xcd }, ++ { CCI_REG8(0x3c31), 0xcd }, { CCI_REG8(0x3c32), 0xcd }, ++ { CCI_REG8(0x3c33), 0xcd }, { CCI_REG8(0x3c34), 0xcd }, ++ { CCI_REG8(0x3c35), 0xcd }, { CCI_REG8(0x3c36), 0xcd }, ++ { CCI_REG8(0x3c37), 0xcd }, { CCI_REG8(0x3c38), 0xcd }, ++ { CCI_REG8(0x3c39), 0xcd }, { CCI_REG8(0x3c3a), 0xcd }, ++ { CCI_REG8(0x3c3b), 0xcd }, { CCI_REG8(0x3c3c), 0xcd }, ++ { CCI_REG8(0x3c3d), 0xcd }, { CCI_REG8(0x3c3e), 0xcd }, ++ { CCI_REG8(0x3c3f), 0xcd }, { CCI_REG8(0x3c40), 0xcd }, ++ { CCI_REG8(0x3c41), 0xcd }, { CCI_REG8(0x3c42), 0xcd }, ++ { CCI_REG8(0x3c43), 0xcd }, { CCI_REG8(0x3c44), 0xcd }, ++ { CCI_REG8(0x3c45), 0xcd }, { CCI_REG8(0x3c46), 0xcd }, ++ { CCI_REG8(0x3c47), 0xcd }, { CCI_REG8(0x3c48), 0xcd }, ++ { CCI_REG8(0x3c49), 0xcd }, { CCI_REG8(0x3c4a), 0xcd }, ++ { CCI_REG8(0x3c4b), 0xcd }, { CCI_REG8(0x3c4c), 0xcd }, ++ { CCI_REG8(0x3c4d), 0xcd }, { CCI_REG8(0x3c4e), 0xcd }, ++ { CCI_REG8(0x3c4f), 0xcd }, { CCI_REG8(0x3c50), 0xcd }, ++ { CCI_REG8(0x3c51), 0xcd }, { CCI_REG8(0x3c52), 0xcd }, ++ { CCI_REG8(0x3c53), 0xcd }, { CCI_REG8(0x3c54), 0xcd }, ++ { CCI_REG8(0x3c55), 0xcd }, { CCI_REG8(0x3c56), 0xcd }, ++ { CCI_REG8(0x3c57), 0xcd }, { CCI_REG8(0x3c58), 0xcd }, ++ { CCI_REG8(0x3c59), 0xcd }, { CCI_REG8(0x3c5a), 0xcd }, ++ { CCI_REG8(0x3c5b), 0xcd }, { CCI_REG8(0x3c5c), 0xcd }, ++ { CCI_REG8(0x3c5d), 0xcd }, { CCI_REG8(0x3c5e), 0xcd }, ++ { CCI_REG8(0x3c5f), 0xcd }, { CCI_REG8(0x3c60), 0xcd }, ++ { CCI_REG8(0x3c61), 0xcd }, { CCI_REG8(0x3c62), 0xcd }, ++ { CCI_REG8(0x3c63), 0xcd }, { CCI_REG8(0x3c64), 0xcd }, ++ { CCI_REG8(0x3c65), 0xcd }, { CCI_REG8(0x3c66), 0xcd }, ++ { CCI_REG8(0x3c67), 0xcd }, { CCI_REG8(0x3c68), 0xcd }, ++ { CCI_REG8(0x3c69), 0xcd }, { CCI_REG8(0x3c6a), 0xcd }, ++ { CCI_REG8(0x3c6b), 0xcd }, { CCI_REG8(0x3c6c), 0xcd }, ++ { CCI_REG8(0x3c6d), 0xcd }, { CCI_REG8(0x3c6e), 0xcd }, ++ { CCI_REG8(0x3c6f), 0xcd }, { CCI_REG8(0x3c70), 0xcd }, ++ { CCI_REG8(0x3c71), 0xcd }, { CCI_REG8(0x3c72), 0xcd }, ++ { CCI_REG8(0x3c73), 0xcd }, { CCI_REG8(0x3c74), 0xcd }, ++ { CCI_REG8(0x3c75), 0xcd }, { CCI_REG8(0x3c76), 0xcd }, ++ { CCI_REG8(0x3c77), 0xcd }, { CCI_REG8(0x3c78), 0xcd }, ++ { CCI_REG8(0x3c79), 0xcd }, { CCI_REG8(0x3c7a), 0xcd }, ++ { CCI_REG8(0x3c7b), 0xcd }, { CCI_REG8(0x3c7c), 0xcd }, ++ { CCI_REG8(0x3c7d), 0xcd }, { CCI_REG8(0x3c7e), 0xcd }, ++ { CCI_REG8(0x3c7f), 0xcd }, { CCI_REG8(0x3c80), 0xcd }, ++ { CCI_REG8(0x3c81), 0xcd }, { CCI_REG8(0x3c82), 0xcd }, ++ { CCI_REG8(0x3c83), 0xcd }, { CCI_REG8(0x3c84), 0xcd }, ++ { CCI_REG8(0x3c85), 0xcd }, { CCI_REG8(0x3c86), 0xcd }, ++ { CCI_REG8(0x3c87), 0xcd }, { CCI_REG8(0x3c88), 0xcd }, ++ { CCI_REG8(0x3c89), 0xcd }, { CCI_REG8(0x3c8a), 0xcd }, ++ { CCI_REG8(0x3c8b), 0xcd }, { CCI_REG8(0x3c8c), 0xcd }, ++ { CCI_REG8(0x3c8d), 0xcd }, { CCI_REG8(0x3c8e), 0xcd }, ++ { CCI_REG8(0x3c8f), 0xcd }, { CCI_REG8(0x3c90), 0xcd }, ++ { CCI_REG8(0x3c91), 0xcd }, { CCI_REG8(0x3c92), 0xcd }, ++ { CCI_REG8(0x3c93), 0xcd }, { CCI_REG8(0x3c94), 0xcd }, ++ { CCI_REG8(0x3c95), 0xcd }, { CCI_REG8(0x3c96), 0xcd }, ++ { CCI_REG8(0x3c97), 0xcd }, { CCI_REG8(0x3c98), 0xcd }, ++ { CCI_REG8(0x3c99), 0xcd }, { CCI_REG8(0x3c9a), 0xcd }, ++ { CCI_REG8(0x3c9b), 0xcd }, { CCI_REG8(0x3c9c), 0xcd }, ++ { CCI_REG8(0x3c9d), 0xcd }, { CCI_REG8(0x3c9e), 0xcd }, ++ { CCI_REG8(0x3c9f), 0xcd }, { CCI_REG8(0x3ca0), 0xcd }, ++ { CCI_REG8(0x3ca1), 0xcd }, { CCI_REG8(0x3ca2), 0xcd }, ++ { CCI_REG8(0x3ca3), 0xcd }, { CCI_REG8(0x3ca4), 0xcd }, ++ { CCI_REG8(0x3ca5), 0xcd }, { CCI_REG8(0x3ca6), 0xcd }, ++ { CCI_REG8(0x3ca7), 0xcd }, { CCI_REG8(0x3ca8), 0xcd }, ++ { CCI_REG8(0x3ca9), 0xcd }, { CCI_REG8(0x3caa), 0xcd }, ++ { CCI_REG8(0x3cab), 0xcd }, { CCI_REG8(0x3cac), 0xcd }, ++ { CCI_REG8(0x3cad), 0xcd }, { CCI_REG8(0x3cae), 0xcd }, ++ { CCI_REG8(0x3caf), 0xcd }, { CCI_REG8(0x3cb0), 0xcd }, ++ { CCI_REG8(0x3cb1), 0x40 }, { CCI_REG8(0x3cb2), 0x40 }, ++ { CCI_REG8(0x3cb3), 0x40 }, { CCI_REG8(0x3cb4), 0x40 }, ++ { CCI_REG8(0x3cb5), 0x40 }, { CCI_REG8(0x3cb6), 0x40 }, ++ { CCI_REG8(0x3cb7), 0x40 }, { CCI_REG8(0x3cb8), 0x40 }, ++ { CCI_REG8(0x3cb9), 0x40 }, { CCI_REG8(0x3cba), 0x40 }, ++ { CCI_REG8(0x3cbb), 0x40 }, { CCI_REG8(0x3cbc), 0x40 }, ++ { CCI_REG8(0x3cbd), 0x40 }, { CCI_REG8(0x3cbe), 0x40 }, ++ { CCI_REG8(0x3cbf), 0x40 }, { CCI_REG8(0x3cc0), 0x40 }, ++ { CCI_REG8(0x3cc1), 0x40 }, { CCI_REG8(0x3cc2), 0x40 }, ++ { CCI_REG8(0x3cc3), 0x40 }, { CCI_REG8(0x3cc4), 0x40 }, ++ { CCI_REG8(0x3cc5), 0x40 }, { CCI_REG8(0x3cc6), 0x40 }, ++ { CCI_REG8(0x3cc7), 0x40 }, { CCI_REG8(0x3cc8), 0x40 }, ++ { CCI_REG8(0x3cc9), 0x40 }, { CCI_REG8(0x3cca), 0x40 }, ++ { CCI_REG8(0x3ccb), 0x40 }, { CCI_REG8(0x3ccc), 0x40 }, ++ { CCI_REG8(0x3ccd), 0x40 }, { CCI_REG8(0x3cce), 0x40 }, ++ { CCI_REG8(0x3ccf), 0x40 }, { CCI_REG8(0x3cd0), 0x40 }, ++ { CCI_REG8(0x3cd1), 0x40 }, { CCI_REG8(0x3cd2), 0x40 }, ++ { CCI_REG8(0x3cd3), 0x40 }, { CCI_REG8(0x3cd4), 0x40 }, ++ { CCI_REG8(0x3cd5), 0x40 }, { CCI_REG8(0x3cd6), 0x40 }, ++ { CCI_REG8(0x3cd7), 0x40 }, { CCI_REG8(0x3cd8), 0x40 }, ++ { CCI_REG8(0x3cd9), 0x40 }, { CCI_REG8(0x3cda), 0x40 }, ++ { CCI_REG8(0x3cdb), 0x40 }, { CCI_REG8(0x3cdc), 0x40 }, ++ { CCI_REG8(0x3cdd), 0x40 }, { CCI_REG8(0x3cde), 0x40 }, ++ { CCI_REG8(0x3cdf), 0x40 }, { CCI_REG8(0x3ce0), 0x40 }, ++ { CCI_REG8(0x3ce1), 0x40 }, { CCI_REG8(0x3ce2), 0x40 }, ++ { CCI_REG8(0x3ce3), 0x40 }, { CCI_REG8(0x3ce4), 0x40 }, ++ { CCI_REG8(0x3ce5), 0x40 }, { CCI_REG8(0x3ce6), 0x40 }, ++ { CCI_REG8(0x3ce7), 0x40 }, { CCI_REG8(0x3ce8), 0x40 }, ++ { CCI_REG8(0x3ce9), 0x40 }, { CCI_REG8(0x3cea), 0x40 }, ++ { CCI_REG8(0x3ceb), 0x40 }, { CCI_REG8(0x3cec), 0x40 }, ++ { CCI_REG8(0x3ced), 0x40 }, { CCI_REG8(0x3cee), 0x40 }, ++ { CCI_REG8(0x3cef), 0x40 }, { CCI_REG8(0x3cf0), 0x40 }, ++ { CCI_REG8(0x3cf1), 0x40 }, { CCI_REG8(0x3cf2), 0x40 }, ++ { CCI_REG8(0x3cf3), 0x40 }, { CCI_REG8(0x3cf4), 0x40 }, ++ { CCI_REG8(0x3cf5), 0x40 }, { CCI_REG8(0x3cf6), 0x40 }, ++ { CCI_REG8(0x3cf7), 0x40 }, { CCI_REG8(0x3cf8), 0x40 }, ++ { CCI_REG8(0x3cf9), 0x40 }, { CCI_REG8(0x3cfa), 0x40 }, ++ { CCI_REG8(0x3cfb), 0x40 }, { CCI_REG8(0x3cfc), 0x40 }, ++ { CCI_REG8(0x3cfd), 0x40 }, { CCI_REG8(0x3cfe), 0x40 }, ++ { CCI_REG8(0x3cff), 0x40 }, { CCI_REG8(0x3d00), 0x40 }, ++ { CCI_REG8(0x3d01), 0x40 }, { CCI_REG8(0x3d02), 0x40 }, ++ { CCI_REG8(0x3d03), 0x40 }, { CCI_REG8(0x3d04), 0x40 }, ++ { CCI_REG8(0x3d05), 0x40 }, { CCI_REG8(0x3d06), 0x40 }, ++ { CCI_REG8(0x3d07), 0x40 }, { CCI_REG8(0x3d08), 0x40 }, ++ { CCI_REG8(0x3d09), 0x40 }, { CCI_REG8(0x3d0a), 0x40 }, ++ { CCI_REG8(0x3d0b), 0xcd }, { CCI_REG8(0x3d0c), 0xcd }, ++ { CCI_REG8(0x3d0d), 0xcd }, { CCI_REG8(0x3d0e), 0xcd }, ++ { CCI_REG8(0x3d0f), 0xcd }, { CCI_REG8(0x3d10), 0xcd }, ++ { CCI_REG8(0x3d11), 0xcd }, { CCI_REG8(0x3d12), 0xcd }, ++ { CCI_REG8(0x3d13), 0xcd }, { CCI_REG8(0x3d14), 0xcd }, ++ { CCI_REG8(0x3d15), 0xcd }, { CCI_REG8(0x3d16), 0xcd }, ++ { CCI_REG8(0x3d17), 0xcd }, { CCI_REG8(0x3d18), 0xcd }, ++ { CCI_REG8(0x3d19), 0xcd }, { CCI_REG8(0x3d1a), 0xcd }, ++ { CCI_REG8(0x3d1b), 0xcd }, { CCI_REG8(0x3d1c), 0xcd }, ++ { CCI_REG8(0x3d1d), 0xcd }, { CCI_REG8(0x3d1e), 0xcd }, ++ { CCI_REG8(0x3d1f), 0xcd }, { CCI_REG8(0x3d20), 0xcd }, ++ { CCI_REG8(0x3d21), 0xcd }, { CCI_REG8(0x3d22), 0xcd }, ++ { CCI_REG8(0x3d23), 0xcd }, { CCI_REG8(0x3d24), 0xcd }, ++ { CCI_REG8(0x3d25), 0xcd }, { CCI_REG8(0x3d26), 0xcd }, ++ { CCI_REG8(0x3d27), 0xcd }, { CCI_REG8(0x3d28), 0xcd }, ++ { CCI_REG8(0x3d29), 0xcd }, { CCI_REG8(0x3d2a), 0xcd }, ++ { CCI_REG8(0x3d2b), 0xcd }, { CCI_REG8(0x3d2c), 0xcd }, ++ { CCI_REG8(0x3d2d), 0xcd }, { CCI_REG8(0x3d2e), 0xcd }, ++ { CCI_REG8(0x3d2f), 0xcd }, { CCI_REG8(0x3d30), 0xcd }, ++ { CCI_REG8(0x3d31), 0xcd }, { CCI_REG8(0x3d32), 0xcd }, ++ { CCI_REG8(0x3d33), 0xcd }, { CCI_REG8(0x3d34), 0xcd }, ++ { CCI_REG8(0x3d35), 0xcd }, { CCI_REG8(0x3d36), 0xcd }, ++ { CCI_REG8(0x3d37), 0xcd }, { CCI_REG8(0x3d38), 0xcd }, ++ { CCI_REG8(0x3d39), 0xcd }, { CCI_REG8(0x3d3a), 0xcd }, ++ { CCI_REG8(0x3d3b), 0xcd }, { CCI_REG8(0x3d3c), 0xcd }, ++ { CCI_REG8(0x3d3d), 0xcd }, { CCI_REG8(0x3d3e), 0xcd }, ++ { CCI_REG8(0x3d3f), 0xcd }, { CCI_REG8(0x3d40), 0xcd }, ++ { CCI_REG8(0x3d41), 0xcd }, { CCI_REG8(0x3d42), 0xcd }, ++ { CCI_REG8(0x3d43), 0xcd }, { CCI_REG8(0x3d44), 0xcd }, ++ { CCI_REG8(0x3d45), 0xcd }, { CCI_REG8(0x3d46), 0xcd }, ++ { CCI_REG8(0x3d47), 0xcd }, { CCI_REG8(0x3d48), 0xcd }, ++ { CCI_REG8(0x3d49), 0xcd }, { CCI_REG8(0x3d4a), 0xcd }, ++ { CCI_REG8(0x3d4b), 0xcd }, { CCI_REG8(0x3d4c), 0xcd }, ++ { CCI_REG8(0x3d4d), 0xcd }, { CCI_REG8(0x3d4e), 0xcd }, ++ { CCI_REG8(0x3d4f), 0xcd }, { CCI_REG8(0x3d50), 0xcd }, ++ { CCI_REG8(0x3d51), 0xcd }, { CCI_REG8(0x3d52), 0xcd }, ++ { CCI_REG8(0x3d53), 0xcd }, { CCI_REG8(0x3d54), 0xcd }, ++ { CCI_REG8(0x3d55), 0xcd }, { CCI_REG8(0x3d56), 0xcd }, ++ { CCI_REG8(0x3d57), 0xcd }, { CCI_REG8(0x3d58), 0xcd }, ++ { CCI_REG8(0x3d59), 0xcd }, { CCI_REG8(0x3d5a), 0xcd }, ++ { CCI_REG8(0x3d5b), 0xcd }, { CCI_REG8(0x3d5c), 0xcd }, ++ { CCI_REG8(0x3d5d), 0xcd }, { CCI_REG8(0x3d5e), 0xcd }, ++ { CCI_REG8(0x3d5f), 0xcd }, { CCI_REG8(0x3d60), 0xcd }, ++ { CCI_REG8(0x3d61), 0xcd }, { CCI_REG8(0x3d62), 0xcd }, ++ { CCI_REG8(0x3d63), 0xcd }, { CCI_REG8(0x3d64), 0xcd }, ++ { CCI_REG8(0x3d65), 0x40 }, { CCI_REG8(0x3d66), 0x40 }, ++ { CCI_REG8(0x3d67), 0x40 }, { CCI_REG8(0x3d68), 0x40 }, ++ { CCI_REG8(0x3d69), 0x40 }, { CCI_REG8(0x3d6a), 0x40 }, ++ { CCI_REG8(0x3d6b), 0x40 }, { CCI_REG8(0x3d6c), 0x40 }, ++ { CCI_REG8(0x3d6d), 0x40 }, { CCI_REG8(0x3d6e), 0x40 }, ++ { CCI_REG8(0x3d6f), 0x40 }, { CCI_REG8(0x3d70), 0x40 }, ++ { CCI_REG8(0x3d71), 0x40 }, { CCI_REG8(0x3d72), 0x40 }, ++ { CCI_REG8(0x3d73), 0x40 }, { CCI_REG8(0x3d74), 0x40 }, ++ { CCI_REG8(0x3d75), 0x40 }, { CCI_REG8(0x3d76), 0x40 }, ++ { CCI_REG8(0x3d77), 0x40 }, { CCI_REG8(0x3d78), 0x40 }, ++ { CCI_REG8(0x3d79), 0x40 }, { CCI_REG8(0x3d7a), 0x40 }, ++ { CCI_REG8(0x3d7b), 0x40 }, { CCI_REG8(0x3d7c), 0x40 }, ++ { CCI_REG8(0x3d7d), 0x40 }, { CCI_REG8(0x3d7e), 0x40 }, ++ { CCI_REG8(0x3d7f), 0x40 }, { CCI_REG8(0x3d80), 0x40 }, ++ { CCI_REG8(0x3d81), 0x40 }, { CCI_REG8(0x3d82), 0x40 }, ++ { CCI_REG8(0x3d83), 0x40 }, { CCI_REG8(0x3d84), 0x40 }, ++ { CCI_REG8(0x3d85), 0x40 }, { CCI_REG8(0x3d86), 0x40 }, ++ { CCI_REG8(0x3d87), 0x40 }, { CCI_REG8(0x3d88), 0x40 }, ++ { CCI_REG8(0x3d89), 0x40 }, { CCI_REG8(0x3d8a), 0x40 }, ++ { CCI_REG8(0x3d8b), 0x40 }, { CCI_REG8(0x3d8c), 0x40 }, ++ { CCI_REG8(0x3d8d), 0x40 }, { CCI_REG8(0x3d8e), 0x40 }, ++ { CCI_REG8(0x3d8f), 0x40 }, { CCI_REG8(0x3d90), 0x40 }, ++ { CCI_REG8(0x3d91), 0x40 }, { CCI_REG8(0x3d92), 0x40 }, ++ { CCI_REG8(0x3d93), 0x40 }, { CCI_REG8(0x3d94), 0x40 }, ++ { CCI_REG8(0x3d95), 0x40 }, { CCI_REG8(0x3d96), 0x40 }, ++ { CCI_REG8(0x3d97), 0x40 }, { CCI_REG8(0x3d98), 0x40 }, ++ { CCI_REG8(0x3d99), 0x40 }, { CCI_REG8(0x3d9a), 0x40 }, ++ { CCI_REG8(0x3d9b), 0x40 }, { CCI_REG8(0x3d9c), 0x40 }, ++ { CCI_REG8(0x3d9d), 0x40 }, { CCI_REG8(0x3d9e), 0x40 }, ++ { CCI_REG8(0x3d9f), 0x40 }, { CCI_REG8(0x3da0), 0x40 }, ++ { CCI_REG8(0x3da1), 0x40 }, { CCI_REG8(0x3da2), 0x40 }, ++ { CCI_REG8(0x3da3), 0x40 }, { CCI_REG8(0x3da4), 0x40 }, ++ { CCI_REG8(0x3da5), 0x40 }, { CCI_REG8(0x3da6), 0x40 }, ++ { CCI_REG8(0x3da7), 0x40 }, { CCI_REG8(0x3da8), 0x40 }, ++ { CCI_REG8(0x3da9), 0x40 }, { CCI_REG8(0x3daa), 0x40 }, ++ { CCI_REG8(0x3dab), 0x40 }, { CCI_REG8(0x3dac), 0x40 }, ++ { CCI_REG8(0x3dad), 0x40 }, { CCI_REG8(0x3dae), 0x40 }, ++ { CCI_REG8(0x3daf), 0x40 }, { CCI_REG8(0x3db0), 0x40 }, ++ { CCI_REG8(0x3db1), 0x40 }, { CCI_REG8(0x3db2), 0x40 }, ++ { CCI_REG8(0x3db3), 0x40 }, { CCI_REG8(0x3db4), 0x40 }, ++ { CCI_REG8(0x3db5), 0x40 }, { CCI_REG8(0x3db6), 0x40 }, ++ { CCI_REG8(0x3db7), 0x40 }, { CCI_REG8(0x3db8), 0x40 }, ++ { CCI_REG8(0x3db9), 0x40 }, { CCI_REG8(0x3dba), 0x40 }, ++ { CCI_REG8(0x3dbb), 0x40 }, { CCI_REG8(0x3dbc), 0x40 }, ++ { CCI_REG8(0x3dbd), 0x40 }, { CCI_REG8(0x3dbe), 0x40 }, ++ { CCI_REG8(0x3dbf), 0xcd }, { CCI_REG8(0x3dc0), 0xcd }, ++ { CCI_REG8(0x3dc1), 0xcd }, { CCI_REG8(0x3dc2), 0xcd }, ++ { CCI_REG8(0x3dc3), 0xcd }, { CCI_REG8(0x3dc4), 0xcd }, ++ { CCI_REG8(0x3dc5), 0xcd }, { CCI_REG8(0x3dc6), 0xcd }, ++ { CCI_REG8(0x3dc7), 0xcd }, { CCI_REG8(0x3dc8), 0xcd }, ++ { CCI_REG8(0x3dc9), 0xcd }, { CCI_REG8(0x3dca), 0xcd }, ++ { CCI_REG8(0x3dcb), 0xcd }, { CCI_REG8(0x3dcc), 0xcd }, ++ { CCI_REG8(0x3dcd), 0xcd }, { CCI_REG8(0x3dce), 0xcd }, ++ { CCI_REG8(0x3dcf), 0xcd }, { CCI_REG8(0x3dd0), 0xcd }, ++ { CCI_REG8(0x3dd1), 0xcd }, { CCI_REG8(0x3dd2), 0xcd }, ++ { CCI_REG8(0x3dd3), 0xcd }, { CCI_REG8(0x3dd4), 0xcd }, ++ { CCI_REG8(0x3dd5), 0xcd }, { CCI_REG8(0x3dd6), 0xcd }, ++ { CCI_REG8(0x3dd7), 0xcd }, { CCI_REG8(0x3dd8), 0xcd }, ++ { CCI_REG8(0x3dd9), 0xcd }, { CCI_REG8(0x3dda), 0xcd }, ++ { CCI_REG8(0x3ddb), 0xcd }, { CCI_REG8(0x3ddc), 0xcd }, ++ { CCI_REG8(0x3ddd), 0xcd }, { CCI_REG8(0x3dde), 0xcd }, ++ { CCI_REG8(0x3ddf), 0xcd }, { CCI_REG8(0x3de0), 0xcd }, ++ { CCI_REG8(0x3de1), 0xcd }, { CCI_REG8(0x3de2), 0xcd }, ++ { CCI_REG8(0x3de3), 0xcd }, { CCI_REG8(0x3de4), 0xcd }, ++ { CCI_REG8(0x3de5), 0xcd }, { CCI_REG8(0x3de6), 0xcd }, ++ { CCI_REG8(0x3de7), 0xcd }, { CCI_REG8(0x3de8), 0xcd }, ++ { CCI_REG8(0x3de9), 0xcd }, { CCI_REG8(0x3dea), 0xcd }, ++ { CCI_REG8(0x3deb), 0xcd }, { CCI_REG8(0x3dec), 0xcd }, ++ { CCI_REG8(0x3ded), 0xcd }, { CCI_REG8(0x3dee), 0xcd }, ++ { CCI_REG8(0x3def), 0xcd }, { CCI_REG8(0x3df0), 0xcd }, ++ { CCI_REG8(0x3df1), 0xcd }, { CCI_REG8(0x3df2), 0xcd }, ++ { CCI_REG8(0x3df3), 0xcd }, { CCI_REG8(0x3df4), 0xcd }, ++ { CCI_REG8(0x3df5), 0xcd }, { CCI_REG8(0x3df6), 0xcd }, ++ { CCI_REG8(0x3df7), 0xcd }, { CCI_REG8(0x3df8), 0xcd }, ++ { CCI_REG8(0x3df9), 0xcd }, { CCI_REG8(0x3dfa), 0xcd }, ++ { CCI_REG8(0x3dfb), 0xcd }, { CCI_REG8(0x3dfc), 0xcd }, ++ { CCI_REG8(0x3dfd), 0xcd }, { CCI_REG8(0x3dfe), 0xcd }, ++ { CCI_REG8(0x3dff), 0xcd }, { CCI_REG8(0x3e00), 0xcd }, ++ { CCI_REG8(0x3e01), 0xcd }, { CCI_REG8(0x3e02), 0xcd }, ++ { CCI_REG8(0x3e03), 0xcd }, { CCI_REG8(0x3e04), 0xcd }, ++ { CCI_REG8(0x3e05), 0xcd }, { CCI_REG8(0x3e06), 0xcd }, ++ { CCI_REG8(0x3e07), 0xcd }, { CCI_REG8(0x3e08), 0xcd }, ++ { CCI_REG8(0x3e09), 0xcd }, { CCI_REG8(0x3e0a), 0xcd }, ++ { CCI_REG8(0x3e0b), 0xcd }, { CCI_REG8(0x3e0c), 0xcd }, ++ { CCI_REG8(0x3e0d), 0xcd }, { CCI_REG8(0x3e0e), 0xcd }, ++ { CCI_REG8(0x3e0f), 0xcd }, { CCI_REG8(0x3e10), 0xcd }, ++ { CCI_REG8(0x3e11), 0xcd }, { CCI_REG8(0x3e12), 0xcd }, ++ { CCI_REG8(0x3e13), 0xcd }, { CCI_REG8(0x3e14), 0xcd }, ++ { CCI_REG8(0x3e15), 0xcd }, { CCI_REG8(0x3e16), 0xcd }, ++ { CCI_REG8(0x3e17), 0xcd }, { CCI_REG8(0x3e18), 0xcd }, ++ { CCI_REG8(0x3e19), 0xcd }, { CCI_REG8(0x3e1a), 0xcd }, ++ { CCI_REG8(0x3e1b), 0xcd }, { CCI_REG8(0x3e1c), 0xcd }, ++ { CCI_REG8(0x3e1d), 0xcd }, { CCI_REG8(0x3e1e), 0xcd }, ++ { CCI_REG8(0x3e1f), 0xcd }, { CCI_REG8(0x3e20), 0xcd }, ++ { CCI_REG8(0x3e21), 0xcd }, { CCI_REG8(0x3e22), 0xcd }, ++ { CCI_REG8(0x3e23), 0xcd }, { CCI_REG8(0x3e24), 0xcd }, ++ { CCI_REG8(0x3e25), 0xcd }, { CCI_REG8(0x3e26), 0xcd }, ++ { CCI_REG8(0x3e27), 0xcd }, { CCI_REG8(0x3e28), 0xcd }, ++ { CCI_REG8(0x3e29), 0xcd }, { CCI_REG8(0x3e2a), 0xcd }, ++ { CCI_REG8(0x3e2b), 0xcd }, { CCI_REG8(0x3e2c), 0xcd }, ++ { CCI_REG8(0x3e2d), 0xcd }, { CCI_REG8(0x3e2e), 0xcd }, ++ { CCI_REG8(0x3e2f), 0xcd }, { CCI_REG8(0x3e30), 0xcd }, ++ { CCI_REG8(0x3e31), 0xcd }, { CCI_REG8(0x3e32), 0xcd }, ++ { CCI_REG8(0x3e33), 0xcd }, { CCI_REG8(0x3e34), 0xcd }, ++ { CCI_REG8(0x3e35), 0xcd }, { CCI_REG8(0x3e36), 0xcd }, ++ { CCI_REG8(0x3e37), 0xcd }, { CCI_REG8(0x3e38), 0xcd }, ++ { CCI_REG8(0x3e39), 0xcd }, { CCI_REG8(0x3e3a), 0xcd }, ++ { CCI_REG8(0x3e3b), 0xcd }, { CCI_REG8(0x3e3c), 0xcd }, ++ { CCI_REG8(0x3e3d), 0xcd }, { CCI_REG8(0x3e3e), 0xcd }, ++ { CCI_REG8(0x3e3f), 0xcd }, { CCI_REG8(0x3e40), 0xcd }, ++ { CCI_REG8(0x3e41), 0xcd }, { CCI_REG8(0x3e42), 0xcd }, ++ { CCI_REG8(0x3e43), 0xcd }, { CCI_REG8(0x3e44), 0xcd }, ++ { CCI_REG8(0x3e45), 0xcd }, { CCI_REG8(0x3e46), 0xcd }, ++ { CCI_REG8(0x3e47), 0xcd }, { CCI_REG8(0x3e48), 0xcd }, ++ { CCI_REG8(0x3e49), 0xcd }, { CCI_REG8(0x3e4a), 0xcd }, ++ { CCI_REG8(0x3e4b), 0xcd }, { CCI_REG8(0x3e4c), 0xcd }, ++ { CCI_REG8(0x3e4d), 0xcd }, { CCI_REG8(0x3e4e), 0xcd }, ++ { CCI_REG8(0x3e4f), 0xcd }, { CCI_REG8(0x3e50), 0xcd }, ++ { CCI_REG8(0x3e51), 0xcd }, { CCI_REG8(0x3e52), 0xcd }, ++ { CCI_REG8(0x3e53), 0xcd }, { CCI_REG8(0x3e54), 0xcd }, ++ { CCI_REG8(0x3e55), 0xcd }, { CCI_REG8(0x3e56), 0xcd }, ++ { CCI_REG8(0x3e57), 0xcd }, { CCI_REG8(0x3e58), 0xcd }, ++ { CCI_REG8(0x3e59), 0xcd }, { CCI_REG8(0x3e5a), 0xcd }, ++ { CCI_REG8(0x3e5b), 0xcd }, { CCI_REG8(0x3e5c), 0xcd }, ++ { CCI_REG8(0x3e5d), 0xcd }, { CCI_REG8(0x3e5e), 0xcd }, ++ { CCI_REG8(0x3e5f), 0xcd }, { CCI_REG8(0x3e60), 0xcd }, ++ { CCI_REG8(0x3e61), 0xcd }, { CCI_REG8(0x3e62), 0xcd }, ++ { CCI_REG8(0x3e63), 0xcd }, { CCI_REG8(0x3e64), 0xcd }, ++ { CCI_REG8(0x3e65), 0xcd }, { CCI_REG8(0x3e66), 0xcd }, ++ { CCI_REG8(0x3e67), 0xcd }, { CCI_REG8(0x3e68), 0xcd }, ++ { CCI_REG8(0x3e69), 0xcd }, { CCI_REG8(0x3e6a), 0xcd }, ++ { CCI_REG8(0x3e6b), 0xcd }, { CCI_REG8(0x3e6c), 0xcd }, ++ { CCI_REG8(0x3e6d), 0xcd }, { CCI_REG8(0x3e6e), 0xcd }, ++ { CCI_REG8(0x3e6f), 0xcd }, { CCI_REG8(0x3e70), 0xcd }, ++ { CCI_REG8(0x3e71), 0xcd }, { CCI_REG8(0x3e72), 0xcd }, ++ { CCI_REG8(0x3e73), 0xcd }, { CCI_REG8(0x3e74), 0xcd }, ++ { CCI_REG8(0x3e75), 0xcd }, { CCI_REG8(0x3e76), 0xcd }, ++ { CCI_REG8(0x3e77), 0xcd }, { CCI_REG8(0x3e78), 0xcd }, ++ { CCI_REG8(0x3e79), 0xcd }, { CCI_REG8(0x3e7a), 0xcd }, ++ { CCI_REG8(0x3e7b), 0xcd }, { CCI_REG8(0x3e7c), 0xcd }, ++ { CCI_REG8(0x3e7d), 0xcd }, { CCI_REG8(0x3e7e), 0xcd }, ++ { CCI_REG8(0x3e7f), 0xcd }, { CCI_REG8(0x3e80), 0xcd }, ++ { CCI_REG8(0x3e81), 0xcd }, { CCI_REG8(0x3e82), 0xcd }, ++ { CCI_REG8(0x3e83), 0xcd }, { CCI_REG8(0x3e84), 0xcd }, ++ { CCI_REG8(0x3e85), 0xcd }, { CCI_REG8(0x3e86), 0xcd }, ++ { CCI_REG8(0x3e87), 0xcd }, { CCI_REG8(0x3e88), 0xcd }, ++ { CCI_REG8(0x3e89), 0xcd }, { CCI_REG8(0x3e8a), 0xcd }, ++ { CCI_REG8(0x3e8b), 0xcd }, { CCI_REG8(0x3e8c), 0xcd }, ++ { CCI_REG8(0x3e8d), 0xcd }, { CCI_REG8(0x3e8e), 0xcd }, ++ { CCI_REG8(0x3e8f), 0xcd }, { CCI_REG8(0x3e90), 0xcd }, ++ { CCI_REG8(0x3e91), 0xcd }, { CCI_REG8(0x3e92), 0xcd }, ++ { CCI_REG8(0x3e93), 0xcd }, { CCI_REG8(0x3e94), 0xcd }, ++ { CCI_REG8(0x3e95), 0xcd }, { CCI_REG8(0x3e96), 0xcd }, ++ { CCI_REG8(0x3e97), 0xcd }, { CCI_REG8(0x3e98), 0xcd }, ++ { CCI_REG8(0x3e99), 0xcd }, { CCI_REG8(0x3e9a), 0xcd }, ++ { CCI_REG8(0x3e9b), 0xcd }, { CCI_REG8(0x3e9c), 0xcd }, ++ { CCI_REG8(0x3e9d), 0xcd }, { CCI_REG8(0x3e9e), 0xcd }, ++ { CCI_REG8(0x3e9f), 0xcd }, { CCI_REG8(0xfff9), 0x06 }, ++ { CCI_REG8(0xc03f), 0x01 }, { CCI_REG8(0xc03e), 0x08 }, ++ { CCI_REG8(0xc02c), 0xff }, { CCI_REG8(0xc005), 0x06 }, ++ { CCI_REG8(0xc006), 0x30 }, { CCI_REG8(0xc007), 0xc0 }, ++ { CCI_REG8(0xc027), 0x01 }, { CCI_REG8(0x30c0), 0x05 }, ++ { CCI_REG8(0x30c1), 0x9f }, { CCI_REG8(0x30c2), 0x06 }, ++ { CCI_REG8(0x30c3), 0x5f }, { CCI_REG8(0x30c4), 0x80 }, ++ { CCI_REG8(0x30c5), 0x08 }, { CCI_REG8(0x30c6), 0x39 }, ++ { CCI_REG8(0x30c7), 0x00 }, { CCI_REG8(0xc046), 0x20 }, ++ { CCI_REG8(0xc043), 0x01 }, { CCI_REG8(0xc04b), 0x01 }, ++ { CCI_REG8(0x0102), 0x01 }, { CCI_REG8(0x0100), 0x00 }, ++ { CCI_REG8(0x0102), 0x00 }, { CCI_REG8(0x3015), 0xf0 }, ++ { CCI_REG8(0x3018), 0xf0 }, { CCI_REG8(0x301c), 0xf0 }, ++ { CCI_REG8(0x301d), 0xf6 }, { CCI_REG8(0x301e), 0xf1 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_9248x6944[] = { ++ { CCI_REG8(0x0305), 0x98 }, { CCI_REG8(0x0306), 0x04 }, ++ { CCI_REG8(0x0307), 0x01 }, { CCI_REG8(0x4837), 0x1a }, ++ { CCI_REG8(0x4888), 0x10 }, { CCI_REG8(0x4860), 0x00 }, ++ { CCI_REG8(0x4850), 0x43 }, { CCI_REG8(0x480C), 0x92 }, ++ { CCI_REG8(0x5001), 0x21 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_8000x6000[] = { ++ { CCI_REG8(0x0305), 0x98 }, { CCI_REG8(0x0306), 0x04 }, ++ { CCI_REG8(0x0307), 0x01 }, { CCI_REG8(0x4837), 0x1a }, ++ { CCI_REG8(0x4888), 0x10 }, { CCI_REG8(0x4860), 0x00 }, ++ { CCI_REG8(0x4850), 0x43 }, { CCI_REG8(0x480C), 0x92 }, ++ { CCI_REG8(0x5001), 0x21 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_4624_3472[] = { ++ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x3504), 0x08 }, ++ { CCI_REG8(0x360d), 0x82 }, { CCI_REG8(0x368a), 0x2e }, ++ { CCI_REG8(0x3712), 0x50 }, { CCI_REG8(0x3822), 0x00 }, ++ { CCI_REG8(0x3827), 0x40 }, { CCI_REG8(0x383d), 0x08 }, ++ { CCI_REG8(0x383f), 0x00 }, { CCI_REG8(0x384c), 0x02 }, ++ { CCI_REG8(0x384d), 0xba }, { CCI_REG8(0x3852), 0x00 }, ++ { CCI_REG8(0x3856), 0x08 }, { CCI_REG8(0x3857), 0x08 }, ++ { CCI_REG8(0x3858), 0x10 }, { CCI_REG8(0x3859), 0x10 }, ++ { CCI_REG8(0x4016), 0x0f }, { CCI_REG8(0x4018), 0x03 }, ++ { CCI_REG8(0x4504), 0x1e }, { CCI_REG8(0x4523), 0x41 }, ++ { CCI_REG8(0x45c0), 0x01 }, { CCI_REG8(0x4641), 0x12 }, ++ { CCI_REG8(0x4643), 0x0c }, { CCI_REG8(0x4915), 0x02 }, ++ { CCI_REG8(0x4916), 0x1d }, { CCI_REG8(0x4a15), 0x02 }, ++ { CCI_REG8(0x4a16), 0x1d }, { CCI_REG8(0x3703), 0x72 }, ++ { CCI_REG8(0x3709), 0xe6 }, { CCI_REG8(0x3a60), 0x68 }, ++ { CCI_REG8(0x3a6f), 0x68 }, { CCI_REG8(0x3a5e), 0xdc }, ++ { CCI_REG8(0x3a6d), 0xdc }, { CCI_REG8(0x3721), 0xc9 }, ++ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x527a), 0x00 }, ++ { CCI_REG8(0x527b), 0x65 }, { CCI_REG8(0x527c), 0x00 }, ++ { CCI_REG8(0x527d), 0x82 }, { CCI_REG8(0x5280), 0x24 }, ++ { CCI_REG8(0x5281), 0x40 }, { CCI_REG8(0x5282), 0x1b }, ++ { CCI_REG8(0x5283), 0x40 }, { CCI_REG8(0x5284), 0x24 }, ++ { CCI_REG8(0x5285), 0x40 }, { CCI_REG8(0x5286), 0x1b }, ++ { CCI_REG8(0x5287), 0x40 }, { CCI_REG8(0x5200), 0x24 }, ++ { CCI_REG8(0x5201), 0x40 }, { CCI_REG8(0x5202), 0x1b }, ++ { CCI_REG8(0x5203), 0x40 }, { CCI_REG8(0x481b), 0x35 }, ++ { CCI_REG8(0x4862), 0x25 }, { CCI_REG8(0x3400), 0x00 }, ++ { CCI_REG8(0x3421), 0x23 }, { CCI_REG8(0x3422), 0xfc }, ++ { CCI_REG8(0x3423), 0x07 }, { CCI_REG8(0x3424), 0x01 }, ++ { CCI_REG8(0x3425), 0x04 }, { CCI_REG8(0x3426), 0x50 }, ++ { CCI_REG8(0x3427), 0x55 }, { CCI_REG8(0x3428), 0x15 }, ++ { CCI_REG8(0x3429), 0x00 }, { CCI_REG8(0x3025), 0x03 }, ++ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x0305), 0x98 }, ++ { CCI_REG8(0x0306), 0x04 }, { CCI_REG8(0x0307), 0x01 }, ++ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 }, ++ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 }, ++ { CCI_REG8(0x480C), 0x92 }, { CCI_REG8(0x5001), 0x21 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_3840x2160[] = { ++ { CCI_REG8(0x034a), 0x05 }, { CCI_REG8(0x034b), 0x05 }, ++ { CCI_REG8(0x3504), 0x08 }, { CCI_REG8(0x360d), 0x82 }, ++ { CCI_REG8(0x368a), 0x2e }, { CCI_REG8(0x3712), 0x50 }, ++ { CCI_REG8(0x3822), 0x00 }, { CCI_REG8(0x3827), 0x40 }, ++ { CCI_REG8(0x383d), 0x08 }, { CCI_REG8(0x383f), 0x00 }, ++ { CCI_REG8(0x384c), 0x02 }, { CCI_REG8(0x384d), 0xba }, ++ { CCI_REG8(0x3852), 0x00 }, { CCI_REG8(0x3856), 0x08 }, ++ { CCI_REG8(0x3857), 0x08 }, { CCI_REG8(0x3858), 0x10 }, ++ { CCI_REG8(0x3859), 0x10 }, { CCI_REG8(0x4016), 0x0f }, ++ { CCI_REG8(0x4018), 0x03 }, { CCI_REG8(0x4504), 0x1e }, ++ { CCI_REG8(0x4523), 0x41 }, { CCI_REG8(0x45c0), 0x01 }, ++ { CCI_REG8(0x4641), 0x12 }, { CCI_REG8(0x4643), 0x0c }, ++ { CCI_REG8(0x4915), 0x02 }, { CCI_REG8(0x4916), 0x1d }, ++ { CCI_REG8(0x4a15), 0x02 }, { CCI_REG8(0x4a16), 0x1d }, ++ { CCI_REG8(0x3703), 0x72 }, { CCI_REG8(0x3709), 0xe6 }, ++ { CCI_REG8(0x3a60), 0x68 }, { CCI_REG8(0x3a6f), 0x68 }, ++ { CCI_REG8(0x3a5e), 0xdc }, { CCI_REG8(0x3a6d), 0xdc }, ++ { CCI_REG8(0x3721), 0xc9 }, { CCI_REG8(0x5250), 0x06 }, ++ { CCI_REG8(0x527a), 0x00 }, { CCI_REG8(0x527b), 0x65 }, ++ { CCI_REG8(0x527c), 0x00 }, { CCI_REG8(0x527d), 0x82 }, ++ { CCI_REG8(0x5280), 0x24 }, { CCI_REG8(0x5281), 0x40 }, ++ { CCI_REG8(0x5282), 0x1b }, { CCI_REG8(0x5283), 0x40 }, ++ { CCI_REG8(0x5284), 0x24 }, { CCI_REG8(0x5285), 0x40 }, ++ { CCI_REG8(0x5286), 0x1b }, { CCI_REG8(0x5287), 0x40 }, ++ { CCI_REG8(0x5200), 0x24 }, { CCI_REG8(0x5201), 0x40 }, ++ { CCI_REG8(0x5202), 0x1b }, { CCI_REG8(0x5203), 0x40 }, ++ { CCI_REG8(0x481b), 0x35 }, { CCI_REG8(0x4862), 0x25 }, ++ { CCI_REG8(0x3400), 0x00 }, { CCI_REG8(0x3421), 0x23 }, ++ { CCI_REG8(0x3422), 0xfc }, { CCI_REG8(0x3423), 0x07 }, ++ { CCI_REG8(0x3424), 0x01 }, { CCI_REG8(0x3425), 0x04 }, ++ { CCI_REG8(0x3426), 0x50 }, { CCI_REG8(0x3427), 0x55 }, ++ { CCI_REG8(0x3428), 0x15 }, { CCI_REG8(0x3429), 0x00 }, ++ { CCI_REG8(0x3025), 0x03 }, { CCI_REG8(0x5250), 0x06 }, ++ { CCI_REG8(0x0305), 0x98 }, { CCI_REG8(0x0306), 0x04 }, ++ { CCI_REG8(0x0345), 0x90 }, { CCI_REG8(0x0307), 0x01 }, ++ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 }, ++ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 }, ++ { CCI_REG8(0x480C), 0x92 }, { CCI_REG8(0x5001), 0x21 }, ++ { CCI_REG8(0x5000), 0x01 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_2312_1736[] = { ++ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x3504), 0x08 }, ++ { CCI_REG8(0x360d), 0x82 }, { CCI_REG8(0x368a), 0x2e }, ++ { CCI_REG8(0x3712), 0x00 }, { CCI_REG8(0x3822), 0x08 }, ++ { CCI_REG8(0x3827), 0x40 }, { CCI_REG8(0x383d), 0x04 }, ++ { CCI_REG8(0x383f), 0x00 }, { CCI_REG8(0x384c), 0x01 }, ++ { CCI_REG8(0x384d), 0x12 }, { CCI_REG8(0x3852), 0x00 }, ++ { CCI_REG8(0x3856), 0x04 }, { CCI_REG8(0x3857), 0x04 }, ++ { CCI_REG8(0x3858), 0x08 }, { CCI_REG8(0x3859), 0x08 }, ++ { CCI_REG8(0x4016), 0x07 }, { CCI_REG8(0x4018), 0x01 }, ++ { CCI_REG8(0x4504), 0x00 }, { CCI_REG8(0x4523), 0x00 }, ++ { CCI_REG8(0x45c0), 0x01 }, { CCI_REG8(0x4641), 0x24 }, ++ { CCI_REG8(0x4643), 0x0c }, { CCI_REG8(0x4837), 0x0b }, ++ { CCI_REG8(0x4915), 0x02 }, { CCI_REG8(0x4916), 0x1d }, ++ { CCI_REG8(0x4a15), 0x02 }, { CCI_REG8(0x4a16), 0x1d }, ++ { CCI_REG8(0x5000), 0x55 }, { CCI_REG8(0x5001), 0x00 }, ++ { CCI_REG8(0x5002), 0x35 }, { CCI_REG8(0x5004), 0xc0 }, ++ { CCI_REG8(0x5068), 0x02 }, { CCI_REG8(0x3703), 0x6a }, ++ { CCI_REG8(0x3709), 0xa3 }, { CCI_REG8(0x3a60), 0x60 }, ++ { CCI_REG8(0x3a6f), 0x60 }, { CCI_REG8(0x3a5e), 0x99 }, ++ { CCI_REG8(0x3a6d), 0x99 }, { CCI_REG8(0x3721), 0xc1 }, ++ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x527a), 0x00 }, ++ { CCI_REG8(0x527b), 0x65 }, { CCI_REG8(0x527c), 0x00 }, ++ { CCI_REG8(0x527d), 0x82 }, { CCI_REG8(0x5280), 0x24 }, ++ { CCI_REG8(0x5281), 0x40 }, { CCI_REG8(0x5282), 0x1b }, ++ { CCI_REG8(0x5283), 0x40 }, { CCI_REG8(0x5284), 0x24 }, ++ { CCI_REG8(0x5285), 0x40 }, { CCI_REG8(0x5286), 0x1b }, ++ { CCI_REG8(0x5287), 0x40 }, { CCI_REG8(0x5200), 0x24 }, ++ { CCI_REG8(0x5201), 0x40 }, { CCI_REG8(0x5202), 0x1b }, ++ { CCI_REG8(0x5203), 0x40 }, { CCI_REG8(0x3684), 0x05 }, ++ { CCI_REG8(0x481b), 0x20 }, { CCI_REG8(0x51b0), 0x38 }, ++ { CCI_REG8(0x51b3), 0x0e }, { CCI_REG8(0x51b5), 0x04 }, ++ { CCI_REG8(0x51b6), 0x00 }, { CCI_REG8(0x51b7), 0x00 }, ++ { CCI_REG8(0x51b9), 0x70 }, { CCI_REG8(0x51bb), 0x10 }, ++ { CCI_REG8(0x51bc), 0x00 }, { CCI_REG8(0x51bd), 0x00 }, ++ { CCI_REG8(0x51b0), 0x38 }, { CCI_REG8(0x54b0), 0x38 }, ++ { CCI_REG8(0x54b3), 0x0e }, { CCI_REG8(0x54b5), 0x04 }, ++ { CCI_REG8(0x54b6), 0x00 }, { CCI_REG8(0x54b7), 0x00 }, ++ { CCI_REG8(0x54b9), 0x70 }, { CCI_REG8(0x54bb), 0x10 }, ++ { CCI_REG8(0x54bc), 0x00 }, { CCI_REG8(0x54bd), 0x00 }, ++ { CCI_REG8(0x57b0), 0x38 }, { CCI_REG8(0x57b3), 0x0e }, ++ { CCI_REG8(0x57b5), 0x04 }, { CCI_REG8(0x57b6), 0x00 }, ++ { CCI_REG8(0x57b7), 0x00 }, { CCI_REG8(0x57b9), 0x70 }, ++ { CCI_REG8(0x57bb), 0x10 }, { CCI_REG8(0x57bc), 0x00 }, ++ { CCI_REG8(0x57bd), 0x00 }, { CCI_REG8(0x0305), 0x98 }, ++ { CCI_REG8(0x0306), 0x04 }, { CCI_REG8(0x0307), 0x01 }, ++ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 }, ++ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 }, ++ { CCI_REG8(0x480C), 0x92 } ++}; ++ ++static const struct cci_reg_sequence ov64a40_1920x1080[] = { ++ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x3504), 0x08 }, ++ { CCI_REG8(0x360d), 0x82 }, { CCI_REG8(0x368a), 0x2e }, ++ { CCI_REG8(0x3712), 0x00 }, { CCI_REG8(0x3822), 0x08 }, ++ { CCI_REG8(0x3827), 0x40 }, { CCI_REG8(0x383d), 0x04 }, ++ { CCI_REG8(0x383f), 0x00 }, { CCI_REG8(0x384c), 0x01 }, ++ { CCI_REG8(0x384d), 0x12 }, { CCI_REG8(0x3852), 0x00 }, ++ { CCI_REG8(0x3856), 0x04 }, { CCI_REG8(0x3857), 0x04 }, ++ { CCI_REG8(0x3858), 0x08 }, { CCI_REG8(0x3859), 0x08 }, ++ { CCI_REG8(0x4016), 0x07 }, { CCI_REG8(0x4018), 0x01 }, ++ { CCI_REG8(0x4504), 0x00 }, { CCI_REG8(0x4523), 0x00 }, ++ { CCI_REG8(0x45c0), 0x01 }, { CCI_REG8(0x4641), 0x24 }, ++ { CCI_REG8(0x4643), 0x0c }, { CCI_REG8(0x4837), 0x0b }, ++ { CCI_REG8(0x4915), 0x02 }, { CCI_REG8(0x4916), 0x1d }, ++ { CCI_REG8(0x4a15), 0x02 }, { CCI_REG8(0x4a16), 0x1d }, ++ { CCI_REG8(0x5000), 0x55 }, { CCI_REG8(0x5001), 0x00 }, ++ { CCI_REG8(0x5002), 0x35 }, { CCI_REG8(0x5004), 0xc0 }, ++ { CCI_REG8(0x5068), 0x02 }, { CCI_REG8(0x3703), 0x6a }, ++ { CCI_REG8(0x3709), 0xa3 }, { CCI_REG8(0x3a60), 0x60 }, ++ { CCI_REG8(0x3a6f), 0x60 }, { CCI_REG8(0x3a5e), 0x99 }, ++ { CCI_REG8(0x3a6d), 0x99 }, { CCI_REG8(0x3721), 0xc1 }, ++ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x527a), 0x00 }, ++ { CCI_REG8(0x527b), 0x65 }, { CCI_REG8(0x527c), 0x00 }, ++ { CCI_REG8(0x527d), 0x82 }, { CCI_REG8(0x5280), 0x24 }, ++ { CCI_REG8(0x5281), 0x40 }, { CCI_REG8(0x5282), 0x1b }, ++ { CCI_REG8(0x5283), 0x40 }, { CCI_REG8(0x5284), 0x24 }, ++ { CCI_REG8(0x5285), 0x40 }, { CCI_REG8(0x5286), 0x1b }, ++ { CCI_REG8(0x5287), 0x40 }, { CCI_REG8(0x5200), 0x24 }, ++ { CCI_REG8(0x5201), 0x40 }, { CCI_REG8(0x5202), 0x1b }, ++ { CCI_REG8(0x5203), 0x40 }, { CCI_REG8(0x3684), 0x05 }, ++ { CCI_REG8(0x481b), 0x20 }, { CCI_REG8(0x51b0), 0x38 }, ++ { CCI_REG8(0x51b3), 0x0e }, { CCI_REG8(0x51b5), 0x04 }, ++ { CCI_REG8(0x51b6), 0x00 }, { CCI_REG8(0x51b7), 0x00 }, ++ { CCI_REG8(0x51b9), 0x70 }, { CCI_REG8(0x51bb), 0x10 }, ++ { CCI_REG8(0x51bc), 0x00 }, { CCI_REG8(0x51bd), 0x00 }, ++ { CCI_REG8(0x51b0), 0x38 }, { CCI_REG8(0x54b0), 0x38 }, ++ { CCI_REG8(0x54b3), 0x0e }, { CCI_REG8(0x54b5), 0x04 }, ++ { CCI_REG8(0x54b6), 0x00 }, { CCI_REG8(0x54b7), 0x00 }, ++ { CCI_REG8(0x54b9), 0x70 }, { CCI_REG8(0x54bb), 0x10 }, ++ { CCI_REG8(0x54bc), 0x00 }, { CCI_REG8(0x54bd), 0x00 }, ++ { CCI_REG8(0x57b0), 0x38 }, { CCI_REG8(0x57b3), 0x0e }, ++ { CCI_REG8(0x57b5), 0x04 }, { CCI_REG8(0x57b6), 0x00 }, ++ { CCI_REG8(0x57b7), 0x00 }, { CCI_REG8(0x57b9), 0x70 }, ++ { CCI_REG8(0x57bb), 0x10 }, { CCI_REG8(0x57bc), 0x00 }, ++ { CCI_REG8(0x57bd), 0x00 }, { CCI_REG8(0x0305), 0x98 }, ++ { CCI_REG8(0x0306), 0x04 }, { CCI_REG8(0x0307), 0x01 }, ++ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 }, ++ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 }, ++ { CCI_REG8(0x480C), 0x92 } ++}; ++ ++/* 456MHz MIPI link frequency with 24MHz input clock. */ ++static const struct cci_reg_sequence ov64a40_pll_config[] = { ++ { OV64A40_PLL1_PRE_DIV0, 0x88 }, ++ { OV64A40_PLL1_PRE_DIV, 0x02 }, ++ { OV64A40_PLL1_MULTIPLIER, 0x0098 }, ++ { OV64A40_PLL1_M_DIV, 0x01 }, ++ { OV64A40_PLL2_SEL_BAK_SA1, 0x00 }, ++ { OV64A40_PLL2_PRE_DIV, 0x12 }, ++ { OV64A40_PLL2_MULTIPLIER, 0x0190 }, ++ { OV64A40_PLL2_PRE_DIV0, 0xd7 }, ++ { OV64A40_PLL2_DIVSP, 0x00 }, ++ { OV64A40_PLL2_DIVDAC, 0x00 }, ++ { OV64A40_PLL2_DACPREDIV, 0x00 } ++}; ++ ++struct ov64a40_reglist { ++ unsigned int num_regs; ++ const struct cci_reg_sequence *regvals; ++}; ++ ++struct ov64a40_subsampling { ++ unsigned int x_odd_inc; ++ unsigned int x_even_inc; ++ unsigned int y_odd_inc; ++ unsigned int y_even_inc; ++ bool vbin; ++ bool hbin; ++}; ++ ++static struct ov64a40_mode { ++ unsigned int width; ++ unsigned int height; ++ struct ov64a40_timings { ++ unsigned int vts; ++ unsigned int ppl; ++ } timings_default[OV64A40_NUM_LINK_FREQ]; ++ const struct ov64a40_reglist reglist; ++ struct v4l2_rect analogue_crop; ++ struct v4l2_rect digital_crop; ++ struct ov64a40_subsampling subsampling; ++} ov64a40_modes[] = { ++ /* Full resolution */ ++ { ++ .width = 9248, ++ .height = 6944, ++ .timings_default = { ++ /* 2.6 FPS */ ++ [OV64A40_LINK_FREQ_456M_ID] = { ++ .vts = 7072, ++ .ppl = 4072, ++ }, ++ /* 2 FPS */ ++ [OV64A40_LINK_FREQ_360M_ID] = { ++ .vts = 7072, ++ .ppl = 5248, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_9248x6944), ++ .regvals = ov64a40_9248x6944, ++ }, ++ .analogue_crop = { ++ .left = 0, ++ .top = 0, ++ .width = 9279, ++ .height = 6975, ++ }, ++ .digital_crop = { ++ .left = 17, ++ .top = 16, ++ .width = 9248, ++ .height = 6944, ++ }, ++ .subsampling = { ++ .x_odd_inc = 1, ++ .x_even_inc = 1, ++ .y_odd_inc = 1, ++ .y_even_inc = 1, ++ .vbin = false, ++ .hbin = false, ++ }, ++ }, ++ /* Analogue crop + digital crop */ ++ { ++ .width = 8000, ++ .height = 6000, ++ .timings_default = { ++ /* 3.0 FPS */ ++ [OV64A40_LINK_FREQ_456M_ID] = { ++ .vts = 6400, ++ .ppl = 3848, ++ }, ++ /* 2.5 FPS */ ++ [OV64A40_LINK_FREQ_360M_ID] = { ++ .vts = 6304, ++ .ppl = 4736, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_8000x6000), ++ .regvals = ov64a40_8000x6000, ++ }, ++ .analogue_crop = { ++ .left = 624, ++ .top = 472, ++ .width = 8047, ++ .height = 6031, ++ }, ++ .digital_crop = { ++ .left = 17, ++ .top = 16, ++ .width = 8000, ++ .height = 6000, ++ }, ++ .subsampling = { ++ .x_odd_inc = 1, ++ .x_even_inc = 1, ++ .y_odd_inc = 1, ++ .y_even_inc = 1, ++ .vbin = false, ++ .hbin = false, ++ }, ++ }, ++ /* 2x2 downscaled */ ++ { ++ .width = 4624, ++ .height = 3472, ++ .timings_default = { ++ /* 10 FPS */ ++ [OV64A40_LINK_FREQ_456M_ID] = { ++ .vts = 3533, ++ .ppl = 2112, ++ }, ++ /* 7 FPS */ ++ [OV64A40_LINK_FREQ_360M_ID] = { ++ .vts = 3939, ++ .ppl = 2720, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_4624_3472), ++ .regvals = ov64a40_4624_3472, ++ }, ++ .analogue_crop = { ++ .left = 0, ++ .top = 0, ++ .width = 9279, ++ .height = 6975, ++ }, ++ .digital_crop = { ++ .left = 9, ++ .top = 8, ++ .width = 4624, ++ .height = 3472, ++ }, ++ .subsampling = { ++ .x_odd_inc = 3, ++ .x_even_inc = 1, ++ .y_odd_inc = 1, ++ .y_even_inc = 1, ++ .vbin = true, ++ .hbin = false, ++ }, ++ }, ++ /* Analogue crop + 2x2 downscale + digital crop */ ++ { ++ .width = 3840, ++ .height = 2160, ++ .timings_default = { ++ /* 20 FPS */ ++ [OV64A40_LINK_FREQ_456M_ID] = { ++ .vts = 2218, ++ .ppl = 1690, ++ }, ++ /* 15 FPS */ ++ [OV64A40_LINK_FREQ_360M_ID] = { ++ .vts = 2270, ++ .ppl = 2202, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_3840x2160), ++ .regvals = ov64a40_3840x2160, ++ }, ++ .analogue_crop = { ++ .left = 784, ++ .top = 1312, ++ .width = 7711, ++ .height = 4351, ++ }, ++ .digital_crop = { ++ .left = 9, ++ .top = 8, ++ .width = 3840, ++ .height = 2160, ++ }, ++ .subsampling = { ++ .x_odd_inc = 3, ++ .x_even_inc = 1, ++ .y_odd_inc = 1, ++ .y_even_inc = 1, ++ .vbin = true, ++ .hbin = false, ++ }, ++ }, ++ /* 4x4 downscaled */ ++ { ++ .width = 2312, ++ .height = 1736, ++ .timings_default = { ++ /* 30 FPS */ ++ [OV64A40_LINK_FREQ_456M_ID] = { ++ .vts = 1998, ++ .ppl = 1248, ++ }, ++ /* 25 FPS */ ++ [OV64A40_LINK_FREQ_360M_ID] = { ++ .vts = 1994, ++ .ppl = 1504, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_2312_1736), ++ .regvals = ov64a40_2312_1736, ++ }, ++ .analogue_crop = { ++ .left = 0, ++ .top = 0, ++ .width = 9279, ++ .height = 6975, ++ }, ++ .digital_crop = { ++ .left = 5, ++ .top = 4, ++ .width = 2312, ++ .height = 1736, ++ }, ++ .subsampling = { ++ .x_odd_inc = 3, ++ .x_even_inc = 1, ++ .y_odd_inc = 3, ++ .y_even_inc = 1, ++ .vbin = true, ++ .hbin = true, ++ }, ++ }, ++ /* Analogue crop + 4x4 downscale + digital crop */ ++ { ++ .width = 1920, ++ .height = 1080, ++ .timings_default = { ++ /* 60 FPS */ ++ [OV64A40_LINK_FREQ_456M_ID] = { ++ .vts = 1397, ++ .ppl = 880, ++ }, ++ /* 45 FPS */ ++ [OV64A40_LINK_FREQ_360M_ID] = { ++ .vts = 1216, ++ .ppl = 1360, ++ }, ++ }, ++ .reglist = { ++ .num_regs = ARRAY_SIZE(ov64a40_1920x1080), ++ .regvals = ov64a40_1920x1080, ++ }, ++ .analogue_crop = { ++ .left = 784, ++ .top = 1312, ++ .width = 7711, ++ .height = 4351, ++ }, ++ .digital_crop = { ++ .left = 7, ++ .top = 6, ++ .width = 1920, ++ .height = 1080, ++ }, ++ .subsampling = { ++ .x_odd_inc = 3, ++ .x_even_inc = 1, ++ .y_odd_inc = 3, ++ .y_even_inc = 1, ++ .vbin = true, ++ .hbin = true, ++ }, ++ }, ++}; ++ ++struct ov64a40 { ++ struct device *dev; ++ ++ struct v4l2_subdev sd; ++ struct media_pad pad; ++ ++ struct regmap *cci; ++ ++ struct ov64a40_mode *mode; ++ ++ struct clk *xclk; ++ ++ struct gpio_desc *reset_gpio; ++ struct regulator_bulk_data supplies[ARRAY_SIZE(ov64a40_supply_names)]; ++ ++ s64 *link_frequencies; ++ unsigned int num_link_frequencies; ++ ++ struct v4l2_ctrl_handler ctrl_handler; ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *link_freq; ++ struct v4l2_ctrl *vblank; ++ struct v4l2_ctrl *hblank; ++ struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *hflip; ++}; ++ ++static inline struct ov64a40 *sd_to_ov64a40(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov64a40, sd); ++} ++ ++static const struct ov64a40_timings * ++ov64a40_get_timings(struct ov64a40 *ov64a40, unsigned int link_freq_index) ++{ ++ s64 link_freq = ov64a40->link_frequencies[link_freq_index]; ++ unsigned int timings_index = link_freq == OV64A40_LINK_FREQ_360M ++ ? OV64A40_LINK_FREQ_360M_ID ++ : OV64A40_LINK_FREQ_456M_ID; ++ ++ return &ov64a40->mode->timings_default[timings_index]; ++} ++ ++static int ov64a40_program_geometry(struct ov64a40 *ov64a40) ++{ ++ struct ov64a40_mode *mode = ov64a40->mode; ++ struct v4l2_rect *anacrop = &mode->analogue_crop; ++ struct v4l2_rect *digicrop = &mode->digital_crop; ++ const struct ov64a40_timings *timings; ++ int ret = 0; ++ ++ /* Analogue crop. */ ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL0, ++ anacrop->left, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL2, ++ anacrop->top, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL4, ++ anacrop->width + anacrop->left, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL6, ++ anacrop->height + anacrop->top, &ret); ++ ++ /* ISP windowing. */ ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL10, ++ digicrop->left, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL12, ++ digicrop->top, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL8, ++ digicrop->width, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRLA, ++ digicrop->height, &ret); ++ ++ /* Total timings. */ ++ timings = ov64a40_get_timings(ov64a40, ov64a40->link_freq->cur.val); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRLC, timings->ppl, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRLE, timings->vts, &ret); ++ ++ return ret; ++} ++ ++static int ov64a40_program_subsampling(struct ov64a40 *ov64a40) ++{ ++ struct ov64a40_subsampling *subsampling = &ov64a40->mode->subsampling; ++ int ret = 0; ++ ++ /* Skipping configuration */ ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL14, ++ OV64A40_SKIPPING_CONFIG(subsampling->x_odd_inc, ++ subsampling->x_even_inc), &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL15, ++ OV64A40_SKIPPING_CONFIG(subsampling->y_odd_inc, ++ subsampling->y_even_inc), &ret); ++ ++ /* Binning configuration */ ++ cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_20, ++ OV64A40_TIMING_CTRL_20_VBIN, ++ subsampling->vbin ? OV64A40_TIMING_CTRL_20_VBIN : 0, ++ &ret); ++ cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_21, ++ OV64A40_TIMING_CTRL_21_HBIN_CONF, ++ subsampling->hbin ? ++ OV64A40_TIMING_CTRL_21_HBIN_CONF : 0, &ret); ++ ++ return ret; ++} ++ ++static int ov64a40_start_streaming(struct ov64a40 *ov64a40, ++ struct v4l2_subdev_state *state) ++{ ++ const struct ov64a40_reglist *reglist = &ov64a40->mode->reglist; ++ const struct ov64a40_timings *timings; ++ unsigned long delay; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(ov64a40->dev); ++ if (ret < 0) ++ return ret; ++ ++ ret = cci_multi_reg_write(ov64a40->cci, ov64a40_init, ++ ARRAY_SIZE(ov64a40_init), NULL); ++ if (ret) ++ goto error_power_off; ++ ++ ret = cci_multi_reg_write(ov64a40->cci, reglist->regvals, ++ reglist->num_regs, NULL); ++ if (ret) ++ goto error_power_off; ++ ++ ret = ov64a40_program_geometry(ov64a40); ++ if (ret) ++ goto error_power_off; ++ ++ ret = ov64a40_program_subsampling(ov64a40); ++ if (ret) ++ goto error_power_off; ++ ++ ret = __v4l2_ctrl_handler_setup(&ov64a40->ctrl_handler); ++ if (ret) ++ goto error_power_off; ++ ++ ret = cci_write(ov64a40->cci, OV64A40_REG_SMIA, ++ OV64A40_REG_SMIA_STREAMING, NULL); ++ if (ret) ++ goto error_power_off; ++ ++ /* Link frequency and flips cannot change while streaming. */ ++ __v4l2_ctrl_grab(ov64a40->link_freq, true); ++ __v4l2_ctrl_grab(ov64a40->vflip, true); ++ __v4l2_ctrl_grab(ov64a40->hflip, true); ++ ++ /* delay: max(4096 xclk pulses, 150usec) + exposure time */ ++ timings = ov64a40_get_timings(ov64a40, ov64a40->link_freq->cur.val); ++ delay = DIV_ROUND_UP(4096, OV64A40_XCLK_FREQ / 1000 / 1000); ++ delay = max(delay, 150ul); ++ ++ /* The sensor has an internal x4 multiplier on the line length. */ ++ delay += DIV_ROUND_UP(timings->ppl * 4 * ov64a40->exposure->cur.val, ++ OV64A40_PIXEL_RATE / 1000 / 1000); ++ fsleep(delay); ++ ++ return 0; ++ ++error_power_off: ++ pm_runtime_mark_last_busy(ov64a40->dev); ++ pm_runtime_put_autosuspend(ov64a40->dev); ++ ++ return ret; ++} ++ ++static int ov64a40_stop_streaming(struct ov64a40 *ov64a40, ++ struct v4l2_subdev_state *state) ++{ ++ cci_update_bits(ov64a40->cci, OV64A40_REG_SMIA, BIT(0), 0, NULL); ++ pm_runtime_mark_last_busy(ov64a40->dev); ++ pm_runtime_put_autosuspend(ov64a40->dev); ++ ++ __v4l2_ctrl_grab(ov64a40->link_freq, false); ++ __v4l2_ctrl_grab(ov64a40->vflip, false); ++ __v4l2_ctrl_grab(ov64a40->hflip, false); ++ ++ return 0; ++} ++ ++static int ov64a40_set_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ struct v4l2_subdev_state *state; ++ int ret; ++ ++ state = v4l2_subdev_lock_and_get_active_state(sd); ++ if (enable) ++ ret = ov64a40_start_streaming(ov64a40, state); ++ else ++ ret = ov64a40_stop_streaming(ov64a40, state); ++ v4l2_subdev_unlock_state(state); ++ ++ return ret; ++} ++ ++static const struct v4l2_subdev_video_ops ov64a40_video_ops = { ++ .s_stream = ov64a40_set_stream, ++}; ++ ++static u32 ov64a40_mbus_code(struct ov64a40 *ov64a40) ++{ ++ unsigned int index = ov64a40->hflip->val << 1 | ov64a40->vflip->val; ++ ++ return ov64a40_mbus_codes[index]; ++} ++ ++static void ov64a40_update_pad_fmt(struct ov64a40 *ov64a40, ++ struct ov64a40_mode *mode, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ fmt->code = ov64a40_mbus_code(ov64a40); ++ fmt->width = mode->width; ++ fmt->height = mode->height; ++ fmt->field = V4L2_FIELD_NONE; ++ fmt->colorspace = V4L2_COLORSPACE_RAW; ++ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; ++ fmt->xfer_func = V4L2_XFER_FUNC_NONE; ++ fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; ++} ++ ++static int ov64a40_init_cfg(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *state) ++{ ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ struct v4l2_mbus_framefmt *format; ++ struct v4l2_rect *crop; ++ ++ format = v4l2_subdev_get_pad_format(sd, state, 0); ++ ov64a40_update_pad_fmt(ov64a40, &ov64a40_modes[0], format); ++ ++ crop = v4l2_subdev_get_pad_crop(sd, state, 0); ++ crop->top = OV64A40_PIXEL_ARRAY_TOP; ++ crop->left = OV64A40_PIXEL_ARRAY_LEFT; ++ crop->width = OV64A40_PIXEL_ARRAY_WIDTH; ++ crop->height = OV64A40_PIXEL_ARRAY_HEIGHT; ++ ++ return 0; ++} ++ ++static int ov64a40_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ ++ if (code->index) ++ return -EINVAL; ++ ++ code->code = ov64a40_mbus_code(ov64a40); ++ ++ return 0; ++} ++ ++static int ov64a40_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ struct ov64a40_mode *mode; ++ u32 code; ++ ++ if (fse->index >= ARRAY_SIZE(ov64a40_modes)) ++ return -EINVAL; ++ ++ code = ov64a40_mbus_code(ov64a40); ++ if (fse->code != code) ++ return -EINVAL; ++ ++ mode = &ov64a40_modes[fse->index]; ++ fse->min_width = mode->width; ++ fse->max_width = mode->width; ++ fse->min_height = mode->height; ++ fse->max_height = mode->height; ++ ++ return 0; ++} ++ ++static int ov64a40_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_selection *sel) ++{ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP: ++ sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0); ++ ++ return 0; ++ ++ case V4L2_SEL_TGT_NATIVE_SIZE: ++ sel->r.top = 0; ++ sel->r.left = 0; ++ sel->r.width = OV64A40_NATIVE_WIDTH; ++ sel->r.height = OV64A40_NATIVE_HEIGHT; ++ ++ return 0; ++ ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.top = OV64A40_PIXEL_ARRAY_TOP; ++ sel->r.left = OV64A40_PIXEL_ARRAY_LEFT; ++ sel->r.width = OV64A40_PIXEL_ARRAY_WIDTH; ++ sel->r.height = OV64A40_PIXEL_ARRAY_HEIGHT; ++ ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int ov64a40_set_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ struct v4l2_mbus_framefmt *format; ++ struct ov64a40_mode *mode; ++ ++ mode = v4l2_find_nearest_size(ov64a40_modes, ++ ARRAY_SIZE(ov64a40_modes), ++ width, height, ++ fmt->format.width, fmt->format.height); ++ ++ ov64a40_update_pad_fmt(ov64a40, mode, &fmt->format); ++ ++ format = v4l2_subdev_get_pad_format(sd, sd_state, 0); ++ if (ov64a40->mode == mode && format->code == fmt->format.code) ++ return 0; ++ ++ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { ++ const struct ov64a40_timings *timings; ++ int vblank_max, vblank_def; ++ int hblank_val; ++ int exp_max; ++ ++ ov64a40->mode = mode; ++ *v4l2_subdev_get_pad_crop(sd, sd_state, 0) = mode->analogue_crop; ++ ++ /* Update control limits according to the new mode. */ ++ timings = ov64a40_get_timings(ov64a40, ++ ov64a40->link_freq->cur.val); ++ vblank_max = OV64A40_VTS_MAX - mode->height; ++ vblank_def = timings->vts - mode->height; ++ __v4l2_ctrl_modify_range(ov64a40->vblank, OV64A40_VBLANK_MIN, ++ vblank_max, 1, vblank_def); ++ __v4l2_ctrl_s_ctrl(ov64a40->vblank, vblank_def); ++ ++ exp_max = timings->vts - OV64A40_EXPOSURE_MARGIN; ++ __v4l2_ctrl_modify_range(ov64a40->exposure, ++ OV64A40_EXPOSURE_MIN, exp_max, ++ 1, OV64A40_EXPOSURE_MIN); ++ ++ hblank_val = timings->ppl * 4 - mode->width; ++ __v4l2_ctrl_modify_range(ov64a40->hblank, ++ hblank_val, hblank_val, 1, hblank_val); ++ } ++ ++ *format = fmt->format; ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_pad_ops ov64a40_pad_ops = { ++ .init_cfg = ov64a40_init_cfg, ++ .enum_mbus_code = ov64a40_enum_mbus_code, ++ .enum_frame_size = ov64a40_enum_frame_size, ++ .get_fmt = v4l2_subdev_get_fmt, ++ .set_fmt = ov64a40_set_format, ++ .get_selection = ov64a40_get_selection, ++}; ++ ++static const struct v4l2_subdev_core_ops ov64a40_core_ops = { ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static const struct v4l2_subdev_ops ov64a40_subdev_ops = { ++ .core = &ov64a40_core_ops, ++ .video = &ov64a40_video_ops, ++ .pad = &ov64a40_pad_ops, ++}; ++ ++static int ov64a40_power_on(struct device *dev) ++{ ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ int ret; ++ ++ ret = clk_prepare_enable(ov64a40->xclk); ++ if (ret) ++ return ret; ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(ov64a40_supply_names), ++ ov64a40->supplies); ++ if (ret) { ++ clk_disable_unprepare(ov64a40->xclk); ++ dev_err(dev, "Failed to enable regulators: %d\n", ret); ++ return ret; ++ } ++ ++ gpiod_set_value_cansleep(ov64a40->reset_gpio, 0); ++ ++ fsleep(5000); ++ ++ return 0; ++} ++ ++static int ov64a40_power_off(struct device *dev) ++{ ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ ++ gpiod_set_value_cansleep(ov64a40->reset_gpio, 1); ++ regulator_bulk_disable(ARRAY_SIZE(ov64a40_supply_names), ++ ov64a40->supplies); ++ clk_disable_unprepare(ov64a40->xclk); ++ ++ return 0; ++} ++ ++static int ov64a40_link_freq_config(struct ov64a40 *ov64a40, int link_freq_id) ++{ ++ s64 link_frequency; ++ int ret = 0; ++ ++ /* Default 456MHz with 24MHz input clock. */ ++ cci_multi_reg_write(ov64a40->cci, ov64a40_pll_config, ++ ARRAY_SIZE(ov64a40_pll_config), &ret); ++ ++ /* Decrease the PLL1 multiplier to obtain 360MHz mipi link frequency. */ ++ link_frequency = ov64a40->link_frequencies[link_freq_id]; ++ if (link_frequency == OV64A40_LINK_FREQ_360M) ++ cci_write(ov64a40->cci, OV64A40_PLL1_MULTIPLIER, 0x0078, &ret); ++ ++ return ret; ++} ++ ++static int ov64a40_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ov64a40 *ov64a40 = container_of(ctrl->handler, struct ov64a40, ++ ctrl_handler); ++ int pm_status; ++ int ret = 0; ++ ++ if (ctrl->id == V4L2_CID_VBLANK) { ++ int exp_max = ov64a40->mode->height + ctrl->val ++ - OV64A40_EXPOSURE_MARGIN; ++ int exp_val = min(ov64a40->exposure->cur.val, exp_max); ++ ++ __v4l2_ctrl_modify_range(ov64a40->exposure, ++ ov64a40->exposure->minimum, ++ exp_max, 1, exp_val); ++ } ++ ++ pm_status = pm_runtime_get_if_active(ov64a40->dev, true); ++ if (!pm_status) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_EXPOSURE: ++ ret = cci_write(ov64a40->cci, OV64A40_REG_MEC_LONG_EXPO, ++ ctrl->val, NULL); ++ break; ++ case V4L2_CID_ANALOGUE_GAIN: ++ ret = cci_write(ov64a40->cci, OV64A40_REG_MEC_LONG_GAIN, ++ ctrl->val << 1, NULL); ++ break; ++ case V4L2_CID_VBLANK: { ++ int vts = ctrl->val + ov64a40->mode->height; ++ ++ cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS_LOW, vts, &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS_MID, ++ (vts >> 8), &ret); ++ cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS_HIGH, ++ (vts >> 16), &ret); ++ break; ++ } ++ case V4L2_CID_VFLIP: ++ ret = cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_20, ++ OV64A40_TIMING_CTRL_20_VFLIP, ++ ctrl->val << 2, ++ NULL); ++ break; ++ case V4L2_CID_HFLIP: ++ ret = cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_21, ++ OV64A40_TIMING_CTRL_21_HFLIP, ++ ctrl->val ? 0 ++ : OV64A40_TIMING_CTRL_21_HFLIP, ++ NULL); ++ break; ++ case V4L2_CID_TEST_PATTERN: ++ ret = cci_write(ov64a40->cci, OV64A40_REG_TEST_PATTERN, ++ ov64a40_test_pattern_val[ctrl->val], NULL); ++ break; ++ case V4L2_CID_LINK_FREQ: ++ ret = ov64a40_link_freq_config(ov64a40, ctrl->val); ++ break; ++ default: ++ dev_err(ov64a40->dev, "Unhandled control: %#x\n", ctrl->id); ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (pm_status > 0) { ++ pm_runtime_mark_last_busy(ov64a40->dev); ++ pm_runtime_put_autosuspend(ov64a40->dev); ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov64a40_ctrl_ops = { ++ .s_ctrl = ov64a40_set_ctrl, ++}; ++ ++static int ov64a40_init_controls(struct ov64a40 *ov64a40) ++{ ++ int exp_max, hblank_val, vblank_max, vblank_def; ++ struct v4l2_ctrl_handler *hdlr = &ov64a40->ctrl_handler; ++ struct v4l2_fwnode_device_properties props; ++ const struct ov64a40_timings *timings; ++ int ret; ++ ++ ret = v4l2_ctrl_handler_init(hdlr, 11); ++ if (ret) ++ return ret; ++ ++ v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, V4L2_CID_PIXEL_RATE, ++ OV64A40_PIXEL_RATE, OV64A40_PIXEL_RATE, 1, ++ OV64A40_PIXEL_RATE); ++ ++ ov64a40->link_freq = ++ v4l2_ctrl_new_int_menu(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ov64a40->num_link_frequencies - 1, ++ 0, ov64a40->link_frequencies); ++ ++ v4l2_ctrl_new_std_menu_items(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_TEST_PATTERN, ++ ARRAY_SIZE(ov64a40_test_pattern_menu) - 1, ++ 0, 0, ov64a40_test_pattern_menu); ++ ++ timings = ov64a40_get_timings(ov64a40, 0); ++ exp_max = timings->vts - OV64A40_EXPOSURE_MARGIN; ++ ov64a40->exposure = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_EXPOSURE, ++ OV64A40_EXPOSURE_MIN, exp_max, 1, ++ OV64A40_EXPOSURE_MIN); ++ ++ hblank_val = timings->ppl * 4 - ov64a40->mode->width; ++ ov64a40->hblank = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_HBLANK, hblank_val, ++ hblank_val, 1, hblank_val); ++ if (ov64a40->hblank) ++ ov64a40->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ vblank_def = timings->vts - ov64a40->mode->height; ++ vblank_max = OV64A40_VTS_MAX - ov64a40->mode->height; ++ ov64a40->vblank = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_VBLANK, OV64A40_VBLANK_MIN, ++ vblank_max, 1, vblank_def); ++ ++ v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, ++ OV64A40_ANA_GAIN_MIN, OV64A40_ANA_GAIN_MAX, 1, ++ OV64A40_ANA_GAIN_DEFAULT); ++ ++ ov64a40->hflip = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ if (ov64a40->hflip) ++ ov64a40->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ ov64a40->vflip = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ if (ov64a40->vflip) ++ ov64a40->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ if (hdlr->error) { ++ ret = hdlr->error; ++ dev_err(ov64a40->dev, "control init failed: %d\n", ret); ++ goto error_free_hdlr; ++ } ++ ++ ret = v4l2_fwnode_device_parse(ov64a40->dev, &props); ++ if (ret) ++ goto error_free_hdlr; ++ ++ ret = v4l2_ctrl_new_fwnode_properties(hdlr, &ov64a40_ctrl_ops, ++ &props); ++ if (ret) ++ goto error_free_hdlr; ++ ++ ov64a40->sd.ctrl_handler = hdlr; ++ ++ return 0; ++ ++error_free_hdlr: ++ v4l2_ctrl_handler_free(hdlr); ++ return ret; ++} ++ ++static int ov64a40_identify(struct ov64a40 *ov64a40) ++{ ++ int ret; ++ u64 id; ++ ++ ret = cci_read(ov64a40->cci, OV64A40_REG_CHIP_ID, &id, NULL); ++ if (ret) { ++ dev_err(ov64a40->dev, "Failed to read chip id: %d\n", ret); ++ return ret; ++ } ++ ++ if (id != OV64A40_CHIP_ID) { ++ dev_err(ov64a40->dev, "chip id mismatch: %#llx\n", id); ++ return -ENODEV; ++ } ++ ++ dev_dbg(ov64a40->dev, "OV64A40 chip identified: %#llx\n", id); ++ ++ return 0; ++} ++ ++static int ov64a40_parse_dt(struct ov64a40 *ov64a40) ++{ ++ struct v4l2_fwnode_endpoint v4l2_fwnode = { ++ .bus_type = V4L2_MBUS_CSI2_DPHY ++ }; ++ struct fwnode_handle *endpoint; ++ int ret = -EINVAL; ++ unsigned int i; ++ ++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(ov64a40->dev), ++ NULL); ++ if (!endpoint) { ++ dev_err(ov64a40->dev, "Failed to find endpoint\n"); ++ return -EINVAL; ++ } ++ ++ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &v4l2_fwnode)) { ++ dev_err(ov64a40->dev, "Failed to parse endpoint\n"); ++ goto error_put_fwnode; ++ ++ } ++ ++ if (v4l2_fwnode.bus.mipi_csi2.num_data_lanes != 2) { ++ dev_err(ov64a40->dev, "Unsupported number of data lanes: %u\n", ++ v4l2_fwnode.bus.mipi_csi2.num_data_lanes); ++ goto error_free_fwnode; ++ } ++ ++ if (!v4l2_fwnode.nr_of_link_frequencies) { ++ dev_warn(ov64a40->dev, "no link frequencies defined\n"); ++ goto error_free_fwnode; ++ } ++ ++ if (v4l2_fwnode.nr_of_link_frequencies > 2) { ++ dev_warn(ov64a40->dev, ++ "Unsupported number of link frequencies\n"); ++ goto error_free_fwnode; ++ } ++ ++ ov64a40->link_frequencies = ++ devm_kcalloc(ov64a40->dev, v4l2_fwnode.nr_of_link_frequencies, ++ sizeof(v4l2_fwnode.link_frequencies[0]), ++ GFP_KERNEL); ++ if (!ov64a40->link_frequencies) { ++ ret = -ENOMEM; ++ goto error_free_fwnode; ++ } ++ ov64a40->num_link_frequencies = v4l2_fwnode.nr_of_link_frequencies; ++ ++ for (i = 0; i < v4l2_fwnode.nr_of_link_frequencies; ++i) { ++ if (v4l2_fwnode.link_frequencies[i] != OV64A40_LINK_FREQ_360M && ++ v4l2_fwnode.link_frequencies[i] != OV64A40_LINK_FREQ_456M) { ++ dev_err(ov64a40->dev, ++ "Unsupported link frequency %lld\n", ++ v4l2_fwnode.link_frequencies[i]); ++ goto error_free_fwnode; ++ } ++ ++ ov64a40->link_frequencies[i] = v4l2_fwnode.link_frequencies[i]; ++ } ++ ++ v4l2_fwnode_endpoint_free(&v4l2_fwnode); ++ ++ /* Register the subdev on the endpoint, so don't put it yet. */ ++ ov64a40->sd.fwnode = endpoint; ++ ++ return 0; ++ ++error_free_fwnode: ++ v4l2_fwnode_endpoint_free(&v4l2_fwnode); ++error_put_fwnode: ++ fwnode_handle_put(endpoint); ++ return ret; ++} ++ ++static int ov64a40_get_regulators(struct ov64a40 *ov64a40) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov64a40->sd); ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ov64a40_supply_names); i++) ++ ov64a40->supplies[i].supply = ov64a40_supply_names[i]; ++ ++ return devm_regulator_bulk_get(&client->dev, ++ ARRAY_SIZE(ov64a40_supply_names), ++ ov64a40->supplies); ++} ++ ++static int ov64a40_probe(struct i2c_client *client) ++{ ++ struct ov64a40 *ov64a40; ++ u32 xclk_freq; ++ int ret; ++ ++ ov64a40 = devm_kzalloc(&client->dev, sizeof(*ov64a40), GFP_KERNEL); ++ if (!ov64a40) ++ return -ENOMEM; ++ ++ ov64a40->dev = &client->dev; ++ v4l2_i2c_subdev_init(&ov64a40->sd, client, &ov64a40_subdev_ops); ++ ++ ov64a40->cci = devm_cci_regmap_init_i2c(client, 16); ++ if (IS_ERR(ov64a40->cci)) { ++ dev_err(&client->dev, "Failed to initialize CCI\n"); ++ return PTR_ERR(ov64a40->cci); ++ } ++ ++ ov64a40->xclk = devm_clk_get(&client->dev, NULL); ++ if (!ov64a40->xclk) ++ return dev_err_probe(&client->dev, PTR_ERR(ov64a40->xclk), ++ "Failed to get clock\n"); ++ ++ xclk_freq = clk_get_rate(ov64a40->xclk); ++ if (xclk_freq != OV64A40_XCLK_FREQ) { ++ dev_err(&client->dev, "Unsupported xclk frequency %u\n", ++ xclk_freq); ++ return -EINVAL; ++ } ++ ++ ret = ov64a40_get_regulators(ov64a40); ++ if (ret) ++ return ret; ++ ++ ov64a40->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(ov64a40->reset_gpio)) ++ return dev_err_probe(&client->dev, PTR_ERR(ov64a40->reset_gpio), ++ "Failed to get reset gpio\n"); ++ ++ ret = ov64a40_parse_dt(ov64a40); ++ if (ret) ++ return ret; ++ ++ ret = ov64a40_power_on(&client->dev); ++ if (ret) ++ goto error_put_fwnode; ++ ++ ret = ov64a40_identify(ov64a40); ++ if (ret) ++ goto error_poweroff; ++ ++ ov64a40->mode = &ov64a40_modes[0]; ++ ++ pm_runtime_set_active(&client->dev); ++ pm_runtime_get_noresume(&client->dev); ++ pm_runtime_enable(&client->dev); ++ pm_runtime_set_autosuspend_delay(&client->dev, 1000); ++ pm_runtime_use_autosuspend(&client->dev); ++ ++ ret = ov64a40_init_controls(ov64a40); ++ if (ret) ++ goto error_poweroff; ++ ++ /* Initialize subdev */ ++ ov64a40->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE ++ | V4L2_SUBDEV_FL_HAS_EVENTS; ++ ov64a40->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ++ ov64a40->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&ov64a40->sd.entity, 1, &ov64a40->pad); ++ if (ret) { ++ dev_err(&client->dev, "failed to init entity pads: %d\n", ret); ++ goto error_handler_free; ++ } ++ ++ ov64a40->sd.state_lock = ov64a40->ctrl_handler.lock; ++ ret = v4l2_subdev_init_finalize(&ov64a40->sd); ++ if (ret < 0) { ++ dev_err(&client->dev, "subdev init error: %d\n", ret); ++ goto error_media_entity; ++ } ++ ++ ret = v4l2_async_register_subdev_sensor(&ov64a40->sd); ++ if (ret < 0) { ++ dev_err(&client->dev, ++ "failed to register sensor sub-device: %d\n", ret); ++ goto error_subdev_cleanup; ++ } ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++ ++ return 0; ++ ++error_subdev_cleanup: ++ v4l2_subdev_cleanup(&ov64a40->sd); ++error_media_entity: ++ media_entity_cleanup(&ov64a40->sd.entity); ++error_handler_free: ++ v4l2_ctrl_handler_free(ov64a40->sd.ctrl_handler); ++error_poweroff: ++ ov64a40_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++error_put_fwnode: ++ fwnode_handle_put(ov64a40->sd.fwnode); ++ ++ return ret; ++} ++ ++static void ov64a40_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd); ++ ++ v4l2_async_unregister_subdev(sd); ++ fwnode_handle_put(ov64a40->sd.fwnode); ++ v4l2_subdev_cleanup(sd); ++ media_entity_cleanup(&sd->entity); ++ v4l2_ctrl_handler_free(sd->ctrl_handler); ++ ++ pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ ov64a40_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++} ++ ++static const struct of_device_id ov64a40_of_ids[] = { ++ { .compatible = "ovti,ov64a40" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, ov64a40_of_ids); ++ ++static const struct dev_pm_ops ov64a40_pm_ops = { ++ SET_RUNTIME_PM_OPS(ov64a40_power_off, ov64a40_power_on, NULL) ++}; ++ ++static struct i2c_driver ov64a40_i2c_driver = { ++ .driver = { ++ .name = "ov64a40", ++ .of_match_table = ov64a40_of_ids, ++ .pm = &ov64a40_pm_ops, ++ }, ++ .probe_new = ov64a40_probe, ++ .remove = ov64a40_remove, ++}; ++ ++module_i2c_driver(ov64a40_i2c_driver); ++ ++MODULE_AUTHOR("Jacopo Mondi "); ++MODULE_DESCRIPTION("OmniVision OV64A40 sensor driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/bcm27xx/patches-6.1/950-1196-media-i2c-Add-ROHM-BU64754-Camera-Autofocus-Actuator.patch b/target/linux/bcm27xx/patches-6.1/950-1196-media-i2c-Add-ROHM-BU64754-Camera-Autofocus-Actuator.patch new file mode 100644 index 0000000000..a50617ee56 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1196-media-i2c-Add-ROHM-BU64754-Camera-Autofocus-Actuator.patch @@ -0,0 +1,368 @@ +From 97ec6aeb265df0bfe7193f00c249b38873fb0fb7 Mon Sep 17 00:00:00 2001 +From: Kieran Bingham +Date: Wed, 13 Sep 2023 17:53:54 +0100 +Subject: [PATCH] media: i2c: Add ROHM BU64754 Camera Autofocus Actuator + +Add support for the ROHM BU64754 Motor Driver for Camera Autofocus. A +V4L2 Subdevice is registered and provides a single +V4L2_CID_FOCUS_ABSOLUTE control. + +Signed-off-by: Kieran Bingham +Signed-off-by: Jacopo Mondi +--- + drivers/media/i2c/Kconfig | 13 ++ + drivers/media/i2c/Makefile | 1 + + drivers/media/i2c/bu64754.c | 315 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 329 insertions(+) + create mode 100644 drivers/media/i2c/bu64754.c + +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -917,6 +917,19 @@ config VIDEO_AK7375 + capability. This is designed for linear control of + voice coil motors, controlled via I2C serial interface. + ++config VIDEO_BU64754 ++ tristate "BU64754 Motor Driver for Camera Autofocus" ++ depends on I2C && VIDEO_DEV ++ select MEDIA_CONTROLLER ++ select VIDEO_V4L2_SUBDEV_API ++ select V4L2_ASYNC ++ select V4L2_CCI_I2C ++ help ++ This is a driver for the BU64754 Motor Driver for Camera ++ Autofocus. The BU64754GWZ is an actuator driver IC which ++ can be controlled the actuator position precisely using ++ with internal Hall Sensor. ++ + config VIDEO_DW9714 + tristate "DW9714 lens voice coil support" + depends on I2C && VIDEO_DEV +--- a/drivers/media/i2c/Makefile ++++ b/drivers/media/i2c/Makefile +@@ -26,6 +26,7 @@ obj-$(CONFIG_VIDEO_ARDUCAM_PIVARIETY) += + obj-$(CONFIG_VIDEO_BT819) += bt819.o + obj-$(CONFIG_VIDEO_BT856) += bt856.o + obj-$(CONFIG_VIDEO_BT866) += bt866.o ++obj-$(CONFIG_VIDEO_BU64754) += bu64754.o + obj-$(CONFIG_VIDEO_CCS) += ccs/ + obj-$(CONFIG_VIDEO_CCS_PLL) += ccs-pll.o + obj-$(CONFIG_VIDEO_CS3308) += cs3308.o +--- /dev/null ++++ b/drivers/media/i2c/bu64754.c +@@ -0,0 +1,315 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * The BU64754GWZ is an actuator driver IC which can control the ++ * actuator position precisely using an internal Hall Sensor. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define BU64754_REG_ACTIVE CCI_REG16(0x07) ++#define BU64754_ACTIVE_MODE 0x8080 ++ ++#define BU64754_REG_SERVE CCI_REG16(0xd9) ++#define BU64754_SERVE_ON 0x0404 ++ ++#define BU64754_REG_POSITION CCI_REG16(0x45) ++#define BU64753_POSITION_MAX 1023 /* 0x3ff */ ++#define BU64753_POSITION_STEPS 1 ++ ++#define BU64754_POWER_ON_DELAY 800 /* uS : t1, t3 */ ++ ++struct bu64754 { ++ struct device *dev; ++ ++ struct v4l2_ctrl_handler ctrls_vcm; ++ struct v4l2_subdev sd; ++ struct regmap *cci; ++ ++ u16 current_val; ++ struct regulator *vdd; ++ struct notifier_block notifier; ++}; ++ ++static inline struct bu64754 *sd_to_bu64754(struct v4l2_subdev *subdev) ++{ ++ return container_of(subdev, struct bu64754, sd); ++} ++ ++static int bu64754_set(struct bu64754 *bu64754, u16 position) ++{ ++ int ret; ++ ++ position &= 0x3ff; /* BU64753_POSITION_MAX */ ++ ret = cci_write(bu64754->cci, BU64754_REG_POSITION, position, NULL); ++ if (ret) { ++ dev_err(bu64754->dev, "Set position failed ret=%d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int bu64754_active(struct bu64754 *bu64754) ++{ ++ int ret; ++ ++ /* Power on */ ++ ret = cci_write(bu64754->cci, BU64754_REG_ACTIVE, BU64754_ACTIVE_MODE, NULL); ++ if (ret < 0) { ++ dev_err(bu64754->dev, "Failed to set active mode ret = %d\n", ++ ret); ++ return ret; ++ } ++ ++ /* Serve on */ ++ ret = cci_write(bu64754->cci, BU64754_REG_SERVE, BU64754_SERVE_ON, NULL); ++ if (ret < 0) { ++ dev_err(bu64754->dev, "Failed to enable serve ret = %d\n", ++ ret); ++ return ret; ++ } ++ ++ return bu64754_set(bu64754, bu64754->current_val); ++} ++ ++static int bu64754_standby(struct bu64754 *bu64754) ++{ ++ int ret; ++ ++ ret = cci_write(bu64754->cci, BU64754_REG_ACTIVE, 0, NULL); ++ if (ret < 0) ++ dev_err(bu64754->dev, "Failed to enter standby mode ret = %d\n", ++ ret); ++ ++ return ret; ++} ++ ++static int bu64754_regulator_event(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct bu64754 *bu64754 = container_of(nb, struct bu64754, notifier); ++ ++ if (action & REGULATOR_EVENT_ENABLE) { ++ /* ++ * Initialisation delay between VDD low->high and availability ++ * i2c operation. ++ */ ++ usleep_range(BU64754_POWER_ON_DELAY, ++ BU64754_POWER_ON_DELAY + 100); ++ ++ bu64754_active(bu64754); ++ } else if (action & REGULATOR_EVENT_PRE_DISABLE) { ++ bu64754_standby(bu64754); ++ } ++ ++ return 0; ++} ++ ++static int bu64754_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct bu64754 *bu64754 = container_of(ctrl->handler, ++ struct bu64754, ctrls_vcm); ++ ++ if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { ++ bu64754->current_val = ctrl->val; ++ return bu64754_set(bu64754, ctrl->val); ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops bu64754_vcm_ctrl_ops = { ++ .s_ctrl = bu64754_set_ctrl, ++}; ++ ++static int bu64754_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ return pm_runtime_resume_and_get(sd->dev); ++} ++ ++static int bu64754_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ pm_runtime_put(sd->dev); ++ return 0; ++} ++ ++static const struct v4l2_subdev_internal_ops bu64754_int_ops = { ++ .open = bu64754_open, ++ .close = bu64754_close, ++}; ++ ++static const struct v4l2_subdev_ops bu64754_ops = { }; ++ ++static void bu64754_subdev_cleanup(struct bu64754 *bu64754) ++{ ++ v4l2_async_unregister_subdev(&bu64754->sd); ++ v4l2_ctrl_handler_free(&bu64754->ctrls_vcm); ++ media_entity_cleanup(&bu64754->sd.entity); ++} ++ ++static int bu64754_init_controls(struct bu64754 *bu64754) ++{ ++ struct v4l2_ctrl_handler *hdl = &bu64754->ctrls_vcm; ++ const struct v4l2_ctrl_ops *ops = &bu64754_vcm_ctrl_ops; ++ ++ v4l2_ctrl_handler_init(hdl, 1); ++ ++ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, ++ 0, BU64753_POSITION_MAX, BU64753_POSITION_STEPS, ++ 0); ++ ++ bu64754->current_val = 0; ++ ++ bu64754->sd.ctrl_handler = hdl; ++ if (hdl->error) { ++ dev_err(bu64754->dev, "%s fail error: 0x%x\n", ++ __func__, hdl->error); ++ return hdl->error; ++ } ++ ++ return 0; ++} ++ ++static int bu64754_probe(struct i2c_client *client) ++{ ++ struct bu64754 *bu64754; ++ int ret; ++ ++ bu64754 = devm_kzalloc(&client->dev, sizeof(*bu64754), GFP_KERNEL); ++ if (!bu64754) ++ return -ENOMEM; ++ ++ bu64754->dev = &client->dev; ++ ++ bu64754->cci = devm_cci_regmap_init_i2c(client, 8); ++ if (IS_ERR(bu64754->cci)) { ++ dev_err(bu64754->dev, "Failed to initialize CCI\n"); ++ return PTR_ERR(bu64754->cci); ++ } ++ ++ bu64754->vdd = devm_regulator_get_optional(&client->dev, "vdd"); ++ if (IS_ERR(bu64754->vdd)) { ++ if (PTR_ERR(bu64754->vdd) != -ENODEV) ++ return PTR_ERR(bu64754->vdd); ++ ++ bu64754->vdd = NULL; ++ } else { ++ bu64754->notifier.notifier_call = bu64754_regulator_event; ++ ++ ret = regulator_register_notifier(bu64754->vdd, ++ &bu64754->notifier); ++ if (ret) { ++ dev_err(bu64754->dev, ++ "could not register regulator notifier\n"); ++ return ret; ++ } ++ } ++ ++ v4l2_i2c_subdev_init(&bu64754->sd, client, &bu64754_ops); ++ bu64754->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ bu64754->sd.internal_ops = &bu64754_int_ops; ++ bu64754->sd.entity.function = MEDIA_ENT_F_LENS; ++ ++ ret = bu64754_init_controls(bu64754); ++ if (ret) ++ goto err_cleanup; ++ ++ ret = media_entity_pads_init(&bu64754->sd.entity, 0, NULL); ++ if (ret < 0) ++ goto err_cleanup; ++ ++ bu64754->sd.entity.function = MEDIA_ENT_F_LENS; ++ ++ ret = v4l2_async_register_subdev(&bu64754->sd); ++ if (ret < 0) ++ goto err_cleanup; ++ ++ if (!bu64754->vdd) ++ pm_runtime_set_active(&client->dev); ++ ++ pm_runtime_enable(&client->dev); ++ pm_runtime_idle(&client->dev); ++ ++ return 0; ++ ++err_cleanup: ++ v4l2_ctrl_handler_free(&bu64754->ctrls_vcm); ++ media_entity_cleanup(&bu64754->sd.entity); ++ ++ return ret; ++} ++ ++static void bu64754_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct bu64754 *bu64754 = sd_to_bu64754(sd); ++ ++ if (bu64754->vdd) ++ regulator_unregister_notifier(bu64754->vdd, ++ &bu64754->notifier); ++ ++ pm_runtime_disable(&client->dev); ++ ++ bu64754_subdev_cleanup(bu64754); ++} ++ ++static int __maybe_unused bu64754_vcm_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct bu64754 *bu64754 = sd_to_bu64754(sd); ++ ++ if (bu64754->vdd) ++ return regulator_disable(bu64754->vdd); ++ ++ return bu64754_standby(bu64754); ++} ++ ++static int __maybe_unused bu64754_vcm_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct bu64754 *bu64754 = sd_to_bu64754(sd); ++ ++ if (bu64754->vdd) ++ return regulator_enable(bu64754->vdd); ++ ++ return bu64754_active(bu64754); ++} ++ ++static const struct of_device_id bu64754_of_table[] = { ++ { .compatible = "rohm,bu64754", }, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(of, bu64754_of_table); ++ ++static const struct dev_pm_ops bu64754_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(bu64754_vcm_suspend, bu64754_vcm_resume) ++ SET_RUNTIME_PM_OPS(bu64754_vcm_suspend, bu64754_vcm_resume, NULL) ++}; ++ ++static struct i2c_driver bu64754_i2c_driver = { ++ .driver = { ++ .name = "bu64754", ++ .pm = &bu64754_pm_ops, ++ .of_match_table = bu64754_of_table, ++ }, ++ .probe_new = bu64754_probe, ++ .remove = bu64754_remove, ++}; ++ ++module_i2c_driver(bu64754_i2c_driver); ++ ++MODULE_AUTHOR("Kieran Bingham"); ++MODULE_DESCRIPTION("BU64754 VCM driver"); ++MODULE_LICENSE("GPL"); ++ diff --git a/target/linux/bcm27xx/patches-6.1/950-1197-overlays-Add-overlay-for-the-OV64A40-Arducam-Camera-.patch b/target/linux/bcm27xx/patches-6.1/950-1197-overlays-Add-overlay-for-the-OV64A40-Arducam-Camera-.patch new file mode 100644 index 0000000000..d3ee0dc68e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1197-overlays-Add-overlay-for-the-OV64A40-Arducam-Camera-.patch @@ -0,0 +1,426 @@ +From 7f67a45ee7c008c3d8e45fde6fa9c4287fb3bc9e Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Thu, 20 Jul 2023 13:18:34 +0200 +Subject: [PATCH] overlays: Add overlay for the OV64A40 Arducam Camera Module + +Arducam have integrated an Omnivision OV64A40 with a ROHM BU64754 VCM +with a Raspberry Pi compatible cable pinout. + +Provide an overlay to support the module. + +Also add support to the camera mux overlays. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Kieran Bingham +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 25 +++++ + .../dts/overlays/camera-mux-2port-overlay.dts | 32 +++++++ + .../dts/overlays/camera-mux-4port-overlay.dts | 64 +++++++++++++ + .../arm/boot/dts/overlays/ov64a40-overlay.dts | 91 +++++++++++++++++++ + arch/arm/boot/dts/overlays/ov64a40.dtsi | 34 +++++++ + 6 files changed, 247 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/ov64a40-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ov64a40.dtsi + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -175,6 +175,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + mz61581.dtbo \ + ov2311.dtbo \ + ov5647.dtbo \ ++ ov64a40.dtbo \ + ov7251.dtbo \ + ov9281.dtbo \ + papirus.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -817,6 +817,7 @@ Params: cam0-arducam-64mp Select A + cam0-imx708 Select IMX708 for camera on port 0 + cam0-ov2311 Select OV2311 for camera on port 0 + cam0-ov5647 Select OV5647 for camera on port 0 ++ cam0-ov64a40 Select OV64A40 for camera on port 0 + cam0-ov7251 Select OV7251 for camera on port 0 + cam0-ov9281 Select OV9281 for camera on port 0 + cam0-imx290-clk-freq Set clock frequency for an IMX290 on port 0 +@@ -829,6 +830,7 @@ Params: cam0-arducam-64mp Select A + cam1-imx708 Select IMX708 for camera on port 1 + cam1-ov2311 Select OV2311 for camera on port 1 + cam1-ov5647 Select OV5647 for camera on port 1 ++ cam1-ov64a40 Select OV64A40 for camera on port 1 + cam1-ov7251 Select OV7251 for camera on port 1 + cam1-ov9281 Select OV9281 for camera on port 1 + cam1-imx290-clk-freq Set clock frequency for an IMX290 on port 1 +@@ -850,6 +852,7 @@ Params: cam0-arducam-64mp Select A + cam0-imx708 Select IMX708 for camera on port 0 + cam0-ov2311 Select OV2311 for camera on port 0 + cam0-ov5647 Select OV5647 for camera on port 0 ++ cam0-ov64a40 Select OV64A40 for camera on port 0 + cam0-ov7251 Select OV7251 for camera on port 0 + cam0-ov9281 Select OV9281 for camera on port 0 + cam0-imx290-clk-freq Set clock frequency for an IMX290 on port 0 +@@ -862,6 +865,7 @@ Params: cam0-arducam-64mp Select A + cam1-imx708 Select IMX708 for camera on port 1 + cam1-ov2311 Select OV2311 for camera on port 1 + cam1-ov5647 Select OV5647 for camera on port 1 ++ cam1-ov64a40 Select OV64A40 for camera on port 1 + cam1-ov7251 Select OV7251 for camera on port 1 + cam1-ov9281 Select OV9281 for camera on port 1 + cam1-imx290-clk-freq Set clock frequency for an IMX290 on port 1 +@@ -874,6 +878,7 @@ Params: cam0-arducam-64mp Select A + cam2-imx708 Select IMX708 for camera on port 2 + cam2-ov2311 Select OV2311 for camera on port 2 + cam2-ov5647 Select OV5647 for camera on port 2 ++ cam2-ov64a40 Select OV64A40 for camera on port 2 + cam2-ov7251 Select OV7251 for camera on port 2 + cam2-ov9281 Select OV9281 for camera on port 2 + cam2-imx290-clk-freq Set clock frequency for an IMX290 on port 2 +@@ -886,6 +891,7 @@ Params: cam0-arducam-64mp Select A + cam3-imx708 Select IMX708 for camera on port 3 + cam3-ov2311 Select OV2311 for camera on port 3 + cam3-ov5647 Select OV5647 for camera on port 3 ++ cam3-ov64a40 Select OV64A40 for camera on port 3 + cam3-ov7251 Select OV7251 for camera on port 3 + cam3-ov9281 Select OV9281 for camera on port 3 + cam3-imx290-clk-freq Set clock frequency for an IMX290 on port 3 +@@ -3222,6 +3228,25 @@ Params: rotation Mounting + vcm Configure a VCM focus drive on the sensor. + + ++Name: ov64a40 ++Info: Arducam OV64A40 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=ov64a40,= ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ vcm Select lens driver state. Default is enabled, ++ but vcm=off will disable. ++ link-frequency Allowable link frequency values to use in Hz: ++ 456000000 (default), 360000000 ++ ++ + Name: ov7251 + Info: Omnivision OV7251 camera module. + Uses Unicam 1, which is the standard camera connector on most Pi +--- a/arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts ++++ b/arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts +@@ -189,6 +189,16 @@ + #undef cam_node + #undef cam_endpoint + #undef cam1_clk ++ ++ #define cam_node ov64a40_0 ++ #define cam_endpoint ov64a40_0_ep ++ #define vcm_node ov64a40_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk + }; + + i2c@1 { +@@ -289,6 +299,16 @@ + #undef cam_node + #undef cam_endpoint + #undef cam1_clk ++ ++ #define cam_node ov64a40_1 ++ #define cam_endpoint ov64a40_1_ep ++ #define vcm_node ov64a40_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk + }; + }; + }; +@@ -450,6 +470,12 @@ + cam0-ov2311 = <&mux_in0>, "remote-endpoint:0=",<&ov2311_0_ep>, + <&ov2311_0_ep>, "remote-endpoint:0=",<&mux_in0>, + <&ov2311_0>, "status=okay"; ++ cam0-ov64a40 = <&mux_in0>, "remote-endpoint:0=",<&ov64a40_0_ep>, ++ <&ov64a40_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&ov64a40_0>, "status=okay", ++ <&ov64a40_0_vcm>, "status=okay", ++ <&ov64a40_0>,"lens-focus:0=", <&ov64a40_0_vcm>; + + cam1-arducam-64mp = <&mux_in1>, "remote-endpoint:0=",<&arducam_64mp_1_ep>, + <&arducam_64mp_1_ep>, "remote-endpoint:0=",<&mux_in1>, +@@ -496,6 +522,12 @@ + cam1-ov2311 = <&mux_in1>, "remote-endpoint:0=",<&ov2311_1_ep>, + <&ov2311_1_ep>, "remote-endpoint:0=",<&mux_in1>, + <&ov2311_1>, "status=okay"; ++ cam1-ov64a40 = <&mux_in1>, "remote-endpoint:0=",<&ov64a40_1_ep>, ++ <&ov64a40_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&ov64a40_1>, "status=okay", ++ <&ov64a40_1_vcm>, "status=okay", ++ <&ov64a40_1>,"lens-focus:0=", <&ov64a40_1_vcm>; + + cam0-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", + <&imx290_0>,"clock-frequency:0"; +--- a/arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts ++++ b/arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts +@@ -247,6 +247,16 @@ + #undef cam_node + #undef cam_endpoint + #undef cam1_clk ++ ++ #define cam_node ov64a40_0 ++ #define cam_endpoint ov64a40_0_ep ++ #define vcm_node ov64a40_0_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk + }; + + i2c@1 { +@@ -347,6 +357,16 @@ + #undef cam_node + #undef cam_endpoint + #undef cam1_clk ++ ++ #define cam_node ov64a40_1 ++ #define cam_endpoint ov64a40_1_ep ++ #define vcm_node ov64a40_1_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk + }; + + i2c@2 { +@@ -447,6 +467,16 @@ + #undef cam_node + #undef cam_endpoint + #undef cam1_clk ++ ++ #define cam_node ov64a40_2 ++ #define cam_endpoint ov64a40_2_ep ++ #define vcm_node ov64a40_2_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk + }; + + i2c@3 { +@@ -547,6 +577,16 @@ + #undef cam_node + #undef cam_endpoint + #undef cam1_clk ++ ++ #define cam_node ov64a40_3 ++ #define cam_endpoint ov64a40_3_ep ++ #define vcm_node ov64a40_3_vcm ++ #define cam1_clk clk_24mhz ++ #include "ov64a40.dtsi" ++ #undef cam_node ++ #undef cam_endpoint ++ #undef vcm_node ++ #undef cam1_clk + }; + }; + }; +@@ -725,6 +765,12 @@ + cam0-ov2311 = <&mux_in0>, "remote-endpoint:0=",<&ov2311_0_ep>, + <&ov2311_0_ep>, "remote-endpoint:0=",<&mux_in0>, + <&ov2311_0>, "status=okay"; ++ cam0-ov64a40 = <&mux_in0>, "remote-endpoint:0=",<&ov64a40_0_ep>, ++ <&ov64a40_0_ep>, "remote-endpoint:0=",<&mux_in0>, ++ <&mux_in0>, "clock-noncontinuous?", ++ <&ov64a40_0>, "status=okay", ++ <&ov64a40_0_vcm>, "status=okay", ++ <&ov64a40_0>,"lens-focus:0=", <&ov64a40_0_vcm>; + + cam1-arducam-64mp = <&mux_in1>, "remote-endpoint:0=",<&arducam_64mp_1_ep>, + <&arducam_64mp_1_ep>, "remote-endpoint:0=",<&mux_in1>, +@@ -771,6 +817,12 @@ + cam1-ov2311 = <&mux_in1>, "remote-endpoint:0=",<&ov2311_1_ep>, + <&ov2311_1_ep>, "remote-endpoint:0=",<&mux_in1>, + <&ov2311_1>, "status=okay"; ++ cam1-ov64a40 = <&mux_in1>, "remote-endpoint:0=",<&ov64a40_1_ep>, ++ <&ov64a40_1_ep>, "remote-endpoint:0=",<&mux_in1>, ++ <&mux_in1>, "clock-noncontinuous?", ++ <&ov64a40_1>, "status=okay", ++ <&ov64a40_1_vcm>, "status=okay", ++ <&ov64a40_1>,"lens-focus:0=", <&ov64a40_1_vcm>; + + cam2-arducam-64mp = <&mux_in2>, "remote-endpoint:0=",<&arducam_64mp_2_ep>, + <&arducam_64mp_2_ep>, "remote-endpoint:0=",<&mux_in2>, +@@ -817,6 +869,12 @@ + cam2-ov2311 = <&mux_in2>, "remote-endpoint:0=",<&ov2311_2_ep>, + <&ov2311_2_ep>, "remote-endpoint:0=",<&mux_in2>, + <&ov2311_2>, "status=okay"; ++ cam2-ov64a40 = <&mux_in2>, "remote-endpoint:0=",<&ov64a40_2_ep>, ++ <&ov64a40_2_ep>, "remote-endpoint:0=",<&mux_in2>, ++ <&mux_in2>, "clock-noncontinuous?", ++ <&ov64a40_2>, "status=okay", ++ <&ov64a40_2_vcm>, "status=okay", ++ <&ov64a40_2>,"lens-focus:0=", <&ov64a40_2_vcm>; + + cam3-arducam-64mp = <&mux_in3>, "remote-endpoint:0=",<&arducam_64mp_3_ep>, + <&arducam_64mp_3_ep>, "remote-endpoint:0=",<&mux_in3>, +@@ -863,6 +921,12 @@ + cam3-ov2311 = <&mux_in3>, "remote-endpoint:0=",<&ov2311_3_ep>, + <&ov2311_3_ep>, "remote-endpoint:0=",<&mux_in3>, + <&ov2311_3>, "status=okay"; ++ cam3-ov64a40 = <&mux_in3>, "remote-endpoint:0=",<&ov64a40_3_ep>, ++ <&ov64a40_3_ep>, "remote-endpoint:0=",<&mux_in3>, ++ <&mux_in3>, "clock-noncontinuous?", ++ <&ov64a40_3>, "status=okay", ++ <&ov64a40_3_vcm>, "status=okay", ++ <&ov64a40_3>,"lens-focus:0=", <&ov64a40_3_vcm>; + + cam0-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0", + <&imx290_0>,"clock-frequency:0"; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ov64a40-overlay.dts +@@ -0,0 +1,91 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for OV64A40 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ i2c_frag: fragment@0 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "ov64a40.dtsi" ++ }; ++ }; ++ ++ csi_frag: fragment@1 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port{ ++ csi_ep: endpoint{ ++ remote-endpoint = <&cam_endpoint>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ clk_frag: fragment@3 { ++ target = <&cam1_clk>; ++ __overlay__ { ++ clock-frequency = <24000000>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&cam_node>; ++ __overlay__ { ++ lens-focus = <&vcm_node>; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&clk_frag>, "target:0=",<&cam0_clk>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "avdd-supply:0=",<&cam0_reg>, ++ <&vcm_node>, "vdd-supply:0=",<&cam0_reg>; ++ vcm = <&vcm_node>, "status", ++ <0>, "=5"; ++ link-frequency = <&cam_endpoint>,"link-frequencies#0"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; ++ ++&vcm_node { ++ status = "okay"; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ov64a40.dtsi +@@ -0,0 +1,34 @@ ++// Fragment that configures an OV64A40 ++ ++cam_node: ov64a40@36 { ++ compatible = "ovti,ov64a40"; ++ reg = <0x36>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "xclk"; ++ ++ avdd-supply = <&cam1_reg>; /* 2.8v */ ++ dovdd-supply = <&cam_dummy_reg>;/* 1.8v */ ++ dvdd-supply = <&cam_dummy_reg>; /* 1.1v */ ++ ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ bus-type = <4>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ link-frequencies = ++ /bits/ 64 <456000000>; ++ }; ++ }; ++}; ++ ++vcm_node: bu64754@76 { ++ compatible = "rohm,bu64754"; ++ reg = <0x76>; ++ status = "disabled"; ++ vdd-supply = <&cam1_reg>; ++}; diff --git a/target/linux/bcm27xx/patches-6.1/950-1199-media-rp1-cfe-Fix-verbose-debug-print.patch b/target/linux/bcm27xx/patches-6.1/950-1199-media-rp1-cfe-Fix-verbose-debug-print.patch new file mode 100644 index 0000000000..8ff96cc568 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1199-media-rp1-cfe-Fix-verbose-debug-print.patch @@ -0,0 +1,26 @@ +From 8ef68aadaa3aa29bc2661ab44db4ddc50e77cef5 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Wed, 4 Oct 2023 11:25:16 +0300 +Subject: [PATCH] media: rp1: cfe: Fix verbose debug print + +Switch a debug print from cfe_dbg() to cfe_dbg_verbose() as it will be +printed often while streaming. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -975,8 +975,8 @@ static void cfe_buffer_queue(struct vb2_ + + if (!cfe->job_queued && cfe->job_ready && + test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) { +- cfe_dbg("Preparing job immediately for channel %u\n", +- node->id); ++ cfe_dbg_verbose("Preparing job immediately for channel %u\n", ++ node->id); + cfe_prepare_next_job(cfe); + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-1200-media-rp1-cfe-Expose-find_format_by_pix.patch b/target/linux/bcm27xx/patches-6.1/950-1200-media-rp1-cfe-Expose-find_format_by_pix.patch new file mode 100644 index 0000000000..f263648af2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1200-media-rp1-cfe-Expose-find_format_by_pix.patch @@ -0,0 +1,33 @@ +From d978e784f433346d3676b5de805b3cea36b835c4 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 29 Sep 2023 16:23:58 +0300 +Subject: [PATCH] media: rp1: cfe: Expose find_format_by_pix() + +Make find_format_by_pix() accessible to other files in the driver. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 2 +- + drivers/media/platform/raspberrypi/rp1_cfe/cfe.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -461,7 +461,7 @@ const struct cfe_fmt *find_format_by_cod + return NULL; + } + +-static const struct cfe_fmt *find_format_by_pix(u32 pixelformat) ++const struct cfe_fmt *find_format_by_pix(u32 pixelformat) + { + unsigned int i; + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h +@@ -36,5 +36,6 @@ extern const struct v4l2_mbus_framefmt c + extern const struct v4l2_mbus_framefmt cfe_default_meta_format; + + const struct cfe_fmt *find_format_by_code(u32 code); ++const struct cfe_fmt *find_format_by_pix(u32 pixelformat); + + #endif diff --git a/target/linux/bcm27xx/patches-6.1/950-1201-media-rp1-cfe-Add-missing-remaps.patch b/target/linux/bcm27xx/patches-6.1/950-1201-media-rp1-cfe-Add-missing-remaps.patch new file mode 100644 index 0000000000..d6dadb6f27 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1201-media-rp1-cfe-Add-missing-remaps.patch @@ -0,0 +1,43 @@ +From cbed711f05a228d0f8f54b1b01f43d4d6489eccc Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 29 Sep 2023 16:24:14 +0300 +Subject: [PATCH] media: rp1: cfe: Add missing remaps + +8-bit bayer formats are missing remap definitions. Add them. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h +@@ -85,24 +85,28 @@ static const struct cfe_fmt formats[] = + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .depth = 8, + .csi_dt = 0x2a, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .depth = 8, + .csi_dt = 0x2a, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .depth = 8, + .csi_dt = 0x2a, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .depth = 8, + .csi_dt = 0x2a, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10P, diff --git a/target/linux/bcm27xx/patches-6.1/950-1202-media-rp1-cfe-Add-missing-compressed-remaps.patch b/target/linux/bcm27xx/patches-6.1/950-1202-media-rp1-cfe-Add-missing-compressed-remaps.patch new file mode 100644 index 0000000000..92d7db369c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1202-media-rp1-cfe-Add-missing-compressed-remaps.patch @@ -0,0 +1,43 @@ +From 93c40564b94367c6ce072d66479af58afa3f08e0 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 29 Sep 2023 17:14:31 +0300 +Subject: [PATCH] media: rp1: cfe: Add missing compressed remaps + +16-bit bayer formats are missing compressed remap definitions. Add them. + +Signed-off-by: Tomi Valkeinen +--- + drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe_fmts.h +@@ -197,24 +197,28 @@ static const struct cfe_fmt formats[] = + .code = MEDIA_BUS_FMT_SBGGR16_1X16, + .depth = 16, + .flags = CFE_FORMAT_FLAG_FE_OUT, ++ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .code = MEDIA_BUS_FMT_SGBRG16_1X16, + .depth = 16, + .flags = CFE_FORMAT_FLAG_FE_OUT, ++ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .code = MEDIA_BUS_FMT_SGRBG16_1X16, + .depth = 16, + .flags = CFE_FORMAT_FLAG_FE_OUT, ++ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB16, + .code = MEDIA_BUS_FMT_SRGGB16_1X16, + .depth = 16, + .flags = CFE_FORMAT_FLAG_FE_OUT, ++ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + /* PiSP Compressed Mode 1 */ + { diff --git a/target/linux/bcm27xx/patches-6.1/950-1203-media-rp1-cfe-Add-cfe_find_16bit_code-and-cfe_find_c.patch b/target/linux/bcm27xx/patches-6.1/950-1203-media-rp1-cfe-Add-cfe_find_16bit_code-and-cfe_find_c.patch new file mode 100644 index 0000000000..42c3b6f42b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1203-media-rp1-cfe-Add-cfe_find_16bit_code-and-cfe_find_c.patch @@ -0,0 +1,74 @@ +From 2e0e1d7b493dffe7baa763d499e51ba42f0bad19 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 29 Sep 2023 17:14:11 +0300 +Subject: [PATCH] media: rp1: cfe: Add cfe_find_16bit_code() and + cfe_find_compressed_code() + +Add helper functions which, given an mbus code, return the 16-bit +remapped mbus code or the compressed mbus code. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 40 +++++++++++++++++++ + .../media/platform/raspberrypi/rp1_cfe/cfe.h | 2 + + 2 files changed, 42 insertions(+) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -473,6 +473,46 @@ const struct cfe_fmt *find_format_by_pix + return NULL; + } + ++/* ++ * Given the mbus code, find the 16 bit remapped code. Returns 0 if no remap ++ * possible. ++ */ ++u32 cfe_find_16bit_code(u32 code) ++{ ++ const struct cfe_fmt *cfe_fmt; ++ ++ cfe_fmt = find_format_by_code(code); ++ ++ if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_16BIT]) ++ return 0; ++ ++ cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_16BIT]); ++ if (!cfe_fmt) ++ return 0; ++ ++ return cfe_fmt->code; ++} ++ ++/* ++ * Given the mbus code, find the 8 bit compressed code. Returns 0 if no remap ++ * possible. ++ */ ++u32 cfe_find_compressed_code(u32 code) ++{ ++ const struct cfe_fmt *cfe_fmt; ++ ++ cfe_fmt = find_format_by_code(code); ++ ++ if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_COMPRESSED]) ++ return 0; ++ ++ cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_COMPRESSED]); ++ if (!cfe_fmt) ++ return 0; ++ ++ return cfe_fmt->code; ++} ++ + static int cfe_calc_format_size_bpl(struct cfe_device *cfe, + const struct cfe_fmt *fmt, + struct v4l2_format *f) +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.h +@@ -37,5 +37,7 @@ extern const struct v4l2_mbus_framefmt c + + const struct cfe_fmt *find_format_by_code(u32 code); + const struct cfe_fmt *find_format_by_pix(u32 pixelformat); ++u32 cfe_find_16bit_code(u32 code); ++u32 cfe_find_compressed_code(u32 code); + + #endif diff --git a/target/linux/bcm27xx/patches-6.1/950-1204-media-rp1-csi2-Fix-csi2_pad_set_fmt.patch b/target/linux/bcm27xx/patches-6.1/950-1204-media-rp1-csi2-Fix-csi2_pad_set_fmt.patch new file mode 100644 index 0000000000..d9b8d264d3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1204-media-rp1-csi2-Fix-csi2_pad_set_fmt.patch @@ -0,0 +1,95 @@ +From eaa8a0ae14a1ca797c1896e9dafbefa1fa51a617 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 29 Sep 2023 16:25:10 +0300 +Subject: [PATCH] media: rp1: csi2: Fix csi2_pad_set_fmt() + +The CSI-2 subdev's set_fmt currently allows setting the source and sink +pad formats quite freely. This is not right, as the CSI-2 block can only +do one of the following when processing the stream: 1) pass through as +is, 2) expand to 16-bits, 3) compress. + +The csi2_pad_set_fmt() should take this into account, and only allow +changing the source side mbus code, compared to the sink side format. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/csi2.c | 61 +++++++++++++++---- + 1 file changed, 48 insertions(+), 13 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -438,25 +438,60 @@ static int csi2_pad_set_fmt(struct v4l2_ + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) + { +- struct v4l2_mbus_framefmt *fmt; +- const struct cfe_fmt *cfe_fmt; +- +- /* TODO: format validation */ ++ if (format->pad < CSI2_NUM_CHANNELS) { ++ /* ++ * Store the sink pad format and propagate it to the source pad. ++ */ ++ ++ struct v4l2_mbus_framefmt *fmt; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); ++ if (!fmt) ++ return -EINVAL; + +- cfe_fmt = find_format_by_code(format->format.code); +- if (!cfe_fmt) +- cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10); ++ *fmt = format->format; + +- format->format.code = cfe_fmt->code; ++ fmt = v4l2_subdev_get_pad_format(sd, state, ++ format->pad + CSI2_NUM_CHANNELS); ++ if (!fmt) ++ return -EINVAL; + +- fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); +- *fmt = format->format; ++ format->format.field = V4L2_FIELD_NONE; + +- if (format->pad < CSI2_NUM_CHANNELS) { +- /* Propagate to the source pad */ +- fmt = v4l2_subdev_get_pad_format(sd, state, +- format->pad + CSI2_NUM_CHANNELS); + *fmt = format->format; ++ } else { ++ /* ++ * Only allow changing the source pad mbus code. ++ */ ++ ++ struct v4l2_mbus_framefmt *sink_fmt, *source_fmt; ++ u32 sink_code; ++ u32 code; ++ ++ sink_fmt = v4l2_subdev_get_pad_format(sd, state, ++ format->pad - CSI2_NUM_CHANNELS); ++ if (!sink_fmt) ++ return -EINVAL; ++ ++ source_fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); ++ if (!source_fmt) ++ return -EINVAL; ++ ++ sink_code = sink_fmt->code; ++ code = format->format.code; ++ ++ /* ++ * If the source code from the user does not match the code in ++ * the sink pad, check that the source code matches either the ++ * 16-bit version or the compressed version of the sink code. ++ */ ++ ++ if (code != sink_code && ++ (code == cfe_find_16bit_code(sink_code) || ++ code == cfe_find_compressed_code(sink_code))) ++ source_fmt->code = code; ++ ++ format->format.code = source_fmt->code; + } + + return 0; diff --git a/target/linux/bcm27xx/patches-6.1/950-1205-media-rp1-fe-Fix-pisp_fe_pad_set_fmt.patch b/target/linux/bcm27xx/patches-6.1/950-1205-media-rp1-fe-Fix-pisp_fe_pad_set_fmt.patch new file mode 100644 index 0000000000..202fe2946d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1205-media-rp1-fe-Fix-pisp_fe_pad_set_fmt.patch @@ -0,0 +1,104 @@ +From 214e8134842a338215831f2efa6d730f413c5ec4 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 29 Sep 2023 17:15:20 +0300 +Subject: [PATCH] media: rp1: fe: Fix pisp_fe_pad_set_fmt() + +pisp_fe_pad_set_fmt() allows setting the pad formats quite freely. This +is not correct, and the function should only allow formats as supported +by the hardware. Fix this by: + +Allow no format changes for FE_CONFIG_PAD and FE_STATS_PAD. They should +always be the hardcoded initial ones. + +Allow setting FE_STREAM_PAD freely (but the mbus code must be +supported), and propagate the format to the FE_OUTPUT0_PAD and +FE_OUTPUT1_PAD pads. + +Allow changing the mbus code for FE_OUTPUT0_PAD and FE_OUTPUT1_PAD pads +only if the mbus code is the compressed version of the sink side code. + +TODO: FE supports scaling and cropping. This should be represented here +too? + +Signed-off-by: Tomi Valkeinen +--- + .../platform/raspberrypi/rp1_cfe/pisp_fe.c | 59 +++++++++++++++---- + 1 file changed, 48 insertions(+), 11 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +@@ -433,26 +433,63 @@ static int pisp_fe_pad_set_fmt(struct v4 + + switch (format->pad) { + case FE_STREAM_PAD: +- case FE_OUTPUT0_PAD: +- case FE_OUTPUT1_PAD: + cfe_fmt = find_format_by_code(format->format.code); + if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT)) + cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16); + + format->format.code = cfe_fmt->code; ++ format->format.field = V4L2_FIELD_NONE; + +- break; ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_STREAM_PAD); ++ *fmt = format->format; + +- case FE_STATS_PAD: +- case FE_CONFIG_PAD: +- format->format.code = MEDIA_BUS_FMT_FIXED; +- break; +- } ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_OUTPUT0_PAD); ++ *fmt = format->format; ++ ++ fmt = v4l2_subdev_get_pad_format(sd, state, FE_OUTPUT1_PAD); ++ *fmt = format->format; ++ ++ return 0; + +- fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); +- *fmt = format->format; ++ case FE_OUTPUT0_PAD: ++ case FE_OUTPUT1_PAD: { ++ /* ++ * TODO: we should allow scaling and cropping by allowing the ++ * user to set the size here. ++ */ ++ struct v4l2_mbus_framefmt *sink_fmt, *source_fmt; ++ u32 sink_code; ++ u32 code; ++ ++ sink_fmt = v4l2_subdev_get_pad_format(sd, state, FE_STREAM_PAD); ++ if (!sink_fmt) ++ return -EINVAL; ++ ++ source_fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); ++ if (!source_fmt) ++ return -EINVAL; ++ ++ sink_code = sink_fmt->code; ++ code = format->format.code; ++ ++ /* ++ * If the source code from the user does not match the code in ++ * the sink pad, check that the source code matches the ++ * compressed version of the sink code. ++ */ ++ ++ if (code != sink_code && ++ code == cfe_find_compressed_code(sink_code)) ++ source_fmt->code = code; ++ ++ return 0; ++ } + +- return 0; ++ case FE_CONFIG_PAD: ++ case FE_STATS_PAD: ++ default: ++ return v4l2_subdev_get_fmt(sd, state, format); ++ } + } + + static int pisp_fe_link_validate(struct v4l2_subdev *sd, diff --git a/target/linux/bcm27xx/patches-6.1/950-1206-media-rp1-csi2-Use-get_frame_desc-to-get-CSI-2-VC-an.patch b/target/linux/bcm27xx/patches-6.1/950-1206-media-rp1-csi2-Use-get_frame_desc-to-get-CSI-2-VC-an.patch new file mode 100644 index 0000000000..bd5789a1b3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1206-media-rp1-csi2-Use-get_frame_desc-to-get-CSI-2-VC-an.patch @@ -0,0 +1,146 @@ +From 425a6b752c38b50c97220db37a67b18b281f56e5 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Thu, 21 Sep 2023 15:28:20 +0300 +Subject: [PATCH] media: rp1: csi2: Use get_frame_desc to get CSI-2 VC and DT + +Use get_frame_desc pad op for asking the CSI-2 VC and DT from the source +device driver, instead of hardcoding to VC 0, and getting the DT from a +formats table. To keep backward compatibility with sources that do not +implement get_frame_desc, implement a fallback mechanism that always +uses VC 0, and gets the DT from the formats table, based on the CSI2's +sink pad's format. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 4 +- + .../media/platform/raspberrypi/rp1_cfe/csi2.c | 75 ++++++++++++++++++- + .../media/platform/raspberrypi/rp1_cfe/csi2.h | 2 +- + 3 files changed, 77 insertions(+), 4 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -838,7 +838,7 @@ static void cfe_start_channel(struct cfe + * this is handled by the CSI2 AUTO_ARM mode. + */ + csi2_start_channel(&cfe->csi2, cfe->fe_csi2_channel, +- fmt->csi_dt, CSI2_MODE_FE_STREAMING, ++ CSI2_MODE_FE_STREAMING, + true, false, width, height); + csi2_set_buffer(&cfe->csi2, cfe->fe_csi2_channel, 0, 0, -1); + pisp_fe_start(&cfe->fe); +@@ -872,7 +872,7 @@ static void cfe_start_channel(struct cfe + } + } + /* Unconditionally start this CSI2 channel. */ +- csi2_start_channel(&cfe->csi2, node->id, fmt->csi_dt, ++ csi2_start_channel(&cfe->csi2, node->id, + mode, + /* Auto arm */ + false, +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -324,12 +324,84 @@ void csi2_set_compression(struct csi2_de + csi2_reg_write(csi2, CSI2_CH_COMP_CTRL(channel), compression); + } + ++static int csi2_get_vc_dt_fallback(struct csi2_device *csi2, ++ unsigned int channel, u8 *vc, u8 *dt) ++{ ++ struct v4l2_subdev *sd = &csi2->sd; ++ struct v4l2_subdev_state *state; ++ struct v4l2_mbus_framefmt *fmt; ++ const struct cfe_fmt *cfe_fmt; ++ ++ state = v4l2_subdev_get_locked_active_state(sd); ++ ++ /* Without Streams API, the channel number matches the sink pad */ ++ fmt = v4l2_subdev_get_pad_format(sd, state, channel); ++ if (!fmt) ++ return -EINVAL; ++ ++ cfe_fmt = find_format_by_code(fmt->code); ++ if (!cfe_fmt) ++ return -EINVAL; ++ ++ *vc = 0; ++ *dt = cfe_fmt->csi_dt; ++ ++ return 0; ++} ++ ++static int csi2_get_vc_dt(struct csi2_device *csi2, unsigned int channel, ++ u8 *vc, u8 *dt) ++{ ++ struct v4l2_mbus_frame_desc remote_desc; ++ const struct media_pad *remote_pad; ++ struct v4l2_subdev *source_sd; ++ int ret; ++ ++ /* Without Streams API, the channel number matches the sink pad */ ++ remote_pad = media_pad_remote_pad_first(&csi2->pad[channel]); ++ if (!remote_pad) ++ return -EPIPE; ++ ++ source_sd = media_entity_to_v4l2_subdev(remote_pad->entity); ++ ++ ret = v4l2_subdev_call(source_sd, pad, get_frame_desc, ++ remote_pad->index, &remote_desc); ++ if (ret == -ENOIOCTLCMD) { ++ csi2_dbg("source does not support get_frame_desc, use fallback\n"); ++ return csi2_get_vc_dt_fallback(csi2, channel, vc, dt); ++ } else if (ret) { ++ csi2_err("Failed to get frame descriptor\n"); ++ return ret; ++ } ++ ++ if (remote_desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { ++ csi2_err("Frame descriptor does not describe CSI-2 link"); ++ return -EINVAL; ++ } ++ ++ if (remote_desc.num_entries != 1) { ++ csi2_err("Frame descriptor does not have a single entry"); ++ return -EINVAL; ++ } ++ ++ *vc = remote_desc.entry[0].bus.csi2.vc; ++ *dt = remote_desc.entry[0].bus.csi2.dt; ++ ++ return 0; ++} ++ + void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, +- u16 dt, enum csi2_mode mode, bool auto_arm, ++ enum csi2_mode mode, bool auto_arm, + bool pack_bytes, unsigned int width, + unsigned int height) + { + u32 ctrl; ++ int ret; ++ u8 vc, dt; ++ ++ ret = csi2_get_vc_dt(csi2, channel, &vc, &dt); ++ if (ret) ++ return; + + csi2_dbg("%s [%u]\n", __func__, channel); + +@@ -369,6 +441,7 @@ void csi2_start_channel(struct csi2_devi + csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), 0); + } + ++ set_field(&ctrl, vc, VC_MASK); + set_field(&ctrl, dt, DT_MASK); + csi2_reg_write(csi2, CSI2_CH_CTRL(channel), ctrl); + csi2->num_lines[channel] = height; +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h +@@ -79,7 +79,7 @@ void csi2_set_compression(struct csi2_de + enum csi2_compression_mode mode, unsigned int shift, + unsigned int offset); + void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, +- u16 dt, enum csi2_mode mode, bool auto_arm, ++ enum csi2_mode mode, bool auto_arm, + bool pack_bytes, unsigned int width, + unsigned int height); + void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel); diff --git a/target/linux/bcm27xx/patches-6.1/950-1207-media-rp1-cfe-Add-is_image_node.patch b/target/linux/bcm27xx/patches-6.1/950-1207-media-rp1-cfe-Add-is_image_node.patch new file mode 100644 index 0000000000..ad589d79cf --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1207-media-rp1-cfe-Add-is_image_node.patch @@ -0,0 +1,91 @@ +From 2b6570e66f2769110311593f52f88dba3271a278 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Fri, 22 Sep 2023 13:47:10 +0300 +Subject: [PATCH] media: rp1: cfe: Add is_image_node() + +The hardware supports streaming from memory (in addition to streaming +from the CSI-2 RX), but the driver does not support this at the moment. + +There are multiple places in the driver which uses +is_image_output_node(), even if the "output" part is not relevant. Thus, +in a minor preparation for the possible support for streaming from +memory, and to make it more obvious that the pieces of code are not +about the "output", add is_image_node() which will return true for both +input and output video nodes. + +While at it, reformat also the metadata related macros to fit inside 80 +columns. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 28 +++++++++++-------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -199,13 +199,20 @@ static const struct node_description nod + + #define is_fe_node(node) (((node)->id) >= FE_OUT0) + #define is_csi2_node(node) (!is_fe_node(node)) +-#define is_image_output_node(node) \ ++ ++#define is_image_output_node(node) \ + (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) +-#define is_meta_output_node(node) \ ++#define is_image_input_node(node) \ ++ (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ++#define is_image_node(node) \ ++ (is_image_output_node(node) || is_image_input_node(node)) ++ ++#define is_meta_output_node(node) \ + (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_META_CAPTURE) +-#define is_meta_input_node(node) \ ++#define is_meta_input_node(node) \ + (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_META_OUTPUT) +-#define is_meta_node(node) (is_meta_output_node(node) || is_meta_input_node(node)) ++#define is_meta_node(node) \ ++ (is_meta_output_node(node) || is_meta_input_node(node)) + + /* To track state across all nodes. */ + #define NUM_STATES 5 +@@ -426,7 +433,7 @@ static int format_show(struct seq_file * + seq_printf(s, "\nNode %u (%s) state: 0x%lx\n", i, + node_desc[i].name, state); + +- if (is_image_output_node(node)) ++ if (is_image_node(node)) + seq_printf(s, "format: " V4L2_FOURCC_CONV " 0x%x\n" + "resolution: %ux%u\nbpl: %u\nsize: %u\n", + V4L2_FOURCC_CONV_ARGS(node->fmt.fmt.pix.pixelformat), +@@ -940,9 +947,8 @@ static int cfe_queue_setup(struct vb2_qu + { + struct cfe_node *node = vb2_get_drv_priv(vq); + struct cfe_device *cfe = node->cfe; +- unsigned int size = is_image_output_node(node) ? +- node->fmt.fmt.pix.sizeimage : +- node->fmt.fmt.meta.buffersize; ++ unsigned int size = is_image_node(node) ? node->fmt.fmt.pix.sizeimage : ++ node->fmt.fmt.meta.buffersize; + + cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); + +@@ -973,8 +979,8 @@ static int cfe_buffer_prepare(struct vb2 + cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__, + node_desc[node->id].name, vb); + +- size = is_image_output_node(node) ? node->fmt.fmt.pix.sizeimage : +- node->fmt.fmt.meta.buffersize; ++ size = is_image_node(node) ? node->fmt.fmt.pix.sizeimage : ++ node->fmt.fmt.meta.buffersize; + if (vb2_plane_size(vb, 0) < size) { + cfe_err("data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); +@@ -1757,7 +1763,7 @@ static int cfe_register_node(struct cfe_ + node->cfe = cfe; + node->id = id; + +- if (is_image_output_node(node)) { ++ if (is_image_node(node)) { + fmt = find_format_by_code(cfe_default_format.code); + if (!fmt) { + cfe_err("Failed to find format code\n"); diff --git a/target/linux/bcm27xx/patches-6.1/950-1208-media-rp1-cfe-Dual-purpose-video-nodes.patch b/target/linux/bcm27xx/patches-6.1/950-1208-media-rp1-cfe-Dual-purpose-video-nodes.patch new file mode 100644 index 0000000000..f68aa3975d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1208-media-rp1-cfe-Dual-purpose-video-nodes.patch @@ -0,0 +1,621 @@ +From c54b8d2fc79c684deacc81a94f6baa1cb56c62be Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Wed, 27 Sep 2023 17:18:09 +0300 +Subject: [PATCH] media: rp1: cfe: Dual purpose video nodes + +The RP1 CSI-2 DMA can capture both video and metadata just fine, but at +the moment the video nodes are only set to support either video or +metadata. + +Make the changes to support both video and metadata. This mostly means +tracking both video format and metadata format separately for each video +node, and using vb2_queue_change_type() to change the vb2 queue type +when needed. + +Briefly, this means that the user can get/set both video and meta +formats to a single video node. The vb2 queue buffer type will be +changed when the user calls REQBUFS or CREATE_BUFS ioctls. This buffer +type will be then used as the "mode" for the video node when the user +starts the streaming, and based on that either the video or the meta +format will be used. + +A bunch of macros are added (node_supports_xxx()), which tell if a node +can support a particular mode, whereas the existing macros +(is_xxx_node()) will tell if the node is currently in a particular mode. +Note that the latter will only work correctly between the start of the +streaming and the end of the streaming, and thus should be only used in +those code paths. + +However, as the userspace (libcamera) does not support dual purpose +video nodes, for the time being let's keep the second video node as +V4L2_CAP_META_CAPTURE only to keep the userspace working. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 271 ++++++++++++------ + 1 file changed, 182 insertions(+), 89 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -116,7 +116,7 @@ const struct v4l2_mbus_framefmt cfe_defa + enum node_ids { + /* CSI2 HW output nodes first. */ + CSI2_CH0, +- CSI2_CH1_EMBEDDED, ++ CSI2_CH1, + CSI2_CH2, + CSI2_CH3, + /* FE only nodes from here on. */ +@@ -130,8 +130,7 @@ enum node_ids { + struct node_description { + unsigned int id; + const char *name; +- enum v4l2_buf_type buf_type; +- unsigned int cap; ++ unsigned int caps; + unsigned int pad_flags; + unsigned int link_pad; + }; +@@ -140,58 +139,55 @@ struct node_description { + static const struct node_description node_desc[NUM_NODES] = { + [CSI2_CH0] = { + .name = "csi2_ch0", +- .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +- .cap = V4L2_CAP_VIDEO_CAPTURE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_NUM_CHANNELS + 0 + }, +- /* This node is assigned for the embedded data channel! */ +- [CSI2_CH1_EMBEDDED] = { ++ /* ++ * TODO: This node should be named "csi2_ch1" and the caps should be set ++ * to both video and meta capture. However, to keep compatibility with ++ * the current libcamera, keep the name as "embedded" and support ++ * only meta capture. ++ */ ++ [CSI2_CH1] = { + .name = "embedded", +- .buf_type = V4L2_BUF_TYPE_META_CAPTURE, +- .cap = V4L2_CAP_META_CAPTURE, ++ .caps = V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_NUM_CHANNELS + 1 + }, + [CSI2_CH2] = { + .name = "csi2_ch2", +- .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +- .cap = V4L2_CAP_META_CAPTURE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_NUM_CHANNELS + 2 + }, + [CSI2_CH3] = { + .name = "csi2_ch3", +- .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +- .cap = V4L2_CAP_META_CAPTURE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_NUM_CHANNELS + 3 + }, + [FE_OUT0] = { + .name = "fe_image0", +- .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +- .cap = V4L2_CAP_VIDEO_CAPTURE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_OUTPUT0_PAD + }, + [FE_OUT1] = { + .name = "fe_image1", +- .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +- .cap = V4L2_CAP_VIDEO_CAPTURE, ++ .caps = V4L2_CAP_VIDEO_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_OUTPUT1_PAD + }, + [FE_STATS] = { + .name = "fe_stats", +- .buf_type = V4L2_BUF_TYPE_META_CAPTURE, +- .cap = V4L2_CAP_META_CAPTURE, ++ .caps = V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_STATS_PAD + }, + [FE_CONFIG] = { + .name = "fe_config", +- .buf_type = V4L2_BUF_TYPE_META_OUTPUT, +- .cap = V4L2_CAP_META_OUTPUT, ++ .caps = V4L2_CAP_META_OUTPUT, + .pad_flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_CONFIG_PAD + }, +@@ -200,17 +196,29 @@ static const struct node_description nod + #define is_fe_node(node) (((node)->id) >= FE_OUT0) + #define is_csi2_node(node) (!is_fe_node(node)) + ++#define node_supports_image_output(node) \ ++ (!!(node_desc[(node)->id].caps & V4L2_CAP_VIDEO_CAPTURE)) ++#define node_supports_meta_output(node) \ ++ (!!(node_desc[(node)->id].caps & V4L2_CAP_META_CAPTURE)) ++#define node_supports_image_input(node) \ ++ (!!(node_desc[(node)->id].caps & V4L2_CAP_VIDEO_OUTPUT)) ++#define node_supports_meta_input(node) \ ++ (!!(node_desc[(node)->id].caps & V4L2_CAP_META_OUTPUT)) ++#define node_supports_image(node) \ ++ (node_supports_image_output(node) || node_supports_image_input(node)) ++#define node_supports_meta(node) \ ++ (node_supports_meta_output(node) || node_supports_meta_input(node)) ++ + #define is_image_output_node(node) \ +- (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + #define is_image_input_node(node) \ +- (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + #define is_image_node(node) \ + (is_image_output_node(node) || is_image_input_node(node)) +- + #define is_meta_output_node(node) \ +- (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_META_CAPTURE) ++ ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_CAPTURE) + #define is_meta_input_node(node) \ +- (node_desc[(node)->id].buf_type == V4L2_BUF_TYPE_META_OUTPUT) ++ ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_OUTPUT) + #define is_meta_node(node) \ + (is_meta_output_node(node) || is_meta_input_node(node)) + +@@ -250,7 +258,9 @@ struct cfe_node { + /* Pointer pointing to next v4l2_buffer */ + struct cfe_buffer *next_frm; + /* Used to store current pixel format */ +- struct v4l2_format fmt; ++ struct v4l2_format vid_fmt; ++ /* Used to store current meta format */ ++ struct v4l2_format meta_fmt; + /* Buffer queue used in video-buf */ + struct vb2_queue buffer_queue; + /* Queue of filled frames */ +@@ -433,20 +443,21 @@ static int format_show(struct seq_file * + seq_printf(s, "\nNode %u (%s) state: 0x%lx\n", i, + node_desc[i].name, state); + +- if (is_image_node(node)) ++ if (node_supports_image(node)) + seq_printf(s, "format: " V4L2_FOURCC_CONV " 0x%x\n" + "resolution: %ux%u\nbpl: %u\nsize: %u\n", +- V4L2_FOURCC_CONV_ARGS(node->fmt.fmt.pix.pixelformat), +- node->fmt.fmt.pix.pixelformat, +- node->fmt.fmt.pix.width, +- node->fmt.fmt.pix.height, +- node->fmt.fmt.pix.bytesperline, +- node->fmt.fmt.pix.sizeimage); +- else ++ V4L2_FOURCC_CONV_ARGS(node->vid_fmt.fmt.pix.pixelformat), ++ node->vid_fmt.fmt.pix.pixelformat, ++ node->vid_fmt.fmt.pix.width, ++ node->vid_fmt.fmt.pix.height, ++ node->vid_fmt.fmt.pix.bytesperline, ++ node->vid_fmt.fmt.pix.sizeimage); ++ ++ if (node_supports_meta(node)) + seq_printf(s, "format: " V4L2_FOURCC_CONV " 0x%x\nsize: %u\n", +- V4L2_FOURCC_CONV_ARGS(node->fmt.fmt.meta.dataformat), +- node->fmt.fmt.meta.dataformat, +- node->fmt.fmt.meta.buffersize); ++ V4L2_FOURCC_CONV_ARGS(node->meta_fmt.fmt.meta.dataformat), ++ node->meta_fmt.fmt.meta.dataformat, ++ node->meta_fmt.fmt.meta.buffersize); + } + + return 0; +@@ -571,11 +582,11 @@ static void cfe_schedule_next_csi2_job(s + node_desc[node->id].name, &buf->vb.vb2_buf); + + if (is_meta_node(node)) { +- size = node->fmt.fmt.meta.buffersize; ++ size = node->meta_fmt.fmt.meta.buffersize; + stride = 0; + } else { +- size = node->fmt.fmt.pix.sizeimage; +- stride = node->fmt.fmt.pix.bytesperline; ++ size = node->vid_fmt.fmt.pix.sizeimage; ++ stride = node->vid_fmt.fmt.pix.bytesperline; + } + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); +@@ -867,10 +878,10 @@ static void cfe_start_channel(struct cfe + width = source_fmt->width; + height = source_fmt->height; + +- if (node->fmt.fmt.pix.pixelformat == ++ if (node->vid_fmt.fmt.pix.pixelformat == + fmt->remap[CFE_REMAP_16BIT]) + mode = CSI2_MODE_REMAP; +- else if (node->fmt.fmt.pix.pixelformat == ++ else if (node->vid_fmt.fmt.pix.pixelformat == + fmt->remap[CFE_REMAP_COMPRESSED]) { + mode = CSI2_MODE_COMPRESSED; + csi2_set_compression(&cfe->csi2, node->id, +@@ -884,7 +895,7 @@ static void cfe_start_channel(struct cfe + /* Auto arm */ + false, + /* Pack bytes */ +- node->id == CSI2_CH1_EMBEDDED ? true : false, ++ is_meta_node(node) ? true : false, + width, height); + } + +@@ -947,10 +958,11 @@ static int cfe_queue_setup(struct vb2_qu + { + struct cfe_node *node = vb2_get_drv_priv(vq); + struct cfe_device *cfe = node->cfe; +- unsigned int size = is_image_node(node) ? node->fmt.fmt.pix.sizeimage : +- node->fmt.fmt.meta.buffersize; ++ unsigned int size = is_image_node(node) ? node->vid_fmt.fmt.pix.sizeimage : ++ node->meta_fmt.fmt.meta.buffersize; + +- cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ cfe_dbg("%s: [%s] type:%u\n", __func__, node_desc[node->id].name, ++ node->buffer_queue.type); + + if (vq->num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->num_buffers; +@@ -979,8 +991,8 @@ static int cfe_buffer_prepare(struct vb2 + cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__, + node_desc[node->id].name, vb); + +- size = is_image_node(node) ? node->fmt.fmt.pix.sizeimage : +- node->fmt.fmt.meta.buffersize; ++ size = is_image_node(node) ? node->vid_fmt.fmt.pix.sizeimage : ++ node->meta_fmt.fmt.meta.buffersize; + if (vb2_plane_size(vb, 0) < size) { + cfe_err("data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); +@@ -995,8 +1007,8 @@ static int cfe_buffer_prepare(struct vb2 + + memcpy(&b->config, addr, sizeof(struct pisp_fe_config)); + return pisp_fe_validate_config(&cfe->fe, &b->config, +- &cfe->node[FE_OUT0].fmt, +- &cfe->node[FE_OUT1].fmt); ++ &cfe->node[FE_OUT0].vid_fmt, ++ &cfe->node[FE_OUT1].vid_fmt); + } + + return 0; +@@ -1256,7 +1268,7 @@ static int cfe_enum_fmt_vid_cap(struct f + struct cfe_device *cfe = node->cfe; + unsigned int i, j; + +- if (!is_image_output_node(node)) ++ if (!node_supports_image_output(node)) + return -EINVAL; + + cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); +@@ -1292,10 +1304,10 @@ static int cfe_g_fmt(struct file *file, + + cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); + +- if (f->type != node->buffer_queue.type) ++ if (!node_supports_image(node)) + return -EINVAL; + +- *f = node->fmt; ++ *f = node->vid_fmt; + + return 0; + } +@@ -1310,7 +1322,7 @@ static int try_fmt_vid_cap(struct cfe_no + f->fmt.pix.width, f->fmt.pix.height, + V4L2_FOURCC_CONV_ARGS(f->fmt.pix.pixelformat)); + +- if (!is_image_output_node(node)) ++ if (!node_supports_image_output(node)) + return -EINVAL; + + /* +@@ -1351,11 +1363,11 @@ static int cfe_s_fmt_vid_cap(struct file + if (ret) + return ret; + +- node->fmt = *f; ++ node->vid_fmt = *f; + + cfe_dbg("%s: Set %ux%u, V4L2 pix " V4L2_FOURCC_CONV "\n", __func__, +- node->fmt.fmt.pix.width, node->fmt.fmt.pix.height, +- V4L2_FOURCC_CONV_ARGS(node->fmt.fmt.pix.pixelformat)); ++ node->vid_fmt.fmt.pix.width, node->vid_fmt.fmt.pix.height, ++ V4L2_FOURCC_CONV_ARGS(node->vid_fmt.fmt.pix.pixelformat)); + + return 0; + } +@@ -1379,11 +1391,11 @@ static int cfe_enum_fmt_meta(struct file + + cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); + +- if (!is_meta_node(node) || f->index != 0) ++ if (!node_supports_meta(node) || f->index != 0) + return -EINVAL; + + switch (node->id) { +- case CSI2_CH1_EMBEDDED: ++ case CSI2_CH0...CSI2_CH3: + f->pixelformat = V4L2_META_FMT_SENSOR_DATA; + return 0; + case FE_STATS: +@@ -1399,8 +1411,11 @@ static int cfe_enum_fmt_meta(struct file + + static int try_fmt_meta(struct cfe_node *node, struct v4l2_format *f) + { ++ if (!node_supports_meta(node)) ++ return -EINVAL; ++ + switch (node->id) { +- case CSI2_CH1_EMBEDDED: ++ case CSI2_CH0...CSI2_CH3: + f->fmt.meta.dataformat = V4L2_META_FMT_SENSOR_DATA; + if (!f->fmt.meta.buffersize) + f->fmt.meta.buffersize = DEFAULT_EMBEDDED_SIZE; +@@ -1422,6 +1437,21 @@ static int try_fmt_meta(struct cfe_node + return -EINVAL; + } + ++static int cfe_g_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) ++{ ++ struct cfe_node *node = video_drvdata(file); ++ struct cfe_device *cfe = node->cfe; ++ ++ cfe_dbg("%s: [%s]\n", __func__, node_desc[node->id].name); ++ ++ if (!node_supports_meta(node)) ++ return -EINVAL; ++ ++ *f = node->meta_fmt; ++ ++ return 0; ++} ++ + static int cfe_s_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) + { + struct cfe_node *node = video_drvdata(file); +@@ -1434,17 +1464,17 @@ static int cfe_s_fmt_meta(struct file *f + if (vb2_is_busy(q)) + return -EBUSY; + +- if (f->type != node->buffer_queue.type) ++ if (!node_supports_meta(node)) + return -EINVAL; + + ret = try_fmt_meta(node, f); + if (ret) + return ret; + +- node->fmt = *f; ++ node->meta_fmt = *f; + + cfe_dbg("%s: Set " V4L2_FOURCC_CONV "\n", __func__, +- V4L2_FOURCC_CONV_ARGS(node->fmt.fmt.meta.dataformat)); ++ V4L2_FOURCC_CONV_ARGS(node->meta_fmt.fmt.meta.dataformat)); + + return 0; + } +@@ -1491,6 +1521,52 @@ static int cfe_enum_framesizes(struct fi + return 0; + } + ++static int cfe_vb2_ioctl_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *p) ++{ ++ struct video_device *vdev = video_devdata(file); ++ struct cfe_node *node = video_get_drvdata(vdev); ++ struct cfe_device *cfe = node->cfe; ++ int ret; ++ ++ cfe_dbg("%s: [%s] type:%u\n", __func__, node_desc[node->id].name, ++ p->type); ++ ++ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && ++ p->type != V4L2_BUF_TYPE_META_CAPTURE && ++ p->type != V4L2_BUF_TYPE_META_OUTPUT) ++ return -EINVAL; ++ ++ ret = vb2_queue_change_type(vdev->queue, p->type); ++ if (ret) ++ return ret; ++ ++ return vb2_ioctl_reqbufs(file, priv, p); ++} ++ ++static int cfe_vb2_ioctl_create_bufs(struct file *file, void *priv, ++ struct v4l2_create_buffers *p) ++{ ++ struct video_device *vdev = video_devdata(file); ++ struct cfe_node *node = video_get_drvdata(vdev); ++ struct cfe_device *cfe = node->cfe; ++ int ret; ++ ++ cfe_dbg("%s: [%s] type:%u\n", __func__, node_desc[node->id].name, ++ p->format.type); ++ ++ if (p->format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE && ++ p->format.type != V4L2_BUF_TYPE_META_CAPTURE && ++ p->format.type != V4L2_BUF_TYPE_META_OUTPUT) ++ return -EINVAL; ++ ++ ret = vb2_queue_change_type(vdev->queue, p->format.type); ++ if (ret) ++ return ret; ++ ++ return vb2_ioctl_create_bufs(file, priv, p); ++} ++ + static int cfe_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) + { +@@ -1498,12 +1574,13 @@ static int cfe_subscribe_event(struct v4 + + switch (sub->type) { + case V4L2_EVENT_FRAME_SYNC: +- if (!is_image_output_node(node)) ++ if (!node_supports_image_output(node)) + break; + + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: +- if (is_meta_input_node(node)) ++ if (!node_supports_image_output(node) && ++ !node_supports_meta_output(node)) + break; + + return v4l2_event_subscribe(fh, sub, 4, NULL); +@@ -1520,19 +1597,19 @@ static const struct v4l2_ioctl_ops cfe_i + .vidioc_try_fmt_vid_cap = cfe_try_fmt_vid_cap, + + .vidioc_enum_fmt_meta_cap = cfe_enum_fmt_meta, +- .vidioc_g_fmt_meta_cap = cfe_g_fmt, ++ .vidioc_g_fmt_meta_cap = cfe_g_fmt_meta, + .vidioc_s_fmt_meta_cap = cfe_s_fmt_meta, + .vidioc_try_fmt_meta_cap = cfe_try_fmt_meta, + + .vidioc_enum_fmt_meta_out = cfe_enum_fmt_meta, +- .vidioc_g_fmt_meta_out = cfe_g_fmt, ++ .vidioc_g_fmt_meta_out = cfe_g_fmt_meta, + .vidioc_s_fmt_meta_out = cfe_s_fmt_meta, + .vidioc_try_fmt_meta_out = cfe_try_fmt_meta, + + .vidioc_enum_framesizes = cfe_enum_framesizes, + +- .vidioc_reqbufs = vb2_ioctl_reqbufs, +- .vidioc_create_bufs = vb2_ioctl_create_bufs, ++ .vidioc_reqbufs = cfe_vb2_ioctl_reqbufs, ++ .vidioc_create_bufs = cfe_vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, +@@ -1610,7 +1687,7 @@ static int cfe_video_link_validate(struc + } + + if (is_image_output_node(node)) { +- struct v4l2_pix_format *pix_fmt = &node->fmt.fmt.pix; ++ struct v4l2_pix_format *pix_fmt = &node->vid_fmt.fmt.pix; + const struct cfe_fmt *fmt = NULL; + unsigned int i; + +@@ -1636,8 +1713,8 @@ static int cfe_video_link_validate(struc + ret = -EINVAL; + goto out; + } +- } else if (node->id == CSI2_CH1_EMBEDDED) { +- struct v4l2_meta_format *meta_fmt = &node->fmt.fmt.meta; ++ } else if (is_csi2_node(node) && is_meta_output_node(node)) { ++ struct v4l2_meta_format *meta_fmt = &node->meta_fmt.fmt.meta; + + if (source_fmt->width * source_fmt->height != + meta_fmt->buffersize || +@@ -1698,15 +1775,17 @@ static int cfe_video_link_notify(struct + + if (link->source->entity != csi2) + return 0; +- if (link->sink->index != 0) ++ if (link->sink->entity != fe) + return 0; +- if (link->source->index == node_desc[CSI2_CH1_EMBEDDED].link_pad) ++ if (link->sink->index != 0) + return 0; + + cfe->fe_csi2_channel = -1; +- if (link->sink->entity == fe && (link->flags & MEDIA_LNK_FL_ENABLED)) { ++ if (link->flags & MEDIA_LNK_FL_ENABLED) { + if (link->source->index == node_desc[CSI2_CH0].link_pad) + cfe->fe_csi2_channel = CSI2_CH0; ++ else if (link->source->index == node_desc[CSI2_CH1].link_pad) ++ cfe->fe_csi2_channel = CSI2_CH1; + else if (link->source->index == node_desc[CSI2_CH2].link_pad) + cfe->fe_csi2_channel = CSI2_CH2; + else if (link->source->index == node_desc[CSI2_CH3].link_pad) +@@ -1763,30 +1842,42 @@ static int cfe_register_node(struct cfe_ + node->cfe = cfe; + node->id = id; + +- if (is_image_node(node)) { ++ if (node_supports_image(node)) { ++ if (node_supports_image_output(node)) ++ node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ else ++ node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ + fmt = find_format_by_code(cfe_default_format.code); + if (!fmt) { + cfe_err("Failed to find format code\n"); + return -EINVAL; + } + +- node->fmt.fmt.pix.pixelformat = fmt->fourcc; +- v4l2_fill_pix_format(&node->fmt.fmt.pix, &cfe_default_format); ++ node->vid_fmt.fmt.pix.pixelformat = fmt->fourcc; ++ v4l2_fill_pix_format(&node->vid_fmt.fmt.pix, &cfe_default_format); + +- ret = try_fmt_vid_cap(node, &node->fmt); ++ ret = try_fmt_vid_cap(node, &node->vid_fmt); + if (ret) + return ret; +- } else { +- ret = try_fmt_meta(node, &node->fmt); ++ } ++ ++ if (node_supports_meta(node)) { ++ if (node_supports_meta_output(node)) ++ node->meta_fmt.type = V4L2_BUF_TYPE_META_CAPTURE; ++ else ++ node->meta_fmt.type = V4L2_BUF_TYPE_META_OUTPUT; ++ ++ ret = try_fmt_meta(node, &node->meta_fmt); + if (ret) + return ret; + } +- node->fmt.type = node_desc[id].buf_type; + + mutex_init(&node->lock); + + q = &node->buffer_queue; +- q->type = node_desc[id].buf_type; ++ q->type = node_supports_image(node) ? node->vid_fmt.type : ++ node->meta_fmt.type; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = node; + q->ops = &cfe_video_qops; +@@ -1812,11 +1903,13 @@ static int cfe_register_node(struct cfe_ + vdev->ioctl_ops = &cfe_ioctl_ops; + vdev->entity.ops = &cfe_media_entity_ops; + vdev->v4l2_dev = &cfe->v4l2_dev; +- vdev->vfl_dir = (is_image_output_node(node) || is_meta_output_node(node)) +- ? VFL_DIR_RX : VFL_DIR_TX; ++ vdev->vfl_dir = (node_supports_image_output(node) || ++ node_supports_meta_output(node)) ? ++ VFL_DIR_RX : ++ VFL_DIR_TX; + vdev->queue = q; + vdev->lock = &node->lock; +- vdev->device_caps = node_desc[id].cap; ++ vdev->device_caps = node_desc[id].caps; + vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; + + /* Define the device names */ +@@ -1829,7 +1922,7 @@ static int cfe_register_node(struct cfe_ + node->pad.flags = node_desc[id].pad_flags; + media_entity_pads_init(&vdev->entity, 1, &node->pad); + +- if (is_meta_node(node)) { ++ if (!node_supports_image(node)) { + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(&node->video_dev, +@@ -1907,7 +2000,7 @@ static int cfe_link_node_pads(struct cfe + if (ret) + return ret; + +- if (node->id != CSI2_CH1_EMBEDDED) { ++ if (node_supports_image(node)) { + /* CSI2 channel # -> FE Input */ + ret = media_create_pad_link(&cfe->csi2.sd.entity, + node_desc[i].link_pad, diff --git a/target/linux/bcm27xx/patches-6.1/950-1209-media-rp1-Drop-LE-handling.patch b/target/linux/bcm27xx/patches-6.1/950-1209-media-rp1-Drop-LE-handling.patch new file mode 100644 index 0000000000..1d6e396f1c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1209-media-rp1-Drop-LE-handling.patch @@ -0,0 +1,127 @@ +From dad296088dffbaf55c1e61cbdc3f7cb1eb504ca6 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Tue, 16 May 2023 15:51:54 +0300 +Subject: [PATCH] media: rp1: Drop LE handling + +The driver registers for line-end interrupts, but never uses them. This +just causes extra interrupt load, with more complexity in the driver. + +Drop the LE handling. It can easily be added back if later needed. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 6 ++-- + .../media/platform/raspberrypi/rp1_cfe/csi2.c | 28 ++++--------------- + .../media/platform/raspberrypi/rp1_cfe/csi2.h | 2 +- + 3 files changed, 10 insertions(+), 26 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -734,13 +734,13 @@ static irqreturn_t cfe_isr(int irq, void + { + struct cfe_device *cfe = dev; + unsigned int i; +- bool sof[NUM_NODES] = {0}, eof[NUM_NODES] = {0}, lci[NUM_NODES] = {0}; ++ bool sof[NUM_NODES] = {0}, eof[NUM_NODES] = {0}; + u32 sts; + + sts = cfg_reg_read(cfe, MIPICFG_INTS); + + if (sts & MIPICFG_INT_CSI_DMA) +- csi2_isr(&cfe->csi2, sof, eof, lci); ++ csi2_isr(&cfe->csi2, sof, eof); + + if (sts & MIPICFG_INT_PISP_FE) + pisp_fe_isr(&cfe->fe, sof + CSI2_NUM_CHANNELS, +@@ -757,7 +757,7 @@ static irqreturn_t cfe_isr(int irq, void + * generate interrupts even though the node is not streaming. + */ + if (!check_state(cfe, NODE_STREAMING, i) || +- !(sof[i] || eof[i] || lci[i])) ++ !(sof[i] || eof[i])) + continue; + + /* +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -258,7 +258,7 @@ static void csi2_isr_handle_errors(struc + spin_unlock(&csi2->errors_lock); + } + +-void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof, bool *lci) ++void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof) + { + unsigned int i; + u32 status; +@@ -290,7 +290,6 @@ void csi2_isr(struct csi2_device *csi2, + + sof[i] = !!(status & IRQ_FS(i)); + eof[i] = !!(status & IRQ_FE_ACK(i)); +- lci[i] = !!(status & IRQ_LE_ACK(i)); + } + + if (csi2_track_errors) +@@ -405,16 +404,12 @@ void csi2_start_channel(struct csi2_devi + + csi2_dbg("%s [%u]\n", __func__, channel); + +- /* +- * Disable the channel, but ensure N != 0! Otherwise we end up with a +- * spurious LE + LE_ACK interrupt when re-enabling the channel. +- */ +- csi2_reg_write(csi2, CSI2_CH_CTRL(channel), 0x100 << __ffs(LC_MASK)); ++ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), 0); + csi2_reg_write(csi2, CSI2_CH_DEBUG(channel), 0); + csi2_reg_write(csi2, CSI2_STATUS, IRQ_CH_MASK(channel)); + +- /* Enable channel and FS/FE/LE interrupts. */ +- ctrl = DMA_EN | IRQ_EN_FS | IRQ_EN_FE_ACK | IRQ_EN_LE_ACK | PACK_LINE; ++ /* Enable channel and FS/FE interrupts. */ ++ ctrl = DMA_EN | IRQ_EN_FS | IRQ_EN_FE_ACK | PACK_LINE; + /* PACK_BYTES ensures no striding for embedded data. */ + if (pack_bytes) + ctrl |= PACK_BYTES; +@@ -423,21 +418,11 @@ void csi2_start_channel(struct csi2_devi + ctrl |= AUTO_ARM; + + if (width && height) { +- int line_int_freq = height >> 2; +- +- line_int_freq = min(max(0x80, line_int_freq), 0x3ff); +- set_field(&ctrl, line_int_freq, LC_MASK); + set_field(&ctrl, mode, CH_MODE_MASK); + csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), + (height << 16) | width); + } else { +- /* +- * Do not disable line interrupts for the embedded data channel, +- * set it to the maximum value. This avoids spamming the ISR +- * with spurious line interrupts. +- */ +- set_field(&ctrl, 0x3ff, LC_MASK); +- set_field(&ctrl, 0x00, CH_MODE_MASK); ++ set_field(&ctrl, 0x0, CH_MODE_MASK); + csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), 0); + } + +@@ -452,8 +437,7 @@ void csi2_stop_channel(struct csi2_devic + csi2_dbg("%s [%u]\n", __func__, channel); + + /* Channel disable. Use FORCE to allow stopping mid-frame. */ +- csi2_reg_write(csi2, CSI2_CH_CTRL(channel), +- (0x100 << __ffs(LC_MASK)) | FORCE); ++ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), FORCE); + /* Latch the above change by writing to the ADDR0 register. */ + csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0); + /* Write this again, the HW needs it! */ +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h +@@ -71,7 +71,7 @@ struct csi2_device { + u32 discards_dt_table[DISCARDS_TABLE_NUM_ENTRIES]; + }; + +-void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof, bool *lci); ++void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof); + void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, + dma_addr_t dmaaddr, unsigned int stride, + unsigned int size); diff --git a/target/linux/bcm27xx/patches-6.1/950-1210-media-rp1-csi2-Use-standard-link_validate.patch b/target/linux/bcm27xx/patches-6.1/950-1210-media-rp1-csi2-Use-standard-link_validate.patch new file mode 100644 index 0000000000..a3836150dc --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1210-media-rp1-csi2-Use-standard-link_validate.patch @@ -0,0 +1,75 @@ +From b6316a8450d3cb99b7599175d59b1b7f710770f5 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Tue, 3 Oct 2023 13:59:02 +0300 +Subject: [PATCH] media: rp1: csi2: Use standard link_validate + +The current csi2_link_validate() skips some important checks. Let's +rather use the standard v4l2_subdev_link_validate_default() as the +link_validate hook. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/csi2.c | 41 +------------------ + 1 file changed, 1 insertion(+), 40 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c +@@ -462,11 +462,6 @@ void csi2_close_rx(struct csi2_device *c + csi2_reg_write(csi2, CSI2_IRQ_MASK, 0); + } + +-static struct csi2_device *to_csi2_device(struct v4l2_subdev *subdev) +-{ +- return container_of(subdev, struct csi2_device, sd); +-} +- + static int csi2_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) + { +@@ -554,45 +549,11 @@ static int csi2_pad_set_fmt(struct v4l2_ + return 0; + } + +-static int csi2_link_validate(struct v4l2_subdev *sd, struct media_link *link, +- struct v4l2_subdev_format *source_fmt, +- struct v4l2_subdev_format *sink_fmt) +-{ +- struct csi2_device *csi2 = to_csi2_device(sd); +- +- csi2_dbg("%s: link \"%s\":%u -> \"%s\":%u\n", __func__, +- link->source->entity->name, link->source->index, +- link->sink->entity->name, link->sink->index); +- +- if ((link->source->entity == &csi2->sd.entity && +- link->source->index == 1) || +- (link->sink->entity == &csi2->sd.entity && +- link->sink->index == 1)) { +- csi2_dbg("Ignore metadata pad for now\n"); +- return 0; +- } +- +- /* The width, height and code must match. */ +- if (source_fmt->format.width != sink_fmt->format.width || +- source_fmt->format.width != sink_fmt->format.width || +- source_fmt->format.code != sink_fmt->format.code) { +- csi2_err("%s: format does not match (source %ux%u 0x%x, sink %ux%u 0x%x)\n", +- __func__, +- source_fmt->format.width, source_fmt->format.height, +- source_fmt->format.code, +- sink_fmt->format.width, sink_fmt->format.height, +- sink_fmt->format.code); +- return -EPIPE; +- } +- +- return 0; +-} +- + static const struct v4l2_subdev_pad_ops csi2_subdev_pad_ops = { + .init_cfg = csi2_init_cfg, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = csi2_pad_set_fmt, +- .link_validate = csi2_link_validate, ++ .link_validate = v4l2_subdev_link_validate_default, + }; + + static const struct media_entity_operations csi2_entity_ops = { diff --git a/target/linux/bcm27xx/patches-6.1/950-1211-media-rp1-fe-Use-standard-link_validate.patch b/target/linux/bcm27xx/patches-6.1/950-1211-media-rp1-fe-Use-standard-link_validate.patch new file mode 100644 index 0000000000..d36ea5bd52 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1211-media-rp1-fe-Use-standard-link_validate.patch @@ -0,0 +1,70 @@ +From 0eeb351222adbc5b534c86f7815ee787babc3485 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Tue, 3 Oct 2023 14:34:43 +0300 +Subject: [PATCH] media: rp1: fe: Use standard link_validate + +The current pisp_fe_link_validate() skips some important checks. Let's +rather use the standard v4l2_subdev_link_validate_default() as the +link_validate hook. + +Signed-off-by: Tomi Valkeinen +--- + .../platform/raspberrypi/rp1_cfe/pisp_fe.c | 36 +------------------ + 1 file changed, 1 insertion(+), 35 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe.c +@@ -388,11 +388,6 @@ void pisp_fe_stop(struct pisp_fe_device + pisp_fe_reg_write(fe, FE_INT_STATUS, ~0); + } + +-static struct pisp_fe_device *to_pisp_fe_device(struct v4l2_subdev *subdev) +-{ +- return container_of(subdev, struct pisp_fe_device, sd); +-} +- + static int pisp_fe_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) + { +@@ -492,40 +487,11 @@ static int pisp_fe_pad_set_fmt(struct v4 + } + } + +-static int pisp_fe_link_validate(struct v4l2_subdev *sd, +- struct media_link *link, +- struct v4l2_subdev_format *source_fmt, +- struct v4l2_subdev_format *sink_fmt) +-{ +- struct pisp_fe_device *fe = to_pisp_fe_device(sd); +- +- pisp_fe_dbg("%s: link \"%s\":%u -> \"%s\":%u\n", __func__, +- link->source->entity->name, link->source->index, +- link->sink->entity->name, link->sink->index); +- +- /* The width, height and code must match. */ +- if (source_fmt->format.width != sink_fmt->format.width || +- source_fmt->format.width != sink_fmt->format.width || +- source_fmt->format.code != sink_fmt->format.code) { +- pisp_fe_err("%s: format does not match (source %ux%u 0x%x, sink %ux%u 0x%x)\n", +- __func__, +- source_fmt->format.width, +- source_fmt->format.height, +- source_fmt->format.code, +- sink_fmt->format.width, +- sink_fmt->format.height, +- sink_fmt->format.code); +- return -EPIPE; +- } +- +- return 0; +-} +- + static const struct v4l2_subdev_pad_ops pisp_fe_subdev_pad_ops = { + .init_cfg = pisp_fe_init_cfg, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = pisp_fe_pad_set_fmt, +- .link_validate = pisp_fe_link_validate, ++ .link_validate = v4l2_subdev_link_validate_default, + }; + + static const struct media_entity_operations pisp_fe_entity_ops = { diff --git a/target/linux/bcm27xx/patches-6.1/950-1212-media-rp1-cfe-Improve-link-validation-for-metadata.patch b/target/linux/bcm27xx/patches-6.1/950-1212-media-rp1-cfe-Improve-link-validation-for-metadata.patch new file mode 100644 index 0000000000..d85a90aac1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1212-media-rp1-cfe-Improve-link-validation-for-metadata.patch @@ -0,0 +1,61 @@ +From e0f52ccfe1e383622fb30708acd38921e84fbff4 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Tue, 3 Oct 2023 14:29:44 +0300 +Subject: [PATCH] media: rp1: cfe: Improve link validation for metadata + +Improve the link validation for metadata by: +- Allowing capture buffers that are larger than the incoming frame + (instead of requiring exact match). + +- Instead of assuming that a metadata unit ("pixel") is 8 bits, use + find_format_by_code() to get the format and use the bit depth from + there. E.g. bit depth for RAW10 metadata will be 10 bits, when we + move to the upstream metadata formats. + +Signed-off-by: Tomi Valkeinen +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 32 +++++++++++++------ + 1 file changed, 22 insertions(+), 10 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -1715,17 +1715,29 @@ static int cfe_video_link_validate(struc + } + } else if (is_csi2_node(node) && is_meta_output_node(node)) { + struct v4l2_meta_format *meta_fmt = &node->meta_fmt.fmt.meta; ++ const struct cfe_fmt *fmt; ++ u32 source_size; + +- if (source_fmt->width * source_fmt->height != +- meta_fmt->buffersize || +- source_fmt->code != MEDIA_BUS_FMT_SENSOR_DATA) { +- cfe_err("WARNING: Wrong metadata width/height/code %ux%u %08x (remote pad set to %ux%u %08x)\n", +- meta_fmt->buffersize, 1, +- MEDIA_BUS_FMT_SENSOR_DATA, +- source_fmt->width, +- source_fmt->height, +- source_fmt->code); +- /* TODO: this should throw an error eventually */ ++ fmt = find_format_by_code(source_fmt->code); ++ if (!fmt || fmt->fourcc != meta_fmt->dataformat) { ++ cfe_err("Metadata format mismatch!\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ source_size = DIV_ROUND_UP(source_fmt->width * source_fmt->height * fmt->depth, 8); ++ ++ if (source_fmt->code != MEDIA_BUS_FMT_SENSOR_DATA) { ++ cfe_err("Bad metadata mbus format\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (source_size > meta_fmt->buffersize) { ++ cfe_err("Metadata buffer too small: %u < %u\n", ++ meta_fmt->buffersize, source_size); ++ ret = -EINVAL; ++ goto out; + } + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-1214-drivers-pinctrl-bcm-Kconfig-Fix-BCM2712-help.patch b/target/linux/bcm27xx/patches-6.1/950-1214-drivers-pinctrl-bcm-Kconfig-Fix-BCM2712-help.patch new file mode 100644 index 0000000000..c3e4140fa2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1214-drivers-pinctrl-bcm-Kconfig-Fix-BCM2712-help.patch @@ -0,0 +1,24 @@ +From 046d03c87ecce5db074eae6ffa2d5298c5f7d5a7 Mon Sep 17 00:00:00 2001 +From: Leon Anavi +Date: Tue, 12 Dec 2023 13:53:37 +0200 +Subject: [PATCH] drivers/pinctrl/bcm/Kconfig: Fix BCM2712 help + +Replace "Broadcom BCM2835 GPIO" with "Broadcom BCM2712 PINCONF" +in the help message. This work was sponsored by GOVCERT.LU. + +Signed-off-by: Leon Anavi +--- + drivers/pinctrl/bcm/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pinctrl/bcm/Kconfig ++++ b/drivers/pinctrl/bcm/Kconfig +@@ -10,7 +10,7 @@ config PINCTRL_BCM2712 + select PINCONF + select GENERIC_PINCONF + help +- Say Y here to enable the Broadcom BCM2835 GPIO driver. ++ Say Y here to enable the Broadcom BCM2712 PINCONF driver. + + config PINCTRL_BCM281XX + bool "Broadcom BCM281xx pinctrl driver" diff --git a/target/linux/bcm27xx/patches-6.1/950-1216-drivers-gpu-drm-panel-fix-waveshare-panel-software-r.patch b/target/linux/bcm27xx/patches-6.1/950-1216-drivers-gpu-drm-panel-fix-waveshare-panel-software-r.patch new file mode 100644 index 0000000000..aeb63589fc --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1216-drivers-gpu-drm-panel-fix-waveshare-panel-software-r.patch @@ -0,0 +1,41 @@ +From a6872b25f18fe46ef9979f9d4a3635a9c3966afd Mon Sep 17 00:00:00 2001 +From: eng33 +Date: Mon, 11 Dec 2023 15:06:45 +0800 +Subject: [PATCH] drivers/gpu/drm/panel:fix waveshare panel software + restart/shutdown display is abnormal Fixed the screen stays white when the + user restarts or shuts down + +Signed-off-by: eng33 +--- + drivers/gpu/drm/panel/panel-waveshare-dsi.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/gpu/drm/panel/panel-waveshare-dsi.c ++++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c +@@ -362,9 +362,18 @@ static void ws_panel_remove(struct i2c_c + { + struct ws_panel *ts = i2c_get_clientdata(i2c); + ++ ws_panel_disable(&ts->base); ++ + drm_panel_remove(&ts->base); + } + ++static void ws_panel_shutdown(struct i2c_client *i2c) ++{ ++ struct ws_panel *ts = i2c_get_clientdata(i2c); ++ ++ ws_panel_disable(&ts->base); ++} ++ + static const struct of_device_id ws_panel_of_ids[] = { + { + .compatible = "waveshare,2.8inch-panel", +@@ -403,6 +412,7 @@ static struct i2c_driver ws_panel_driver + }, + .probe = ws_panel_probe, + .remove = ws_panel_remove, ++ .shutdown = ws_panel_shutdown, + }; + module_i2c_driver(ws_panel_driver); + diff --git a/target/linux/bcm27xx/patches-6.1/950-1217-firmware-psci-Pass-given-partition-number-through.patch b/target/linux/bcm27xx/patches-6.1/950-1217-firmware-psci-Pass-given-partition-number-through.patch new file mode 100644 index 0000000000..7feeb224d1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1217-firmware-psci-Pass-given-partition-number-through.patch @@ -0,0 +1,33 @@ +From 6988ae7c909dc342322a82daaa3a95b78d038305 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 11 Dec 2023 16:58:07 +0000 +Subject: [PATCH] firmware/psci: Pass given partition number through + +Pi 5 uses BL31 as its armstub file, so the reset goes via PSCI. Parse +any "reboot" parameter as a partition number to reboot into. +N.B. This code path is only used if reboot mode has been set to warm +or soft. + +Signed-off-by: Phil Elwell +--- + drivers/firmware/psci/psci.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/firmware/psci/psci.c ++++ b/drivers/firmware/psci/psci.c +@@ -314,7 +314,14 @@ static int psci_sys_reset(struct notifie + * reset_type[30:0] = 0 (SYSTEM_WARM_RESET) + * cookie = 0 (ignored by the implementation) + */ +- invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), 0, 0, 0); ++ // Allow extra arguments separated by spaces after ++ // the partition number. ++ unsigned long val; ++ u8 partition = 0; ++ ++ if (data && sscanf(data, "%lu", &val) == 1 && val < 63) ++ partition = val; ++ invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), 0, partition, 0); + } else { + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); + } diff --git a/target/linux/bcm27xx/patches-6.1/950-1218-dts-bcm2712-rpi-5-b-Enable-warm-reboot-mode.patch b/target/linux/bcm27xx/patches-6.1/950-1218-dts-bcm2712-rpi-5-b-Enable-warm-reboot-mode.patch new file mode 100644 index 0000000000..8bcf587e6d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1218-dts-bcm2712-rpi-5-b-Enable-warm-reboot-mode.patch @@ -0,0 +1,23 @@ +From 5d87d7f91cb4f1d0f391f6fe9dd0524b363b78e3 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 11 Dec 2023 17:00:56 +0000 +Subject: [PATCH] dts: bcm2712-rpi-5-b: Enable warm reboot mode + +Switch to warm reboot mode so that the partition number is preserved. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -428,7 +428,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g + + / { + chosen: chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; ++ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; + stdout-path = "serial10:115200n8"; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1222-drivers-media-i2c-imx296-imx477-Configure-tigger_mod.patch b/target/linux/bcm27xx/patches-6.1/950-1222-drivers-media-i2c-imx296-imx477-Configure-tigger_mod.patch new file mode 100644 index 0000000000..be1eb5611e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1222-drivers-media-i2c-imx296-imx477-Configure-tigger_mod.patch @@ -0,0 +1,85 @@ +From 083f39e40d980b47ab12b451d40b9f935bb22a5b Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Wed, 6 Dec 2023 14:27:57 +0000 +Subject: [PATCH] drivers: media: i2c: imx296,imx477: Configure tigger_mode + every time + +Don't assume the camera has been reset each time we start streaming, +but always write registers relating to trigger_mode, even in mode 0. + +IMX477: Stop driving XVS on stop streaming, to avoid spurious pulses. + +Signed-off-by: Nick Hollinghurst +--- + drivers/media/i2c/imx296.c | 9 +++++---- + drivers/media/i2c/imx477.c | 29 ++++++++++++++--------------- + 2 files changed, 19 insertions(+), 19 deletions(-) + +--- a/drivers/media/i2c/imx296.c ++++ b/drivers/media/i2c/imx296.c +@@ -650,10 +650,11 @@ static int imx296_stream_on(struct imx29 + imx296_write(sensor, IMX296_CTRL00, 0, &ret); + usleep_range(2000, 5000); + +- if (trigger_mode == 1) { +- imx296_write(sensor, IMX296_CTRL0B, IMX296_CTRL0B_TRIGEN, &ret); +- imx296_write(sensor, IMX296_LOWLAGTRG, IMX296_LOWLAGTRG_FAST, &ret); +- } ++ /* external trigger mode: 0=normal, 1=triggered */ ++ imx296_write(sensor, IMX296_CTRL0B, ++ (trigger_mode == 1) ? IMX296_CTRL0B_TRIGEN : 0, &ret); ++ imx296_write(sensor, IMX296_LOWLAGTRG, ++ (trigger_mode == 1) ? IMX296_LOWLAGTRG_FAST : 0, &ret); + + imx296_write(sensor, IMX296_CTRL0A, 0, &ret); + +--- a/drivers/media/i2c/imx477.c ++++ b/drivers/media/i2c/imx477.c +@@ -1742,26 +1742,21 @@ static int imx477_start_streaming(struct + imx477_write_reg(imx477, 0x0b05, IMX477_REG_VALUE_08BIT, !!dpc_enable); + imx477_write_reg(imx477, 0x0b06, IMX477_REG_VALUE_08BIT, !!dpc_enable); + +- /* Set vsync trigger mode */ +- if (trigger_mode != 0) { +- /* trigger_mode == 1 for source, 2 for sink */ +- const u32 val = (trigger_mode == 1) ? 1 : 0; +- +- imx477_write_reg(imx477, IMX477_REG_MC_MODE, +- IMX477_REG_VALUE_08BIT, 1); +- imx477_write_reg(imx477, IMX477_REG_MS_SEL, +- IMX477_REG_VALUE_08BIT, val); +- imx477_write_reg(imx477, IMX477_REG_XVS_IO_CTRL, +- IMX477_REG_VALUE_08BIT, val); +- imx477_write_reg(imx477, IMX477_REG_EXTOUT_EN, +- IMX477_REG_VALUE_08BIT, val); +- } +- + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(imx477->sd.ctrl_handler); + if (ret) + return ret; + ++ /* Set vsync trigger mode: 0=standalone, 1=source, 2=sink */ ++ imx477_write_reg(imx477, IMX477_REG_MC_MODE, ++ IMX477_REG_VALUE_08BIT, (trigger_mode > 0) ? 1 : 0); ++ imx477_write_reg(imx477, IMX477_REG_MS_SEL, ++ IMX477_REG_VALUE_08BIT, (trigger_mode <= 1) ? 1 : 0); ++ imx477_write_reg(imx477, IMX477_REG_XVS_IO_CTRL, ++ IMX477_REG_VALUE_08BIT, (trigger_mode == 1) ? 1 : 0); ++ imx477_write_reg(imx477, IMX477_REG_EXTOUT_EN, ++ IMX477_REG_VALUE_08BIT, (trigger_mode == 1) ? 1 : 0); ++ + /* set stream on register */ + return imx477_write_reg(imx477, IMX477_REG_MODE_SELECT, + IMX477_REG_VALUE_08BIT, IMX477_MODE_STREAMING); +@@ -1778,6 +1773,10 @@ static void imx477_stop_streaming(struct + IMX477_REG_VALUE_08BIT, IMX477_MODE_STANDBY); + if (ret) + dev_err(&client->dev, "%s failed to set stream\n", __func__); ++ ++ /* Stop driving XVS out (there is still a weak pull-up) */ ++ imx477_write_reg(imx477, IMX477_REG_EXTOUT_EN, ++ IMX477_REG_VALUE_08BIT, 0); + } + + static int imx477_set_stream(struct v4l2_subdev *sd, int enable) diff --git a/target/linux/bcm27xx/patches-6.1/950-1223-overlays-Add-always-on-parameter-to-imx477-and-imx29.patch b/target/linux/bcm27xx/patches-6.1/950-1223-overlays-Add-always-on-parameter-to-imx477-and-imx29.patch new file mode 100644 index 0000000000..d705df6f40 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1223-overlays-Add-always-on-parameter-to-imx477-and-imx29.patch @@ -0,0 +1,99 @@ +From 3ed57f25f3074f6abfe570fc11aa7d370fdc499a Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Wed, 6 Dec 2023 14:38:03 +0000 +Subject: [PATCH] overlays: Add "always-on" parameter to imx477 and imx296 + +Leave the camera's power supplies up, to prevent the camera +clamping its 1.8V digital I/Os to ground. This may be useful +when synchronizing multiple camera systems using XVS or XTRIG. + +Signed-off-by: Nick Hollinghurst +--- + arch/arm/boot/dts/overlays/README | 6 ++++++ + arch/arm/boot/dts/overlays/imx296-overlay.dts | 9 +++++++++ + arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi | 9 +++++++++ + 3 files changed, 24 insertions(+) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2520,6 +2520,8 @@ Params: rotation Mounting + clock-frequency Sets the clock frequency to match that used on + the board, which should be one of 54000000 + (the default), 37125000 or 74250000. ++ always-on Leave the regulator powered up, to stop the ++ camera clamping I/Os such as XTRIG to 0V. + + + Name: imx327 +@@ -2558,6 +2560,8 @@ Params: rotation Mounting + configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). ++ always-on Leave the regulator powered up, to stop the ++ camera clamping I/Os such as XVS to 0V. + + + Name: imx462 +@@ -2596,6 +2600,8 @@ Params: rotation Mounting + configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). ++ always-on Leave the regulator powered up, to stop the ++ camera clamping I/Os such as XVS to 0V. + + + Name: imx519 +--- a/arch/arm/boot/dts/overlays/imx296-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx296-overlay.dts +@@ -37,6 +37,13 @@ + }; + }; + ++ reg_alwayson_frag: fragment@99 { ++ target = <&cam1_reg>; ++ __dormant__ { ++ regulator-always-on; ++ }; ++ }; ++ + i2c_frag: fragment@100 { + target = <&i2c_csi_dsi>; + __overlay__ { +@@ -98,8 +105,10 @@ + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <®_frag>, "target:0=",<&cam0_reg>, ++ <®_alwayson_frag>, "target:0=",<&cam0_reg>, + <&imx296>, "clocks:0=",<&cam0_clk>, + <&imx296>, "avdd-supply:0=",<&cam0_reg>; + clock-frequency = <&clk_over>, "clock-frequency:0"; ++ always-on = <0>, "+99"; + }; + }; +--- a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi ++++ b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi +@@ -33,6 +33,13 @@ + }; + }; + ++ reg_alwayson_frag: fragment@99 { ++ target = <&cam1_reg>; ++ __dormant__ { ++ regulator-always-on; ++ }; ++ }; ++ + i2c_frag: fragment@100 { + target = <&i2c_csi_dsi>; + __overlay__ { +@@ -69,8 +76,10 @@ + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <®_frag>, "target:0=",<&cam0_reg>, ++ <®_alwayson_frag>, "target:0=",<&cam0_reg>, + <&cam_node>, "clocks:0=",<&cam0_clk>, + <&cam_node>, "VANA-supply:0=",<&cam0_reg>; ++ always-on = <0>, "+99"; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1224-input-edt-ft5x06-Correct-prefix-length-in-snprintf.patch b/target/linux/bcm27xx/patches-6.1/950-1224-input-edt-ft5x06-Correct-prefix-length-in-snprintf.patch new file mode 100644 index 0000000000..6fb8fc0b95 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1224-input-edt-ft5x06-Correct-prefix-length-in-snprintf.patch @@ -0,0 +1,29 @@ +From e0ecfaf1abfd5ef63ceec7606352020a80a2742b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 18 Dec 2023 11:49:36 +0000 +Subject: [PATCH] input: edt-ft5x06: Correct prefix length in snprintf + +snprintf takes the length of the array that we can print into, +and has to fit the NULL terminator in there too. +Printing the prefix is generally "12-3456 " which is 8 desired +characters (the length of EDT_NAME_PREFIX_LEN) and the NULL. +The space is therefore being truncated to fit the NULL in. + +Increase the length snprintf is allowed to use. + +Signed-off-by: Dave Stevenson +--- + drivers/input/touchscreen/edt-ft5x06.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/input/touchscreen/edt-ft5x06.c ++++ b/drivers/input/touchscreen/edt-ft5x06.c +@@ -966,7 +966,7 @@ static int edt_ft5x06_ts_identify(struct + char *model_name = tsdata->name; + char *fw_version = tsdata->fw_version; + +- snprintf(model_name, EDT_NAME_PREFIX_LEN, "%s ", dev_name(&client->dev)); ++ snprintf(model_name, EDT_NAME_PREFIX_LEN + 1, "%s ", dev_name(&client->dev)); + model_name += strlen(model_name); + + /* see what we find if we assume it is a M06 * diff --git a/target/linux/bcm27xx/patches-6.1/950-1225-ARM-dts-bcm2712-rpi-5-b-Allow-RTC-to-be-disabled.patch b/target/linux/bcm27xx/patches-6.1/950-1225-ARM-dts-bcm2712-rpi-5-b-Allow-RTC-to-be-disabled.patch new file mode 100644 index 0000000000..5a3e6df555 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1225-ARM-dts-bcm2712-rpi-5-b-Allow-RTC-to-be-disabled.patch @@ -0,0 +1,38 @@ +From da5fd98469edd797ed77d9a8690a608c6b54f9e6 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 19 Dec 2023 14:55:21 +0000 +Subject: [PATCH] ARM: dts: bcm2712-rpi-5-b: Allow RTC to be disabled + +Add a dtparam "rtc", so that "dtparam=rtc=off" can be used to disable +the Pi 5's onboard RTC. + +See: https://forums.raspberrypi.com/viewtopic.php?t=361813 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 1 + + arch/arm/boot/dts/overlays/README | 3 +++ + 2 files changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -819,6 +819,7 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; + pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; + random = <&random>, "status"; ++ rtc = <&rpi_rtc>, "status"; + rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; + spi = <&spi0>, "status"; + suspend = <&pwr_key>, "linux,code:0=205"; +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -307,6 +307,9 @@ Params: + random Set to "on" to enable the hardware random + number generator (default "on") + ++ rtc Set to "off" to disable the onboard Real Time ++ Clock (2712 only, default "on") ++ + rtc_bbat_vchg Set the RTC backup battery charging voltage in + microvolts. If set to 0 or not specified, the + trickle charger is disabled. diff --git a/target/linux/bcm27xx/patches-6.1/950-1226-i2c-designware-Look-for-CNT-values-in-DT.patch b/target/linux/bcm27xx/patches-6.1/950-1226-i2c-designware-Look-for-CNT-values-in-DT.patch new file mode 100644 index 0000000000..ccba16ad8e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1226-i2c-designware-Look-for-CNT-values-in-DT.patch @@ -0,0 +1,57 @@ +From 0a09088e24c013ef608b1bb79501ef890cefc767 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 19 Dec 2023 11:16:25 +0000 +Subject: [PATCH] i2c: designware: Look for *CNT values in DT + +The i2c-designware driver supports reading precise timing values from +ACPI, but the Device Tree support relies on a combination of standard +rise and fall times and hard-coded minimum timings. The result of this +is that it is difficult to get optimum timings, particularly given that +the values are bus speed-specific and only one set can be stored in +DT at a time. + +Add support for initialisation from DT that is similar to that for +ACPI. + +Signed-off-by: Phil Elwell +--- + drivers/i2c/busses/i2c-designware-platdrv.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/i2c/busses/i2c-designware-platdrv.c ++++ b/drivers/i2c/busses/i2c-designware-platdrv.c +@@ -132,9 +132,18 @@ static int mscc_twi_set_sda_hold_time(st + return 0; + } + ++static void dw_i2c_read_of_cnt(struct device_node *np, const char *name, u16 *pval) ++{ ++ u32 val; ++ ++ if (!of_property_read_u32(np, name, &val)) ++ *pval = (u16)val; ++} ++ + static int dw_i2c_of_configure(struct platform_device *pdev) + { + struct dw_i2c_dev *dev = platform_get_drvdata(pdev); ++ struct device_node *np = pdev->dev.of_node; + + switch (dev->flags & MODEL_MASK) { + case MODEL_MSCC_OCELOT: +@@ -146,6 +155,15 @@ static int dw_i2c_of_configure(struct pl + break; + } + ++ dw_i2c_read_of_cnt(np, "snps,ss_hcnt", &dev->ss_hcnt); ++ dw_i2c_read_of_cnt(np, "snps,ss_lcnt", &dev->ss_lcnt); ++ dw_i2c_read_of_cnt(np, "snps,fs_hcnt", &dev->fs_hcnt); ++ dw_i2c_read_of_cnt(np, "snps,fs_lcnt", &dev->fs_lcnt); ++ dw_i2c_read_of_cnt(np, "snps,fp_hcnt", &dev->fp_hcnt); ++ dw_i2c_read_of_cnt(np, "snps,fp_lcnt", &dev->fp_lcnt); ++ dw_i2c_read_of_cnt(np, "snps,hs_hcnt", &dev->hs_hcnt); ++ dw_i2c_read_of_cnt(np, "snps,hs_lcnt", &dev->hs_lcnt); ++ + return 0; + } + diff --git a/target/linux/bcm27xx/patches-6.1/950-1227-dts-rp1-Add-I2C-timings.patch b/target/linux/bcm27xx/patches-6.1/950-1227-dts-rp1-Add-I2C-timings.patch new file mode 100644 index 0000000000..892f31ec9f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1227-dts-rp1-Add-I2C-timings.patch @@ -0,0 +1,103 @@ +From 660d569b1a623e4b64350e608bbf8bc2cc6332e9 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 19 Dec 2023 11:27:20 +0000 +Subject: [PATCH] dts: rp1: Add I2C timings + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/rp1.dtsi | 42 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +--- a/arch/arm/boot/dts/rp1.dtsi ++++ b/arch/arm/boot/dts/rp1.dtsi +@@ -305,6 +305,12 @@ + compatible = "snps,designware-i2c"; + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS>; ++ snps,ss_hcnt = <978>; ++ snps,ss_lcnt = <990>; ++ snps,fs_hcnt = <200>; ++ snps,fs_lcnt = <268>; ++ snps,fp_hcnt = <60>; ++ snps,fp_lcnt = <107>; + status = "disabled"; + }; + +@@ -313,6 +319,12 @@ + compatible = "snps,designware-i2c"; + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS>; ++ snps,ss_hcnt = <978>; ++ snps,ss_lcnt = <990>; ++ snps,fs_hcnt = <200>; ++ snps,fs_lcnt = <268>; ++ snps,fp_hcnt = <60>; ++ snps,fp_lcnt = <107>; + status = "disabled"; + }; + +@@ -321,6 +333,12 @@ + compatible = "snps,designware-i2c"; + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS>; ++ snps,ss_hcnt = <978>; ++ snps,ss_lcnt = <990>; ++ snps,fs_hcnt = <200>; ++ snps,fs_lcnt = <268>; ++ snps,fp_hcnt = <60>; ++ snps,fp_lcnt = <107>; + status = "disabled"; + }; + +@@ -329,6 +347,12 @@ + compatible = "snps,designware-i2c"; + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS>; ++ snps,ss_hcnt = <978>; ++ snps,ss_lcnt = <990>; ++ snps,fs_hcnt = <200>; ++ snps,fs_lcnt = <268>; ++ snps,fp_hcnt = <60>; ++ snps,fp_lcnt = <107>; + status = "disabled"; + }; + +@@ -337,6 +361,12 @@ + compatible = "snps,designware-i2c"; + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS>; ++ snps,ss_hcnt = <978>; ++ snps,ss_lcnt = <990>; ++ snps,fs_hcnt = <200>; ++ snps,fs_lcnt = <268>; ++ snps,fp_hcnt = <60>; ++ snps,fp_lcnt = <107>; + status = "disabled"; + }; + +@@ -345,6 +375,12 @@ + compatible = "snps,designware-i2c"; + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS>; ++ snps,ss_hcnt = <978>; ++ snps,ss_lcnt = <990>; ++ snps,fs_hcnt = <200>; ++ snps,fs_lcnt = <268>; ++ snps,fp_hcnt = <60>; ++ snps,fp_lcnt = <107>; + status = "disabled"; + }; + +@@ -353,6 +389,12 @@ + compatible = "snps,designware-i2c"; + interrupts = ; + clocks = <&rp1_clocks RP1_CLK_SYS>; ++ snps,ss_hcnt = <978>; ++ snps,ss_lcnt = <990>; ++ snps,fs_hcnt = <200>; ++ snps,fs_lcnt = <268>; ++ snps,fp_hcnt = <60>; ++ snps,fp_lcnt = <107>; + status = "disabled"; + }; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1228-drivers-media-pisp_be-pisp_fe-Update-UAPI-header-lic.patch b/target/linux/bcm27xx/patches-6.1/950-1228-drivers-media-pisp_be-pisp_fe-Update-UAPI-header-lic.patch new file mode 100644 index 0000000000..fc77e4d1cf --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1228-drivers-media-pisp_be-pisp_fe-Update-UAPI-header-lic.patch @@ -0,0 +1,58 @@ +From 74c6c159c2b499bdf3c39961bd40eb9243624226 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 29 Nov 2023 13:09:05 +0000 +Subject: [PATCH] drivers: media: pisp_be: pisp_fe: Update UAPI header licenses + +Update the license tags on the pisp UAPI header files with the +"Linux-syscall-note" clause. Also replace the "GPL-2.0" tag with the +preferred "GPL-2.0-only" tag. + +Signed-off-by: Naushir Patuck +--- + drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h | 2 +- + drivers/media/platform/raspberrypi/rp1_cfe/pisp_common.h | 2 +- + drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe_config.h | 2 +- + drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h | 2 +- + drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h | 2 +- + 5 files changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h +@@ -1,4 +1,4 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ + /* + * PiSP Back End configuration definitions. + * +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_common.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_common.h +@@ -1,4 +1,4 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ + /* + * RP1 PiSP common definitions. + * +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe_config.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_fe_config.h +@@ -1,4 +1,4 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ + /* + * RP1 PiSP Front End Driver Configuration structures + * +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h +@@ -1,4 +1,4 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ + /* + * RP1 PiSP Front End statistics definitions + * +--- a/drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h +@@ -1,4 +1,4 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ + /* + * RP1 PiSP Front End image definitions. + * diff --git a/target/linux/bcm27xx/patches-6.1/950-1229-drivers-media-cfe-Add-more-robust-ISR-handlers.patch b/target/linux/bcm27xx/patches-6.1/950-1229-drivers-media-cfe-Add-more-robust-ISR-handlers.patch new file mode 100644 index 0000000000..b79cad417f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1229-drivers-media-cfe-Add-more-robust-ISR-handlers.patch @@ -0,0 +1,207 @@ +From 6fb7a0b4c1dd6cf5b12ec2b2c197dcf8e58cd2b9 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Mon, 18 Dec 2023 09:52:45 +0000 +Subject: [PATCH] drivers: media: cfe: Add more robust ISR handlers + +Update the ISR logic to be more robust to sensors in problematic states +where interrupts may start arriving overlapped and/or missing. + +1) Test for cur_frame in the FE handler, and if present, dequeue it in +an error state so that it does not get orphaned. + +2) Move the sequence counter and timestamp variables to the node +structures. This allows the ISR to track channels running ahead when +interrupts arrive unordered. + +3) Add a test to ensure we don't have a spurios (but harmlesS) call to +the FE handler in some circumstances. + +Signed-off-by: Naushir Patuck +--- + .../media/platform/raspberrypi/rp1_cfe/cfe.c | 92 ++++++++++--------- + 1 file changed, 49 insertions(+), 43 deletions(-) + +--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c ++++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +@@ -272,6 +272,8 @@ struct cfe_node { + /* Pointer to the parent handle */ + struct cfe_device *cfe; + struct media_pad pad; ++ unsigned int fs_count; ++ u64 ts; + }; + + struct cfe_device { +@@ -311,9 +313,6 @@ struct cfe_device { + struct pisp_fe_device fe; + + int fe_csi2_channel; +- +- unsigned int sequence; +- u64 ts; + }; + + static inline bool is_fe_enabled(struct cfe_device *cfe) +@@ -393,17 +392,6 @@ static bool test_all_nodes(struct cfe_de + return true; + } + +-static void clear_all_nodes(struct cfe_device *cfe, unsigned long precond, +- unsigned long state) +-{ +- unsigned int i; +- +- for (i = 0; i < NUM_NODES; i++) { +- if (check_state(cfe, precond, i)) +- clear_state(cfe, state, i); +- } +-} +- + static int mipi_cfg_regs_show(struct seq_file *s, void *data) + { + struct cfe_device *cfe = s->private; +@@ -656,22 +644,22 @@ static void cfe_prepare_next_job(struct + } + + static void cfe_process_buffer_complete(struct cfe_node *node, +- unsigned int sequence) ++ enum vb2_buffer_state state) + { + struct cfe_device *cfe = node->cfe; + + cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__, + node_desc[node->id].name, &node->cur_frm->vb.vb2_buf); + +- node->cur_frm->vb.sequence = sequence; +- vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); ++ node->cur_frm->vb.sequence = node->fs_count - 1; ++ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); + } + + static void cfe_queue_event_sof(struct cfe_node *node) + { + struct v4l2_event event = { + .type = V4L2_EVENT_FRAME_SYNC, +- .u.frame_sync.frame_sequence = node->cfe->sequence, ++ .u.frame_sync.frame_sequence = node->fs_count - 1, + }; + + v4l2_event_queue(&node->video_dev, &event); +@@ -680,28 +668,53 @@ static void cfe_queue_event_sof(struct c + static void cfe_sof_isr_handler(struct cfe_node *node) + { + struct cfe_device *cfe = node->cfe; ++ bool matching_fs = true; ++ unsigned int i; + + cfe_dbg_verbose("%s: [%s] seq %u\n", __func__, node_desc[node->id].name, +- cfe->sequence); +- +- node->cur_frm = node->next_frm; +- node->next_frm = NULL; ++ node->fs_count); + + /* +- * If this is the first node to see a frame start, sample the +- * timestamp to use for all frames across all channels. ++ * If the sensor is producing unexpected frame event ordering over a ++ * sustained period of time, guard against the possibility of coming ++ * here and orphaning the cur_frm if it's not been dequeued already. ++ * Unfortunately, there is not enough hardware state to tell if this ++ * may have occurred. + */ +- if (!test_any_node(cfe, NODE_STREAMING | FS_INT)) +- cfe->ts = ktime_get_ns(); ++ if (WARN(node->cur_frm, "%s: [%s] Orphanded frame at seq %u\n", ++ __func__, node_desc[node->id].name, node->fs_count)) ++ cfe_process_buffer_complete(node, VB2_BUF_STATE_ERROR); + +- set_state(cfe, FS_INT, node->id); ++ node->cur_frm = node->next_frm; ++ node->next_frm = NULL; ++ node->fs_count++; + +- /* If all nodes have seen a frame start, we can queue another job. */ +- if (test_all_nodes(cfe, NODE_STREAMING, FS_INT)) ++ node->ts = ktime_get_ns(); ++ for (i = 0; i < NUM_NODES; i++) { ++ if (!check_state(cfe, NODE_STREAMING, i) || i == node->id) ++ continue; ++ /* ++ * This checks if any other node has seen a FS. If yes, use the ++ * same timestamp, eventually across all node buffers. ++ */ ++ if (cfe->node[i].fs_count >= node->fs_count) ++ node->ts = cfe->node[i].ts; ++ /* ++ * This checks if all other node have seen a matching FS. If ++ * yes, we can flag another job to be queued. ++ */ ++ if (matching_fs && cfe->node[i].fs_count != node->fs_count) ++ matching_fs = false; ++ } ++ ++ if (matching_fs) + cfe->job_queued = false; + + if (node->cur_frm) +- node->cur_frm->vb.vb2_buf.timestamp = cfe->ts; ++ node->cur_frm->vb.vb2_buf.timestamp = node->ts; ++ ++ set_state(cfe, FS_INT, node->id); ++ clear_state(cfe, FE_INT, node->id); + + if (is_image_output_node(node)) + cfe_queue_event_sof(node); +@@ -712,22 +725,14 @@ static void cfe_eof_isr_handler(struct c + struct cfe_device *cfe = node->cfe; + + cfe_dbg_verbose("%s: [%s] seq %u\n", __func__, node_desc[node->id].name, +- cfe->sequence); ++ node->fs_count - 1); + + if (node->cur_frm) +- cfe_process_buffer_complete(node, cfe->sequence); ++ cfe_process_buffer_complete(node, VB2_BUF_STATE_DONE); + + node->cur_frm = NULL; + set_state(cfe, FE_INT, node->id); +- +- /* +- * If all nodes have seen a frame end, we can increment +- * the sequence counter now. +- */ +- if (test_all_nodes(cfe, NODE_STREAMING, FE_INT)) { +- cfe->sequence++; +- clear_all_nodes(cfe, NODE_STREAMING, FE_INT | FS_INT); +- } ++ clear_state(cfe, FS_INT, node->id); + } + + static irqreturn_t cfe_isr(int irq, void *dev) +@@ -794,7 +799,8 @@ static irqreturn_t cfe_isr(int irq, void + * frame first before the FS handler for the current + * frame. + */ +- if (check_state(cfe, FS_INT, node->id)) { ++ if (check_state(cfe, FS_INT, node->id) && ++ !check_state(cfe, FE_INT, node->id)) { + cfe_dbg("%s: [%s] Handling missing previous FE interrupt\n", + __func__, node_desc[node->id].name); + cfe_eof_isr_handler(node); +@@ -1131,6 +1137,7 @@ static int cfe_start_streaming(struct vb + + clear_state(cfe, FS_INT | FE_INT, node->id); + set_state(cfe, NODE_STREAMING, node->id); ++ node->fs_count = 0; + cfe_start_channel(node); + + if (!test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) { +@@ -1166,7 +1173,6 @@ static int cfe_start_streaming(struct vb + csi2_open_rx(&cfe->csi2); + + cfe_dbg("Starting sensor streaming\n"); +- cfe->sequence = 0; + ret = v4l2_subdev_call(cfe->sensor, video, s_stream, 1); + if (ret < 0) { + cfe_err("stream on failed in subdev\n"); diff --git a/target/linux/bcm27xx/patches-6.1/950-1231-ASoC-dwc-Defer-bclk_ratio-handling-to-hw_params.patch b/target/linux/bcm27xx/patches-6.1/950-1231-ASoC-dwc-Defer-bclk_ratio-handling-to-hw_params.patch new file mode 100644 index 0000000000..c187507545 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1231-ASoC-dwc-Defer-bclk_ratio-handling-to-hw_params.patch @@ -0,0 +1,89 @@ +From dfc04900c40eb14f9364d56e96db2cc3340a1f21 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 3 Jan 2024 14:43:43 +0000 +Subject: [PATCH] ASoC: dwc: Defer bclk_ratio handling to hw_params + +bclk_ratio is only a factor in clock producer mode, and needs to +override the default value of num_channels * sample_size. +Move the bclk_ratio handling into the hw_params method, only latching +the value in set_bclk_ratio, to address both of those matters. + +See: https://github.com/raspberrypi/linux/issues/5817 + +Signed-off-by: Phil Elwell +--- + sound/soc/dwc/dwc-i2s.c | 38 +++++++++++++++++++++----------------- + sound/soc/dwc/local.h | 1 + + 2 files changed, 22 insertions(+), 17 deletions(-) + +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -263,6 +263,25 @@ static int dw_i2s_hw_params(struct snd_p + return -EINVAL; + } + ++ if ((dev->capability & DW_I2S_MASTER) && dev->bclk_ratio) { ++ switch (dev->bclk_ratio) { ++ case 32: ++ dev->ccr = 0x00; ++ break; ++ ++ case 48: ++ dev->ccr = 0x08; ++ break; ++ ++ case 64: ++ dev->ccr = 0x10; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ } ++ + config->chan_nr = params_channels(params); + + switch (config->chan_nr) { +@@ -436,23 +455,7 @@ static int dw_i2s_set_bclk_ratio(struct + + dev_dbg(dev->dev, "%s(%d)\n", __func__, ratio); + +- switch (ratio) { +- case 32: +- dev->ccr = 0x00; +- break; +- +- case 48: +- dev->ccr = 0x08; +- break; +- +- case 64: +- dev->ccr = 0x10; +- break; +- default: +- return -EINVAL; +- } +- +- i2s_write_reg(dev->i2s_base, CCR, dev->ccr); ++ dev->bclk_ratio = ratio; + + return 0; + } +@@ -746,6 +749,7 @@ static int dw_i2s_probe(struct platform_ + } + } + ++ dev->bclk_ratio = 0; + dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; + dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; + if (pdata) { +--- a/sound/soc/dwc/local.h ++++ b/sound/soc/dwc/local.h +@@ -107,6 +107,7 @@ struct dw_i2s_dev { + unsigned int quirks; + unsigned int i2s_reg_comp1; + unsigned int i2s_reg_comp2; ++ unsigned int bclk_ratio; + struct device *dev; + u32 ccr; + u32 xfer_resolution; diff --git a/target/linux/bcm27xx/patches-6.1/950-1232-drm-vc4-Fix-reading-of-frame-count-on-GEN5-Pi4.patch b/target/linux/bcm27xx/patches-6.1/950-1232-drm-vc4-Fix-reading-of-frame-count-on-GEN5-Pi4.patch new file mode 100644 index 0000000000..4374e24244 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1232-drm-vc4-Fix-reading-of-frame-count-on-GEN5-Pi4.patch @@ -0,0 +1,79 @@ +From d5066442e39dd9bf4ba6431ffb3f99e3d5085d3f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 4 Jan 2024 12:02:43 +0000 +Subject: [PATCH] drm/vc4: Fix reading of frame count on GEN5 / Pi4 + +The frame count values moved within registers DISPSTAT1 and +DISPSTAT2 with GEN5, so update the accessor function to +accommodate that. + +Fixes: b51cd7ad143d ("drm/vc4: hvs: Fix frame count register readout") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hvs.c | 23 +++++++++++++++++++++-- + drivers/gpu/drm/vc4/vc4_regs.h | 6 ++++++ + 2 files changed, 27 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -823,10 +823,28 @@ u8 vc4_hvs_get_fifo_frame_count(struct v + if (!drm_dev_enter(drm, &idx)) + return 0; + +- if (vc4->gen >= VC4_GEN_6) { ++ switch (vc4->gen) { ++ case VC4_GEN_6: + field = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_STATUS(fifo)), + SCALER6_DISPX_STATUS_FRCNT); +- } else { ++ break; ++ case VC4_GEN_5: ++ switch (fifo) { ++ case 0: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), ++ SCALER5_DISPSTAT1_FRCNT0); ++ break; ++ case 1: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), ++ SCALER5_DISPSTAT1_FRCNT1); ++ break; ++ case 2: ++ field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2), ++ SCALER5_DISPSTAT2_FRCNT2); ++ break; ++ } ++ break; ++ case VC4_GEN_4: + switch (fifo) { + case 0: + field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1), +@@ -841,6 +859,7 @@ u8 vc4_hvs_get_fifo_frame_count(struct v + SCALER_DISPSTAT2_FRCNT2); + break; + } ++ break; + } + + drm_dev_exit(idx); +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -424,6 +424,10 @@ + # define SCALER_DISPSTAT1_FRCNT0_SHIFT 18 + # define SCALER_DISPSTAT1_FRCNT1_MASK VC4_MASK(17, 12) + # define SCALER_DISPSTAT1_FRCNT1_SHIFT 12 ++# define SCALER5_DISPSTAT1_FRCNT0_MASK VC4_MASK(25, 20) ++# define SCALER5_DISPSTAT1_FRCNT0_SHIFT 20 ++# define SCALER5_DISPSTAT1_FRCNT1_MASK VC4_MASK(19, 14) ++# define SCALER5_DISPSTAT1_FRCNT1_SHIFT 14 + + #define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \ + (x) * (SCALER_DISPSTAT1 - \ +@@ -442,6 +446,8 @@ + #define SCALER_DISPSTAT2 0x00000068 + # define SCALER_DISPSTAT2_FRCNT2_MASK VC4_MASK(17, 12) + # define SCALER_DISPSTAT2_FRCNT2_SHIFT 12 ++# define SCALER5_DISPSTAT2_FRCNT2_MASK VC4_MASK(19, 14) ++# define SCALER5_DISPSTAT2_FRCNT2_SHIFT 14 + + #define SCALER_DISPBASE2 0x0000006c + #define SCALER_DISPALPHA2 0x00000070 diff --git a/target/linux/bcm27xx/patches-6.1/950-1233-ARM-dts-bcm2712-rpi-5-b-Add-eth_ledx-parameters.patch b/target/linux/bcm27xx/patches-6.1/950-1233-ARM-dts-bcm2712-rpi-5-b-Add-eth_ledx-parameters.patch new file mode 100644 index 0000000000..f0c6efa362 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1233-ARM-dts-bcm2712-rpi-5-b-Add-eth_ledx-parameters.patch @@ -0,0 +1,56 @@ +From eeb5969ae34df16024f39a77496a44ae94bfab13 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 4 Jan 2024 13:56:39 +0000 +Subject: [PATCH] ARM: dts: bcm2712-rpi-5-b: Add eth_ledx parameters + +Include the dtparams controlling the Ethernet jack LEDs, as used on +other Pis. + +See: https://github.com/raspberrypi/linux/issues/5825 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 2 ++ + arch/arm/boot/dts/overlays/README | 6 +++--- + 2 files changed, 5 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -830,6 +830,8 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + act_led_trigger = <&act_led>, "linux,default-trigger"; + pwr_led_activelow = <&pwr_led>, "gpios:8"; + pwr_led_trigger = <&pwr_led>, "linux,default-trigger"; ++ eth_led0 = <&phy1>,"led-modes:0"; ++ eth_led1 = <&phy1>,"led-modes:4"; + drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; + drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; + drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -207,7 +207,7 @@ Params: + 0 means never downshift (default 2). Pi3B+ only. + + eth_led0 Set mode of LED0 - amber on Pi3B+ (default "1"), +- green on Pi4 (default "0"). ++ green on Pi4/5 (default "0"). + The legal values are: + + Pi3B+ +@@ -217,7 +217,7 @@ Params: + 4=link100/1000/activity 5=link10/1000/activity + 6=link10/100/activity 14=off 15=on + +- Pi4 ++ Pi4/5 + + 0=Speed/Activity 1=Speed + 2=Flash activity 3=FDX +@@ -226,7 +226,7 @@ Params: + 8=Link 9=Activity + + eth_led1 Set mode of LED1 - green on Pi3B+ (default "6"), +- amber on Pi4 (default "8"). See eth_led0 for ++ amber on Pi4/5 (default "8"). See eth_led0 for + legal values. + + eth_max_speed Set the maximum speed a link is allowed diff --git a/target/linux/bcm27xx/patches-6.1/950-1234-ARM-dts-bcm2712-rpi-5-b-Add-fan-speed-dtparams.patch b/target/linux/bcm27xx/patches-6.1/950-1234-ARM-dts-bcm2712-rpi-5-b-Add-fan-speed-dtparams.patch new file mode 100644 index 0000000000..da2345fdf7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1234-ARM-dts-bcm2712-rpi-5-b-Add-fan-speed-dtparams.patch @@ -0,0 +1,71 @@ +From 2c085a1ff40521ab89d8f1894757aa83b59b4607 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 4 Jan 2024 12:09:10 +0000 +Subject: [PATCH] ARM: dts: bcm2712-rpi-5-b: Add fan speed dtparams + +Add dtparams for adjusting the Pi 5 cooling fan speeds and temperature +thresholds. + +See: https://github.com/raspberrypi/linux/issues/5820 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2712-rpi-5-b.dts | 13 +++++++++++++ + arch/arm/boot/dts/overlays/README | 25 +++++++++++++++++++++++++ + 2 files changed, 38 insertions(+) + +--- a/arch/arm/boot/dts/bcm2712-rpi-5-b.dts ++++ b/arch/arm/boot/dts/bcm2712-rpi-5-b.dts +@@ -844,5 +844,18 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; + drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; + drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; ++ ++ fan_temp0 = <&cpu_tepid>,"temperature:0"; ++ fan_temp1 = <&cpu_warm>,"temperature:0"; ++ fan_temp2 = <&cpu_hot>,"temperature:0"; ++ fan_temp3 = <&cpu_vhot>,"temperature:0"; ++ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0"; ++ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0"; ++ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0"; ++ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0"; ++ fan_temp0_speed = <&fan>, "cooling-levels:4"; ++ fan_temp1_speed = <&fan>, "cooling-levels:8"; ++ fan_temp2_speed = <&fan>, "cooling-levels:12"; ++ fan_temp3_speed = <&fan>, "cooling-levels:16"; + }; + }; +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -233,6 +233,31 @@ Params: + to negotiate. Legal values are 10, 100 and + 1000 (default 1000). Pi3B+ only. + ++ fan_temp0 Temperature threshold (in millicelcius) for ++ 1st cooling level (default 50000). Pi5 only. ++ fan_temp0_hyst Temperature hysteresis (in millicelcius) for ++ 1st cooling level (default 5000). Pi5 only. ++ fan_temp0_speed Fan PWM setting for 1st cooling level (0-255, ++ default 75). Pi5 only. ++ fan_temp1 Temperature threshold (in millicelcius) for ++ 2nd cooling level (default 60000). Pi5 only. ++ fan_temp1_hyst Temperature hysteresis (in millicelcius) for ++ 2nd cooling level (default 5000). Pi5 only. ++ fan_temp1_speed Fan PWM setting for 2nd cooling level (0-255, ++ default 125). Pi5 only. ++ fan_temp2 Temperature threshold (in millicelcius) for ++ 3rd cooling level (default 67500). Pi5 only. ++ fan_temp2_hyst Temperature hysteresis (in millicelcius) for ++ 3rd cooling level (default 5000). Pi5 only. ++ fan_temp2_speed Fan PWM setting for 3rd cooling level (0-255, ++ default 175). Pi5 only. ++ fan_temp3 Temperature threshold (in millicelcius) for ++ 4th cooling level (default 75000). Pi5 only. ++ fan_temp3_hyst Temperature hysteresis (in millicelcius) for ++ 4th cooling level (default 5000). Pi5 only. ++ fan_temp3_speed Fan PWM setting for 4th cooling level (0-255, ++ default 250). Pi5 only. ++ + hdmi Set to "off" to disable the HDMI interface + (default "on") + diff --git a/target/linux/bcm27xx/patches-6.1/950-1235-drm-vc4-don-t-check-if-plane-state-fb-state-fb.patch b/target/linux/bcm27xx/patches-6.1/950-1235-drm-vc4-don-t-check-if-plane-state-fb-state-fb.patch new file mode 100644 index 0000000000..7c7c05c5ef --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1235-drm-vc4-don-t-check-if-plane-state-fb-state-fb.patch @@ -0,0 +1,93 @@ +From 146bbf9627f6c37816939de29538ec8ee9a7be1a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Fri, 5 Jan 2024 15:07:34 -0300 +Subject: [PATCH] drm/vc4: don't check if plane->state->fb == state->fb +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently, when using non-blocking commits, we can see the following +kernel warning: + +[ 110.908514] ------------[ cut here ]------------ +[ 110.908529] refcount_t: underflow; use-after-free. +[ 110.908620] WARNING: CPU: 0 PID: 1866 at lib/refcount.c:87 refcount_dec_not_one+0xb8/0xc0 +[ 110.908664] Modules linked in: rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device cmac algif_hash aes_arm64 aes_generic algif_skcipher af_alg bnep hid_logitech_hidpp vc4 brcmfmac hci_uart btbcm brcmutil bluetooth snd_soc_hdmi_codec cfg80211 cec drm_display_helper drm_dma_helper drm_kms_helper snd_soc_core snd_compress snd_pcm_dmaengine fb_sys_fops sysimgblt syscopyarea sysfillrect raspberrypi_hwmon ecdh_generic ecc rfkill libaes i2c_bcm2835 binfmt_misc joydev snd_bcm2835(C) bcm2835_codec(C) bcm2835_isp(C) v4l2_mem2mem videobuf2_dma_contig snd_pcm bcm2835_v4l2(C) raspberrypi_gpiomem bcm2835_mmal_vchiq(C) videobuf2_v4l2 snd_timer videobuf2_vmalloc videobuf2_memops videobuf2_common snd videodev vc_sm_cma(C) mc hid_logitech_dj uio_pdrv_genirq uio i2c_dev drm fuse dm_mod drm_panel_orientation_quirks backlight ip_tables x_tables ipv6 +[ 110.909086] CPU: 0 PID: 1866 Comm: kodi.bin Tainted: G C 6.1.66-v8+ #32 +[ 110.909104] Hardware name: Raspberry Pi 3 Model B Rev 1.2 (DT) +[ 110.909114] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 110.909132] pc : refcount_dec_not_one+0xb8/0xc0 +[ 110.909152] lr : refcount_dec_not_one+0xb4/0xc0 +[ 110.909170] sp : ffffffc00913b9c0 +[ 110.909177] x29: ffffffc00913b9c0 x28: 000000556969bbb0 x27: 000000556990df60 +[ 110.909205] x26: 0000000000000002 x25: 0000000000000004 x24: ffffff8004448480 +[ 110.909230] x23: ffffff800570b500 x22: ffffff802e03a7bc x21: ffffffecfca68c78 +[ 110.909257] x20: ffffff8002b42000 x19: ffffff802e03a600 x18: 0000000000000000 +[ 110.909283] x17: 0000000000000011 x16: ffffffffffffffff x15: 0000000000000004 +[ 110.909308] x14: 0000000000000fff x13: ffffffed577e47e0 x12: 0000000000000003 +[ 110.909333] x11: 0000000000000000 x10: 0000000000000027 x9 : c912d0d083728c00 +[ 110.909359] x8 : c912d0d083728c00 x7 : 65646e75203a745f x6 : 746e756f63666572 +[ 110.909384] x5 : ffffffed579f62ee x4 : ffffffed579eb01e x3 : 0000000000000000 +[ 110.909409] x2 : 0000000000000000 x1 : ffffffc00913b750 x0 : 0000000000000001 +[ 110.909434] Call trace: +[ 110.909441] refcount_dec_not_one+0xb8/0xc0 +[ 110.909461] vc4_bo_dec_usecnt+0x4c/0x1b0 [vc4] +[ 110.909903] vc4_cleanup_fb+0x44/0x50 [vc4] +[ 110.910315] drm_atomic_helper_cleanup_planes+0x88/0xa4 [drm_kms_helper] +[ 110.910669] vc4_atomic_commit_tail+0x390/0x9dc [vc4] +[ 110.911079] commit_tail+0xb0/0x164 [drm_kms_helper] +[ 110.911397] drm_atomic_helper_commit+0x1d0/0x1f0 [drm_kms_helper] +[ 110.911716] drm_atomic_commit+0xb0/0xdc [drm] +[ 110.912569] drm_mode_atomic_ioctl+0x348/0x4b8 [drm] +[ 110.913330] drm_ioctl_kernel+0xec/0x15c [drm] +[ 110.914091] drm_ioctl+0x24c/0x3b0 [drm] +[ 110.914850] __arm64_sys_ioctl+0x9c/0xd4 +[ 110.914873] invoke_syscall+0x4c/0x114 +[ 110.914897] el0_svc_common+0xd0/0x118 +[ 110.914917] do_el0_svc+0x38/0xd0 +[ 110.914936] el0_svc+0x30/0x8c +[ 110.914958] el0t_64_sync_handler+0x84/0xf0 +[ 110.914979] el0t_64_sync+0x18c/0x190 +[ 110.914996] ---[ end trace 0000000000000000 ]--- + +This happens because, although `prepare_fb` and `cleanup_fb` are +perfectly balanced, we cannot guarantee consistency in the check +plane->state->fb == state->fb. This means that sometimes we can increase +the refcount in `prepare_fb` and don't decrease it in `cleanup_fb`. The +opposite can also be true. + +In fact, the struct drm_plane .state shouldn't be accessed directly +but instead, the `drm_atomic_get_new_plane_state()` helper function should +be used. So, we could stick to this check, but using +`drm_atomic_get_new_plane_state()`. But actually, this check is not really +needed. We can increase and decrease the refcount symmetrically without +problems. + +This is going to make the code more simple and consistent. + +Signed-off-by: Maíra Canal +--- + drivers/gpu/drm/vc4/vc4_plane.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -2225,9 +2225,6 @@ static int vc4_prepare_fb(struct drm_pla + + drm_gem_plane_helper_prepare_fb(plane, state); + +- if (plane->state->fb == state->fb) +- return 0; +- + return vc4_bo_inc_usecnt(bo); + } + +@@ -2236,7 +2233,7 @@ static void vc4_cleanup_fb(struct drm_pl + { + struct vc4_bo *bo; + +- if (plane->state->fb == state->fb || !state->fb) ++ if (!state->fb) + return; + + bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base); diff --git a/target/linux/bcm27xx/patches-6.1/950-1236-spi-bcm2835-Support-spi0-0cs-and-SPI_NO_CS-mode.patch b/target/linux/bcm27xx/patches-6.1/950-1236-spi-bcm2835-Support-spi0-0cs-and-SPI_NO_CS-mode.patch new file mode 100644 index 0000000000..6039363a40 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1236-spi-bcm2835-Support-spi0-0cs-and-SPI_NO_CS-mode.patch @@ -0,0 +1,42 @@ +From 5d9075ed7e73dc6ccebf78710c78f39ddc2dd78e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 8 Jan 2024 11:42:57 +0000 +Subject: [PATCH] spi: bcm2835: Support spi0-0cs and SPI_NO_CS mode + +The forced conversion of native CS lines into software CS lines is done +whether or not the controller has been given any CS lines to use. This +breaks the use of the spi0-0cs overlay to prevent SPI from claiming any +CS lines, particularly with spidev which doesn't pass in the SPI_NO_CS +flag at creation. + +Use the presence of an empty cs-gpios property as an indication that no +CS lines should be used, bypassing the native CS conversion code. + +See: https://github.com/raspberrypi/linux/issues/5835 + +Signed-off-by: Phil Elwell +--- + drivers/spi/spi-bcm2835.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -1222,6 +1222,7 @@ static int bcm2835_spi_setup(struct spi_ + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + struct bcm2835_spidev *slv = spi_get_ctldata(spi); + struct gpio_chip *chip; ++ int len; + int ret; + u32 cs; + +@@ -1287,6 +1288,10 @@ static int bcm2835_spi_setup(struct spi_ + goto err_cleanup; + } + ++ /* Skip forced CS conversion if controller has an empty cs-gpios property */ ++ if (of_find_property(ctlr->dev.of_node, "cs-gpios", &len) && len == 0) ++ return 0; ++ + /* + * Translate native CS to GPIO + * diff --git a/target/linux/bcm27xx/patches-6.1/950-1237-drivers-media-imx519-Add-V4L2_CID_LINK_FREQ-control.patch b/target/linux/bcm27xx/patches-6.1/950-1237-drivers-media-imx519-Add-V4L2_CID_LINK_FREQ-control.patch new file mode 100644 index 0000000000..889ddd77dc --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1237-drivers-media-imx519-Add-V4L2_CID_LINK_FREQ-control.patch @@ -0,0 +1,51 @@ +From 55ed8cded4af6530276b26f567601bed868ae8f5 Mon Sep 17 00:00:00 2001 +From: Lee Jackson +Date: Wed, 10 Jan 2024 08:52:54 +0800 +Subject: [PATCH] drivers: media: imx519: Add V4L2_CID_LINK_FREQ control + +Add V4L2_CID_LINK_FREQ as a read-only control with a value of 408 Mhz. +This will be used by the CFE driver to corretly setup the DPHY timing +parameters in the CSI-2 block. + +Signed-off-by: Lee Jackson +--- + drivers/media/i2c/imx519.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/media/i2c/imx519.c ++++ b/drivers/media/i2c/imx519.c +@@ -145,6 +145,10 @@ struct imx519_mode { + struct imx519_reg_list reg_list; + }; + ++static const s64 imx519_link_freq_menu[] = { ++ IMX519_DEFAULT_LINK_FREQ, ++}; ++ + static const struct imx519_reg mode_common_regs[] = { + {0x0100, 0x00}, + {0x0136, 0x18}, +@@ -1819,6 +1823,7 @@ static int imx519_init_controls(struct i + struct v4l2_ctrl_handler *ctrl_hdlr; + struct i2c_client *client = v4l2_get_subdevdata(&imx519->sd); + struct v4l2_fwnode_device_properties props; ++ struct v4l2_ctrl *link_freq; + unsigned int i; + int ret; + +@@ -1837,6 +1842,15 @@ static int imx519_init_controls(struct i + IMX519_PIXEL_RATE, 1, + IMX519_PIXEL_RATE); + ++ /* LINK_FREQ is also read only */ ++ link_freq = ++ v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx519_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(imx519_link_freq_menu) - 1, 0, ++ imx519_link_freq_menu); ++ if (link_freq) ++ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ + /* + * Create the controls here, but mode specific limits are setup + * in the imx519_set_framing_limits() call below. diff --git a/target/linux/bcm27xx/patches-6.1/950-1238-drivers-media-arducam_64mp-Add-V4L2_CID_LINK_FREQ-co.patch b/target/linux/bcm27xx/patches-6.1/950-1238-drivers-media-arducam_64mp-Add-V4L2_CID_LINK_FREQ-co.patch new file mode 100644 index 0000000000..df353ffc31 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1238-drivers-media-arducam_64mp-Add-V4L2_CID_LINK_FREQ-co.patch @@ -0,0 +1,56 @@ +From 5e339e1502c9be0f624398cf774e5880a6d1a677 Mon Sep 17 00:00:00 2001 +From: Lee Jackson +Date: Wed, 10 Jan 2024 09:06:16 +0800 +Subject: [PATCH] drivers: media: arducam_64mp: Add V4L2_CID_LINK_FREQ control + +Add V4L2_CID_LINK_FREQ as a read-only control with a value of 456 Mhz. +This will be used by the CFE driver to corretly setup the DPHY timing +parameters in the CSI-2 block. + +Signed-off-by: Lee Jackson +--- + drivers/media/i2c/arducam_64mp.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/drivers/media/i2c/arducam_64mp.c ++++ b/drivers/media/i2c/arducam_64mp.c +@@ -143,6 +143,10 @@ struct arducam_64mp_mode { + struct arducam_64mp_reg_list reg_list; + }; + ++static const s64 arducam_64mp_link_freq_menu[] = { ++ ARDUCAM_64MP_DEFAULT_LINK_FREQ, ++}; ++ + static const struct arducam_64mp_reg mode_common_regs[] = { + {0x0100, 0x00}, + {0x0136, 0x18}, +@@ -2272,9 +2276,11 @@ static int arducam_64mp_init_controls(st + struct v4l2_ctrl_handler *ctrl_hdlr; + struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd); + struct v4l2_fwnode_device_properties props; ++ struct v4l2_ctrl *link_freq; + unsigned int i; + int ret; + u8 test_pattern_max; ++ u8 link_freq_max; + + ctrl_hdlr = &arducam_64mp->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16); +@@ -2292,6 +2298,16 @@ static int arducam_64mp_init_controls(st + ARDUCAM_64MP_PIXEL_RATE, 1, + ARDUCAM_64MP_PIXEL_RATE); + ++ /* LINK_FREQ is also read only */ ++ link_freq_max = ARRAY_SIZE(arducam_64mp_link_freq_menu) - 1; ++ link_freq = ++ v4l2_ctrl_new_int_menu(ctrl_hdlr, &arducam_64mp_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ link_freq_max, 0, ++ arducam_64mp_link_freq_menu); ++ if (link_freq) ++ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ + /* + * Create the controls here, but mode specific limits are setup + * in the arducam_64mp_set_framing_limits() call below. diff --git a/target/linux/bcm27xx/patches-6.1/950-1239-drivers-gpu-drm-panel-Modify-the-DSI-mode-to-fix-the.patch b/target/linux/bcm27xx/patches-6.1/950-1239-drivers-gpu-drm-panel-Modify-the-DSI-mode-to-fix-the.patch new file mode 100644 index 0000000000..e106b0609a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1239-drivers-gpu-drm-panel-Modify-the-DSI-mode-to-fix-the.patch @@ -0,0 +1,25 @@ +From 7af1e18d2e90ec64f7cb78cdb5163b63b9fbb056 Mon Sep 17 00:00:00 2001 +From: eng33 +Date: Wed, 3 Jan 2024 11:45:04 +0800 +Subject: [PATCH] drivers/gpu/drm/panel:Modify the DSI mode to fix the problem + that 7.9inch cannot be displayed + +Signed-off-by: eng33 +--- + drivers/gpu/drm/panel/panel-waveshare-dsi.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/panel/panel-waveshare-dsi.c ++++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c +@@ -340,9 +340,8 @@ static int ws_panel_probe(struct i2c_cli + */ + drm_panel_add(&ts->base); + +- ts->dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | +- MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +- MIPI_DSI_MODE_LPM); ++ ts->dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | ++ MIPI_DSI_CLOCK_NON_CONTINUOUS; + ts->dsi->format = MIPI_DSI_FMT_RGB888; + ts->dsi->lanes = 2; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1240-drivers-gpu-drm-panel-Modified-the-timing-of-11.9inc.patch b/target/linux/bcm27xx/patches-6.1/950-1240-drivers-gpu-drm-panel-Modified-the-timing-of-11.9inc.patch new file mode 100644 index 0000000000..0f04b21137 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1240-drivers-gpu-drm-panel-Modified-the-timing-of-11.9inc.patch @@ -0,0 +1,22 @@ +From aec3f9b6058448c54b74349f16b21185148a8c6e Mon Sep 17 00:00:00 2001 +From: eng33 +Date: Wed, 3 Jan 2024 11:46:50 +0800 +Subject: [PATCH] drivers/gpu/drm/panel:Modified the timing of 11.9inch to fix + the issue that 11.9inch was displayed abnormally + +Signed-off-by: eng33 +--- + drivers/gpu/drm/panel/panel-waveshare-dsi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/panel/panel-waveshare-dsi.c ++++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c +@@ -131,7 +131,7 @@ static const struct drm_display_mode ws_ + .hdisplay = 320, + .hsync_start = 320 + 60, + .hsync_end = 320 + 60 + 60, +- .htotal = 320 + 60 + 60 + 120, ++ .htotal = 320 + 60 + 60 + 60, + .vdisplay = 1480, + .vsync_start = 1480 + 60, + .vsync_end = 1480 + 60 + 60, diff --git a/target/linux/bcm27xx/patches-6.1/950-1241-drm-vc4-Add-2712-support-to-vc4_plane_async_set_fb.patch b/target/linux/bcm27xx/patches-6.1/950-1241-drm-vc4-Add-2712-support-to-vc4_plane_async_set_fb.patch new file mode 100644 index 0000000000..c13eb354fb --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1241-drm-vc4-Add-2712-support-to-vc4_plane_async_set_fb.patch @@ -0,0 +1,88 @@ +From a14da0fdb0e052a672c269df7f18c9de698bd827 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 4 Jan 2024 15:02:42 +0000 +Subject: [PATCH] drm/vc4: Add 2712 support to vc4_plane_async_set_fb + +vc4_plane_async_set_fb directly overwrites the plane address in +the dlist entry, but hadn't been updated for the GEN6 / 2712 +dlist format, corrupting the address in the process. + +Add support for the 2712 dlist format to the function. + +Fixes: 1ab1fbbb7e76 ("drm/vc4: hvs: Support BCM2712 HVS") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_plane.c | 46 +++++++++++++++++++++++---------- + 1 file changed, 33 insertions(+), 13 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1865,7 +1865,7 @@ static int vc6_plane_mode_set(struct drm + * The UPM buffer will be allocated in + * vc6_plane_allocate_upm(). + */ +- VC4_SET_FIELD(upper_32_bits(paddr) & 0xf, ++ VC4_SET_FIELD(upper_32_bits(paddr) & 0xff, + SCALER6_PTR0_UPPER_ADDR)); + + /* Pointer Word 1 */ +@@ -2068,7 +2068,8 @@ void vc4_plane_async_set_fb(struct drm_p + { + struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); + struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0); +- uint32_t addr; ++ struct vc4_dev *vc4 = to_vc4_dev(plane->dev); ++ dma_addr_t dma_addr = bo->dma_addr + fb->offsets[0]; + int idx; + + if (!drm_dev_enter(plane->dev, &idx)) +@@ -2078,19 +2079,38 @@ void vc4_plane_async_set_fb(struct drm_p + * because this is only called on the primary plane. + */ + WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); +- addr = bo->dma_addr + fb->offsets[0]; + +- /* Write the new address into the hardware immediately. The +- * scanout will start from this address as soon as the FIFO +- * needs to refill with pixels. +- */ +- writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset[0]]); ++ if (vc4->gen == VC4_GEN_6) { ++ u32 value; + +- /* Also update the CPU-side dlist copy, so that any later +- * atomic updates that don't do a new modeset on our plane +- * also use our updated address. +- */ +- vc4_state->dlist[vc4_state->ptr0_offset[0]] = addr; ++ value = vc4_state->dlist[vc4_state->ptr0_offset[0]] & ++ ~SCALER6_PTR0_UPPER_ADDR_MASK; ++ value |= VC4_SET_FIELD(upper_32_bits(dma_addr) & 0xff, ++ SCALER6_PTR0_UPPER_ADDR); ++ ++ writel(value, &vc4_state->hw_dlist[vc4_state->ptr0_offset[0]]); ++ vc4_state->dlist[vc4_state->ptr0_offset[0]] = value; ++ ++ value = lower_32_bits(dma_addr); ++ writel(value, &vc4_state->hw_dlist[vc4_state->ptr0_offset[0] + 1]); ++ vc4_state->dlist[vc4_state->ptr0_offset[0] + 1] = value; ++ } else { ++ u32 addr; ++ ++ addr = (u32)dma_addr; ++ ++ /* Write the new address into the hardware immediately. The ++ * scanout will start from this address as soon as the FIFO ++ * needs to refill with pixels. ++ */ ++ writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset[0]]); ++ ++ /* Also update the CPU-side dlist copy, so that any later ++ * atomic updates that don't do a new modeset on our plane ++ * also use our updated address. ++ */ ++ vc4_state->dlist[vc4_state->ptr0_offset[0]] = addr; ++ } + + drm_dev_exit(idx); + } diff --git a/target/linux/bcm27xx/patches-6.1/950-1242-drm-vc4-Fix-atomic_async_check-to-call-the-right-mod.patch b/target/linux/bcm27xx/patches-6.1/950-1242-drm-vc4-Fix-atomic_async_check-to-call-the-right-mod.patch new file mode 100644 index 0000000000..683c4a46ff --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1242-drm-vc4-Fix-atomic_async_check-to-call-the-right-mod.patch @@ -0,0 +1,38 @@ +From bfe927647253ab3a86be16320baa1579518c6786 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 17 Jan 2024 17:00:35 +0000 +Subject: [PATCH] drm/vc4: Fix atomic_async_check to call the right mode_set + function + +vc4_plane_atomic_async_check was always calling vc4_plane_mode_set +to validate and generate the dlist for the check. If async_check +decided it had to fall back to a sync commit, then this GEN4/5 +dlist could get used on GEN6. + +Call either vc4_plane_mode_set or vc6_plane_mode_set as appropriate. + +Fixes: 1ab1fbbb7e76 ("drm/vc4: hvs: Support BCM2712 HVS") +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_plane.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -2194,11 +2194,15 @@ static int vc4_plane_atomic_async_check( + { + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, + plane); ++ struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + struct vc4_plane_state *old_vc4_state, *new_vc4_state; + int ret; + u32 i; + +- ret = vc4_plane_mode_set(plane, new_plane_state); ++ if (vc4->gen >= VC4_GEN_6) ++ ret = vc6_plane_mode_set(plane, new_plane_state); ++ else ++ ret = vc4_plane_mode_set(plane, new_plane_state); + if (ret) + return ret; + diff --git a/target/linux/bcm27xx/patches-6.1/950-1244-drm-rp1-rp1-vec-Allow-non-standard-modes-with-variou.patch b/target/linux/bcm27xx/patches-6.1/950-1244-drm-rp1-rp1-vec-Allow-non-standard-modes-with-variou.patch new file mode 100644 index 0000000000..fb20dfe94d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1244-drm-rp1-rp1-vec-Allow-non-standard-modes-with-variou.patch @@ -0,0 +1,343 @@ +From 04b88e1a8b867b045bc90d997e8e0260b00dbb15 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Thu, 11 Jan 2024 12:13:03 +0000 +Subject: [PATCH] drm: rp1: rp1-vec: Allow non-standard modes with various + crops + +Tweak sync timings in the advertised modelines. + +Accept other, custom modes, provided they fit within the active +area of one of the existing hardware-supported TV modes. + +Instead of always padding symmetrically, try to respect the user's +[hv]sync_start values, allowing the image to be shifted around +the screen (to fine-tune overscan correction). + +Signed-off-by: Nick Hollinghurst +--- + drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c | 66 ++++++++++++--------- + drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 74 ++++++++++++++++++------ + 2 files changed, 96 insertions(+), 44 deletions(-) + +--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -208,26 +207,26 @@ static void rp1vec_connector_destroy(str + static const struct drm_display_mode rp1vec_modes[4] = { + { /* Full size 525/60i with Rec.601 pixel rate */ + DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, +- 720, 720 + 14, 720 + 14 + 64, 858, 0, +- 480, 480 + 7, 480 + 7 + 6, 525, 0, ++ 720, 720 + 16, 720 + 16 + 64, 858, 0, ++ 480, 480 + 6, 480 + 6 + 6, 525, 0, + DRM_MODE_FLAG_INTERLACE) + }, + { /* Cropped and horizontally squashed to be TV-safe */ + DRM_MODE("704x432i", DRM_MODE_TYPE_DRIVER, 15429, +- 704, 704 + 72, 704 + 72 + 72, 980, 0, +- 432, 432 + 31, 432 + 31 + 6, 525, 0, ++ 704, 704 + 76, 704 + 76 + 72, 980, 0, ++ 432, 432 + 30, 432 + 30 + 6, 525, 0, + DRM_MODE_FLAG_INTERLACE) + }, + { /* Full size 625/50i with Rec.601 pixel rate */ + DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, + 720, 720 + 20, 720 + 20 + 64, 864, 0, +- 576, 576 + 4, 576 + 4 + 6, 625, 0, ++ 576, 576 + 5, 576 + 5 + 5, 625, 0, + DRM_MODE_FLAG_INTERLACE) + }, + { /* Cropped and squashed, for square(ish) pixels */ + DRM_MODE("704x512i", DRM_MODE_TYPE_DRIVER, 15429, + 704, 704 + 80, 704 + 80 + 72, 987, 0, +- 512, 512 + 36, 512 + 36 + 6, 625, 0, ++ 512, 512 + 37, 512 + 37 + 5, 625, 0, + DRM_MODE_FLAG_INTERLACE) + } + }; +@@ -298,27 +297,42 @@ static enum drm_mode_status rp1vec_mode_ + const struct drm_display_mode *mode) + { + /* +- * Check the mode roughly matches one of our standard modes +- * (optionally half-height and progressive). Ignore H/V sync +- * timings which for interlaced TV are approximate at best. ++ * Check the mode roughly matches something we can generate. ++ * The hardware driver is very prescriptive about pixel clocks, ++ * line and frame durations, but we'll tolerate rounding errors. ++ * Within each hardware mode, allow image size and position to vary ++ * (to fine-tune overscan correction or emulate retro devices). ++ * Don't check sync timings here: the HW driver will sanitize them. + */ +- int i, prog; + +- prog = !(mode->flags & DRM_MODE_FLAG_INTERLACE); +- +- for (i = 0; i < ARRAY_SIZE(rp1vec_modes); i++) { +- const struct drm_display_mode *ref = rp1vec_modes + i; ++ int prog = !(mode->flags & DRM_MODE_FLAG_INTERLACE); ++ int vtotal_full = mode->vtotal << prog; ++ int vdisplay_full = mode->vdisplay << prog; ++ ++ /* Reject very small frames */ ++ if (vtotal_full < 256 || mode->hdisplay < 256) ++ return MODE_BAD; ++ ++ /* Check lines, frame period (ms) and vertical size limit */ ++ if (vtotal_full >= 524 && vtotal_full <= 526 && ++ mode->htotal * vtotal_full > 33 * mode->clock && ++ mode->htotal * vtotal_full < 34 * mode->clock && ++ vdisplay_full <= 480) ++ goto vgood; ++ if (vtotal_full >= 624 && vtotal_full <= 626 && ++ mode->htotal * vtotal_full > 39 * mode->clock && ++ mode->htotal * vtotal_full < 41 * mode->clock && ++ vdisplay_full <= 576) ++ goto vgood; ++ return MODE_BAD; + +- if (mode->hdisplay == ref->hdisplay && +- mode->vdisplay == (ref->vdisplay >> prog) && +- mode->clock + 2 >= ref->clock && +- mode->clock <= ref->clock + 2 && +- mode->htotal + 2 >= ref->htotal && +- mode->htotal <= ref->htotal + 2 && +- mode->vtotal + 2 >= (ref->vtotal >> prog) && +- mode->vtotal <= (ref->vtotal >> prog) + 2) +- return MODE_OK; +- } ++vgood: ++ /* Check pixel rate (kHz) and horizontal size limit */ ++ if (mode->clock == 13500 && mode->hdisplay <= 720) ++ return MODE_OK; ++ if (mode->clock >= 15428 && mode->clock <= 15429 && ++ mode->hdisplay <= 800) ++ return MODE_OK; + return MODE_BAD; + } + +@@ -440,7 +454,7 @@ static int rp1vec_platform_probe(struct + ret = drmm_mode_config_init(drm); + if (ret) + goto err_free_drm; +- drm->mode_config.max_width = 768; ++ drm->mode_config.max_width = 800; + drm->mode_config.max_height = 576; + drm->mode_config.fb_base = 0; + drm->mode_config.preferred_depth = 32; +--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c ++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -82,13 +81,13 @@ static const struct rp1vec_ipixfmt my_fo + /* + * Hardware mode descriptions (@ 108 MHz clock rate). + * These rely largely on "canned" register settings. +- * TODO: Port the generating software from FP to integer, +- * or better factorize the differences between modes. + */ + + struct rp1vec_hwmode { +- u16 total_cols; /* active columns, plus padding for filter context */ ++ u16 total_cols; /* max active columns incl. padding and windowing */ + u16 rows_per_field; /* active lines per field (including partial ones) */ ++ u16 ref_hfp; /* nominal (hsync_start - hdisplay) when max width */ ++ u16 ref_vfp; /* nominal (vsync_start - vdisplay) when max height */ + bool interlaced; /* set for interlaced */ + bool first_field_odd; /* set for interlaced and 30fps */ + u32 yuv_scaling; /* three 10-bit fields {Y, U, V} in 2.8 format */ +@@ -103,6 +102,8 @@ static const struct rp1vec_hwmode rp1vec + { + .total_cols = 724, + .rows_per_field = 240, ++ .ref_hfp = 12, ++ .ref_vfp = 2, + .interlaced = false, + .first_field_odd = false, + .yuv_scaling = 0x1071d0cf, +@@ -118,6 +119,8 @@ static const struct rp1vec_hwmode rp1vec + }, { + .total_cols = 815, + .rows_per_field = 240, ++ .ref_hfp = 16, ++ .ref_vfp = 2, + .interlaced = false, + .first_field_odd = false, + .yuv_scaling = 0x1c131962, +@@ -135,6 +138,8 @@ static const struct rp1vec_hwmode rp1vec + { + .total_cols = 724, + .rows_per_field = 243, ++ .ref_hfp = 12, ++ .ref_vfp = 3, + .interlaced = true, + .first_field_odd = true, + .yuv_scaling = 0x1071d0cf, +@@ -150,6 +155,8 @@ static const struct rp1vec_hwmode rp1vec + }, { + .total_cols = 815, + .rows_per_field = 243, ++ .ref_hfp = 16, ++ .ref_vfp = 3, + .interlaced = true, + .first_field_odd = true, + .yuv_scaling = 0x1c131962, +@@ -170,6 +177,8 @@ static const struct rp1vec_hwmode rp1vec + { + .total_cols = 724, + .rows_per_field = 288, ++ .ref_hfp = 16, ++ .ref_vfp = 2, + .interlaced = false, + .first_field_odd = false, + .yuv_scaling = 0x11c1f8e0, +@@ -185,6 +194,8 @@ static const struct rp1vec_hwmode rp1vec + }, { + .total_cols = 804, + .rows_per_field = 288, ++ .ref_hfp = 24, ++ .ref_vfp = 2, + .interlaced = false, + .first_field_odd = false, + .yuv_scaling = 0x1e635d7f, +@@ -202,6 +213,8 @@ static const struct rp1vec_hwmode rp1vec + { + .total_cols = 724, + .rows_per_field = 288, ++ .ref_hfp = 16, ++ .ref_vfp = 5, + .interlaced = true, + .first_field_odd = false, + .yuv_scaling = 0x11c1f8e0, +@@ -217,6 +230,8 @@ static const struct rp1vec_hwmode rp1vec + }, { + .total_cols = 804, + .rows_per_field = 288, ++ .ref_hfp = 24, ++ .ref_vfp = 5, + .interlaced = true, + .first_field_odd = false, + .yuv_scaling = 0x1e635d7f, +@@ -237,6 +252,8 @@ static const struct rp1vec_hwmode rp1vec + { + .total_cols = 724, + .rows_per_field = 240, ++ .ref_hfp = 12, ++ .ref_vfp = 2, + .interlaced = false, + .first_field_odd = false, + .yuv_scaling = 0x11c1f8e0, +@@ -252,6 +269,8 @@ static const struct rp1vec_hwmode rp1vec + }, { + .total_cols = 815, + .rows_per_field = 240, ++ .ref_hfp = 16, ++ .ref_vfp = 2, + .interlaced = false, + .first_field_odd = false, + .yuv_scaling = 0x1e635d7f, +@@ -269,6 +288,8 @@ static const struct rp1vec_hwmode rp1vec + { + .total_cols = 724, + .rows_per_field = 243, ++ .ref_hfp = 12, ++ .ref_vfp = 3, + .interlaced = true, + .first_field_odd = true, + .yuv_scaling = 0x11c1f8e0, +@@ -284,6 +305,8 @@ static const struct rp1vec_hwmode rp1vec + }, { + .total_cols = 815, + .rows_per_field = 243, ++ .ref_hfp = 16, ++ .ref_vfp = 3, + .interlaced = true, + .first_field_odd = true, + .yuv_scaling = 0x1e635d7f, +@@ -308,11 +331,11 @@ void rp1vec_hw_setup(struct rp1_vec *vec + { + unsigned int i, mode_family, mode_ilaced, mode_narrow; + const struct rp1vec_hwmode *hwm; +- unsigned int w, h; ++ int w, h, hpad, vpad; + + /* Pick the appropriate "base" mode, which we may modify */ + mode_ilaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); +- if (mode->vtotal > 263 * (1 + mode_ilaced)) ++ if (mode->vtotal >= 272 * (1 + mode_ilaced)) + mode_family = 1; + else + mode_family = (tvstd == RP1VEC_TVSTD_PAL_M || tvstd == RP1VEC_TVSTD_PAL60) ? 2 : 0; +@@ -326,13 +349,28 @@ void rp1vec_hw_setup(struct rp1_vec *vec + tvstd, rp1vec_tvstd_names[tvstd]); + + w = mode->hdisplay; +- h = mode->vdisplay; +- if (mode_ilaced) +- h >>= 1; ++ h = mode->vdisplay >> mode_ilaced; + if (w > hwm->total_cols) + w = hwm->total_cols; + if (h > hwm->rows_per_field) +- w = hwm->rows_per_field; ++ h = hwm->rows_per_field; ++ ++ /* ++ * Add padding so a framebuffer with the given dimensions and ++ * [hv]sync_start can be displayed in the chosen hardware mode. ++ * ++ * |<----- mode->hsync_start ----->| ++ * |<------ w ------>| | ++ * | | >|--|< ref_hfp ++ * |<- hpad ->| ++ * |<------------ total_cols ----------->| ++ * ________FRAMEBUFFERCONTENTS__________ ++ * ' `--\____/-<\/\/\>-' ++ */ ++ hpad = max(0, mode->hsync_start - hwm->ref_hfp - w); ++ hpad = min(hpad, hwm->total_cols - w); ++ vpad = max(0, ((mode->vsync_start - hwm->ref_vfp) >> mode_ilaced) - h); ++ vpad = min(vpad, hwm->rows_per_field - h); + + /* Configure the hardware */ + VEC_WRITE(VEC_APB_TIMEOUT, 0x38); +@@ -347,18 +385,18 @@ void rp1vec_hw_setup(struct rp1_vec *vec + BITS(VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1, h - 1)); + VEC_WRITE(VEC_YUV_SCALING, hwm->yuv_scaling); + VEC_WRITE(VEC_BACK_PORCH, +- BITS(VEC_BACK_PORCH_HBP_MINUS1, (hwm->total_cols - w - 1) >> 1) | +- BITS(VEC_BACK_PORCH_VBP_MINUS1, (hwm->rows_per_field - h - 1) >> 1)); ++ BITS(VEC_BACK_PORCH_HBP_MINUS1, hwm->total_cols - w - hpad - 1) | ++ BITS(VEC_BACK_PORCH_VBP_MINUS1, hwm->rows_per_field - h - vpad - 1)); + VEC_WRITE(VEC_FRONT_PORCH, +- BITS(VEC_FRONT_PORCH_HFP_MINUS1, (hwm->total_cols - w - 2) >> 1) | +- BITS(VEC_FRONT_PORCH_VFP_MINUS1, (hwm->rows_per_field - h - 2) >> 1)); ++ BITS(VEC_FRONT_PORCH_HFP_MINUS1, hpad - 1) | ++ BITS(VEC_FRONT_PORCH_VFP_MINUS1, vpad - 1)); + VEC_WRITE(VEC_MODE, + BITS(VEC_MODE_HIGH_WATER, 0xE0) | + BITS(VEC_MODE_ALIGN16, !((w | mode->hdisplay) & 15)) | +- BITS(VEC_MODE_VFP_EN, (hwm->rows_per_field > h + 1)) | +- BITS(VEC_MODE_VBP_EN, (hwm->rows_per_field > h)) | +- BITS(VEC_MODE_HFP_EN, (hwm->total_cols > w + 1)) | +- BITS(VEC_MODE_HBP_EN, (hwm->total_cols > w)) | ++ BITS(VEC_MODE_VFP_EN, (vpad > 0)) | ++ BITS(VEC_MODE_VBP_EN, (hwm->rows_per_field > h + vpad)) | ++ BITS(VEC_MODE_HFP_EN, (hpad > 0)) | ++ BITS(VEC_MODE_HBP_EN, (hwm->total_cols > w + hpad)) | + BITS(VEC_MODE_FIELDS_PER_FRAME_MINUS1, hwm->interlaced) | + BITS(VEC_MODE_FIRST_FIELD_ODD, hwm->first_field_odd)); + for (i = 0; i < ARRAY_SIZE(hwm->back_end_regs); ++i) { diff --git a/target/linux/bcm27xx/patches-6.1/950-1245-ARM-pl011-Add-rs485-to-the-RP1-support.patch b/target/linux/bcm27xx/patches-6.1/950-1245-ARM-pl011-Add-rs485-to-the-RP1-support.patch new file mode 100644 index 0000000000..c94619c914 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1245-ARM-pl011-Add-rs485-to-the-RP1-support.patch @@ -0,0 +1,24 @@ +From ab8ba584f91576c41d921076221ceb48e2930ae0 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 18 Jan 2024 11:08:03 +0000 +Subject: [PATCH] ARM: pl011: Add rs485 to the RP1 support + +pl011_axi_probe, added for RP1 support, lacks the rs485 additions that +appeared during its development. + +Signed-off-by: Phil Elwell +--- + drivers/tty/serial/amba-pl011.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -3026,6 +3026,8 @@ static int pl011_axi_probe(struct platfo + uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM; + uap->port.irq = irq; + uap->port.ops = &amba_pl011_pops; ++ uap->port.rs485_config = pl011_rs485_config; ++ uap->port.rs485_supported = pl011_rs485_supported; + + snprintf(uap->type, sizeof(uap->type), "PL011 AXI"); + diff --git a/target/linux/bcm27xx/patches-6.1/950-1246-fixup-irqchip-irq-bcm2712-mip-Support-for-2712-s-MIP.patch b/target/linux/bcm27xx/patches-6.1/950-1246-fixup-irqchip-irq-bcm2712-mip-Support-for-2712-s-MIP.patch new file mode 100644 index 0000000000..8fc8d0c768 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-1246-fixup-irqchip-irq-bcm2712-mip-Support-for-2712-s-MIP.patch @@ -0,0 +1,38 @@ +From 3bb5880ab3dd31f75c07c3c33bf29c5d469b28f3 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 18 Jan 2024 15:41:21 +0000 +Subject: [PATCH] fixup! irqchip: irq-bcm2712-mip: Support for 2712's MIP + +Use irq_domain_add_hierarchy so that the root pointer is initialised +correctly. Failure to do so leads to (at least) lockdep warnings when +they are enabled. + +See: https://github.com/raspberrypi/linux/issues/5866 + +Signed-off-by: Phil Elwell +--- + drivers/irqchip/irq-bcm2712-mip.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +--- a/drivers/irqchip/irq-bcm2712-mip.c ++++ b/drivers/irqchip/irq-bcm2712-mip.c +@@ -209,16 +209,14 @@ static int mip_init_domains(struct mip_p + return -ENXIO; + } + +- middle_domain = irq_domain_add_tree(NULL, +- &mip_irq_domain_ops, +- priv); ++ middle_domain = irq_domain_add_hierarchy(gic_domain, 0, 0, NULL, ++ &mip_irq_domain_ops, ++ priv); + if (!middle_domain) { + pr_err("Failed to create the MIP middle domain\n"); + return -ENOMEM; + } + +- middle_domain->parent = gic_domain; +- + msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node), + &mip_msi_domain_info, + middle_domain); diff --git a/target/linux/bcm27xx/patches-6.1/960-hwrng-iproc-set-quality-to-1000.patch b/target/linux/bcm27xx/patches-6.1/960-hwrng-iproc-set-quality-to-1000.patch index c1b4879a7c..cabe36ba71 100644 --- a/target/linux/bcm27xx/patches-6.1/960-hwrng-iproc-set-quality-to-1000.patch +++ b/target/linux/bcm27xx/patches-6.1/960-hwrng-iproc-set-quality-to-1000.patch @@ -15,7 +15,7 @@ Signed-off-by: Álvaro Fernández Rojas --- a/drivers/char/hw_random/iproc-rng200.c +++ b/drivers/char/hw_random/iproc-rng200.c -@@ -252,6 +252,7 @@ static int iproc_rng200_probe(struct pla +@@ -253,6 +253,7 @@ static int iproc_rng200_probe(struct pla priv->rng.name = pdev->name; priv->rng.cleanup = iproc_rng200_cleanup; diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1 index d11c946dbc..c6301662f7 100644 --- a/target/linux/generic/config-6.1 +++ b/target/linux/generic/config-6.1 @@ -605,6 +605,7 @@ CONFIG_BASE_SMALL=0 # CONFIG_BAYCOM_SER_FDX is not set # CONFIG_BAYCOM_SER_HDX is not set # CONFIG_BCACHE is not set +# CONFIG_BCM2712_MIP is not set # CONFIG_BCM47XX is not set # CONFIG_BCM54140_PHY is not set # CONFIG_BCM63XX is not set @@ -1036,6 +1037,8 @@ CONFIG_CMDLINE="" # CONFIG_COMMON_CLK_PWM is not set # CONFIG_COMMON_CLK_PXA is not set # CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_RP1 is not set +# CONFIG_COMMON_CLK_RP1_SDIO is not set # CONFIG_COMMON_CLK_RS9_PCIE is not set # CONFIG_COMMON_CLK_SI514 is not set # CONFIG_COMMON_CLK_SI5341 is not set @@ -1725,6 +1728,9 @@ CONFIG_DQL=y # CONFIG_DRM_RCAR_USE_LVDS is not set # CONFIG_DRM_RCAR_USE_MIPI_DSI is not set # CONFIG_DRM_ROCKCHIP is not set +# CONFIG_DRM_RP1_DPI is not set +# CONFIG_DRM_RP1_DSI is not set +# CONFIG_DRM_RP1_VEC is not set # CONFIG_DRM_SII902X is not set # CONFIG_DRM_SII9234 is not set # CONFIG_DRM_SIL_SII8620 is not set @@ -2083,6 +2089,7 @@ CONFIG_FB_NOTIFY=y # CONFIG_FB_PXA is not set # CONFIG_FB_RADEON is not set # CONFIG_FB_RIVA is not set +# CONFIG_FB_RPISENSE is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_S3 is not set # CONFIG_FB_SAVAGE is not set @@ -2283,6 +2290,7 @@ CONFIG_GPIOLIB_FASTPATH_LIMIT=512 # CONFIG_GPIO_AMDPT is not set # CONFIG_GPIO_AMD_FCH is not set # CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BRCMSTB is not set # CONFIG_GPIO_BT8XX is not set # CONFIG_GPIO_CADENCE is not set # CONFIG_GPIO_CASCADE is not set @@ -2853,6 +2861,7 @@ CONFIG_INPUT_MISC=y # CONFIG_INPUT_POWERMATE is not set # CONFIG_INPUT_PWM_BEEPER is not set # CONFIG_INPUT_PWM_VIBRA is not set +# CONFIG_INPUT_RASPBERRYPI_BUTTON is not set # CONFIG_INPUT_REGULATOR_HAPTIC is not set # CONFIG_INPUT_SOC_BUTTON_ARRAY is not set # CONFIG_INPUT_SPARSEKMAP is not set @@ -3609,6 +3618,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_PM8921_CORE is not set # CONFIG_MFD_PM8XXX is not set # CONFIG_MFD_QCOM_PM8008 is not set +# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set # CONFIG_MFD_RC5T583 is not set # CONFIG_MFD_RDC321X is not set # CONFIG_MFD_RETU is not set @@ -3618,6 +3628,8 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_ROHM_BD71828 is not set # CONFIG_MFD_ROHM_BD718XX is not set # CONFIG_MFD_ROHM_BD957XMUF is not set +# CONFIG_MFD_RP1 is not set +# CONFIG_MFD_RPISENSE_CORE is not set # CONFIG_MFD_RSMU_I2C is not set # CONFIG_MFD_RSMU_SPI is not set # CONFIG_MFD_RT4831 is not set @@ -4839,6 +4851,7 @@ CONFIG_PCI_SYSCALL=y # CONFIG_PHYLIB is not set # CONFIG_PHYLIB_LEDS is not set # CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_BRCM_USB is not set # CONFIG_PHY_CADENCE_DP is not set # CONFIG_PHY_CADENCE_DPHY is not set # CONFIG_PHY_CADENCE_DPHY_RX is not set @@ -4875,6 +4888,7 @@ CONFIG_PINCONF=y # CONFIG_PINCTRL is not set # CONFIG_PINCTRL_AMD is not set # CONFIG_PINCTRL_AXP209 is not set +# CONFIG_PINCTRL_BCM2712 is not set # CONFIG_PINCTRL_CEDARFORK is not set # CONFIG_PINCTRL_CY8C95X0 is not set # CONFIG_PINCTRL_EXYNOS is not set @@ -4895,6 +4909,7 @@ CONFIG_PINCONF=y # CONFIG_PINCTRL_MTK_V2 is not set # CONFIG_PINCTRL_OCELOT is not set # CONFIG_PINCTRL_PISTACHIO is not set +# CONFIG_PINCTRL_RP1 is not set # CONFIG_PINCTRL_SC7280 is not set # CONFIG_PINCTRL_SC8180X is not set # CONFIG_PINCTRL_SDX55 is not set @@ -5053,6 +5068,7 @@ CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240 # CONFIG_PWM_MEDIATEK is not set # CONFIG_PWM_PCA9685 is not set # CONFIG_PWM_RASPBERRYPI_POE is not set +# CONFIG_PWM_RP1 is not set # CONFIG_PWM_XILINX is not set CONFIG_PWRSEQ_EMMC=y # CONFIG_PWRSEQ_SD8787 is not set @@ -5127,6 +5143,7 @@ CONFIG_RANDOM_TRUST_CPU=y # CONFIG_RANDSTRUCT_NONE is not set # CONFIG_RAPIDIO is not set # CONFIG_RAS is not set +# CONFIG_RASPBERRYPI_GPIOMEM is not set # CONFIG_RBTREE_TEST is not set # CONFIG_RCU_BOOST is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 @@ -5251,6 +5268,7 @@ CONFIG_REISERFS_FS_XATTR=y # CONFIG_RENESAS_PHY is not set # CONFIG_RESET_ATH79 is not set # CONFIG_RESET_BERLIN is not set +# CONFIG_RESET_BRCMSTB is not set # CONFIG_RESET_BRCMSTB_RESCAL is not set # CONFIG_RESET_CONTROLLER is not set # CONFIG_RESET_IMX7 is not set @@ -5779,6 +5797,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_Q54SJ108A2 is not set # CONFIG_SENSORS_RM3100_I2C is not set # CONFIG_SENSORS_RM3100_SPI is not set +# CONFIG_SENSORS_RP1_ADC is not set # CONFIG_SENSORS_SBRMI is not set # CONFIG_SENSORS_SBTSI is not set # CONFIG_SENSORS_SCH5627 is not set @@ -6593,6 +6612,7 @@ CONFIG_STDBINUTILS=y # CONFIG_STMMAC_PCI is not set # CONFIG_STMMAC_PLATFORM is not set # CONFIG_STMMAC_SELFTESTS is not set +# CONFIG_STMPE_ADC is not set # CONFIG_STM_DUMMY is not set # CONFIG_STM_SOURCE_CONSOLE is not set CONFIG_STP=y @@ -7510,6 +7530,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_BT848 is not set # CONFIG_VIDEO_BT856 is not set # CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_BU64754 is not set # CONFIG_VIDEO_CADENCE is not set # CONFIG_VIDEO_CADENCE_CSI2RX is not set # CONFIG_VIDEO_CADENCE_CSI2TX is not set @@ -7603,6 +7624,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_OV5675 is not set # CONFIG_VIDEO_OV5693 is not set # CONFIG_VIDEO_OV5695 is not set +# CONFIG_VIDEO_OV64A40 is not set # CONFIG_VIDEO_OV6650 is not set # CONFIG_VIDEO_OV7251 is not set # CONFIG_VIDEO_OV7640 is not set From beccf65a93a3a54d4af7cbdbff4b7d51ce52a58c Mon Sep 17 00:00:00 2001 From: Marty Jones Date: Mon, 6 Nov 2023 22:21:44 -0500 Subject: [PATCH 17/19] linux-firmware: add Raspberry Pi 5 NVRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RPi 5 expects the same NVRAM as the one from RPi 4 on a different file. Signed-off-by: Marty Jones [Reword commit description, add missing PKG_RELEASE bump] Signed-off-by: Álvaro Fernández Rojas --- package/firmware/linux-firmware/Makefile | 2 +- package/firmware/linux-firmware/broadcom.mk | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/package/firmware/linux-firmware/Makefile b/package/firmware/linux-firmware/Makefile index 79341c30cb..f7f1f978e3 100644 --- a/package/firmware/linux-firmware/Makefile +++ b/package/firmware/linux-firmware/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=linux-firmware PKG_VERSION:=20231211 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE_URL:=@KERNEL/linux/kernel/firmware PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz diff --git a/package/firmware/linux-firmware/broadcom.mk b/package/firmware/linux-firmware/broadcom.mk index 4f64b423eb..088a2665cc 100644 --- a/package/firmware/linux-firmware/broadcom.mk +++ b/package/firmware/linux-firmware/broadcom.mk @@ -125,9 +125,15 @@ define Package/brcmfmac-nvram-43455-sdio/install $(LN) \ brcmfmac43455-sdio.raspberrypi,4-model-b.txt \ $(1)/lib/firmware/brcm/brcmfmac43455-sdio.Raspberry\ Pi\ Foundation-Raspberry\ Pi\ 4\ Model\ B.txt + $(LN) \ + brcmfmac43455-sdio.raspberrypi,4-model-b.txt \ + $(1)/lib/firmware/brcm/brcmfmac43455-sdio.raspberrypi,5-model-b.txt $(LN) \ brcmfmac43455-sdio.raspberrypi,4-model-b.txt \ $(1)/lib/firmware/brcm/brcmfmac43455-sdio.Raspberry\ Pi\ Foundation-Raspberry\ Pi\ Compute\ Module\ 4.txt + $(LN) \ + brcmfmac43455-sdio.raspberrypi,4-model-b.txt \ + $(1)/lib/firmware/brcm/brcmfmac43455-sdio.Raspberry\ Pi\ Foundation-Raspberry\ Pi\ 5\ Model\ B.txt $(INSTALL_DATA) \ $(PKG_BUILD_DIR)/brcm/brcmfmac43455-sdio.MINIX-NEO\ Z83-4.txt \ $(1)/lib/firmware/brcm/ From 8b63d9ac4ae9bd9a83a656825fb0c74fe0f4f25f Mon Sep 17 00:00:00 2001 From: Marty Jones Date: Thu, 18 Jan 2024 09:52:22 -0500 Subject: [PATCH 18/19] bcm27xx: add new bcm2712 subtarget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for Raspberry Pi 5. Instead of using 16K pages like Raspberry Pi OS, OpenWrt uses 4K pages due to incompatibilities with F2FS and other applications. There are multiple RPi forum posts with different cases and users are forcing kernel8.img to workaround them, which is the 64 bit kernel of the RPi 4. However, this isn't possible in OpenWrt because we only ship one kernel and we would have to add RPi 5 support to bcm2711 subtarget (RPi 4) for that workaround to work in OpenWrt. Specification: - Processor Broadcom BCM2712 2.4GHz quad-core 64-bit Arm Cortex-A76 CPU, with cryptographic extension, 512KB L2 caches per core, 2048KB L3 cache Features: - VideoCore VII GPU, supports OpenGL ES 3.1, Vulkan 1.2 - Dual 4Kp60 HDMI display output with HDR support 4Kp60 HEVC decoder - LPDDR4X-4267 SDRAM 4GB and 8GB - Dual-band 802.11ac Wi-Fi - Bluetooth 5.0 / Bluetooth Low Energy - microSD card slot, with support for SDR104 high-speed mode - 2 x USB 3.0 ports - 2 x USB 2.0 ports - Gigabit Ethernet - 2 x 4 lane MIPI camera/display - PCIe 2.0 x1 - 5V/5A power via USB-C - Raspberry Pi standard 40-pin header - Real-time clock RTC - Power button Build system: x86_64 Build-tested: bcm2712 Run-tested: bcm2712/RPi5 Signed-off-by: Marty Jones [Remove device variant, improve description] Signed-off-by: Álvaro Fernández Rojas --- target/linux/bcm27xx/Makefile | 2 +- .../bcm27xx/base-files/etc/board.d/02_network | 1 + target/linux/bcm27xx/base-files/etc/diag.sh | 1 + target/linux/bcm27xx/bcm2712/config-6.1 | 600 ++++++++++++++++++ target/linux/bcm27xx/bcm2712/target.mk | 12 + target/linux/bcm27xx/image/Makefile | 18 + 6 files changed, 633 insertions(+), 1 deletion(-) create mode 100644 target/linux/bcm27xx/bcm2712/config-6.1 create mode 100644 target/linux/bcm27xx/bcm2712/target.mk diff --git a/target/linux/bcm27xx/Makefile b/target/linux/bcm27xx/Makefile index 99c5fa75aa..702a59ecb8 100644 --- a/target/linux/bcm27xx/Makefile +++ b/target/linux/bcm27xx/Makefile @@ -9,7 +9,7 @@ ARCH:=arm BOARD:=bcm27xx BOARDNAME:=Broadcom BCM27xx FEATURES:=audio boot-part display ext4 fpu gpio rootfs-part rtc squashfs usb usbgadget -SUBTARGETS:=bcm2708 bcm2709 bcm2710 bcm2711 +SUBTARGETS:=bcm2708 bcm2709 bcm2710 bcm2711 bcm2712 KERNEL_PATCHVER:=6.1 diff --git a/target/linux/bcm27xx/base-files/etc/board.d/02_network b/target/linux/bcm27xx/base-files/etc/board.d/02_network index 23bc9afdb9..f246139c38 100644 --- a/target/linux/bcm27xx/base-files/etc/board.d/02_network +++ b/target/linux/bcm27xx/base-files/etc/board.d/02_network @@ -17,6 +17,7 @@ raspberrypi,3-model-b-plus |\ raspberrypi,400 |\ raspberrypi,4-compute-module |\ raspberrypi,4-model-b |\ +raspberrypi,5-model-b |\ raspberrypi,model-b |\ raspberrypi,model-b-plus |\ raspberrypi,model-b-rev2) diff --git a/target/linux/bcm27xx/base-files/etc/diag.sh b/target/linux/bcm27xx/base-files/etc/diag.sh index 180b31ec95..92d72bea11 100644 --- a/target/linux/bcm27xx/base-files/etc/diag.sh +++ b/target/linux/bcm27xx/base-files/etc/diag.sh @@ -14,6 +14,7 @@ set_state() { raspberrypi,400 |\ raspberrypi,4-compute-module |\ raspberrypi,4-model-b |\ + raspberrypi,5-model-b |\ raspberrypi,model-b-plus) status_led="led1" ;; diff --git a/target/linux/bcm27xx/bcm2712/config-6.1 b/target/linux/bcm27xx/bcm2712/config-6.1 new file mode 100644 index 0000000000..08445ffee2 --- /dev/null +++ b/target/linux/bcm27xx/bcm2712/config-6.1 @@ -0,0 +1,600 @@ +CONFIG_64BIT=y +# CONFIG_AIO is not set +CONFIG_APERTURE_HELPERS=y +CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM2835=y +CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y +CONFIG_ARCH_BRCMSTB=y +CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_KEEP_MEMBLOCK=y +CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_STACKWALK=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANTS_NO_INSTR=y +CONFIG_ARCH_WANTS_THP_SWAP=y +CONFIG_ARM64=y +CONFIG_ARM64_4K_PAGES=y +CONFIG_ARM64_CNP=y +CONFIG_ARM64_EPAN=y +CONFIG_ARM64_ERRATUM_1165522=y +CONFIG_ARM64_ERRATUM_1286807=y +CONFIG_ARM64_ERRATUM_1463225=y +CONFIG_ARM64_HW_AFDBM=y +CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_PAN=y +CONFIG_ARM64_PA_BITS=48 +CONFIG_ARM64_PA_BITS_48=y +CONFIG_ARM64_PTR_AUTH=y +CONFIG_ARM64_PTR_AUTH_KERNEL=y +CONFIG_ARM64_SVE=y +CONFIG_ARM64_TAGGED_ADDR_ABI=y +CONFIG_ARM64_VA_BITS=39 +CONFIG_ARM64_VA_BITS_39=y +CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y +CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y +CONFIG_ARM_BRCMSTB_AVS_CPUFREQ=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_V2M=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +CONFIG_ARM_GIC_V3_ITS_PCI=y +# CONFIG_ARM_MHU_V2 is not set +# CONFIG_ARM_PL172_MPMC is not set +CONFIG_ARM_PSCI_FW=y +CONFIG_ARM_RASPBERRYPI_CPUFREQ=y +# CONFIG_ARM_SMMU is not set +# CONFIG_ARM_SMMU_V3 is not set +CONFIG_ARM_TIMER_SP804=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +CONFIG_BCM2708_VCMEM=y +CONFIG_BCM2711_THERMAL=y +CONFIG_BCM2712_IOMMU=y +CONFIG_BCM2712_MIP=y +CONFIG_BCM2835_MBOX=y +CONFIG_BCM2835_POWER=y +CONFIG_BCM2835_SMI=y +CONFIG_BCM2835_SMI_DEV=m +CONFIG_BCM2835_THERMAL=y +CONFIG_BCM2835_VCHIQ=y +# CONFIG_BCM2835_VCHIQ_MMAL is not set +CONFIG_BCM2835_WDT=y +CONFIG_BCM7038_L1_IRQ=y +CONFIG_BCM7120_L2_IRQ=y +CONFIG_BCM7XXX_PHY=y +CONFIG_BCMA=y +CONFIG_BCMA_BLOCKIO=y +# CONFIG_BCMA_DEBUG is not set +# CONFIG_BCMA_DRIVER_GMAC_CMN is not set +CONFIG_BCMA_DRIVER_PCI=y +CONFIG_BCMA_FALLBACK_SPROM=y +CONFIG_BCMA_HOST_PCI=y +CONFIG_BCMA_HOST_PCI_POSSIBLE=y +# CONFIG_BCMA_HOST_SOC is not set +CONFIG_BCMGENET=y +CONFIG_BCM_NET_PHYLIB=y +CONFIG_BCM_VCIO=y +# CONFIG_BCM_VC_SM_CMA is not set +CONFIG_BCM_VIDEOCORE=y +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NVME=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y +CONFIG_BRCMSTB_DPFE=y +CONFIG_BRCMSTB_L2_IRQ=y +CONFIG_BRCMSTB_MEMC=y +CONFIG_BRCMSTB_PM=y +# CONFIG_BRCMSTB_THERMAL is not set +CONFIG_BRCM_CHAR_DRIVERS=y +CONFIG_BRCM_USB_PINMAP=y +CONFIG_BROADCOM_PHY=y +CONFIG_CC_HAVE_SHADOW_CALL_STACK=y +CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y +CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" +CONFIG_CC_NO_ARRAY_BOUNDS=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLK_BCM2711_DVP=y +CONFIG_CLK_BCM2835=y +CONFIG_CLK_RASPBERRYPI=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=5 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SYSFS is not set +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_RP1=y +# CONFIG_COMMON_CLK_RP1_SDIO is not set +CONFIG_COMMON_CLK_XGENE=y +CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 +# CONFIG_COMPAT_32BIT_TIME is not set +CONFIG_CONFIGFS_FS=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_CONTEXT_TRACKING=y +CONFIG_CONTEXT_TRACKING_IDLE=y +CONFIG_CONTIG_ALLOC=y +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CRC16=y +CONFIG_CRYPTO_AES_ARM64=y +CONFIG_CRYPTO_AES_ARM64_BS=y +CONFIG_CRYPTO_AES_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y +CONFIG_CRYPTO_LIB_SHA1=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LIB_UTILS=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA256_ARM64=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_SHA3=y +CONFIG_CRYPTO_SHA3_ARM64=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_SHA512_ARM64=y +CONFIG_CRYPTO_SHA512_ARM64_CE=y +CONFIG_CRYPTO_SM3=y +CONFIG_CRYPTO_SM3_ARM64_CE=y +CONFIG_CRYPTO_SM4=y +CONFIG_CRYPTO_SM4_ARM64_CE=y +CONFIG_CRYPTO_SM4_ARM64_CE_BLK=y +CONFIG_CRYPTO_XTS=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DIMLIB=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_DMADEVICES=y +CONFIG_DMA_BCM2708=y +CONFIG_DMA_BCM2835=y +CONFIG_DMA_CMA=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_OPS=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DNOTIFY=y +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EXCLUSIVE_SYSTEM_RAM=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXTCON=y +CONFIG_F2FS_FS=y +CONFIG_FB=y +CONFIG_FB_BCM2708=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +CONFIG_FB_SIMPLE=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FRAME_POINTER=y +CONFIG_FREEZER=y +CONFIG_FSL_ERRATUM_A008585=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_ALGS=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_FWNODE_MDIO=y +CONFIG_FW_CACHE=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_FW_LOADER_SYSFS=y +CONFIG_GCC11_NO_ARRAY_BOUNDS=y +CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IOREMAP=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_INJECTION=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GLOB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_BCM_VIRT=y +CONFIG_GPIO_BRCMSTB=y +CONFIG_GPIO_CDEV=y +# CONFIG_GPIO_FSM is not set +CONFIG_GPIO_GENERIC=y +CONFIG_GPIO_RASPBERRYPI_EXP=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_PCIE is not set +CONFIG_HOTPLUG_PCI_SHPC=y +CONFIG_HWMON=y +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_IPROC_RNG200=y +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_BCM2708 is not set +CONFIG_I2C_BCM2835=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_BRCMSTB=y +CONFIG_I2C_DESIGNWARE_CORE=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_INPUT=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_RASPBERRYPI_BUTTON=y +CONFIG_IOMMU_API=y +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set +CONFIG_IOMMU_DEFAULT_DMA_STRICT=y +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_IOMMU_DMA=y +CONFIG_IOMMU_IOVA=y +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_DART is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KEYS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PWM=y +CONFIG_LEDS_TRIGGER_ACTPWR=y +CONFIG_LEDS_TRIGGER_INPUT=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_MACB=y +CONFIG_MACB_PCI=y +CONFIG_MACB_USE_HWSTAMP=y +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MDIO_BCM_UNIMAC=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_DEVRES=y +CONFIG_MEMFD_CREATE=y +CONFIG_MEMORY=y +CONFIG_MEMORY_ISOLATION=y +CONFIG_MFD_CORE=y +CONFIG_MFD_RP1=y +CONFIG_MFD_SYSCON=y +CONFIG_MICROCHIP_PHY=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +# CONFIG_MMC_BCM2835 is not set +CONFIG_MMC_BCM2835_DMA=y +CONFIG_MMC_BCM2835_MMC=y +CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2 +CONFIG_MMC_BCM2835_SDHOST=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_CQHCI=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_BRCMSTB=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_IPROC=y +CONFIG_MMC_SDHCI_OF_DWCMSHC=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_SELFTESTS=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=4 +CONFIG_NVMEM=y +CONFIG_NVMEM_LAYOUTS=y +CONFIG_NVME_CORE=y +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_MULTIPATH is not set +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_CONFIGFS=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IOMMU=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_RESOLVE=y +CONFIG_PADATA=y +CONFIG_PAGE_POOL=y +CONFIG_PAGE_SIZE_LESS_THAN_256KB=y +CONFIG_PAGE_SIZE_LESS_THAN_64KB=y +CONFIG_PARTITION_PERCPU=y +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEAER_INJECT=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_PERFORMANCE is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +CONFIG_PCIEASPM_POWER_SUPERSAVE=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_BRCMSTB=y +CONFIG_PCIE_DPC=y +CONFIG_PCIE_DW=y +CONFIG_PCIE_DW_HOST=y +CONFIG_PCIE_DW_PLAT=y +CONFIG_PCIE_DW_PLAT_HOST=y +CONFIG_PCIE_MICROCHIP_HOST=y +CONFIG_PCIE_PME=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_ECAM=y +CONFIG_PCI_HOST_COMMON=y +CONFIG_PCI_HOST_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_STUB=y +CONFIG_PGTABLE_LEVELS=3 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +CONFIG_PHYS_ADDR_T_64BIT=y +# CONFIG_PHY_BRCM_SATA is not set +CONFIG_PHY_BRCM_USB=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BCM2712=y +CONFIG_PINCTRL_BCM2835=y +CONFIG_PINCTRL_RP1=y +CONFIG_PM=y +CONFIG_PM_CLK=y +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_OPP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_SUPPLY=y +CONFIG_PPS=y +CONFIG_PREEMPT_NONE_BUILD=y +CONFIG_PRINTK_TIME=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_OPTIONAL=y +CONFIG_PWM=y +CONFIG_PWM_BCM2835=y +CONFIG_PWM_BRCMSTB=y +CONFIG_PWM_RP1=y +CONFIG_PWM_SYSFS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_RANDSTRUCT_NONE=y +CONFIG_RAS=y +CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_RASPBERRYPI_GPIOMEM=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_RATIONAL=y +# CONFIG_RAVE_SP_CORE is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_RESET_BRCMSTB=y +CONFIG_RESET_BRCMSTB_RESCAL=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_RASPBERRYPI=y +CONFIG_RESET_SIMPLE=y +CONFIG_RFS_ACCEL=y +CONFIG_RODATA_FULL_DEFAULT_ENABLED=y +# CONFIG_RPIVID_MEM is not set +# CONFIG_RPI_POE_POWER is not set +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_BRCMSTB=y +CONFIG_RTC_DRV_RPI=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_SCSI=y +CONFIG_SCSI_COMMON=y +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SENSORS_RASPBERRYPI_HWMON=y +CONFIG_SENSORS_RP1_ADC=y +CONFIG_SERIAL_8250_BCM2835AUX=y +CONFIG_SERIAL_8250_BCM7271=y +# CONFIG_SERIAL_8250_DMA is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +CONFIG_SMSC_PHY=y +CONFIG_SOCK_RX_QUEUE_MAPPING=y +CONFIG_SOC_BRCMSTB=y +CONFIG_SOC_BUS=y +CONFIG_SOFTIRQ_ON_OWN_STACK=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SRCU=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +# CONFIG_TEXTSEARCH is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_OF=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +# CONFIG_UACCE is not set +# CONFIG_UCLAMP_TASK is not set +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNMAP_KERNEL_AT_EL0=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +# CONFIG_USB_BRCMSTB is not set +CONFIG_USB_COMMON=y +CONFIG_USB_DWCOTG=y +CONFIG_USB_GADGET=y +# CONFIG_USB_HCD_BCMA is not set +CONFIG_USB_PCI=y +CONFIG_USB_PHY=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_UAS=y +# CONFIG_USB_UHCI_HCD is not set +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_VCHIQ_CDEV=y +CONFIG_VMAP_STACK=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZONE_DMA32=y diff --git a/target/linux/bcm27xx/bcm2712/target.mk b/target/linux/bcm27xx/bcm2712/target.mk new file mode 100644 index 0000000000..4fe9910351 --- /dev/null +++ b/target/linux/bcm27xx/bcm2712/target.mk @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ARCH:=aarch64 +SUBTARGET:=bcm2712 +BOARDNAME:=BCM2712 boards (64 bit) +CPU_TYPE:=cortex-a76 +FEATURES+=pci pcie + +define Target/Description + Build firmware image for BCM2712 devices. + This firmware features a 64 bit kernel. +endef diff --git a/target/linux/bcm27xx/image/Makefile b/target/linux/bcm27xx/image/Makefile index ad79ac7d0c..e55a7b17b5 100644 --- a/target/linux/bcm27xx/image/Makefile +++ b/target/linux/bcm27xx/image/Makefile @@ -172,4 +172,22 @@ ifeq ($(SUBTARGET),bcm2711) TARGET_DEVICES += rpi-4 endif +define Device/rpi-5 + DEVICE_MODEL := 5 + KERNEL_IMG := kernel_2712.img + DEVICE_DTS := broadcom/bcm2712-rpi-5-b + SUPPORTED_DEVICES := raspberrypi,5-model-b + DEVICE_PACKAGES := \ + cypress-firmware-43455-sdio \ + brcmfmac-nvram-43455-sdio \ + kmod-brcmfmac wpad-basic-mbedtls \ + kmod-hwmon-pwmfan kmod-thermal \ + kmod-usb-dwc3 kmod-usb3 + IMAGE/sysupgrade.img.gz := boot-common | boot-2711 | sdcard-img | gzip | append-metadata + IMAGE/factory.img.gz := boot-common | boot-2711 | sdcard-img | gzip +endef +ifeq ($(SUBTARGET),bcm2712) + TARGET_DEVICES += rpi-5 +endif + $(eval $(call BuildImage)) From 7441c2bef60cb5c110e3049c381bea6c65647f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Fri, 26 Jan 2024 10:19:40 +0100 Subject: [PATCH 19/19] qualcommax: refresh 6.1 patches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refresh patches for Linux 6.1 which no longer apply cleanly after adding ipq4019 MDIO MDC rate fix pending patches. Fixes: 53f338be43e0 ("generic: 6.1: add pending patch for ipq4019 MDIO MDC rate fix") Signed-off-by: Álvaro Fernández Rojas --- ...64-dts-qcom-ipq8074-add-A53-PLL-node.patch | 2 +- ...4-dts-qcom-ipq8074-add-thermal-nodes.patch | 4 ++-- ...-dts-qcom-ipq8074-add-clocks-to-APCS.patch | 2 +- ...pq8074-pass-XO-and-sleep-clocks-to-G.patch | 2 +- ...pq8074-align-TLMM-pin-configuration-.patch | 2 +- ...pq8074-set-Gen2-PCIe-pcie-max-link-s.patch | 2 +- ...m-ipq8074-add-critical-thermal-trips.patch | 24 +++++++++---------- ...pq8074-include-the-GPLL0-as-clock-pr.patch | 2 +- ...pq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch | 2 +- ...qcom-ipq8074-use-msi-parent-for-PCIe.patch | 6 ++--- ...com-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch | 4 ++-- ...0121-arm64-dts-ipq8074-Add-WLAN-node.patch | 2 +- ...64-dts-qcom-ipq8074-add-QFPROM-fuses.patch | 2 +- 13 files changed, 28 insertions(+), 28 deletions(-) diff --git a/target/linux/qualcommax/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch b/target/linux/qualcommax/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch index dd57eae360..5a4b1bbc99 100644 --- a/target/linux/qualcommax/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch +++ b/target/linux/qualcommax/patches-6.1/0001-v6.2-arm64-dts-qcom-ipq8074-add-A53-PLL-node.patch @@ -15,7 +15,7 @@ Link: https://lore.kernel.org/r/20220818220628.339366-9-robimarko@gmail.com --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -675,6 +675,14 @@ +@@ -677,6 +677,14 @@ #mbox-cells = <1>; }; diff --git a/target/linux/qualcommax/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch b/target/linux/qualcommax/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch index bad75e4597..f5abd27965 100644 --- a/target/linux/qualcommax/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch +++ b/target/linux/qualcommax/patches-6.1/0005-v6.2-arm64-dts-qcom-ipq8074-add-thermal-nodes.patch @@ -20,7 +20,7 @@ Link: https://lore.kernel.org/r/20220818220245.338396-5-robimarko@gmail.com --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -274,6 +274,16 @@ +@@ -276,6 +276,16 @@ status = "disabled"; }; @@ -37,7 +37,7 @@ Link: https://lore.kernel.org/r/20220818220245.338396-5-robimarko@gmail.com cryptobam: dma-controller@704000 { compatible = "qcom,bam-v1.7.0"; reg = <0x00704000 0x20000>; -@@ -874,4 +884,90 @@ +@@ -876,4 +886,90 @@ , ; }; diff --git a/target/linux/qualcommax/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch b/target/linux/qualcommax/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch index e229851649..96b49e60bf 100644 --- a/target/linux/qualcommax/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch +++ b/target/linux/qualcommax/patches-6.1/0006-v6.2-arm64-dts-qcom-ipq8074-add-clocks-to-APCS.patch @@ -18,7 +18,7 @@ Link: https://lore.kernel.org/r/20220818220849.339732-4-robimarko@gmail.com --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -680,6 +680,8 @@ +@@ -682,6 +682,8 @@ apcs_glb: mailbox@b111000 { compatible = "qcom,ipq8074-apcs-apps-global"; reg = <0x0b111000 0x1000>; diff --git a/target/linux/qualcommax/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch b/target/linux/qualcommax/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch index 1f99de002b..0f3fdfe4d4 100644 --- a/target/linux/qualcommax/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch +++ b/target/linux/qualcommax/patches-6.1/0012-v6.2-arm64-dts-qcom-ipq8074-pass-XO-and-sleep-clocks-to-G.patch @@ -20,7 +20,7 @@ Link: https://lore.kernel.org/r/20221030175703.1103224-3-robimarko@gmail.com --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -361,9 +361,11 @@ +@@ -363,9 +363,11 @@ gcc: gcc@1800000 { compatible = "qcom,gcc-ipq8074"; reg = <0x01800000 0x80000>; diff --git a/target/linux/qualcommax/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch b/target/linux/qualcommax/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch index 1ce1140682..c9fef2cab4 100644 --- a/target/linux/qualcommax/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch +++ b/target/linux/qualcommax/patches-6.1/0017-v6.2-arm64-dts-qcom-ipq8074-align-TLMM-pin-configuration-.patch @@ -17,7 +17,7 @@ Link: https://lore.kernel.org/r/20221108142357.67202-2-krzysztof.kozlowski@linar --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -318,35 +318,35 @@ +@@ -320,35 +320,35 @@ interrupt-controller; #interrupt-cells = <0x2>; diff --git a/target/linux/qualcommax/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch b/target/linux/qualcommax/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch index 8719bf74c4..2578aa9343 100644 --- a/target/linux/qualcommax/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch +++ b/target/linux/qualcommax/patches-6.1/0019-v6.3-arm64-dts-qcom-ipq8074-set-Gen2-PCIe-pcie-max-link-s.patch @@ -14,7 +14,7 @@ Signed-off-by: Robert Marko --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -766,6 +766,7 @@ +@@ -768,6 +768,7 @@ linux,pci-domain = <1>; bus-range = <0x00 0xff>; num-lanes = <1>; diff --git a/target/linux/qualcommax/patches-6.1/0023-v6.5-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch b/target/linux/qualcommax/patches-6.1/0023-v6.5-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch index e720eb2b85..98e0a08a27 100644 --- a/target/linux/qualcommax/patches-6.1/0023-v6.5-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch +++ b/target/linux/qualcommax/patches-6.1/0023-v6.5-arm64-dts-qcom-ipq8074-add-critical-thermal-trips.patch @@ -17,7 +17,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -896,6 +896,14 @@ +@@ -898,6 +898,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 4>; @@ -32,7 +32,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; nss0-thermal { -@@ -903,6 +911,14 @@ +@@ -905,6 +913,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 5>; @@ -47,7 +47,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; nss1-thermal { -@@ -910,6 +926,14 @@ +@@ -912,6 +928,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 6>; @@ -62,7 +62,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; wcss-phya0-thermal { -@@ -917,6 +941,14 @@ +@@ -919,6 +943,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 7>; @@ -77,7 +77,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; wcss-phya1-thermal { -@@ -924,6 +956,14 @@ +@@ -926,6 +958,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 8>; @@ -92,7 +92,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; cpu0_thermal: cpu0-thermal { -@@ -931,6 +971,14 @@ +@@ -933,6 +973,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 9>; @@ -107,7 +107,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; cpu1_thermal: cpu1-thermal { -@@ -938,6 +986,14 @@ +@@ -940,6 +988,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 10>; @@ -122,7 +122,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; cpu2_thermal: cpu2-thermal { -@@ -945,6 +1001,14 @@ +@@ -947,6 +1003,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 11>; @@ -137,7 +137,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; cpu3_thermal: cpu3-thermal { -@@ -952,6 +1016,14 @@ +@@ -954,6 +1018,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 12>; @@ -152,7 +152,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; cluster_thermal: cluster-thermal { -@@ -959,6 +1031,14 @@ +@@ -961,6 +1033,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 13>; @@ -167,7 +167,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; wcss-phyb0-thermal { -@@ -966,6 +1046,14 @@ +@@ -968,6 +1048,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 14>; @@ -182,7 +182,7 @@ Link: https://lore.kernel.org/r/20230607184448.2512179-1-robimarko@gmail.com }; wcss-phyb1-thermal { -@@ -973,6 +1061,14 @@ +@@ -975,6 +1063,14 @@ polling-delay = <1000>; thermal-sensors = <&tsens 15>; diff --git a/target/linux/qualcommax/patches-6.1/0028-v6.7-arm64-dts-qcom-ipq8074-include-the-GPLL0-as-clock-pr.patch b/target/linux/qualcommax/patches-6.1/0028-v6.7-arm64-dts-qcom-ipq8074-include-the-GPLL0-as-clock-pr.patch index 5ae4fb5671..dee770e4cd 100644 --- a/target/linux/qualcommax/patches-6.1/0028-v6.7-arm64-dts-qcom-ipq8074-include-the-GPLL0-as-clock-pr.patch +++ b/target/linux/qualcommax/patches-6.1/0028-v6.7-arm64-dts-qcom-ipq8074-include-the-GPLL0-as-clock-pr.patch @@ -19,7 +19,7 @@ Reviewed-by: Konrad Dybcio --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -682,8 +682,8 @@ +@@ -684,8 +684,8 @@ apcs_glb: mailbox@b111000 { compatible = "qcom,ipq8074-apcs-apps-global"; reg = <0x0b111000 0x1000>; diff --git a/target/linux/qualcommax/patches-6.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch b/target/linux/qualcommax/patches-6.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch index 69d4126f76..4bd0d9298f 100644 --- a/target/linux/qualcommax/patches-6.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch +++ b/target/linux/qualcommax/patches-6.1/0110-arm64-dts-qcom-ipq8074-pass-QMP-PCI-PHY-PIPE-clocks-.patch @@ -17,7 +17,7 @@ Signed-off-by: Robert Marko --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -396,8 +396,8 @@ +@@ -398,8 +398,8 @@ gcc: gcc@1800000 { compatible = "qcom,gcc-ipq8074"; reg = <0x01800000 0x80000>; diff --git a/target/linux/qualcommax/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch b/target/linux/qualcommax/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch index 9fefd8852a..2aedbd7028 100644 --- a/target/linux/qualcommax/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch +++ b/target/linux/qualcommax/patches-6.1/0111-arm64-dts-qcom-ipq8074-use-msi-parent-for-PCIe.patch @@ -12,7 +12,7 @@ Signed-off-by: Robert Marko --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -699,7 +699,7 @@ +@@ -701,7 +701,7 @@ reg = <0x0b000000 0x1000>, <0x0b002000 0x1000>; ranges = <0 0xb00a000 0xffd>; @@ -21,7 +21,7 @@ Signed-off-by: Robert Marko compatible = "arm,gic-v2m-frame"; msi-controller; reg = <0x0 0xffd>; -@@ -811,8 +811,7 @@ +@@ -813,8 +813,7 @@ ranges = <0x81000000 0x0 0x00000000 0x10200000 0x0 0x10000>, /* I/O */ <0x82000000 0x0 0x10220000 0x10220000 0x0 0xfde0000>; /* MEM */ @@ -31,7 +31,7 @@ Signed-off-by: Robert Marko #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc 0 142 -@@ -873,8 +872,7 @@ +@@ -875,8 +874,7 @@ ranges = <0x81000000 0x0 0x00000000 0x20200000 0x0 0x10000>, /* I/O */ <0x82000000 0x0 0x20220000 0x20220000 0x0 0xfde0000>; /* MEM */ diff --git a/target/linux/qualcommax/patches-6.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch b/target/linux/qualcommax/patches-6.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch index e37ba37e96..f5f93d389e 100644 --- a/target/linux/qualcommax/patches-6.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch +++ b/target/linux/qualcommax/patches-6.1/0120-arm64-dts-qcom-Enable-Q6v5-WCSS-for-ipq8074-SoC.patch @@ -49,7 +49,7 @@ Signed-off-by: Robert Marko soc: soc { #address-cells = <0x1>; #size-cells = <0x1>; -@@ -409,6 +435,11 @@ +@@ -411,6 +437,11 @@ #hwlock-cells = <1>; }; @@ -61,7 +61,7 @@ Signed-off-by: Robert Marko spmi_bus: spmi@200f000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x0200f000 0x001000>, -@@ -913,6 +944,56 @@ +@@ -915,6 +946,56 @@ "axi_s_sticky"; status = "disabled"; }; diff --git a/target/linux/qualcommax/patches-6.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch b/target/linux/qualcommax/patches-6.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch index bd5410c934..1aaa187d8a 100644 --- a/target/linux/qualcommax/patches-6.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch +++ b/target/linux/qualcommax/patches-6.1/0121-arm64-dts-ipq8074-Add-WLAN-node.patch @@ -15,7 +15,7 @@ Signed-off-by: Robert Marko --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -994,6 +994,117 @@ +@@ -996,6 +996,117 @@ }; }; }; diff --git a/target/linux/qualcommax/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch b/target/linux/qualcommax/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch index 3a6f4e9c87..5776ab1af7 100644 --- a/target/linux/qualcommax/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch +++ b/target/linux/qualcommax/patches-6.1/0129-arm64-dts-qcom-ipq8074-add-QFPROM-fuses.patch @@ -12,7 +12,7 @@ Signed-off-by: Robert Marko --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi -@@ -340,6 +340,113 @@ +@@ -342,6 +342,113 @@ status = "disabled"; };