diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+#include "bcm2835.dtsi"
+#include "bcm270x.dtsi"
+
+/ {
+	__overrides__ {
+		arm_freq;
+	};
+};
+
+&vc4 {
+	status = "disabled";
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-b.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-b.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-b.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-b.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2708.dtsi"
+#include "bcm2708-rpi.dtsi"
+#include "bcm283x-rpi-smsc9512.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_28.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	compatible = "raspberrypi,model-b", "brcm,bcm2835";
+	model = "Raspberry Pi Model B";
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <28 29 30 31>;
+		brcm,function = <6>; /* alt2 */
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins = <40 45>;
+		brcm,function = <4>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&gpio 16 1>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+&cam1_reg {
+	gpio = <&gpio 21 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2708.dtsi"
+#include "bcm2708-rpi.dtsi"
+#include "bcm283x-rpi-smsc9514.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_28.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
+	model = "Raspberry Pi Model B+";
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins = <40 45>;
+		brcm,function = <4>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&gpio 47 0>;
+	};
+
+	pwr_led: pwr {
+		label = "led1";
+		linux,default-trigger = "input";
+		gpios = <&gpio 35 0>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+&cam1_reg {
+	gpio = <&gpio 41 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+
+		pwr_led_gpio = <&pwr_led>,"gpios:4";
+		pwr_led_activelow = <&pwr_led>,"gpios:8";
+		pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2708.dtsi"
+#include "bcm2708-rpi.dtsi"
+#include "bcm283x-rpi-smsc9512.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	compatible = "raspberrypi,model-b", "brcm,bcm2835";
+	model = "Raspberry Pi Model B";
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <28 29 30 31>;
+		brcm,function = <6>; /* alt2 */
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins = <40 45>;
+		brcm,function = <4>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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>;
+	};
+};
+
+/delete-node/ &i2c0mux;
+
+i2c0: &i2c0if {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+	clock-frequency = <100000>;
+};
+
+i2c_csi_dsi: &i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+/ {
+	aliases {
+		i2c0 = &i2c0;
+	};
+
+	__overrides__ {
+		i2c0 = <&i2c0>, "status";
+	};
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&gpio 16 1>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+&cam1_reg {
+	gpio = <&gpio 27 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-bt.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-bt.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-bt.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-bt.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+
+&uart0 {
+	bt: bluetooth {
+		compatible = "brcm,bcm43438-bt";
+		max-speed = <3000000>;
+		shutdown-gpios = <&gpio 45 GPIO_ACTIVE_HIGH>;
+		status = "disabled";
+	};
+};
+
+&uart1 {
+	minibt: bluetooth {
+		compatible = "brcm,bcm43438-bt";
+		max-speed = <460800>;
+		shutdown-gpios = <&gpio 45 GPIO_ACTIVE_HIGH>;
+		status = "disabled";
+	};
+};
+
+/ {
+	__overrides__ {
+		krnbt = <&bt>,"status";
+		krnbt_baudrate = <&bt>,"max-speed:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-cm.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-cm.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-cm.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-cm.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2708-rpi-cm.dtsi"
+#include "bcm283x-rpi-csi0-2lane.dtsi"
+#include "bcm283x-rpi-csi1-4lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_28.dtsi"
+
+/ {
+	compatible = "raspberrypi,compute-module", "brcm,bcm2835";
+	model = "Raspberry Pi Compute Module";
+
+	cam1_reg: cam1_reg {
+		compatible = "regulator-fixed";
+		regulator-name = "cam1-regulator";
+		gpio = <&gpio 2 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		status = "disabled";
+	};
+	cam0_reg: cam0_reg {
+		compatible = "regulator-fixed";
+		regulator-name = "cam0-regulator";
+		gpio = <&gpio 30 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		status = "disabled";
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins;
+		brcm,function;
+	};
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+&hdmi {
+	hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+#include "bcm2708.dtsi"
+#include "bcm2708-rpi.dtsi"
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&gpio 47 0>;
+	};
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* Downstream modifications common to bcm2835, bcm2836, bcm2837 */
+
+#include "bcm2835-rpi.dtsi"
+#include "bcm270x-rpi.dtsi"
+
+/ {
+	memory@0 {
+		device_type = "memory";
+		reg = <0x0 0x0>;
+	};
+
+	aliases {
+		i2c2 = &i2c2;
+	};
+
+	__overrides__ {
+		i2c2_iknowwhatimdoing = <&i2c2>,"status";
+		i2c2_baudrate = <&i2c2>,"clock-frequency:0";
+		sd_poll_once = <&sdhost>,"non-removable?";
+	};
+};
+
+&sdhost {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdhost_gpio48>;
+	status = "okay";
+};
+
+&hdmi {
+	power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
+	status = "disabled";
+};
+
+&i2c2 {
+	status = "disabled";
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-zero.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-zero.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-zero.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-zero.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2708.dtsi"
+#include "bcm2708-rpi.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_28.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	compatible = "raspberrypi,model-zero", "brcm,bcm2835";
+	model = "Raspberry Pi Zero";
+
+	chosen {
+		bootargs = "coherent_pool=1M snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1";
+	};
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins = <>;
+		brcm,function = <>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "actpwr";
+		gpios = <&gpio 47 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+	brcm,disable-headphones = <1>;
+};
+
+&cam1_reg {
+	gpio = <&gpio 41 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2708.dtsi"
+#include "bcm2708-rpi.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_28.dtsi"
+#include "bcm2708-rpi-bt.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	compatible = "raspberrypi,model-zero-w", "brcm,bcm2835";
+	model = "Raspberry Pi Zero W";
+
+	chosen {
+		bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1";
+	};
+
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart0;
+		mmc1 = &mmcnr;
+	};
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	sdio_pins: sdio_pins {
+		brcm,pins = <34 35 36 37 38 39>;
+		brcm,function = <7>; /* ALT3 = SD1 */
+		brcm,pull = <0 2 2 2 2 2>;
+	};
+
+	bt_pins: bt_pins {
+		brcm,pins = <43>;
+		brcm,function = <4>; /* alt0:GPCLK2 */
+		brcm,pull = <0>; /* none */
+	};
+
+	uart0_pins: uart0_pins {
+		brcm,pins = <30 31 32 33>;
+		brcm,function = <7>; /* alt3=UART0 */
+		brcm,pull = <2 0 0 2>; /* up none none up */
+	};
+
+	uart1_pins: uart1_pins {
+		brcm,pins;
+		brcm,function;
+		brcm,pull;
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins = <>;
+		brcm,function = <>;
+	};
+};
+
+&mmcnr {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdio_pins>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins &bt_pins>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "actpwr";
+		gpios = <&gpio 47 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+	brcm,disable-headphones = <1>;
+};
+
+&cam1_reg {
+	gpio = <&gpio 44 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2709.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2709.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2709.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2709.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+#include "bcm2836.dtsi"
+#include "bcm270x.dtsi"
+
+/ {
+	soc {
+		ranges = <0x7e000000 0x3f000000 0x01000000>,
+		         <0x40000000 0x40000000 0x00040000>;
+
+		/delete-node/ timer@7e003000;
+	};
+
+	__overrides__ {
+		arm_freq = <&v7_cpu0>, "clock-frequency:0",
+			   <&v7_cpu1>, "clock-frequency:0",
+			   <&v7_cpu2>, "clock-frequency:0",
+			   <&v7_cpu3>, "clock-frequency:0";
+	};
+};
+
+&vc4 {
+	status = "disabled";
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2709-rpi-2-b.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2709-rpi-2-b.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2709-rpi-2-b.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2709.dtsi"
+#include "bcm2709-rpi.dtsi"
+#include "bcm283x-rpi-smsc9514.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_28.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
+	model = "Raspberry Pi 2 Model B";
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins = <40 45>;
+		brcm,function = <4>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&gpio 47 0>;
+	};
+
+	pwr_led: pwr {
+		label = "led1";
+		linux,default-trigger = "input";
+		gpios = <&gpio 35 0>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+&cam1_reg {
+	gpio = <&gpio 41 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+
+		pwr_led_gpio = <&pwr_led>,"gpios:4";
+		pwr_led_activelow = <&pwr_led>,"gpios:8";
+		pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2709-rpi.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2709-rpi.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2709-rpi.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2709-rpi.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2 @
+#include "bcm2708-rpi.dtsi"
+
+&vchiq {
+	compatible = "brcm,bcm2836-vchiq", "brcm,bcm2835-vchiq";
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm270x.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm270x.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm270x.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm270x.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* Downstream bcm283x.dtsi diff */
+#include <dt-bindings/power/raspberrypi-power.h>
+
+/ {
+	chosen {
+		bootargs = "coherent_pool=1M snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1";
+		/delete-property/ stdout-path;
+	};
+
+	soc: soc {
+
+		watchdog: watchdog@7e100000 {
+			/* Add label */
+		};
+
+		random: rng@7e104000 {
+			/* Add label */
+		};
+
+		spi0: spi@7e204000 {
+			/* Add label */
+		};
+
+#ifndef BCM2711
+		pixelvalve0: pixelvalve@7e206000 {
+			/* Add label */
+			status = "disabled";
+		};
+
+		pixelvalve1: pixelvalve@7e207000 {
+			/* Add label */
+			status = "disabled";
+		};
+#endif
+
+		/delete-node/ sdhci@7e300000;
+
+		sdhci: mmc: mmc@7e300000 {
+			compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci";
+			reg = <0x7e300000 0x100>;
+			interrupts = <2 30>;
+			clocks = <&clocks BCM2835_CLOCK_EMMC>;
+			dmas = <&dma 11>;
+			dma-names = "rx-tx";
+			brcm,overclock-50 = <0>;
+			status = "disabled";
+		};
+
+		/* A clone of mmc but with non-removable set */
+		mmcnr: mmcnr@7e300000 {
+			compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci";
+			reg = <0x7e300000 0x100>;
+			interrupts = <2 30>;
+			clocks = <&clocks BCM2835_CLOCK_EMMC>;
+			dmas = <&dma 11>;
+			dma-names = "rx-tx";
+			brcm,overclock-50 = <0>;
+			non-removable;
+			status = "disabled";
+		};
+
+		hvs: hvs@7e400000 {
+			/* Add label */
+			status = "disabled";
+		};
+
+		firmwarekms: firmwarekms@7e600000 {
+			compatible = "raspberrypi,rpi-firmware-kms";
+			/* SMI interrupt reg */
+			reg = <0x7e600000 0x100>;
+			interrupts = <2 16>;
+			brcm,firmware = <&firmware>;
+			status = "disabled";
+		};
+
+		smi: smi@7e600000 {
+			compatible = "brcm,bcm2835-smi";
+			reg = <0x7e600000 0x100>;
+			interrupts = <2 16>;
+			clocks = <&clocks BCM2835_CLOCK_SMI>;
+			assigned-clocks = <&clocks BCM2835_CLOCK_SMI>;
+			assigned-clock-rates = <125000000>;
+			dmas = <&dma 4>;
+			dma-names = "rx-tx";
+			status = "disabled";
+		};
+
+		csi0: csi@7e800000 {
+			compatible = "brcm,bcm2835-unicam";
+			reg = <0x7e800000 0x800>,
+			      <0x7e802000 0x4>;
+			interrupts = <2 6>;
+			clocks = <&clocks BCM2835_CLOCK_CAM0>,
+				 <&firmware_clocks 4>;
+			clock-names = "lp", "vpu";
+			power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#clock-cells = <1>;
+			status = "disabled";
+		};
+
+		csi1: csi@7e801000 {
+			compatible = "brcm,bcm2835-unicam";
+			reg = <0x7e801000 0x800>,
+			      <0x7e802004 0x4>;
+			interrupts = <2 7>;
+			clocks = <&clocks BCM2835_CLOCK_CAM1>,
+				 <&firmware_clocks 4>;
+			clock-names = "lp", "vpu";
+			power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#clock-cells = <1>;
+			status = "disabled";
+		};
+
+#ifndef BCM2711
+		pixelvalve2: pixelvalve@7e807000 {
+			/* Add label */
+			status = "disabled";
+		};
+#endif
+
+		hdmi@7e902000 { /* hdmi */
+			status = "disabled";
+		};
+
+		usb@7e980000 { /* usb */
+			compatible = "brcm,bcm2708-usb";
+			reg = <0x7e980000 0x10000>,
+			      <0x7e006000 0x1000>;
+			interrupt-names = "usb",
+					  "soft";
+			interrupts = <1 9>,
+				     <2 0>;
+		};
+
+#ifndef BCM2711
+		v3d@7ec00000 { /* vd3 */
+			compatible = "brcm,vc4-v3d";
+			power-domains = <&power RPI_POWER_DOMAIN_V3D>;
+			status = "disabled";
+		};
+#endif
+
+		axiperf: axiperf {
+			compatible = "brcm,bcm2835-axiperf";
+			reg = <0x7e009800 0x100>,
+			      <0x7ee08000 0x100>;
+			firmware = <&firmware>;
+			status = "disabled";
+		};
+	};
+
+	__overrides__ {
+		cam0-pwdn-ctrl;
+		cam0-pwdn;
+		cam0-led-ctrl;
+		cam0-led;
+	};
+};
+
+&gpio {
+	interrupts = <2 17>, <2 18>;
+
+	dpi_18bit_cpadhi_gpio0: dpi_18bit_cpadhi_gpio0 {
+		brcm,pins = <0 1 2 3 4 5 6 7 8 9
+			     12 13 14 15 16 17
+			     20 21 22 23 24 25>;
+		brcm,function = <BCM2835_FSEL_ALT2>;
+		brcm,pull = <0>; /* no pull */
+	};
+	dpi_18bit_cpadhi_gpio2: dpi_18bit_cpadhi_gpio2 {
+		brcm,pins = <2 3 4 5 6 7 8 9
+			     12 13 14 15 16 17
+			     20 21 22 23 24 25>;
+		brcm,function = <BCM2835_FSEL_ALT2>;
+	};
+	dpi_18bit_gpio0: dpi_18bit_gpio0 {
+		brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
+			     12 13 14 15 16 17 18 19
+			     20 21>;
+		brcm,function = <BCM2835_FSEL_ALT2>;
+	};
+	dpi_18bit_gpio2: dpi_18bit_gpio2 {
+		brcm,pins = <2 3 4 5 6 7 8 9 10 11
+			     12 13 14 15 16 17 18 19
+			     20 21>;
+		brcm,function = <BCM2835_FSEL_ALT2>;
+	};
+};
+
+&uart0 {
+	/* Enable CTS bug workaround */
+	cts-event-workaround;
+};
+
+&i2s {
+	#sound-dai-cells = <0>;
+	dmas = <&dma 2>, <&dma 3>;
+	dma-names = "tx", "rx";
+};
+
+&sdhost {
+	dmas = <&dma (13|(1<<29))>;
+	dma-names = "rx-tx";
+	bus-width = <4>;
+	brcm,overclock-50 = <0>;
+	brcm,pio-limit = <1>;
+};
+
+&spi0 {
+	dmas = <&dma 6>, <&dma 7>;
+	dma-names = "tx", "rx";
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm270x-rpi.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm270x-rpi.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm270x-rpi.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm270x-rpi.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* Downstream modifications to bcm2835-rpi.dtsi */
+
+/ {
+	aliases {
+		audio = &audio;
+		aux = &aux;
+		sound = &sound;
+		soc = &soc;
+		dma = &dma;
+		intc = &intc;
+		watchdog = &watchdog;
+		random = &random;
+		mailbox = &mailbox;
+		gpio = &gpio;
+		uart0 = &uart0;
+		uart1 = &uart1;
+		sdhost = &sdhost;
+		mmc = &mmc;
+		mmc1 = &mmc;
+		mmc0 = &sdhost;
+		i2s = &i2s;
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c10 = &i2c_csi_dsi;
+		spi0 = &spi0;
+		spi1 = &spi1;
+		spi2 = &spi2;
+		usb = &usb;
+		leds = &leds;
+		fb = &fb;
+		thermal = &thermal;
+		axiperf = &axiperf;
+	};
+
+	/* Define these notional regulators for use by overlays */
+	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";
+	};
+
+	leds: leds {
+		compatible = "gpio-leds";
+	};
+
+	soc {
+		gpiomem {
+			compatible = "brcm,bcm2835-gpiomem";
+			reg = <0x7e200000 0x1000>;
+		};
+
+		fb: fb {
+			compatible = "brcm,bcm2708-fb";
+			firmware = <&firmware>;
+			status = "okay";
+		};
+
+		vcsm: vcsm {
+			compatible = "raspberrypi,bcm2835-vcsm";
+			firmware = <&firmware>;
+			status = "okay";
+		};
+
+		/* External sound card */
+		sound: sound {
+			status = "disabled";
+		};
+	};
+
+	__overrides__ {
+		cache_line_size;
+
+		uart0 = <&uart0>,"status";
+		uart1 = <&uart1>,"status";
+		i2s = <&i2s>,"status";
+		spi = <&spi0>,"status";
+		i2c0 = <&i2c0if>,"status",<&i2c0mux>,"status";
+		i2c1 = <&i2c1>,"status";
+		i2c0_baudrate = <&i2c0if>,"clock-frequency:0";
+		i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+
+		audio = <&audio>,"status";
+		watchdog = <&watchdog>,"status";
+		random = <&random>,"status";
+		sd_overclock = <&sdhost>,"brcm,overclock-50:0";
+		sd_force_pio = <&sdhost>,"brcm,force-pio?";
+		sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
+		sd_debug     = <&sdhost>,"brcm,debug";
+		sdio_overclock = <&mmc>,"brcm,overclock-50:0",
+				 <&mmcnr>,"brcm,overclock-50:0";
+		axiperf      = <&axiperf>,"status";
+	};
+};
+
+&uart0 {
+	skip-init;
+};
+
+&uart1 {
+	skip-init;
+};
+
+&txp {
+	status = "disabled";
+};
+
+&i2c0if {
+	status = "disabled";
+};
+
+&i2c0mux {
+	status = "disabled";
+};
+
+&i2c1 {
+	status = "disabled";
+};
+
+&clocks {
+	firmware = <&firmware>;
+};
+
+&sdhci {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_gpio48>;
+	bus-width = <4>;
+};
+
+&cpu_thermal {
+	/delete-node/ trips;
+};
+
+&vec {
+	status = "disabled";
+};
+
+&vchiq {
+	/* Onboard audio */
+	audio: bcm2835_audio {
+		compatible = "brcm,bcm2835-audio";
+		brcm,pwm-channels = <8>;
+		status = "disabled";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2710.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2710.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+#include "bcm2837.dtsi"
+#include "bcm270x.dtsi"
+
+/ {
+	compatible = "brcm,bcm2837", "brcm,bcm2836";
+
+	arm-pmu {
+		compatible = "arm,cortex-a53-pmu", "arm,cortex-a7-pmu";
+	};
+
+	soc {
+		/delete-node/ timer@7e003000;
+	};
+
+	__overrides__ {
+		arm_freq = <&cpu0>, "clock-frequency:0",
+		       <&cpu1>, "clock-frequency:0",
+		       <&cpu2>, "clock-frequency:0",
+		       <&cpu3>, "clock-frequency:0";
+	};
+};
+
+&vc4 {
+	status = "disabled";
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2710-rpi-2-b.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710-rpi-2-b.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2710-rpi-2-b.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710-rpi-2-b.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2710.dtsi"
+#include "bcm2709-rpi.dtsi"
+#include "bcm283x-rpi-smsc9514.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_28.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	compatible = "raspberrypi,2-model-b-rev2", "brcm,bcm2837";
+	model = "Raspberry Pi 2 Model B rev 1.2";
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins = <40 45>;
+		brcm,function = <4>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&gpio 47 0>;
+	};
+
+	pwr_led: pwr {
+		label = "led1";
+		linux,default-trigger = "input";
+		gpios = <&gpio 35 0>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+&cam1_reg {
+	gpio = <&gpio 41 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+
+		pwr_led_gpio = <&pwr_led>,"gpios:4";
+		pwr_led_activelow = <&pwr_led>,"gpios:8";
+		pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2710-rpi-3-b.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2710-rpi-3-b.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710-rpi-3-b.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2710.dtsi"
+#include "bcm2709-rpi.dtsi"
+#include "bcm283x-rpi-smsc9514.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_44.dtsi"
+#include "bcm271x-rpi-bt.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
+	model = "Raspberry Pi 3 Model B";
+
+	chosen {
+		bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1";
+	};
+
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart0;
+		mmc1 = &mmcnr;
+	};
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	sdio_pins: sdio_pins {
+		brcm,pins =     <34 35 36 37 38 39>;
+		brcm,function = <7>; // alt3 = SD1
+		brcm,pull =     <0 2 2 2 2 2>;
+	};
+
+	bt_pins: bt_pins {
+		brcm,pins = <43>;
+		brcm,function = <4>; /* alt0:GPCLK2 */
+		brcm,pull = <0>;
+	};
+
+	uart0_pins: uart0_pins {
+		brcm,pins = <32 33>;
+		brcm,function = <7>; /* alt3=UART0 */
+		brcm,pull = <0 2>;
+	};
+
+	uart1_pins: uart1_pins {
+		brcm,pins;
+		brcm,function;
+		brcm,pull;
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins = <40 41>;
+		brcm,function = <4>;
+	};
+};
+
+&mmcnr {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdio_pins>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&soc {
+	virtgpio: virtgpio {
+		compatible = "brcm,bcm2835-virtgpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		firmware = <&firmware>;
+		status = "okay";
+	};
+
+};
+
+&firmware {
+	expgpio: expgpio {
+		compatible = "raspberrypi,firmware-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		status = "okay";
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins &bt_pins>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&bt {
+	max-speed = <921600>;
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&virtgpio 0 0>;
+	};
+
+	pwr_led: pwr {
+		label = "led1";
+		linux,default-trigger = "input";
+		gpios = <&expgpio 7 0>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&expgpio 4 GPIO_ACTIVE_LOW>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+&cam1_reg {
+	gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+
+		pwr_led_gpio = <&pwr_led>,"gpios:4";
+		pwr_led_activelow = <&pwr_led>,"gpios:8";
+		pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2710.dtsi"
+#include "bcm2709-rpi.dtsi"
+#include "bcm283x-rpi-lan7515.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_44.dtsi"
+#include "bcm271x-rpi-bt.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	compatible = "raspberrypi,3-model-b-plus", "brcm,bcm2837";
+	model = "Raspberry Pi 3 Model B+";
+
+	chosen {
+		bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1";
+	};
+
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart0;
+		mmc1 = &mmcnr;
+	};
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	sdio_pins: sdio_pins {
+		brcm,pins =     <34 35 36 37 38 39>;
+		brcm,function = <7>; // alt3 = SD1
+		brcm,pull =     <0 2 2 2 2 2>;
+	};
+
+	bt_pins: bt_pins {
+		brcm,pins = <43>;
+		brcm,function = <4>; /* alt0:GPCLK2 */
+		brcm,pull = <0>;
+	};
+
+	uart0_pins: uart0_pins {
+		brcm,pins = <32 33>;
+		brcm,function = <7>; /* alt3=UART0 */
+		brcm,pull = <0 2>;
+	};
+
+	uart1_pins: uart1_pins {
+		brcm,pins;
+		brcm,function;
+		brcm,pull;
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins = <40 41>;
+		brcm,function = <4>;
+	};
+};
+
+&mmcnr {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdio_pins>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&firmware {
+	expgpio: expgpio {
+		compatible = "raspberrypi,firmware-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		status = "okay";
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins &bt_pins>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&gpio 29 0>;
+	};
+
+	pwr_led: pwr {
+		label = "led1";
+		linux,default-trigger = "default-on";
+		gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+&eth_phy {
+	microchip,eee-enabled;
+	microchip,tx-lpi-timer = <600>; /* non-aggressive*/
+	microchip,downshift-after = <2>;
+};
+
+&cam1_reg {
+	gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+
+		pwr_led_gpio = <&pwr_led>,"gpios:4";
+		pwr_led_activelow = <&pwr_led>,"gpios:8";
+		pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
+
+		eee = <&eth_phy>,"microchip,eee-enabled?";
+		tx_lpi_timer = <&eth_phy>,"microchip,tx-lpi-timer:0";
+		eth_led0 = <&eth_phy>,"microchip,led-modes:0";
+		eth_led1 = <&eth_phy>,"microchip,led-modes:4";
+		eth_downshift_after = <&eth_phy>,"microchip,downshift-after:0";
+		eth_max_speed = <&eth_phy>,"max-speed:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2710-rpi-cm3.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2710-rpi-cm3.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2710-rpi-cm3.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+#include "bcm2710.dtsi"
+#include "bcm2709-rpi.dtsi"
+#include "bcm283x-rpi-csi0-2lane.dtsi"
+#include "bcm283x-rpi-csi1-4lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_28.dtsi"
+/ {
+	compatible = "raspberrypi,3-compute-module", "brcm,bcm2837";
+	model = "Raspberry Pi Compute Module 3";
+
+	cam1_reg: cam1_reg {
+		compatible = "regulator-fixed";
+		regulator-name = "cam1-regulator";
+		gpio = <&gpio 2 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		status = "disabled";
+	};
+	cam0_reg: cam0_reg {
+		compatible = "regulator-fixed";
+		regulator-name = "cam0-regulator";
+		gpio = <&gpio 30 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		status = "disabled";
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <1>; /* output */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	audio_pins: audio_pins {
+		brcm,pins;
+		brcm,function;
+	};
+};
+
+&soc {
+	virtgpio: virtgpio {
+		compatible = "brcm,bcm2835-virtgpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		firmware = <&firmware>;
+		status = "okay";
+	};
+
+};
+
+&firmware {
+	expgpio: expgpio {
+		compatible = "raspberrypi,firmware-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		status = "okay";
+	};
+};
+
+&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>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&virtgpio 0 0>;
+	};
+};
+
+&hdmi {
+	hpd-gpios = <&expgpio 0 GPIO_ACTIVE_LOW>;
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2711.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2711.dtsi	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:303 @
 			status = "disabled";
 		};
 
+		vec: vec@7ec13000 {
+			compatible = "brcm,bcm2711-vec";
+			reg = <0x7ec13000 0x1000>;
+			clocks = <&clocks BCM2835_CLOCK_VEC>;
+			interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
 		dvp: clock@7ef00000 {
 			compatible = "brcm,brcm2711-dvp";
 			reg = <0x7ef00000 0x10>;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:319 @
 			#reset-cells = <1>;
 		};
 
+		aon_intr: interrupt-controller@7ef00100 {
+			compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc";
+			reg = <0x7ef00100 0x30>;
+			interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			status = "disabled";
+		};
+
 		hdmi0: hdmi@7ef00700 {
 			compatible = "brcm,bcm2711-hdmi0";
 			reg = <0x7ef00700 0x300>,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:338 @
 			      <0x7ef01f00 0x400>,
 			      <0x7ef00200 0x80>,
 			      <0x7ef04300 0x100>,
-			      <0x7ef20000 0x100>;
+			      <0x7ef20000 0x100>,
+			      <0x7ef00100 0x30>;
 			reg-names = "hdmi",
 				    "dvp",
 				    "phy",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:348 @
 				    "metadata",
 				    "csc",
 				    "cec",
-				    "hd";
+				    "hd",
+				    "intr2";
+			clocks = <&firmware_clocks 13>,
+				 <&firmware_clocks 14>,
+				 <&dvp 0>,
+				 <&clk_27MHz>;
 			clock-names = "hdmi", "bvb", "audio", "cec";
 			resets = <&dvp 0>;
+			interrupt-parent = <&aon_intr>;
+			interrupts = <0>, <1>, <2>,
+				     <3>, <4>, <5>;
+			interrupt-names = "cec-tx", "cec-rx", "cec-low",
+					  "wakeup", "hpd-connected", "hpd-removed";
 			ddc = <&ddc0>;
-			dmas = <&dma 10>;
+			dmas = <&dma (10 | (1 << 27) | (1 << 24)| (15 << 20) | (10 << 16))>;
 			dma-names = "audio-rx";
 			status = "disabled";
 		};
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:385 @
 			      <0x7ef06f00 0x400>,
 			      <0x7ef00280 0x80>,
 			      <0x7ef09300 0x100>,
-			      <0x7ef20000 0x100>;
+			      <0x7ef20000 0x100>,
+			      <0x7ef00100 0x30>;
 			reg-names = "hdmi",
 				    "dvp",
 				    "phy",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:395 @
 				    "metadata",
 				    "csc",
 				    "cec",
-				    "hd";
+				    "hd",
+				    "intr2";
 			ddc = <&ddc1>;
 			clock-names = "hdmi", "bvb", "audio", "cec";
+			clocks = <&firmware_clocks 13>,
+				 <&firmware_clocks 14>,
+				 <&dvp 0>,
+				 <&clk_27MHz>;
 			resets = <&dvp 1>;
-			dmas = <&dma 17>;
+			interrupt-parent = <&aon_intr>;
+			interrupts = <8>, <7>, <6>,
+				     <9>, <10>, <11>;
+			interrupt-names = "cec-tx", "cec-rx", "cec-low",
+					  "wakeup", "hpd-connected", "hpd-removed";
+			dmas = <&dma (17 | (1 << 27) | (1 << 24)| (15 << 20) | (10 << 16))>;
 			dma-names = "audio-rx";
 			status = "disabled";
 		};
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:510 @
 	scb {
 		compatible = "simple-bus";
 		#address-cells = <2>;
-		#size-cells = <1>;
+		#size-cells = <2>;
 
-		ranges = <0x0 0x7c000000  0x0 0xfc000000  0x03800000>,
-			 <0x6 0x00000000  0x6 0x00000000  0x40000000>;
+		ranges = <0x0 0x7c000000  0x0 0xfc000000  0x0 0x03800000>,
+			 <0x6 0x00000000  0x6 0x00000000  0x0 0x40000000>;
 
 		pcie0: pcie@7d500000 {
 			compatible = "brcm,bcm2711-pcie";
-			reg = <0x0 0x7d500000 0x9310>;
+			reg = <0x0 0x7d500000  0x0 0x9310>;
 			device_type = "pci";
 			#address-cells = <3>;
 			#interrupt-cells = <1>;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:531 @
 			msi-controller;
 			msi-parent = <&pcie0>;
 
-			ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
-				  0x0 0x04000000>;
+			ranges = <0x02000000 0x0 0xc0000000 0x6 0x00000000
+				  0x0 0x40000000>;
 			/*
 			 * The wrapper around the PCIe block has a bug
 			 * preventing it from accessing beyond the first 3GB of
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:545 @
 
 		genet: ethernet@7d580000 {
 			compatible = "brcm,bcm2711-genet-v5";
-			reg = <0x0 0x7d580000 0x10000>;
+			reg = <0x0 0x7d580000  0x0 0x10000>;
 			#address-cells = <0x1>;
 			#size-cells = <0x1>;
 			interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:582 @
 
 &dsi1 {
 	interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+	compatible = "brcm,bcm2711-dsi1";
 };
 
 &gpio {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1053 @
 	alloc-ranges = <0x0 0x00000000 0x40000000>;
 };
 
-&i2c0 {
+&i2c0if {
 	compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
 	interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
 };
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1109 @
 &usb {
 	interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
 };
-
-&vec {
-	interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
-};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2711-rpi-400.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711-rpi-400.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2711-rpi-400.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711-rpi-400.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+#include "bcm2711.dtsi"
+#include "bcm2835-rpi.dtsi"
+
+#include <dt-bindings/reset/raspberrypi,firmware-reset.h>
+
+/ {
+	compatible = "raspberrypi,400", "brcm,bcm2711";
+	model = "Raspberry Pi 400";
+
+	chosen {
+		/* 8250 auxiliary UART instead of pl011 */
+		stdout-path = "serial1:115200n8";
+	};
+
+	/* Will be filled by the bootloader */
+	memory@0 {
+		device_type = "memory";
+		reg = <0 0 0>;
+	};
+
+	aliases {
+		emmc2bus = &emmc2bus;
+		ethernet0 = &genet;
+		pcie0 = &pcie0;
+		blconfig = &blconfig;
+	};
+
+	leds {
+		act {
+			gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+		};
+
+		pwr {
+			label = "PWR";
+			gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+			default-state = "keep";
+			linux,default-trigger = "default-on";
+		};
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
+	};
+
+	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 = <&expgpio 4 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;
+		gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&ddc0 {
+	status = "okay";
+};
+
+&ddc1 {
+	status = "okay";
+};
+
+&firmware {
+	firmware_clocks: clocks {
+		compatible = "raspberrypi,firmware-clocks";
+		#clock-cells = <1>;
+	};
+
+	expgpio: gpio {
+		compatible = "raspberrypi,firmware-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names = "BT_ON",
+				  "WL_ON",
+				  "PWR_LED_OFF",
+				  "GLOBAL_RESET",
+				  "VDD_SD_IO_SEL",
+				  "CAM_GPIO",
+				  "SD_PWR_ON",
+				  "SD_OC_N";
+		status = "okay";
+	};
+
+	reset: reset {
+		compatible = "raspberrypi,firmware-reset";
+		#reset-cells = <1>;
+	};
+};
+
+&gpio {
+	/*
+	 * Parts taken from rpi_SCH_4b_4p0_reduced.pdf and
+	 * the official GPU firmware DT blob.
+	 *
+	 * Legend:
+	 * "FOO" = GPIO line named "FOO" on the schematic
+	 * "FOO_N" = GPIO line named "FOO" on schematic, active low
+	 */
+	gpio-line-names = "ID_SDA",
+			  "ID_SCL",
+			  "SDA1",
+			  "SCL1",
+			  "GPIO_GCLK",
+			  "GPIO5",
+			  "GPIO6",
+			  "SPI_CE1_N",
+			  "SPI_CE0_N",
+			  "SPI_MISO",
+			  "SPI_MOSI",
+			  "SPI_SCLK",
+			  "GPIO12",
+			  "GPIO13",
+			  /* Serial port */
+			  "TXD1",
+			  "RXD1",
+			  "GPIO16",
+			  "GPIO17",
+			  "GPIO18",
+			  "GPIO19",
+			  "GPIO20",
+			  "GPIO21",
+			  "GPIO22",
+			  "GPIO23",
+			  "GPIO24",
+			  "GPIO25",
+			  "GPIO26",
+			  "GPIO27",
+			  "RGMII_MDIO",
+			  "RGMIO_MDC",
+			  /* Used by BT module */
+			  "CTS0",
+			  "RTS0",
+			  "TXD0",
+			  "RXD0",
+			  /* Used by Wifi */
+			  "SD1_CLK",
+			  "SD1_CMD",
+			  "SD1_DATA0",
+			  "SD1_DATA1",
+			  "SD1_DATA2",
+			  "SD1_DATA3",
+			  /* Shared with SPI flash */
+			  "PWM0_MISO",
+			  "PWM1_MOSI",
+			  "STATUS_LED_G_CLK",
+			  "SPIFLASH_CE_N",
+			  "SDA0",
+			  "SCL0",
+			  "RGMII_RXCLK",
+			  "RGMII_RXCTL",
+			  "RGMII_RXD0",
+			  "RGMII_RXD1",
+			  "RGMII_RXD2",
+			  "RGMII_RXD3",
+			  "RGMII_TXCLK",
+			  "RGMII_TXCTL",
+			  "RGMII_TXD0",
+			  "RGMII_TXD1",
+			  "RGMII_TXD2",
+			  "RGMII_TXD3";
+};
+
+&hdmi0 {
+	clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>;
+	clock-names = "hdmi", "bvb", "audio", "cec";
+	status = "okay";
+};
+
+&hdmi1 {
+	clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>;
+	clock-names = "hdmi", "bvb", "audio", "cec";
+	status = "okay";
+};
+
+&hvs {
+	clocks = <&firmware_clocks 4>;
+};
+
+&pixelvalve0 {
+	status = "okay";
+};
+
+&pixelvalve1 {
+	status = "okay";
+};
+
+&pixelvalve2 {
+	status = "okay";
+};
+
+&pixelvalve4 {
+	status = "okay";
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>;
+	status = "okay";
+};
+
+&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";
+	};
+};
+
+/* SDHCI is used to control the SDIO for wireless */
+&sdhci {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_gpio34>;
+	bus-width = <4>;
+	non-removable;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	status = "okay";
+
+	brcmf: wifi@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+	};
+};
+
+/* EMMC2 is used to drive the SD card */
+&emmc2 {
+	vqmmc-supply = <&sd_io_1v8_reg>;
+	vmmc-supply = <&sd_vcc_reg>;
+	broken-cd;
+	status = "okay";
+};
+
+&genet {
+	phy-handle = <&phy1>;
+	phy-mode = "rgmii-rxid";
+	status = "okay";
+};
+
+&genet_mdio {
+	phy1: ethernet-phy@1 {
+		/* No PHY interrupt */
+		reg = <0x1>;
+	};
+};
+
+&pcie0 {
+	pci@1,0 {
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges;
+
+		reg = <0 0 0 0 0>;
+
+		usb@1,0 {
+			reg = <0x10000 0 0 0 0>;
+			resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>;
+		};
+	};
+};
+
+/* uart0 communicates with the BT module */
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "brcm,bcm43438-bt";
+		max-speed = <2000000>;
+		shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+/* uart1 is mapped to the pin header */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_gpio14>;
+	status = "okay";
+};
+
+&vchiq {
+	interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&vc4 {
+	status = "okay";
+};
+
+&vec {
+	status = "disabled";
+};
+
+// =============================================
+// Downstream rpi- changes
+
+#define BCM2711
+
+#include "bcm270x.dtsi"
+#include "bcm271x-rpi-bt.dtsi"
+
+/ {
+	soc {
+		/delete-node/ pixelvalve@7e807000;
+		/delete-node/ hdmi@7e902000;
+	};
+};
+
+#include "bcm2711-rpi.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_44.dtsi"
+
+/ {
+	chosen {
+		bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1";
+	};
+
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart0;
+		mmc0 = &emmc2;
+		mmc1 = &mmcnr;
+		mmc2 = &sdhost;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		i2c20 = &ddc0;
+		i2c21 = &ddc1;
+		spi3 = &spi3;
+		spi4 = &spi4;
+		spi5 = &spi5;
+		spi6 = &spi6;
+		/delete-property/ intc;
+	};
+
+	/delete-node/ wifi-pwrseq;
+};
+
+&mmcnr {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdio_pins>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_pins &bt_pins>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+};
+
+&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>;
+	};
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi3_pins: spi3_pins {
+		brcm,pins = <1 2 3>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi3_cs_pins: spi3_cs_pins {
+		brcm,pins = <0 24>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi4_pins: spi4_pins {
+		brcm,pins = <5 6 7>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi4_cs_pins: spi4_cs_pins {
+		brcm,pins = <4 25>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi5_pins: spi5_pins {
+		brcm,pins = <13 14 15>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi5_cs_pins: spi5_cs_pins {
+		brcm,pins = <12 26>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi6_pins: spi6_pins {
+		brcm,pins = <19 20 21>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi6_cs_pins: spi6_cs_pins {
+		brcm,pins = <18 27>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c3_pins: i2c3 {
+		brcm,pins = <4 5>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c4_pins: i2c4 {
+		brcm,pins = <8 9>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c5_pins: i2c5 {
+		brcm,pins = <12 13>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c6_pins: i2c6 {
+		brcm,pins = <22 23>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+	};
+
+	sdio_pins: sdio_pins {
+		brcm,pins =     <34 35 36 37 38 39>;
+		brcm,function = <BCM2835_FSEL_ALT3>; // alt3 = SD1
+		brcm,pull =     <0 2 2 2 2 2>;
+	};
+
+	bt_pins: bt_pins {
+		brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0
+				 // to fool pinctrl
+		brcm,function = <0>;
+		brcm,pull = <2>;
+	};
+
+	uart0_pins: uart0_pins {
+		brcm,pins = <32 33>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+		brcm,pull = <0 2>;
+	};
+
+	uart1_pins: uart1_pins {
+		brcm,pins;
+		brcm,function;
+		brcm,pull;
+	};
+
+	uart2_pins: uart2_pins {
+		brcm,pins = <0 1>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+
+	uart3_pins: uart3_pins {
+		brcm,pins = <4 5>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+
+	uart4_pins: uart4_pins {
+		brcm,pins = <8 9>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+
+	uart5_pins: uart5_pins {
+		brcm,pins = <12 13>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+// =============================================
+// Board specific stuff here
+
+/ {
+	power_ctrl: power_ctrl {
+		compatible = "gpio-poweroff";
+		gpios = <&expgpio 5 0>;
+		force;
+	};
+};
+
+&sdhost {
+	status = "disabled";
+};
+
+&phy1 {
+	led-modes = <0x00 0x08>; /* link/activity link */
+};
+
+&gpio {
+	audio_pins: audio_pins {
+		brcm,pins = <>;
+		brcm,function = <>;
+	};
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "default-on";
+		default-state = "on";
+		gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+	};
+
+	pwr_led: pwr {
+		label = "led1";
+		linux,default-trigger = "default-on";
+		gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&pwm1 {
+	status = "disabled";
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+	brcm,disable-headphones = <1>;
+};
+
+&genet_mdio {
+	clock-frequency = <1950000>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+
+		pwr_led_gpio = <&pwr_led>,"gpios:4";
+		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";
+
+		sd_poll_once = <&emmc2>, "non-removable?";
+		spi_dma4 = <&spi0>, "dmas:0=", <&dma40>,
+			   <&spi0>, "dmas:8=", <&dma40>;
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2711-rpi-4-b.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2711-rpi-4-b.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711-rpi-4-b.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5 @
 /dts-v1/;
 #include "bcm2711.dtsi"
 #include "bcm2835-rpi.dtsi"
-#include "bcm283x-rpi-usb-peripheral.dtsi"
 
 #include <dt-bindings/reset/raspberrypi,firmware-reset.h>
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:27 @
 		emmc2bus = &emmc2bus;
 		ethernet0 = &genet;
 		pcie0 = &pcie0;
+		blconfig = &blconfig;
 	};
 
 	leds {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:98 @
 				  "VDD_SD_IO_SEL",
 				  "CAM_GPIO",
 				  "SD_PWR_ON",
-				  "";
+				  "SD_OC_N";
 		status = "okay";
 	};
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:219 @
 	status = "okay";
 };
 
+&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";
+	};
+};
+
 /* SDHCI is used to control the SDIO for wireless */
 &sdhci {
 	#address-cells = <1>;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:320 @
 &vec {
 	status = "disabled";
 };
+
+// =============================================
+// Downstream rpi- changes
+
+#define BCM2711
+
+#include "bcm270x.dtsi"
+#include "bcm271x-rpi-bt.dtsi"
+
+/ {
+	soc {
+		/delete-node/ pixelvalve@7e807000;
+		/delete-node/ hdmi@7e902000;
+	};
+};
+
+#include "bcm2711-rpi.dtsi"
+#include "bcm283x-rpi-csi1-2lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_44.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	chosen {
+		bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1";
+	};
+
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart0;
+		mmc0 = &emmc2;
+		mmc1 = &mmcnr;
+		mmc2 = &sdhost;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		i2c20 = &ddc0;
+		i2c21 = &ddc1;
+		spi3 = &spi3;
+		spi4 = &spi4;
+		spi5 = &spi5;
+		spi6 = &spi6;
+		/delete-property/ intc;
+	};
+
+	/delete-node/ wifi-pwrseq;
+};
+
+&mmcnr {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdio_pins>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_pins &bt_pins>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+};
+
+&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>;
+	};
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi3_pins: spi3_pins {
+		brcm,pins = <1 2 3>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi3_cs_pins: spi3_cs_pins {
+		brcm,pins = <0 24>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi4_pins: spi4_pins {
+		brcm,pins = <5 6 7>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi4_cs_pins: spi4_cs_pins {
+		brcm,pins = <4 25>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi5_pins: spi5_pins {
+		brcm,pins = <13 14 15>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi5_cs_pins: spi5_cs_pins {
+		brcm,pins = <12 26>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi6_pins: spi6_pins {
+		brcm,pins = <19 20 21>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi6_cs_pins: spi6_cs_pins {
+		brcm,pins = <18 27>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c3_pins: i2c3 {
+		brcm,pins = <4 5>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c4_pins: i2c4 {
+		brcm,pins = <8 9>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c5_pins: i2c5 {
+		brcm,pins = <12 13>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c6_pins: i2c6 {
+		brcm,pins = <22 23>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+	};
+
+	sdio_pins: sdio_pins {
+		brcm,pins =     <34 35 36 37 38 39>;
+		brcm,function = <BCM2835_FSEL_ALT3>; // alt3 = SD1
+		brcm,pull =     <0 2 2 2 2 2>;
+	};
+
+	bt_pins: bt_pins {
+		brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0
+				 // to fool pinctrl
+		brcm,function = <0>;
+		brcm,pull = <2>;
+	};
+
+	uart0_pins: uart0_pins {
+		brcm,pins = <32 33>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+		brcm,pull = <0 2>;
+	};
+
+	uart1_pins: uart1_pins {
+		brcm,pins;
+		brcm,function;
+		brcm,pull;
+	};
+
+	uart2_pins: uart2_pins {
+		brcm,pins = <0 1>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+
+	uart3_pins: uart3_pins {
+		brcm,pins = <4 5>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+
+	uart4_pins: uart4_pins {
+		brcm,pins = <8 9>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+
+	uart5_pins: uart5_pins {
+		brcm,pins = <12 13>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+// =============================================
+// Board specific stuff here
+
+&sdhost {
+	status = "disabled";
+};
+
+&phy1 {
+	led-modes = <0x00 0x08>; /* link/activity link */
+};
+
+&gpio {
+	audio_pins: audio_pins {
+		brcm,pins = <40 41>;
+		brcm,function = <4>;
+	};
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+	};
+
+	pwr_led: pwr {
+		label = "led1";
+		linux,default-trigger = "default-on";
+		gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&pwm1 {
+	status = "disabled";
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+};
+
+&cam1_reg {
+	gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+
+		pwr_led_gpio = <&pwr_led>,"gpios:4";
+		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";
+
+		sd_poll_once = <&emmc2>, "non-removable?";
+		spi_dma4 = <&spi0>, "dmas:0=", <&dma40>,
+			   <&spi0>, "dmas:8=", <&dma40>;
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2711-rpi-cm4.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711-rpi-cm4.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2711-rpi-cm4.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711-rpi-cm4.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+#include "bcm2711.dtsi"
+#include "bcm2835-rpi.dtsi"
+
+#include <dt-bindings/reset/raspberrypi,firmware-reset.h>
+
+/ {
+	compatible = "raspberrypi,4-compute-module", "brcm,bcm2711";
+	model = "Raspberry Pi Compute Module 4";
+
+	chosen {
+		/* 8250 auxiliary UART instead of pl011 */
+		stdout-path = "serial1:115200n8";
+	};
+
+	/* Will be filled by the bootloader */
+	memory@0 {
+		device_type = "memory";
+		reg = <0 0 0>;
+	};
+
+	aliases {
+		emmc2bus = &emmc2bus;
+		ethernet0 = &genet;
+		pcie0 = &pcie0;
+		blconfig = &blconfig;
+	};
+
+	leds {
+		act {
+			gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+		};
+
+		pwr {
+			label = "PWR";
+			gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+			default-state = "keep";
+			linux,default-trigger = "default-on";
+		};
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
+	};
+
+	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 = <&expgpio 4 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;
+		gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&ddc0 {
+	status = "okay";
+};
+
+&ddc1 {
+	status = "okay";
+};
+
+&firmware {
+	firmware_clocks: clocks {
+		compatible = "raspberrypi,firmware-clocks";
+		#clock-cells = <1>;
+	};
+
+	expgpio: gpio {
+		compatible = "raspberrypi,firmware-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names = "BT_ON",
+				  "WL_ON",
+				  "PWR_LED_OFF",
+				  "ANT1",
+				  "VDD_SD_IO_SEL",
+				  "CAM_GPIO",
+				  "SD_PWR_ON",
+				  "ANT2";
+		status = "okay";
+
+		ant1: ant1 {
+			gpio-hog;
+			gpios = <3 GPIO_ACTIVE_HIGH>;
+			output-high;
+		};
+
+		ant2: ant2 {
+			gpio-hog;
+			gpios = <7 GPIO_ACTIVE_HIGH>;
+			output-low;
+		};
+	};
+
+	reset: reset {
+		compatible = "raspberrypi,firmware-reset";
+		#reset-cells = <1>;
+	};
+};
+
+&gpio {
+	/*
+	 * Parts taken from rpi_SCH_4b_4p0_reduced.pdf and
+	 * the official GPU firmware DT blob.
+	 *
+	 * Legend:
+	 * "FOO" = GPIO line named "FOO" on the schematic
+	 * "FOO_N" = GPIO line named "FOO" on schematic, active low
+	 */
+	gpio-line-names = "ID_SDA",
+			  "ID_SCL",
+			  "SDA1",
+			  "SCL1",
+			  "GPIO_GCLK",
+			  "GPIO5",
+			  "GPIO6",
+			  "SPI_CE1_N",
+			  "SPI_CE0_N",
+			  "SPI_MISO",
+			  "SPI_MOSI",
+			  "SPI_SCLK",
+			  "GPIO12",
+			  "GPIO13",
+			  /* Serial port */
+			  "TXD1",
+			  "RXD1",
+			  "GPIO16",
+			  "GPIO17",
+			  "GPIO18",
+			  "GPIO19",
+			  "GPIO20",
+			  "GPIO21",
+			  "GPIO22",
+			  "GPIO23",
+			  "GPIO24",
+			  "GPIO25",
+			  "GPIO26",
+			  "GPIO27",
+			  "RGMII_MDIO",
+			  "RGMIO_MDC",
+			  /* Used by BT module */
+			  "CTS0",
+			  "RTS0",
+			  "TXD0",
+			  "RXD0",
+			  /* Used by Wifi */
+			  "SD1_CLK",
+			  "SD1_CMD",
+			  "SD1_DATA0",
+			  "SD1_DATA1",
+			  "SD1_DATA2",
+			  "SD1_DATA3",
+			  /* Shared with SPI flash */
+			  "PWM0_MISO",
+			  "PWM1_MOSI",
+			  "STATUS_LED_G_CLK",
+			  "SPIFLASH_CE_N",
+			  "SDA0",
+			  "SCL0",
+			  "RGMII_RXCLK",
+			  "RGMII_RXCTL",
+			  "RGMII_RXD0",
+			  "RGMII_RXD1",
+			  "RGMII_RXD2",
+			  "RGMII_RXD3",
+			  "RGMII_TXCLK",
+			  "RGMII_TXCTL",
+			  "RGMII_TXD0",
+			  "RGMII_TXD1",
+			  "RGMII_TXD2",
+			  "RGMII_TXD3";
+};
+
+&hdmi0 {
+	clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>;
+	clock-names = "hdmi", "bvb", "audio", "cec";
+	status = "okay";
+};
+
+&hdmi1 {
+	clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>;
+	clock-names = "hdmi", "bvb", "audio", "cec";
+	status = "okay";
+};
+
+&hvs {
+	clocks = <&firmware_clocks 4>;
+};
+
+&pixelvalve0 {
+	status = "okay";
+};
+
+&pixelvalve1 {
+	status = "okay";
+};
+
+&pixelvalve2 {
+	status = "okay";
+};
+
+&pixelvalve4 {
+	status = "okay";
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>;
+	status = "okay";
+};
+
+&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";
+	};
+};
+
+/* SDHCI is used to control the SDIO for wireless */
+&sdhci {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_gpio34>;
+	bus-width = <4>;
+	non-removable;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	status = "okay";
+
+	brcmf: wifi@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+	};
+};
+
+/* EMMC2 is used to drive the EMMC card */
+&emmc2 {
+	bus-width = <8>;
+	vqmmc-supply = <&sd_io_1v8_reg>;
+	vmmc-supply = <&sd_vcc_reg>;
+	broken-cd;
+	status = "okay";
+};
+
+&genet {
+	phy-handle = <&phy1>;
+	phy-mode = "rgmii-rxid";
+	status = "okay";
+};
+
+&genet_mdio {
+	phy1: ethernet-phy@1 {
+		/* No PHY interrupt */
+		reg = <0x1>;
+	};
+};
+
+&pcie0 {
+	pci@1,0 {
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges;
+
+		reg = <0 0 0 0 0>;
+
+		usb@1,0 {
+			reg = <0x10000 0 0 0 0>;
+			resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>;
+		};
+	};
+};
+
+/* uart0 communicates with the BT module */
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "brcm,bcm43438-bt";
+		max-speed = <2000000>;
+		shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+/* uart1 is mapped to the pin header */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_gpio14>;
+	status = "okay";
+};
+
+&vchiq {
+	interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&vc4 {
+	status = "okay";
+};
+
+&vec {
+	status = "disabled";
+};
+
+// =============================================
+// Downstream rpi- changes
+
+#define BCM2711
+
+#include "bcm270x.dtsi"
+#include "bcm271x-rpi-bt.dtsi"
+
+/ {
+	soc {
+		/delete-node/ pixelvalve@7e807000;
+		/delete-node/ hdmi@7e902000;
+	};
+};
+
+#include "bcm2711-rpi.dtsi"
+#include "bcm283x-rpi-csi0-2lane.dtsi"
+#include "bcm283x-rpi-csi1-4lane.dtsi"
+#include "bcm283x-rpi-i2c0mux_0_44.dtsi"
+#include "bcm283x-rpi-cam1-regulator.dtsi"
+
+/ {
+	chosen {
+		bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1";
+	};
+
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart0;
+		mmc0 = &emmc2;
+		mmc1 = &mmcnr;
+		mmc2 = &sdhost;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		i2c20 = &ddc0;
+		i2c21 = &ddc1;
+		spi3 = &spi3;
+		spi4 = &spi4;
+		spi5 = &spi5;
+		spi6 = &spi6;
+		/delete-property/ intc;
+	};
+
+	/delete-node/ wifi-pwrseq;
+};
+
+&mmcnr {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdio_pins>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_pins &bt_pins>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+};
+
+&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>;
+	};
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <9 10 11>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+	};
+
+	spi0_cs_pins: spi0_cs_pins {
+		brcm,pins = <8 7>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi3_pins: spi3_pins {
+		brcm,pins = <1 2 3>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi3_cs_pins: spi3_cs_pins {
+		brcm,pins = <0 24>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi4_pins: spi4_pins {
+		brcm,pins = <5 6 7>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi4_cs_pins: spi4_cs_pins {
+		brcm,pins = <4 25>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi5_pins: spi5_pins {
+		brcm,pins = <13 14 15>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi5_cs_pins: spi5_cs_pins {
+		brcm,pins = <12 26>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	spi6_pins: spi6_pins {
+		brcm,pins = <19 20 21>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+	};
+
+	spi6_cs_pins: spi6_cs_pins {
+		brcm,pins = <18 27>;
+		brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c3_pins: i2c3 {
+		brcm,pins = <4 5>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c4_pins: i2c4 {
+		brcm,pins = <8 9>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c5_pins: i2c5 {
+		brcm,pins = <12 13>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2c6_pins: i2c6 {
+		brcm,pins = <22 23>;
+		brcm,function = <BCM2835_FSEL_ALT5>;
+		brcm,pull = <BCM2835_PUD_UP>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <BCM2835_FSEL_ALT0>;
+	};
+
+	sdio_pins: sdio_pins {
+		brcm,pins =     <34 35 36 37 38 39>;
+		brcm,function = <BCM2835_FSEL_ALT3>; // alt3 = SD1
+		brcm,pull =     <0 2 2 2 2 2>;
+	};
+
+	bt_pins: bt_pins {
+		brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0
+				 // to fool pinctrl
+		brcm,function = <0>;
+		brcm,pull = <2>;
+	};
+
+	uart0_pins: uart0_pins {
+		brcm,pins = <32 33>;
+		brcm,function = <BCM2835_FSEL_ALT3>;
+		brcm,pull = <0 2>;
+	};
+
+	uart1_pins: uart1_pins {
+		brcm,pins;
+		brcm,function;
+		brcm,pull;
+	};
+
+	uart2_pins: uart2_pins {
+		brcm,pins = <0 1>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+
+	uart3_pins: uart3_pins {
+		brcm,pins = <4 5>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+
+	uart4_pins: uart4_pins {
+		brcm,pins = <8 9>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+
+	uart5_pins: uart5_pins {
+		brcm,pins = <12 13>;
+		brcm,function = <BCM2835_FSEL_ALT4>;
+		brcm,pull = <0 2>;
+	};
+};
+
+&i2c0if {
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
+
+// =============================================
+// Board specific stuff here
+
+&pcie0 {
+       brcm,enable-l1ss;
+};
+
+&sdhost {
+	status = "disabled";
+};
+
+&phy1 {
+	led-modes = <0x00 0x08>; /* link/activity link */
+};
+
+&gpio {
+	audio_pins: audio_pins {
+		brcm,pins = <>;
+		brcm,function = <>;
+	};
+};
+
+&leds {
+	act_led: act {
+		label = "led0";
+		linux,default-trigger = "mmc0";
+		gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+	};
+
+	pwr_led: pwr {
+		label = "led1";
+		linux,default-trigger = "default-on";
+		gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&pwm1 {
+	status = "disabled";
+};
+
+&audio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&audio_pins>;
+	brcm,disable-headphones = <1>;
+};
+
+cam0_reg: &cam1_reg {
+	gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>;
+};
+
+/ {
+	__overrides__ {
+		act_led_gpio = <&act_led>,"gpios:4";
+		act_led_activelow = <&act_led>,"gpios:8";
+		act_led_trigger = <&act_led>,"linux,default-trigger";
+
+		pwr_led_gpio = <&pwr_led>,"gpios:4";
+		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";
+
+		ant1 =  <&ant1>,"output-high?=on",
+			<&ant1>, "output-low?=off",
+			<&ant2>, "output-high?=off",
+			<&ant2>, "output-low?=on";
+		ant2 =  <&ant1>,"output-high?=off",
+			<&ant1>, "output-low?=on",
+			<&ant2>, "output-high?=on",
+			<&ant2>, "output-low?=off";
+		noant = <&ant1>,"output-high?=off",
+			<&ant1>, "output-low?=on",
+			<&ant2>, "output-high?=off",
+			<&ant2>, "output-low?=on";
+
+		sd_poll_once = <&emmc2>, "non-removable?";
+		spi_dma4 = <&spi0>, "dmas:0=", <&dma40>,
+			   <&spi0>, "dmas:8=", <&dma40>;
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2711-rpi.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711-rpi.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2711-rpi.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2711-rpi.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+#include "bcm270x-rpi.dtsi"
+
+/ {
+	__overrides__ {
+		arm_freq;
+	};
+
+	v3dbus: v3dbus {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <2>;
+		ranges = <0x7c500000  0x0 0xfc500000  0x0 0x03300000>,
+			 <0x40000000  0x0 0xff800000  0x0 0x00800000>;
+		dma-ranges = <0x00000000  0x0 0x00000000  0x4 0x00000000>;
+
+		v3d: v3d@7ec04000 {
+			compatible = "brcm,2711-v3d";
+			reg =
+			    <0x7ec00000  0x0 0x4000>,
+			    <0x7ec04000  0x0 0x4000>;
+			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 = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+	};
+
+	scb: scb {
+	     /* Add a label */
+	};
+};
+
+&vc4 {
+	raspberrypi,firmware = <&firmware>;
+};
+
+&cma {
+	/* Limit cma to the lower 768MB to allow room for HIGHMEM on 32-bit */
+	alloc-ranges = <0x0 0x00000000 0x30000000>;
+};
+
+&scb {
+	ranges = <0x0 0x7c000000  0x0 0xfc000000  0x0 0x03800000>,
+		 <0x0 0x40000000  0x0 0xff800000  0x0 0x00800000>,
+		 <0x6 0x00000000  0x6 0x00000000  0x0 0x40000000>,
+		 <0x0 0x00000000  0x0 0x00000000  0x0 0xfc000000>;
+	dma-ranges = <0x0 0x00000000  0x0 0x00000000  0x4 0x00000000>;
+
+	dma40: dma@7e007b00 {
+		compatible = "brcm,bcm2711-dma";
+		reg = <0x0 0x7e007b00  0x0 0x400>;
+		interrupts =
+			<GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
+			<GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
+			<GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
+			<GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
+		interrupt-names = "dma11",
+			"dma12",
+			"dma13",
+			"dma14";
+		#dma-cells = <1>;
+		brcm,dma-channel-mask = <0x7800>;
+	};
+
+	xhci: xhci@7e9c0000 {
+		compatible = "generic-xhci";
+		status = "disabled";
+		reg = <0x0 0x7e9c0000  0x0 0x100000>;
+		interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+		power-domains = <&power RPI_POWER_DOMAIN_USB>;
+	};
+
+	hevc-decoder@7eb00000 {
+		compatible = "raspberrypi,rpivid-hevc-decoder";
+		reg = <0x0 0x7eb00000  0x0 0x10000>;
+		status = "okay";
+	};
+
+	rpivid-local-intc@7eb10000 {
+		compatible = "raspberrypi,rpivid-local-intc";
+		reg = <0x0 0x7eb10000  0x0 0x1000>;
+		status = "okay";
+		interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	h264-decoder@7eb20000 {
+		compatible = "raspberrypi,rpivid-h264-decoder";
+		reg = <0x0 0x7eb20000  0x0 0x10000>;
+		status = "okay";
+	};
+
+	vp9-decoder@7eb30000 {
+		compatible = "raspberrypi,rpivid-vp9-decoder";
+		reg = <0x0 0x7eb30000  0x0 0x10000>;
+		status = "okay";
+	};
+};
+
+&dma40 {
+	/* The VPU firmware uses DMA channel 11 for VCHIQ */
+	brcm,dma-channel-mask = <0x7000>;
+};
+
+&vchiq {
+	compatible = "brcm,bcm2711-vchiq";
+};
+
+&firmwarekms {
+	compatible = "raspberrypi,rpi-firmware-kms-2711";
+	interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&smi {
+	interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&mmc {
+	interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&mmcnr {
+	interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&csi0 {
+	interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&csi1 {
+	interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&random {
+	compatible = "brcm,bcm2711-rng200";
+	status = "okay";
+};
+
+&usb {
+	/* Enable the FIQ support */
+	reg = <0x7e980000 0x10000>,
+	      <0x7e00b200 0x200>;
+	interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+		     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+	status = "disabled";
+};
+
+&gpio {
+	interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+		     <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&emmc2 {
+	mmc-ddr-3_3v;
+};
+
+&vc4 {
+	status = "disabled";
+};
+
+&pixelvalve0 {
+	status = "disabled";
+};
+
+&pixelvalve1 {
+	status = "disabled";
+};
+
+&pixelvalve2 {
+	status = "disabled";
+};
+
+&pixelvalve3 {
+	status = "disabled";
+};
+
+&pixelvalve4 {
+	status = "disabled";
+};
+
+&hdmi0 {
+	dmas = <&dma (10|(1<<27)|(1<<24)|(10<<16)|(15<<20))>;
+	status = "disabled";
+};
+
+&ddc0 {
+	status = "disabled";
+};
+
+&hdmi1 {
+	dmas = <&dma (17|(1<<27)|(1<<24)|(10<<16)|(15<<20))>;
+	status = "disabled";
+};
+
+&ddc1 {
+	status = "disabled";
+};
+
+&dvp {
+	status = "disabled";
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm271x-rpi-bt.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm271x-rpi-bt.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm271x-rpi-bt.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm271x-rpi-bt.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+
+&uart0 {
+	bt: bluetooth {
+		compatible = "brcm,bcm43438-bt";
+		max-speed = <3000000>;
+		shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+		status = "disabled";
+	};
+};
+
+&uart1 {
+	minibt: bluetooth {
+		compatible = "brcm,bcm43438-bt";
+		max-speed = <460800>;
+		shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+		status = "disabled";
+	};
+};
+
+/ {
+	__overrides__ {
+		krnbt = <&bt>,"status";
+		krnbt_baudrate = <&bt>,"max-speed:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-common.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-common.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-common.dtsi	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-common.dtsi	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:109 @
 			status = "okay";
 		};
 
+		vec: vec@7e806000 {
+			compatible = "brcm,bcm2835-vec";
+			reg = <0x7e806000 0x1000>;
+			clocks = <&clocks BCM2835_CLOCK_VEC>;
+			interrupts = <2 27>;
+			status = "disabled";
+		};
+
 		pixelvalve@7e807000 {
 			compatible = "brcm,bcm2835-pixelvalve2";
 			reg = <0x7e807000 0x100>;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:127 @
 			compatible = "brcm,bcm2835-hdmi";
 			reg = <0x7e902000 0x600>,
 			      <0x7e808000 0x100>;
+			reg-names = "hdmi",
+				    "hd";
 			interrupts = <2 8>, <2 9>;
 			ddc = <&i2c2>;
 			clocks = <&clocks BCM2835_PLLH_PIX>,
 				 <&clocks BCM2835_CLOCK_HSM>;
 			clock-names = "pixel", "hdmi";
-			dmas = <&dma 17>;
+			dmas = <&dma (17|(1<<27)|(1<<24))>;
 			dma-names = "audio-rx";
 			status = "disabled";
 		};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835.dtsi	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835.dtsi	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:22 @
 
 	soc {
 		ranges = <0x7e000000 0x20000000 0x02000000>;
-		dma-ranges = <0x40000000 0x00000000 0x20000000>;
+		dma-ranges = <0x80000000 0x00000000 0x20000000>;
 	};
 
 	arm-pmu {
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-a.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-a.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-a.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-a.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:124 @
 	pinctrl-0 = <&uart0_gpio14>;
 	status = "okay";
 };
+
+/* i2c0 on camera/display connector is gpio 0&1. Not exposed on header.
+ * To avoid having to remap everything, map both ports to gpios 0&1
+ */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio0>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:129 @
 	pinctrl-0 = <&uart0_gpio14>;
 	status = "okay";
 };
+
+/* i2c on camera/display connector is gpio 28&29 */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio28>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-b.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-b.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-b.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-b.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:119 @
 	pinctrl-0 = <&uart0_gpio14>;
 	status = "okay";
 };
+
+/* camera/display connector use BSC1 on GPIOS 2&3.
+ * To avoid having to remap everything, map both ports to gpios 0&1
+ */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio0>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts	2021-07-25 16:45:34.748814264 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:131 @
 	pinctrl-0 = <&uart0_gpio14>;
 	status = "okay";
 };
+
+/* i2c on camera/display connector is gpio 28&29 */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio28>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:124 @
 	pinctrl-0 = <&uart0_gpio14>;
 	status = "okay";
 };
+
+/* i2c0 on camera/display connector is gpio 0&1. Not exposed on header.
+ * To avoid having to remap everything, map both ports to gpios 0&1
+ */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio0>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:98 @
 	pinctrl-0 = <&uart0_gpio14>;
 	status = "okay";
 };
+
+/* WHAT TO DO HERE? */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio28>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi.dtsi	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi.dtsi	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:22 @
 
 			mboxes = <&mailbox>;
 			dma-ranges;
+
+			firmware_clocks: clocks {
+				compatible = "raspberrypi,firmware-clocks";
+				#clock-cells = <1>;
+			};
 		};
 
 		power: power {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:57 @
 	};
 };
 
-&i2c0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&i2c0_gpio0>;
+&i2c0if {
 	status = "okay";
 	clock-frequency = <100000>;
 };
 
+&i2c0mux {
+	pinctrl-0 = <&i2c0_gpio0>;
+	/* pinctrl-1 varies based on platform */
+	status = "okay";
+};
+
 &i2c1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c1_gpio2>;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:79 @
 	power-domains = <&power RPI_POWER_DOMAIN_USB>;
 };
 
+&vc4 {
+	raspberrypi,firmware = <&firmware>;
+};
+
 &vec {
 	power-domains = <&power RPI_POWER_DOMAIN_VEC>;
 	status = "okay";
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-zero.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-zero.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-zero.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-zero.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:120 @
 	pinctrl-0 = <&uart0_gpio14>;
 	status = "okay";
 };
+
+/* i2c on camera/display connector is gpio 28&29 */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio28>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:152 @
 	pinctrl-0 = <&uart1_gpio14>;
 	status = "okay";
 };
+
+/* i2c on camera/display connector is gpio 28&29 */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio28>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2836-rpi-2-b.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2836-rpi-2-b.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2836-rpi-2-b.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:131 @
 	pinctrl-0 = <&uart0_gpio14>;
 	status = "okay";
 };
+
+/* i2c on camera/display connector is gpio 28&29 */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio28>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:181 @
 	pinctrl-0 = <&uart1_gpio14>;
 	status = "okay";
 };
+
+/* i2c on camera/display connector is gpio 44&45 */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio44>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2837-rpi-3-b.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2837-rpi-3-b.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2837-rpi-3-b.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:177 @
 	status = "okay";
 	bus-width = <4>;
 };
+
+/* i2c on camera/display connector is gpio 44&45 */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio44>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:184 @
 	pinctrl-0 = <&uart1_gpio14>;
 	status = "okay";
 };
+
+/* i2c on camera/display connector is gpio 44&45 */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio44>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:97 @
 	pinctrl-0 = <&uart0_gpio14>;
 	status = "okay";
 };
+
+/* WHAT TO DO HERE? */
+&i2c0mux {
+	pinctrl-1 = <&i2c0_gpio28>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm283x.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm283x.dtsi	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x.dtsi	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:337 @
 			status = "disabled";
 		};
 
-		i2c0: i2c@7e205000 {
+		i2c0if: i2c@7e205000 {
 			compatible = "brcm,bcm2835-i2c";
 			reg = <0x7e205000 0x200>;
 			interrupts = <2 21>;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:347 @
 			status = "disabled";
 		};
 
+		i2c0mux: i2c0mux {
+			compatible = "i2c-mux-pinctrl";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			i2c-parent = <&i2c0if>;
+
+			pinctrl-names = "i2c0", "i2c_csi_dsi";
+
+			status = "disabled";
+
+			i2c0: i2c@0 {
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			i2c_csi_dsi: i2c@1 {
+				reg = <1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
 		dpi: dpi@7e208000 {
 			compatible = "brcm,bcm2835-dpi";
 			reg = <0x7e208000 0x8c>;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:491 @
 			status = "disabled";
 		};
 
-		vec: vec@7e806000 {
-			compatible = "brcm,bcm2835-vec";
-			reg = <0x7e806000 0x1000>;
-			clocks = <&clocks BCM2835_CLOCK_VEC>;
-			interrupts = <2 27>;
-			status = "disabled";
-		};
-
 		usb: usb@7e980000 {
 			compatible = "brcm,bcm2835-usb";
 			reg = <0x7e980000 0x10000>;
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-cam1-regulator.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-cam1-regulator.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-cam1-regulator.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-cam1-regulator.dtsi	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	cam1_reg: cam1_reg {
+		compatible = "regulator-fixed";
+		regulator-name = "cam1-reg";
+		enable-active-high;
+		status = "disabled";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-csi0-2lane.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-csi0-2lane.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-csi0-2lane.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-csi0-2lane.dtsi	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+// SPDX-License-Identifier: GPL-2.0-only
+&csi0 {
+	brcm,num-data-lanes = <2>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+// SPDX-License-Identifier: GPL-2.0-only
+&csi1 {
+	brcm,num-data-lanes = <2>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-csi1-4lane.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-csi1-4lane.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-csi1-4lane.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-csi1-4lane.dtsi	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+// SPDX-License-Identifier: GPL-2.0-only
+&csi1 {
+	brcm,num-data-lanes = <4>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_28.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_28.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_28.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_28.dtsi	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+&i2c0mux {
+	pinctrl-0 = <&i2c0_gpio0>;
+	pinctrl-1 = <&i2c0_gpio28>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_44.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_44.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_44.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-i2c0mux_0_44.dtsi	2021-07-25 16:45:34.758814097 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+&i2c0mux {
+	pinctrl-0 = <&i2c0_gpio0>;
+	pinctrl-1 = <&i2c0_gpio44>;
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi	1970-01-01 01:00:00.000000000 +0100
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
-// SPDX-License-Identifier: GPL-2.0
-&usb {
-	dr_mode = "peripheral";
-	g-rx-fifo-size = <256>;
-	g-np-tx-fifo-size = <32>;
-	g-tx-fifo-size = <256 256 512 512 512 768 768>;
-};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/Makefile linux-5.10.52-v7l+/arch/arm/boot/dts/Makefile
--- linux-5.10.52-orig/arch/arm/boot/dts/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/Makefile	2021-07-25 16:45:34.658815773 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
 # SPDX-License-Identifier: GPL-2.0
+
+dtb-$(CONFIG_ARCH_BCM2835) += \
+	bcm2708-rpi-b.dtb \
+	bcm2708-rpi-b-rev1.dtb \
+	bcm2708-rpi-b-plus.dtb \
+	bcm2708-rpi-cm.dtb \
+	bcm2708-rpi-zero.dtb \
+	bcm2708-rpi-zero-w.dtb \
+	bcm2709-rpi-2-b.dtb \
+	bcm2710-rpi-2-b.dtb \
+	bcm2710-rpi-3-b.dtb \
+	bcm2710-rpi-3-b-plus.dtb \
+	bcm2711-rpi-4-b.dtb \
+	bcm2711-rpi-400.dtb \
+	bcm2710-rpi-cm3.dtb \
+	bcm2711-rpi-cm4.dtb
+
 dtb-$(CONFIG_ARCH_ALPINE) += \
 	alpine-db.dtb
 dtb-$(CONFIG_MACH_ARTPEC6) += \
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:112 @
 	bcm2837-rpi-3-b.dtb \
 	bcm2837-rpi-3-b-plus.dtb \
 	bcm2837-rpi-cm3-io3.dtb \
-	bcm2711-rpi-4-b.dtb \
 	bcm2835-rpi-zero.dtb \
 	bcm2835-rpi-zero-w.dtb
 dtb-$(CONFIG_ARCH_BCM_5301X) += \
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1427 @
 	aspeed-bmc-opp-zaius.dtb \
 	aspeed-bmc-portwell-neptune.dtb \
 	aspeed-bmc-quanta-q71l.dtb
+
+targets += dtbs dtbs_install
+targets += $(dtb-y)
+
+subdir-y	:= overlays
+
+# Enable fixups to support overlays on BCM2835 platforms
+ifeq ($(CONFIG_ARCH_BCM2835),y)
+	DTC_FLAGS ?= -@
+endif
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/act-led-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/act-led-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/act-led-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/act-led-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/* Pi3 uses a GPIO expander to drive the LEDs which can only be accessed
+   from the VPU. There is a special driver for this with a separate DT node,
+   which has the unfortunate consequence of breaking the act_led_gpio and
+   act_led_activelow dtparams.
+
+   This overlay changes the GPIO controller back to the standard one and
+   restores the dtparams.
+*/
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&act_led>;
+		frag0: __overlay__ {
+			gpios = <&gpio 0 0>;
+		};
+	};
+
+	__overrides__ {
+		gpio = <&frag0>,"gpios:4";
+		activelow = <&frag0>,"gpios:8";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/adafruit18-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adafruit18-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/adafruit18-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adafruit18-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for Adafruit 1.8" TFT LCD with ST7735R chip 160x128
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			af18: adafruit18@0 {
+				compatible = "fbtft,adafruit18";
+				reg = <0>;
+				pinctrl-names = "default";
+				spi-max-frequency = <40000000>;
+				rotate = <90>;
+				buswidth = <8>;
+				fps = <50>;
+				height = <160>;
+				width = <128>;
+				reset-gpios = <&gpio 25 1>;
+				dc-gpios = <&gpio 24 0>;
+				led-gpios = <&gpio 18 0>;
+				debug = <0>;
+			};
+		};
+	};
+
+	__overrides__ {
+		green = <&af18>, "compatible=fbtft,adafruit18_green";
+		speed     = <&af18>,"spi-max-frequency:0";
+		rotate    = <&af18>,"rotate:0";
+		fps       = <&af18>,"fps:0";
+		bgr       = <&af18>,"bgr?";
+		debug     = <&af18>,"debug:0";
+		dc_pin    = <&af18>,"dc-gpios:4";
+		reset_pin = <&af18>,"reset-gpios:4";
+		led_pin   = <&af18>,"led-gpios:4";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for ADAU1977 ADC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+    
+	fragment@0 {
+        	target = <&i2c>;
+        	
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+			
+			adau1977: codec@11 {
+                        	compatible = "adi,adau1977";
+                        	reg = <0x11>;
+                        	reset-gpios = <&gpio 5 0>;
+				AVDD-supply = <&vdd_3v3_reg>;
+                	};
+        	};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "adi,adau1977-adc";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+
+    fragment@0 {
+        target = <&i2s>;
+        __overlay__ {
+            status = "okay";
+        };
+    };
+
+    fragment@1 {
+        target-path = "/";
+        __overlay__ {
+                adau7002_codec: adau7002-codec {
+                #sound-dai-cells = <0>;
+                compatible = "adi,adau7002";
+/*                IOVDD-supply = <&supply>;*/
+                status = "okay";
+            };
+        };
+    };
+
+    fragment@2 {
+        target = <&sound>;
+            sound_overlay: __overlay__ {
+            compatible = "simple-audio-card";
+            simple-audio-card,format = "i2s";
+            simple-audio-card,name = "adau7002";
+            simple-audio-card,bitclock-slave = <&dailink0_slave>;
+            simple-audio-card,frame-slave = <&dailink0_slave>;
+            simple-audio-card,widgets =
+                    "Microphone", "Microphone Jack";
+            simple-audio-card,routing =
+                    "PDM_DAT", "Microphone Jack";
+            status = "okay";
+            simple-audio-card,cpu {
+                sound-dai = <&i2s>;
+            };
+            dailink0_slave: simple-audio-card,codec {
+                sound-dai = <&adau7002_codec>;
+            };
+        };
+    };
+
+
+    __overrides__ {
+        card-name = <&sound_overlay>,"simple-audio-card,name";
+    };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ads1015-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ads1015-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ads1015-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ads1015-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * 2016 - Erik Sejr
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+    /* ----------- ADS1015 ------------ */
+    fragment@0 {
+        target = <&i2c_arm>;
+        __overlay__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            status = "okay";
+            ads1015: ads1015@48 {
+                compatible = "ti,ads1015";
+                status = "okay";
+                #address-cells = <1>;
+                #size-cells = <0>;
+                reg = <0x48>;
+            };
+        };
+    };
+
+    fragment@1 {
+        target = <&ads1015>;
+        __overlay__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            channel_a: channel_a {
+                reg = <4>;
+                ti,gain = <2>;
+                ti,datarate = <4>;
+            };
+        };
+    };
+
+    fragment@2 {
+        target = <&ads1015>;
+        __dormant__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            channel_b: channel_b {
+                reg = <5>;
+                ti,gain = <2>;
+                ti,datarate = <4>;
+            };
+        };
+    };
+
+    fragment@3 {
+        target = <&ads1015>;
+        __dormant__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            channel_c: channel_c {
+                reg = <6>;
+                ti,gain = <2>;
+                ti,datarate = <4>;
+            };
+        };
+    };
+
+    fragment@4 {
+        target = <&ads1015>;
+        __dormant__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            channel_d: channel_d {
+                reg = <7>;
+                ti,gain = <2>;
+                ti,datarate = <4>;
+            };
+        };
+    };
+
+    __overrides__ {
+        addr =            <&ads1015>,"reg:0";
+        cha_enable =      <0>,"=1";
+        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_cfg =         <&channel_b>,"reg:0";
+        chb_gain =        <&channel_b>,"ti,gain:0";
+        chb_datarate =    <&channel_b>,"ti,datarate:0";
+        chc_enable =      <0>,"=3";
+        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_cfg =         <&channel_d>,"reg:0";
+        chd_gain =        <&channel_d>,"ti,gain:0";
+        chd_datarate =    <&channel_d>,"ti,datarate:0";
+   };
+
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ads1115-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ads1115-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ads1115-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ads1115-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * TI ADS1115 multi-channel ADC overlay
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	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>;
+			#size-cells = <0>;
+
+			channel_a: channel_a {
+				reg = <4>;
+				ti,gain = <1>;
+				ti,datarate = <7>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&ads1115>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			channel_b: channel_b {
+				reg = <5>;
+				ti,gain = <1>;
+				ti,datarate = <7>;
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&ads1115>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			channel_c: channel_c {
+				reg = <6>;
+				ti,gain = <1>;
+				ti,datarate = <7>;
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&ads1115>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			channel_d: channel_d {
+				reg = <7>;
+				ti,gain = <1>;
+				ti,datarate = <7>;
+			};
+		};
+	};
+
+	__overrides__ {
+		addr =            <&ads1115>,"reg:0";
+		cha_enable =      <0>,"=1";
+		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_cfg =         <&channel_b>,"reg:0";
+		chb_gain =        <&channel_b>,"ti,gain:0";
+		chb_datarate =    <&channel_b>,"ti,datarate:0";
+		chc_enable =      <0>,"=3";
+		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_cfg =         <&channel_d>,"reg:0";
+		chd_gain =        <&channel_d>,"ti,gain:0";
+		chd_datarate =    <&channel_d>,"ti,datarate:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ads7846-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ads7846-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ads7846-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ads7846-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Generic Device Tree overlay for the ADS7846 touch controller
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			ads7846_pins: ads7846_pins {
+				brcm,pins = <255>; /* illegal default value */
+				brcm,function = <0>; /* in */
+				brcm,pull = <0>; /* none */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ads7846: ads7846@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&ads7846_pins>;
+
+				spi-max-frequency = <2000000>;
+				interrupts = <255 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 255 0>;
+
+				/* driver defaults */
+				ti,x-min = /bits/ 16 <0>;
+				ti,y-min = /bits/ 16 <0>;
+				ti,x-max = /bits/ 16 <0x0FFF>;
+				ti,y-max = /bits/ 16 <0x0FFF>;
+				ti,pressure-min = /bits/ 16 <0>;
+				ti,pressure-max = /bits/ 16 <0xFFFF>;
+				ti,x-plate-ohms = /bits/ 16 <400>;
+			};
+		};
+	};
+	__overrides__ {
+		cs =     <&ads7846>,"reg:0";
+		speed =  <&ads7846>,"spi-max-frequency:0";
+		penirq = <&ads7846_pins>,"brcm,pins:0", /* REQUIRED */
+			 <&ads7846>,"interrupts:0",
+			 <&ads7846>,"pendown-gpio:4";
+		penirq_pull = <&ads7846_pins>,"brcm,pull:0";
+		swapxy = <&ads7846>,"ti,swap-xy?";
+		xmin =   <&ads7846>,"ti,x-min;0";
+		ymin =   <&ads7846>,"ti,y-min;0";
+		xmax =   <&ads7846>,"ti,x-max;0";
+		ymax =   <&ads7846>,"ti,y-max;0";
+		pmin =   <&ads7846>,"ti,pressure-min;0";
+		pmax =   <&ads7846>,"ti,pressure-max;0";
+		xohms =  <&ads7846>,"ti,x-plate-ohms;0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/adv7282m-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adv7282m-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/adv7282m-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adv7282m-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for Analog Devices ADV7282-M video to CSI2 bridge on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			adv728x: adv728x@21 {
+				compatible = "adi,adv7282-m";
+				reg = <0x21>;
+				status = "okay";
+				clock-frequency = <24000000>;
+				port {
+					adv728x_0: endpoint {
+						remote-endpoint = <&csi1_ep>;
+						clock-lanes = <0>;
+						data-lanes = <1>;
+						link-frequencies =
+							/bits/ 64 <297000000>;
+
+						mclk-frequency = <12000000>;
+					};
+				};
+			};
+		};
+	};
+	fragment@1 {
+		target = <&csi1>;
+		__overlay__ {
+			status = "okay";
+
+			port {
+				csi1_ep: endpoint {
+					remote-endpoint = <&adv728x_0>;
+					data-lanes = <1>;
+				};
+			};
+		};
+	};
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		addr =			<&adv728x>,"reg:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/adv728x-m-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adv728x-m-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/adv728x-m-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/adv728x-m-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for Analog Devices ADV728[0|1|2]-M video to CSI2 bridges on VC
+// I2C bus
+
+#include "adv7282m-overlay.dts"
+
+/{
+	compatible = "brcm,bcm2835";
+
+	// Fragment numbers deliberately high to avoid conflicts with the
+	// included adv7282m overlay file.
+
+	fragment@101 {
+		target = <&adv728x>;
+		__dormant__ {
+			compatible = "adi,adv7280-m";
+		};
+	};
+	fragment@102 {
+		target = <&adv728x>;
+		__dormant__ {
+			compatible = "adi,adv7281-m";
+		};
+	};
+	fragment@103 {
+		target = <&adv728x>;
+		__dormant__ {
+			compatible = "adi,adv7281-ma";
+		};
+	};
+
+	__overrides__ {
+		adv7280m = <0>, "+101";
+		adv7281m = <0>, "+102";
+		adv7281ma = <0>, "+103";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for Digital Dreamtime Akkordion using IQaudIO DAC+ or DACZero
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4c>;
+				AVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		frag2: __overlay__ {
+			compatible = "iqaudio,iqaudio-dac";
+			card_name = "Akkordion";
+			dai_name = "IQaudIO DAC";
+			dai_stream_name = "IQaudIO DAC HiFi";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain = <&frag2>,"iqaudio,24db_digital_gain?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-boss2-dac-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-boss2-dac-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-boss2-dac-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-boss2-dac-audio-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* * Definitions for Allo Boss2 DAC boards
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			#sound-dai-cells = <0>;
+			status = "okay";
+			cpu_port: port {
+				cpu_endpoint: endpoint {
+					remote-endpoint = <&codec_endpoint>;
+					bitclock-master = <&codec_endpoint>;
+					frame-master = <&codec_endpoint>;
+					dai-format = "i2s";
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+			allo-cs43130@30 {
+				#sound-dai-cells = <0>;
+				compatible = "allo,allo-cs43198";
+				clock44-gpio = <&gpio 5 0>;
+				clock48-gpio = <&gpio 6 0>;
+				reg = <0x30>;
+				port {
+					codec_endpoint: endpoint {
+					remote-endpoint = <&cpu_endpoint>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		boss2_dac: __overlay__ {
+			compatible = "audio-graph-card";
+			label = "Allo Boss2";
+			dais = <&cpu_port>;
+			status = "okay";
+		};
+	};
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Definitions for Allo Boss DAC board
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			boss_osc: boss_osc {
+				compatible = "allo,dac-clk";
+				#clock-cells = <0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4d {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				clocks = <&boss_osc>;
+				reg = <0x4d>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		boss_dac: __overlay__ {
+			compatible = "allo,boss-dac";
+			i2s-controller = <&i2s>;
+			mute-gpios = <&gpio 6 1>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain = <&boss_dac>,"allo,24db_digital_gain?";
+		slave = <&boss_dac>,"allo,slave?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-digione-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-digione-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-digione-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-digione-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for Allo DigiOne
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8804@3b {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8804";
+				reg = <0x3b>;
+				PVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+				wlf,reset-gpio = <&gpio 17 0>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "allo,allo-digione";
+			i2s-controller = <&i2s>;
+			status = "okay";
+			clock44-gpio = <&gpio 5 0>;
+			clock48-gpio = <&gpio 6 0>;
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Definitions for Allo Katana DAC boards
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			#sound-dai-cells = <0>;
+			status = "okay";
+			cpu_port: port {
+				cpu_endpoint: endpoint {
+					remote-endpoint = <&codec_endpoint>;
+					bitclock-master = <&codec_endpoint>;
+					frame-master = <&codec_endpoint>;
+					dai-format = "i2s";
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			allo-katana-codec@30 {
+				#sound-dai-cells = <0>;
+				compatible = "allo,allo-katana-codec";
+				reg = <0x30>;
+				port {
+					codec_endpoint: endpoint {
+					remote-endpoint = <&cpu_endpoint>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		katana_dac: __overlay__ {
+			compatible = "audio-graph-card";
+			label = "Allo Katana";
+			dais = <&cpu_port>;
+			status = "okay";
+		};
+	};
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Definitions for Allo Piano DAC (2.0/2.1) boards
+ *
+ * NB. The Piano DAC 2.1 board contains 2x TI PCM5142 DAC's. One DAC is stereo
+ * (left/right) and the other provides a subwoofer output, using DSP on the
+ * chip for digital high/low pass crossover.
+ * The initial support for this hardware, that doesn't require any codec driver
+ * modifications, uses only one DAC chip for stereo (left/right) output, the
+ * chip with 0x4c slave address. The other chip at 0x4d is currently ignored!
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5142@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5142";
+				reg = <0x4c>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		piano_dac: __overlay__ {
+			compatible = "allo,piano-dac";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain =
+			<&piano_dac>,"allo,24db_digital_gain?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for Piano DAC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			allo_pcm5122_4c: pcm5122@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4c>;
+				sound-name-prefix = "Main";
+				status = "okay";
+			};
+			allo_pcm5122_4d: pcm5122@4d {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4d>;
+				sound-name-prefix = "Sub";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		piano_dac: __overlay__ {
+			compatible = "allo,piano-dac-plus";
+			audio-codec = <&allo_pcm5122_4c &allo_pcm5122_4d>;
+			i2s-controller = <&i2s>;
+			mute1-gpios = <&gpio 6 1>;
+			mute2-gpios = <&gpio 25 1>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain =
+			<&piano_dac>,"allo,24db_digital_gain?";
+		glb_mclk =
+			<&piano_dac>,"allo,glb_mclk?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/anyspi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/anyspi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/anyspi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/anyspi-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Universal device tree overlay for SPI devices
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev1>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target-path = "spi1/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target-path = "spi1/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@4 {
+		target-path = "spi1/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@5 {
+		target-path = "spi2/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@6 {
+		target-path = "spi2/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@7 {
+		target-path = "spi2/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@8 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			anyspi_00: anyspi@0 {
+				reg = <0>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	fragment@9 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			anyspi_01: anyspi@1 {
+				reg = <1>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	fragment@10 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			anyspi_10: anyspi@0 {
+				reg = <0>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	fragment@11 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			anyspi_11: anyspi@1 {
+				reg = <1>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	fragment@12 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			anyspi_12: anyspi@2 {
+				reg = <2>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	fragment@13 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			anyspi_20: anyspi@0 {
+				reg = <0>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	fragment@14 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			anyspi_21: anyspi@1 {
+				reg = <1>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	fragment@15 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			anyspi_22: anyspi@2 {
+				reg = <2>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	__overrides__ {
+		spi0-0 = <0>, "+0+8";
+		spi0-1 = <0>, "+1+9";
+		spi1-0 = <0>, "+2+10";
+		spi1-1 = <0>, "+3+11";
+		spi1-2 = <0>, "+4+12";
+		spi2-0 = <0>, "+5+13";
+		spi2-1 = <0>, "+6+14";
+		spi2-2 = <0>, "+7+15";
+		dev = <&anyspi_00>,"compatible",
+		      <&anyspi_01>,"compatible",
+		      <&anyspi_10>,"compatible",
+		      <&anyspi_11>,"compatible",
+		      <&anyspi_12>,"compatible",
+		      <&anyspi_20>,"compatible",
+		      <&anyspi_21>,"compatible",
+		      <&anyspi_22>,"compatible";
+		speed = <&anyspi_00>, "spi-max-frequency:0",
+		        <&anyspi_01>, "spi-max-frequency:0",
+		        <&anyspi_10>, "spi-max-frequency:0",
+		        <&anyspi_11>, "spi-max-frequency:0",
+		        <&anyspi_12>, "spi-max-frequency:0",
+		        <&anyspi_20>, "spi-max-frequency:0",
+		        <&anyspi_21>, "spi-max-frequency:0",
+		        <&anyspi_22>, "spi-max-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/apds9960-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/apds9960-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/apds9960-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/apds9960-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for APDS-9960 ambient light and gesture sensor
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			apds9960_pins: apds9960_pins@39 {
+				brcm,pins = <4>;
+				brcm,function = <0>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			apds9960: apds@39 {
+				compatible = "avago,apds9960";
+				reg = <0x39>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c1>;
+		__overlay__ {
+			apds9960_irq: apds@39 {
+				#interrupt-cells=<2>;
+				interrupt-parent = <&gpio>;
+				interrupts = <4 1>;
+			};
+		};
+	};
+
+	__overrides__ {
+		gpiopin = <&apds9960_pins>,"brcm,pins:0",
+				<&apds9960_irq>,"interrupts:0";
+		noints = <0>,"!1!3";
+	};
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+
+    fragment@0 {
+        target = <&sound>;
+        __overlay__ {
+            compatible = "simple-audio-card";
+            simple-audio-card,name = "ApplePi-DAC";
+
+            status = "okay";
+
+            playback_link: simple-audio-card,dai-link@1 {
+                format = "i2s";
+
+                p_cpu_dai: cpu {
+                    sound-dai = <&i2s>;
+                    dai-tdm-slot-num = <2>;
+                    dai-tdm-slot-width = <32>;
+                };
+
+                p_codec_dai: codec {
+                    sound-dai = <&codec_out>;
+                };
+            };
+        };
+    };
+
+    fragment@1 {
+        target-path = "/";
+        __overlay__ {
+            codec_out: pcm1794a-codec {
+                #sound-dai-cells = <0>;
+                compatible = "ti,pcm1794a";
+                status = "okay";
+            };
+        };
+    };
+
+    fragment@2 {
+        target = <&i2s>;
+        __overlay__ {
+            #sound-dai-cells = <0>;
+            status = "okay";
+        };
+    };
+};
+
+/*
+   Written by: Leonid Ayzenshtat
+   Company: Orchard Audio (www.orchardaudio.com)
+
+   compile with:
+   dtc -@ -H epapr -O dtb -o ApplePi-DAC.dtbo -W no-unit_address_vs_reg ApplePi-DAC.dts
+*/
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/at86rf233-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/at86rf233-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/at86rf233-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/* Overlay for Atmel AT86RF233 IEEE 802.15.4 WPAN transceiver on spi0.0 */
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			lowpan0: at86rf233@0 {
+				compatible = "atmel,at86rf233";
+				reg = <0>;
+				interrupt-parent = <&gpio>;
+				interrupts = <23 4>; /* active high */
+				reset-gpio = <&gpio 24 1>;
+				sleep-gpio = <&gpio 25 1>;
+				spi-max-frequency = <3000000>;
+				xtal-trim = /bits/ 8 <0xf>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&gpio>;
+		__overlay__ {
+			lowpan0_pins: lowpan0_pins {
+				brcm,pins = <23 24 25>;
+				brcm,function = <0 1 1>; /* in out out */
+			};
+		};
+	};
+
+	__overrides__ {
+		interrupt = <&lowpan0>, "interrupts:0",
+			<&lowpan0_pins>, "brcm,pins:0";
+		reset     = <&lowpan0>, "reset-gpio:4",
+			<&lowpan0_pins>, "brcm,pins:4";
+		sleep     = <&lowpan0>, "sleep-gpio:4",
+			<&lowpan0_pins>, "brcm,pins:8";
+		speed     = <&lowpan0>, "spi-max-frequency:0";
+		trim      = <&lowpan0>, "xtal-trim.0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for audioinjector.net audio add on soundcard
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			cs42448_mclk: codec-mclk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <49152000>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			cs42448: cs42448@48 {
+				#sound-dai-cells = <0>;
+				compatible = "cirrus,cs42448";
+				reg = <0x48>;
+				clocks = <&cs42448_mclk>;
+				clock-names = "mclk";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		snd: __overlay__ {
+			compatible = "ai,audioinjector-octo-soundcard";
+			mult-gpios = <&gpio 27 0>, <&gpio 22 0>, <&gpio 23 0>,
+				     <&gpio 24 0>;
+			reset-gpios = <&gpio 5 0>;
+			i2s-controller = <&i2s>;
+			codec = <&cs42448>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		non-stop-clocks = <&snd>, "non-stop-clocks?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for audioinjector.net audio isolated soundcard
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			cs4272_mclk: codec-mclk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <24576000>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			cs4272: cs4271@10 {
+				#sound-dai-cells = <0>;
+				compatible = "cirrus,cs4271";
+				reg = <0x10>;
+				reset-gpio = <&gpio 5 0>;
+				clocks = <&cs4272_mclk>;
+				clock-names = "mclk";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		snd: __overlay__ {
+			compatible = "ai,audioinjector-isolated-soundcard";
+			mute-gpios = <&gpio 17 0>;
+			i2s-controller = <&i2s>;
+			codec = <&cs4272>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for audioinjector.net audio add on soundcard
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			cs4265: cs4265@4e {
+				#sound-dai-cells = <0>;
+				compatible = "cirrus,cs4265";
+				reg = <0x4e>;
+				reset-gpios = <&gpio 5 0>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "simple-audio-card";
+			i2s-controller = <&i2s>;
+			status = "okay";
+
+			simple-audio-card,name = "audioinjector-ultra";
+
+			simple-audio-card,widgets =
+				"Line", "OUTPUTS",
+				"Line", "INPUTS";
+
+			simple-audio-card,routing =
+				"OUTPUTS","LINEOUTL",
+				"OUTPUTS","LINEOUTR",
+				"OUTPUTS","SPDIFOUT",
+				"LINEINL","INPUTS",
+				"LINEINR","INPUTS",
+				"MICL","INPUTS",
+				"MICR","INPUTS";
+
+			simple-audio-card,format = "i2s";
+
+			simple-audio-card,bitclock-master = <&sound_master>;
+			simple-audio-card,frame-master = <&sound_master>;
+
+			simple-audio-card,cpu {
+				sound-dai = <&i2s>;
+				dai-tdm-slot-num = <2>;
+				dai-tdm-slot-width = <32>;
+			};
+
+			sound_master: simple-audio-card,codec {
+				sound-dai = <&cs4265>;
+				system-clock-frequency = <12288000>;
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for audioinjector.net audio add on soundcard
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8731@1a {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8731";
+				reg = <0x1a>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "ai,audioinjector-pi-soundcard";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for audiosense add on soundcard
+/dts-v1/;
+/plugin/;
+#include <dt-bindings/pinctrl/bcm2835.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			codec_reg_1v8: codec-reg-1v8 {
+				compatible = "regulator-fixed";
+				regulator-name = "tlv320aic3204_1v8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			/* audio external oscillator */
+			codec_osc: codec_osc {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <12000000>;	/* 12 MHz */
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&gpio>;
+		__overlay__ {
+			codec_rst: codec-rst {
+				brcm,pins = <26>;
+				brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			codec: tlv320aic32x4@18 {
+				#sound-dai-cells = <0>;
+				compatible = "ti,tlv320aic32x4";
+				reg = <0x18>;
+
+				clocks = <&codec_osc>;
+				clock-names = "mclk";
+
+				iov-supply = <&vdd_3v3_reg>;
+				ldoin-supply = <&vdd_3v3_reg>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+				reset-gpios = <&gpio 26 GPIO_ACTIVE_HIGH>;
+
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "as,audiosense-pi";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/audremap-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audremap-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/audremap-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/audremap-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "brcm,bcm2835";
+
+        fragment@0 {
+                target = <&audio_pins>;
+                frag0: __overlay__ {
+                };
+        };
+
+	fragment@1 {
+                target = <&audio_pins>;
+                __overlay__ {
+                        brcm,pins = < 12 13 >;
+                        brcm,function = < 4 >; /* alt0 alt0 */
+                };
+        };
+
+	fragment@2 {
+		target = <&audio_pins>;
+		__dormant__ {
+                        brcm,pins = < 18 19 >;
+                        brcm,function = < 2 >; /* alt5 alt5 */
+		};
+	};
+
+	fragment@3 {
+		target = <&audio>;
+		__overlay__  {
+			brcm,disable-headphones = <0>;
+		};
+	};
+
+	__overrides__ {
+		swap_lr = <&frag0>, "swap_lr?";
+		enable_jack = <&frag0>, "enable_jack?";
+		pins_12_13 = <0>,"+1-2";
+		pins_18_19 = <0>,"-1+2";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/balena-fin-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/balena-fin-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/balena-fin-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&mmcnr>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdio_pins>;
+			bus-width = <4>;
+			brcm,overclock-50 = <35>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			sdio_pins: sdio_pins {
+				brcm,pins = <34 35 36 37 38 39>;
+				brcm,function = <7>; /* ALT3 = SD1 */
+				brcm,pull = <0 2 2 2 2 2>;
+			};
+
+			power_ctrl_pins: power_ctrl_pins {
+				brcm,pins = <40>;
+				brcm,function = <1>; // out
+			};
+		};
+	};
+
+	fragment@2 {
+		target-path = "/";
+		__overlay__ {
+			// We should switch to mmc-pwrseq-sd8787 after making it
+			// compatible with sd8887
+			// Currently that module requires two GPIOs to function since it
+			// targets a slightly different chip
+			power_ctrl: power_ctrl {
+				compatible = "gpio-poweroff";
+				gpios = <&gpio 40 1>;
+				force;
+				pinctrl-names = "default";
+				pinctrl-0 = <&power_ctrl_pins>;
+			};
+
+			i2c_soft: i2c@0 {
+				compatible = "i2c-gpio";
+				gpios = <&gpio 43 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) /* sda */
+				         &gpio 42 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) /* scl */>;
+				i2c-gpio,delay-us = <5>;
+				i2c-gpio,scl-open-drain;
+				i2c-gpio,sda-open-drain;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			sd8xxx-wlan {
+				drvdbg = <0x6>;
+				drv_mode = <0x1>;
+				cfg80211_wext = <0xf>;
+				sta_name = "wlan";
+				wfd_name = "p2p";
+				cal_data_cfg = "none";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c_soft>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			gpio_expander: gpio_expander@20 {
+				compatible = "nxp,pca9554";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x20>;
+				status = "okay";
+			};
+
+			// rtc clock
+			ds1307: ds1307@68 {
+				compatible = "dallas,ds1307";
+				reg = <0x68>;
+				status = "okay";
+			};
+
+			// RGB LEDs (>= v1.1.0)
+			pca9633: pca9633@62 {
+				compatible = "nxp,pca9633";
+				reg = <0x62>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				red@0 {
+					label = "red";
+					reg = <0>;
+					linux,default-trigger = "none";
+				};
+				green@1 {
+					label = "green";
+					reg = <1>;
+					linux,default-trigger = "none";
+				};
+				blue@2 {
+					label = "blue";
+					reg = <2>;
+					linux,default-trigger = "none";
+				};
+				unused@3 {
+					label = "unused";
+					reg = <3>;
+					linux,default-trigger = "none";
+				};
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/cap1106-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/cap1106-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/cap1106-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/cap1106-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for cap1106 from  Microchip Semiconductor
+// add CONFIG_KEYBOARD_CAP11XX=y
+
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "brcm,bcm2835";
+        fragment@0 {
+                target = <&i2c1>;
+                __overlay__{
+                        status = "okay";
+                        cap1106: cap1106@28 {
+                                compatible = "microchip,cap1106";
+                                pinctrl-0 = <&cap1106_pins>;
+                                pinctrl-names = "default";
+                                interrupt-parent = <&gpio>;
+                                interrupts = <4 2>;
+                                reg = <0x28>;
+                                autorepeat;
+                                microchip,sensor-gain = <2>;
+
+                                linux,keycodes = <2>,           /* KEY_1 */
+                                                <3>,            /* KEY_2 */
+                                                <4>,            /* KEY_3 */
+                                                <5>,            /* KEY_4 */
+                                                <6>,            /* KEY_5 */
+                                                <7>;            /* KEY_6 */
+
+                                #address-cells = <1>;
+                                #size-cells = <0>;
+                                status = "okay";
+
+                        };
+                };
+        };
+        fragment@1 {
+                target = <&gpio>;
+                __overlay__ {
+                        cap1106_pins: cap1106_pins {
+                                brcm,pins = <4>;
+                                brcm,function = <0>; /* in */
+                                brcm,pull = <0>; /* none */
+                        };
+                };
+        };
+
+        __overrides__ {
+                int_pin = <&cap1106>, "interrupts:0",
+                          <&cap1106_pins>, "brcm,pins:0";
+        };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/chipdip-i2s-master-dac-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/chipdip-i2s-master-dac-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/chipdip-i2s-master-dac-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/chipdip-i2s-master-dac-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for ChipDip I2S master DAC
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+    fragment@0 {
+        target = <&sound>;
+        __overlay__ {
+            compatible = "simple-audio-card";
+            simple-audio-card,name = "ChipDip I2S master DAC";
+            status="okay";
+            playback_link: simple-audio-card,dai-link@0 {
+                format = "i2s";
+		bitclock-master = <&p_codec_dai>;
+                frame-master = <&p_codec_dai>;
+                p_cpu_dai: cpu {
+                        sound-dai = <&i2s>;
+			dai-tdm-slot-num = <2>;
+			dai-tdm-slot-width = <32>;
+				};
+
+                p_codec_dai: codec {
+                        sound-dai = <&codec_out>;
+                };
+            };
+        };
+    }; 
+
+    fragment@1 {
+        target-path = "/";
+        __overlay__ {
+            codec_out: spdif-transmitter {
+                #address-cells = <0>;
+                #size-cells = <0>;
+                #sound-dai-cells = <0>;
+                compatible = "linux,spdif-dit";
+                status = "okay";
+            };
+        };
+    };
+ 
+    fragment@2 {
+        target = <&i2s>;
+        __overlay__ {
+            #sound-dai-cells = <0>;
+            status = "okay";
+        };
+    };
+}; 
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/cma-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/cma-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/cma-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/cma-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * cma.dts
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&cma>;
+		frag0: __overlay__ {
+			/*
+			 * The default size when using this overlay is 256 MB
+			 * and should be kept as is for backwards
+			 * compatibility.
+			 */
+			size = <0x10000000>;
+		};
+	};
+
+	__overrides__ {
+		cma-512 = <&frag0>,"size:0=",<0x20000000>;
+		cma-448 = <&frag0>,"size:0=",<0x1c000000>;
+		cma-384 = <&frag0>,"size:0=",<0x18000000>;
+		cma-320 = <&frag0>,"size:0=",<0x14000000>;
+		cma-256 = <&frag0>,"size:0=",<0x10000000>;
+		cma-192 = <&frag0>,"size:0=",<0xC000000>;
+		cma-128 = <&frag0>,"size:0=",<0x8000000>;
+		cma-96  = <&frag0>,"size:0=",<0x6000000>;
+		cma-64  = <&frag0>,"size:0=",<0x4000000>;
+		cma-size = <&frag0>,"size:0"; /* in bytes, 4MB aligned */
+		cma-default = <0>,"-0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/dht11-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dht11-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/dht11-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dht11-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Overlay for the DHT11/21/22 humidity/temperature sensor modules.
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+
+			dht11: dht11@0 {
+				compatible = "dht11";
+				pinctrl-names = "default";
+				pinctrl-0 = <&dht11_pins>;
+				gpios = <&gpio 4 0>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			dht11_pins: dht11_pins@0 {
+				brcm,pins = <4>;
+				brcm,function = <0>; // in
+				brcm,pull = <0>; // off
+			};
+		};
+	};
+
+	__overrides__ {
+		gpiopin = <&dht11_pins>,"brcm,pins:0",
+			<&dht11_pins>, "reg:0",
+			<&dht11>,"gpios:4",
+			<&dht11>,"reg:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for Dion Audio LOCO DAC-AMP
+
+/*
+ * PCM5242 DAC (in hardware mode) and TPA3118 AMP.
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			pcm5102a-codec {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5102a";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "dionaudio,loco-pcm5242-tpa3118";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Definitions for Dion Audio LOCO-V2 DAC-AMP
+ *  eg. dtoverlay=dionaudio-loco-v2
+ *
+ * PCM5242 DAC (in software mode) and TPA3255 AMP.
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&sound>;
+		frag0: __overlay__ {
+			compatible = "dionaudio,dionaudio-loco-v2";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4d>;
+				status = "okay";
+			};
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain = <&frag0>,"dionaudio,24db_digital_gain?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/disable-bt-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/disable-bt-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/disable-bt-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/disable-bt-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/* Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15.
+   To disable the systemd service that initialises the modem so it doesn't use
+   the UART:
+
+       sudo systemctl disable hciuart
+*/
+
+#include <dt-bindings/gpio/gpio.h>
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&uart1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&uart0>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart0_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&bt>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&uart0_pins>;
+		__overlay__ {
+			brcm,pins;
+			brcm,function;
+			brcm,pull;
+		};
+	};
+
+	fragment@4 {
+		target = <&bt_pins>;
+		__overlay__ {
+			brcm,pins;
+			brcm,function;
+			brcm,pull;
+		};
+	};
+
+	fragment@5 {
+		target-path = "/aliases";
+		__overlay__ {
+			serial0 = "/soc/serial@7e201000";
+			serial1 = "/soc/serial@7e215040";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/disable-wifi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/disable-wifi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/disable-wifi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/disable-wifi-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&mmc>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&mmcnr>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/dpi18cpadhi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dpi18cpadhi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/dpi18cpadhi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dpi18cpadhi-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * dpi18cpadhi-overlay.dts
+ */
+
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&fb>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&dpi_18bit_cpadhi_gpio0>;
+		};
+	};
+
+	fragment@1 {
+		target = <&vc4>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&dpi_18bit_cpadhi_gpio0>;
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/dpi18-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dpi18-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/dpi18-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dpi18-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	// There is no DPI driver module, but we need a platform device
+	// node (that doesn't already use pinctrl) to hang the pinctrl
+	// reference on - leds will do
+
+	fragment@0 {
+		target = <&fb>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&dpi18_pins>;
+		};
+	};
+
+	fragment@1 {
+		target = <&vc4>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&dpi18_pins>;
+		};
+	};
+
+	fragment@2 {
+		target = <&gpio>;
+		__overlay__ {
+			dpi18_pins: dpi18_pins {
+				brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
+					     12 13 14 15 16 17 18 19 20
+					     21>;
+				brcm,function = <6>; /* alt2 */
+				brcm,pull = <0>; /* no pull */
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/dpi24-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dpi24-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/dpi24-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dpi24-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	// There is no DPI driver module, but we need a platform device
+	// node (that doesn't already use pinctrl) to hang the pinctrl
+	// reference on - leds will do
+
+	fragment@0 {
+		target = <&fb>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&dpi24_pins>;
+		};
+	};
+
+	fragment@1 {
+		target = <&vc4>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&dpi24_pins>;
+		};
+	};
+
+	fragment@2 {
+		target = <&gpio>;
+		__overlay__ {
+			dpi24_pins: dpi24_pins {
+				brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
+					     12 13 14 15 16 17 18 19 20
+					     21 22 23 24 25 26 27>;
+				brcm,function = <6>; /* alt2 */
+				brcm,pull = <0>; /* no pull */
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/draws-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/draws-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/draws-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/draws-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+#include <dt-bindings/clock/bcm2835.h>
+/*
+ * Device tree overlay for the DRAWS Hardware
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+    fragment@0 {
+        target = <&i2s>;
+        __overlay__ {
+            status = "okay";
+        };
+    };
+
+    fragment@1 {
+        target-path = "/";
+        __overlay__ {
+            regulators {
+                compatible = "simple-bus";
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                udrc0_ldoin: udrc0_ldoin {
+                    compatible = "regulator-fixed";
+                    regulator-name = "ldoin";
+                    regulator-min-microvolt = <3300000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                };
+
+                sc16is752_clk: sc16is752_draws_clk {
+                    compatible = "fixed-clock";
+                    #clock-cells = <0>;
+                    clock-frequency = <1843200>;
+                };
+            };
+
+            pps: pps {
+                compatible = "pps-gpio";
+                pinctrl-names = "default";
+                pinctrl-0 = <&pps_pins>;
+                gpios = <&gpio 7 0>;
+                status = "okay";
+            };
+
+            iio-hwmon {
+                compatible = "iio-hwmon";
+                status = "okay";
+                io-channels = <&tla2024 4>, <&tla2024 5>, <&tla2024 6>,
+                              <&tla2024 7>;
+            };
+        };
+    };
+
+    fragment@2 {
+        target = <&i2c_arm>;
+        __overlay__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            status = "okay";
+
+            tlv320aic32x4: tlv320aic32x4@18 {
+                compatible = "ti,tlv320aic32x4";
+                reg = <0x18>;
+                #sound-dai-cells = <0>;
+                status = "okay";
+
+                clocks = <&clocks BCM2835_CLOCK_GP0>;
+                clock-names = "mclk";
+                assigned-clocks = <&clocks BCM2835_CLOCK_GP0>;
+                assigned-clock-rates = <25000000>;
+
+                pinctrl-names = "default";
+                pinctrl-0 = <&gpclk0_pin &aic3204_reset>;
+
+                reset-gpios = <&gpio 13 0>;
+
+                iov-supply = <&udrc0_ldoin>;
+                ldoin-supply = <&udrc0_ldoin>;
+            };
+
+            sc16is752: sc16is752@50 {
+                compatible = "nxp,sc16is752";
+                reg = <0x50>;
+                clocks = <&sc16is752_clk>;
+                interrupt-parent = <&gpio>;
+                interrupts = <17 2>; /* IRQ_TYPE_EDGE_FALLING */
+
+                pinctrl-names = "default";
+                pinctrl-0 = <&sc16is752_irq>;
+            };
+
+            tla2024: tla2024@48 {
+                compatible = "ti,ads1015";
+                reg = <0x48>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+                #io-channel-cells = <1>;
+
+                adc_ch4: channel@4 {
+                    reg = <4>;
+                    ti,gain = <1>;
+                    ti,datarate = <4>;
+                };
+
+                adc_ch5: channel@5 {
+                    reg = <5>;
+                    ti,gain = <1>;
+                    ti,datarate = <4>;
+                };
+
+                adc_ch6: channel@6 {
+                    reg = <6>;
+                    ti,gain = <2>;
+                    ti,datarate = <4>;
+                };
+
+                adc_ch7: channel@7 {
+                    reg = <7>;
+                    ti,gain = <2>;
+                    ti,datarate = <4>;
+                };
+            };
+        };
+    };
+
+    fragment@3 {
+        target = <&sound>;
+        snd: __overlay__ {
+            compatible = "simple-audio-card";
+            i2s-controller = <&i2s>;
+            status = "okay";
+
+            simple-audio-card,name = "draws";
+            simple-audio-card,format = "i2s";
+
+            simple-audio-card,bitclock-master = <&dailink0_master>;
+            simple-audio-card,frame-master = <&dailink0_master>;
+
+            simple-audio-card,widgets =
+                "Line", "Line In",
+                "Line", "Line Out";
+
+            simple-audio-card,routing =
+                "IN1_R", "Line In",
+                "IN1_L", "Line In",
+                "CM_L", "Line In",
+                "CM_R", "Line In",
+                "Line Out", "LOR",
+                "Line Out", "LOL";
+
+            dailink0_master: simple-audio-card,cpu {
+                sound-dai = <&i2s>;
+            };
+
+            simple-audio-card,codec {
+                sound-dai = <&tlv320aic32x4>;
+            };
+        };
+    };
+
+    fragment@4 {
+        target = <&gpio>;
+        __overlay__ {
+            gpclk0_pin: gpclk0_pin {
+                brcm,pins = <4>;
+                brcm,function = <4>;
+            };
+
+            aic3204_reset: aic3204_reset {
+                brcm,pins = <13>;
+                brcm,function = <1>;
+                brcm,pull = <1>;
+            };
+
+            aic3204_gpio: aic3204_gpio {
+                brcm,pins = <26>;
+            };
+
+            sc16is752_irq: sc16is752_irq {
+                brcm,pins = <17>;
+                brcm,function = <0>;
+                brcm,pull = <2>;
+            };
+
+            pps_pins: pps_pins {
+                brcm,pins = <7>;
+                brcm,function = <0>;
+                brcm,pull = <0>;
+            };
+        };
+    };
+
+    __overrides__ {
+        draws_adc_ch4_gain = <&adc_ch4>,"ti,gain:0";
+        draws_adc_ch4_datarate = <&adc_ch4>,"ti,datarate:0";
+        draws_adc_ch5_gain = <&adc_ch5>,"ti,gain:0";
+        draws_adc_ch5_datarate = <&adc_ch5>,"ti,datarate:0";
+        draws_adc_ch6_gain = <&adc_ch6>,"ti,gain:0";
+        draws_adc_ch6_datarate = <&adc_ch6>,"ti,datarate:0";
+        draws_adc_ch7_gain = <&adc_ch7>,"ti,gain:0";
+        draws_adc_ch7_datarate = <&adc_ch7>,"ti,datarate:0";
+        alsaname = <&snd>, "simple-audio-card,name";
+    };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/dwc2-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dwc2-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/dwc2-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dwc2-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&usb>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		dwc2_usb: __overlay__ {
+			compatible = "brcm,bcm2835-usb";
+			dr_mode = "otg";
+			g-np-tx-fifo-size = <32>;
+			g-rx-fifo-size = <558>;
+			g-tx-fifo-size = <512 512 512 512 512 256 256>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		dr_mode = <&dwc2_usb>, "dr_mode";
+		g-np-tx-fifo-size = <&dwc2_usb>,"g-np-tx-fifo-size:0";
+		g-rx-fifo-size = <&dwc2_usb>,"g-rx-fifo-size:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&usb>;
+		__overlay__ {
+			compatible = "brcm,bcm2708-usb";
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for RaspberryPi 7" Touchscreen panel
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+			ft5406: ts@38 {
+				compatible = "edt,edt-ft5406";
+				reg = <0x38>;
+
+				touchscreen-size-x = < 800 >;
+				touchscreen-size-y = < 480 >;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		sizex = <&ft5406>,"touchscreen-size-x:0";
+		sizey = <&ft5406>,"touchscreen-size-y:0";
+		invx = <&ft5406>,"touchscreen-inverted-x?";
+		invy = <&ft5406>,"touchscreen-inverted-y?";
+		swapxy = <&ft5406>,"touchscreen-swapped-x-y?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/enc28j60-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/enc28j60-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/enc28j60-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for the Microchip ENC28J60 Ethernet Controller
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			eth1: enc28j60@0{
+				compatible = "microchip,enc28j60";
+				reg = <0>; /* CE0 */
+				pinctrl-names = "default";
+				pinctrl-0 = <&eth1_pins>;
+				interrupt-parent = <&gpio>;
+				interrupts = <25 0x2>; /* falling edge */
+				spi-max-frequency = <12000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&gpio>;
+		__overlay__ {
+			eth1_pins: eth1_pins {
+				brcm,pins = <25>;
+				brcm,function = <0>; /* in */
+				brcm,pull = <0>; /* none */
+			};
+		};
+	};
+
+	__overrides__ {
+		int_pin = <&eth1>, "interrupts:0",
+		          <&eth1_pins>, "brcm,pins:0";
+		speed   = <&eth1>, "spi-max-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for the Microchip ENC28J60 Ethernet Controller - SPI2 Compute Module
+// Interrupt pin: 39
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi2>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			eth1: enc28j60@0{
+				compatible = "microchip,enc28j60";
+				reg = <0>; /* CE0 */
+				pinctrl-names = "default";
+				pinctrl-0 = <&eth1_pins>;
+				interrupt-parent = <&gpio>;
+				interrupts = <39 0x2>; /* falling edge */
+				spi-max-frequency = <12000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			eth1_pins: eth1_pins {
+				brcm,pins = <39>;
+				brcm,function = <0>; /* in */
+				brcm,pull = <0>; /* none */
+			};
+		};
+	};
+
+	__overrides__ {
+		int_pin = <&eth1>, "interrupts:0",
+		          <&eth1_pins>, "brcm,pins:0";
+		speed   = <&eth1>, "spi-max-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/exc3000-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/exc3000-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/exc3000-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/exc3000-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Device tree overlay for I2C connected EETI EXC3000 multiple touch controller
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			exc3000_pins: exc3000_pins {
+				brcm,pins = <4>; // interrupt
+				brcm,function = <0>; // in
+				brcm,pull = <2>; // pull-up
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			exc3000: exc3000@2a {
+				compatible = "eeti,exc3000";
+				reg = <0x2a>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&exc3000_pins>;
+				interrupt-parent = <&gpio>;
+				interrupts = <4 8>; // active low level-sensitive
+				touchscreen-size-x = <4096>;
+				touchscreen-size-y = <4096>;
+			};
+		};
+	};
+
+	__overrides__ {
+		interrupt = <&exc3000_pins>,"brcm,pins:0",
+			<&exc3000>,"interrupts:0";
+		sizex = <&exc3000>,"touchscreen-size-x:0";
+		sizey = <&exc3000>,"touchscreen-size-y:0";
+		invx = <&exc3000>,"touchscreen-inverted-x?";
+		invy = <&exc3000>,"touchscreen-inverted-y?";
+		swapxy = <&exc3000>,"touchscreen-swapped-x-y?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for Fe-Pi Audio
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			sgtl5000_mclk: sgtl5000_mclk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <12288000>;
+				clock-output-names = "sgtl5000-mclk";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&soc>;
+		__overlay__ {
+			reg_1v8: reg_1v8@0 {
+				compatible = "regulator-fixed";
+				regulator-name = "1V8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			sgtl5000@0a {
+				#sound-dai-cells = <0>;
+				compatible = "fsl,sgtl5000";
+				reg = <0x0a>;
+				clocks = <&sgtl5000_mclk>;
+				micbias-resistor-k-ohms = <2>;
+				micbias-voltage-m-volts = <3000>;
+				VDDA-supply = <&vdd_3v3_reg>;
+				VDDIO-supply = <&vdd_3v3_reg>;
+				VDDD-supply = <&reg_1v8>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "fe-pi,fe-pi-audio";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/fsm-demo-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/fsm-demo-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/fsm-demo-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/fsm-demo-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Demo overlay for the gpio-fsm driver
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio-fsm.h>
+
+#define BUTTON1 GF_IP(0)
+#define BUTTON2 GF_SW(0)
+#define RED   GF_OP(0) // GPIO7
+#define AMBER GF_OP(1) // GPIO8
+#define GREEN GF_OP(2) // GPIO25
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			fsm_demo: fsm-demo {
+				compatible = "rpi,gpio-fsm";
+
+				debug = <0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				num-swgpios = <1>;
+				gpio-line-names = "button2";
+				input-gpios  = <&gpio 6 1>;  // BUTTON1 (active-low)
+				output-gpios = <&gpio 7 0>,  // RED
+					       <&gpio 8 0>,  // AMBER
+					       <&gpio 25 0>; // GREEN
+				shutdown-timeout-ms = <2000>;
+
+				start {
+					start_state;
+					set = <RED 1>, <AMBER 0>, <GREEN 0>;
+					start2 = <GF_DELAY 250>;
+				};
+
+				start2 {
+					set = <RED 0>, <AMBER 1>;
+					go = <GF_DELAY 250>;
+				};
+
+				go {
+					set = <RED 0>, <AMBER 0>, <GREEN 1>;
+					ready_wait = <BUTTON1 0>;
+					shutdown1 = <GF_SHUTDOWN 0>;
+				};
+
+				ready_wait {
+					// Clear the soft GPIO
+					set = <BUTTON2 0>;
+					ready = <GF_DELAY 1000>;
+					shutdown1 = <GF_SHUTDOWN 0>;
+				};
+
+				ready {
+					stopping = <BUTTON1 1>, <BUTTON2 1>;
+					shutdown1 = <GF_SHUTDOWN 0>;
+				};
+
+				stopping {
+					set = <GREEN 0>, <AMBER 1>;
+					stopped = <GF_DELAY 1000>;
+				};
+
+				stopped {
+					set = <AMBER 0>, <RED 1>;
+					get_set = <GF_DELAY 3000>;
+					shutdown1 = <GF_SHUTDOWN 0>;
+				};
+
+				get_set {
+					set = <AMBER 1>;
+					go = <GF_DELAY 1000>;
+				};
+
+				shutdown1 {
+					set = <RED 0>, <AMBER 0>, <GREEN 1>;
+					shutdown2 = <GF_SHUTDOWN 250>;
+				};
+
+				shutdown2 {
+					set = <AMBER 1>, <GREEN 0>;
+					shutdown3 = <GF_SHUTDOWN 250>;
+				};
+
+				shutdown3 {
+					set = <RED 1>, <AMBER 0>;
+					shutdown4 = <GF_SHUTDOWN 250>;
+				};
+
+				shutdown4 {
+					shutdown_state;
+					set = <RED 0>, <AMBER 0>, <GREEN 0>;
+				};
+			};
+	       };
+        };
+
+	__overrides__ {
+		fsm_debug = <&fsm_demo>,"debug:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ghost-amp-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ghost-amp-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ghost-amp-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ghost-amp-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for the PCM5122-based Ghost amplifier using gpio-fsm
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio-fsm.h>
+
+#define ENABLE   GF_SW(0)
+#define FAULT    GF_IP(0) // GPIO5
+#define RELAY1   GF_OP(0) // GPIO22
+#define RELAY2   GF_OP(1) // GPIO23
+#define RELAYSSR GF_OP(2) // GPIO24
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4c>;
+				AVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		iqaudio_dac: __overlay__ {
+			compatible = "iqaudio,iqaudio-dac";
+			i2s-controller = <&i2s>;
+			mute-gpios = <&amp 0 0>;
+			iqaudio-dac,auto-mute-amp;
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target-path = "/";
+		__overlay__ {
+			amp: ghost-amp {
+				compatible = "rpi,gpio-fsm";
+				pinctrl-names = "default";
+				pinctrl-0 = <&ghost_amp_pins>;
+
+				debug = <0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				num-swgpios = <1>;
+				gpio-line-names = "enable";
+				input-gpios  = <&gpio 5 1>;  // FAULT (active low)
+				output-gpios = <&gpio 22 0>, // RELAY1
+					       <&gpio 23 0>, // RELAY2
+					       <&gpio 24 0>; // RELAYSSR
+				shutdown-timeout-ms = <1000>;
+
+				amp_off {
+					start_state;
+					shutdown_state;
+
+					set = <RELAYSSR 0>,
+					      <RELAY2 0>,
+					      <RELAY1 0>;
+					amp_on_1 = <ENABLE 1>;
+					fault = <FAULT 1>;
+				};
+
+				amp_on_1 {
+					set = <RELAY1 1>;
+					amp_on_2 = <GF_DELAY 1000>;
+					amp_off = <GF_SHUTDOWN 0>;
+					fault = <FAULT 1>;
+				};
+
+				amp_on_2 {
+					set = <RELAY2 1>;
+					amp_on_wait = <ENABLE 0>;
+					amp_on = <GF_DELAY 1>;
+					fault = <FAULT 1>;
+				};
+
+				amp_on {
+					set = <RELAYSSR 1>;
+					amp_on_wait = <ENABLE 0>;
+					fault = <FAULT 1>;
+				};
+
+				amp_on_wait {
+					set = <RELAYSSR 0>;
+					amp_off_1 = <GF_DELAY (30*60*1000)>,
+						    <GF_SHUTDOWN 0>;
+					amp_on = <ENABLE 1>;
+					fault = <FAULT 1>;
+				};
+
+				amp_off_1 {
+					set = <RELAY2 0>;
+					amp_on = <ENABLE 1>;
+					amp_off = <GF_DELAY 100>;
+					fault = <FAULT 1>;
+				};
+
+				// Keep this a distinct state to prevent
+				// changes and for the diagnostic output
+				fault {
+					set = <RELAYSSR 0>,
+					      <RELAY2 0>,
+					      <RELAY1 0>;
+					amp_off = <FAULT 0>;
+					shutdown_state;
+				};
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&gpio>;
+		__overlay__ {
+			ghost_amp_pins: ghost_amp_pins {
+				brcm,pins = <5 22 23 24>;
+				brcm,function = <0 1 1 1>; /* in out out out */
+				brcm,pull = <2 0 0 0>; /* up none none none */
+			};
+		};
+	};
+
+	__overrides__ {
+		fsm_debug = <&amp>,"debug:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/goodix-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/goodix-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/goodix-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/goodix-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Device tree overlay for I2C connected Goodix gt9271 multiple touch controller
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			goodix_pins: goodix_pins {
+				brcm,pins = <4 17>; // interrupt and reset
+				brcm,function = <0 0>; // in
+				brcm,pull = <2 2>; // pull-up
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			gt9271: gt9271@14 {
+				compatible = "goodix,gt9271";
+				reg = <0x14>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&goodix_pins>;
+				interrupt-parent = <&gpio>;
+				interrupts = <4 2>; // high-to-low edge triggered
+				irq-gpios = <&gpio 4 0>; // Pin7 on GPIO header
+				reset-gpios = <&gpio 17 1>; // Pin11 on GPIO header
+			};
+		};
+	};
+
+	__overrides__ {
+		interrupt = <&goodix_pins>,"brcm,pins:0",
+			<&gt9271>,"interrupts:0",
+			<&gt9271>,"irq-gpios:4";
+		reset = <&goodix_pins>,"brcm,pins:4",
+			<&gt9271>,"reset-gpios:4";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for Google voiceHAT v1 soundcard overlay
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			googlevoicehat_pins: googlevoicehat_pins {
+				brcm,pins = <16>;
+				brcm,function = <1>; /* out */
+				brcm,pull = <0>; /* up */
+			};
+		};
+	};
+
+
+	fragment@2 {
+		target-path = "/";
+		__overlay__ {
+			voicehat-codec {
+				#sound-dai-cells = <0>;
+				compatible = "google,voicehat";
+				pinctrl-names = "default";
+				pinctrl-0 = <&googlevoicehat_pins>;
+				sdmode-gpios= <&gpio 16 0>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "googlevoicehat,googlevoicehat-soundcard";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Overlay for the Raspberry Pi GPIO Fan @ BCM GPIO12.
+ * References: 
+ *	- https://www.raspberrypi.org/forums/viewtopic.php?f=107&p=1367135#p1365084
+ *
+ * Optional parameters:
+ *	- "gpiopin"	- BCM number of the pin driving the fan, default 12 (GPIO12);
+ * 	- "temp"	- CPU temperature at which fan is started in millicelsius, default 55000;
+ *
+ * Requires:
+ *	- kernel configurations: CONFIG_SENSORS_GPIO_FAN=m;
+ *	- kernel rebuild;
+ *	- N-MOSFET connected to gpiopin, 2N7002-[https://en.wikipedia.org/wiki/2N7000];
+ *	- DC Fan connected to N-MOSFET Drain terminal, a 12V fan is working fine and quite silently;
+ *	  [https://www.tme.eu/en/details/ee40101s1-999-a/dc12v-fans/sunon/ee40101s1-1000u-999/]
+ *
+ *                   ┌─────────────────────┐
+ *                   │Fan negative terminal│
+ *                   └┬────────────────────┘
+ *                    │D
+ *             G   │──┘
+ * [GPIO12]──────┤ │<─┐  2N7002
+ *                 │──┤
+ *                    │S
+ *                   ─┴─
+ *                   GND
+ *
+ * Build:
+ * 	- `sudo dtc -W no-unit_address_vs_reg -@ -I dts -O dtb -o /boot/overlays/gpio-fan.dtbo gpio-fan-overlay.dts`
+ * Activate:
+ *	- sudo nano /boot/config.txt add "dtoverlay=gpio-fan" or "dtoverlay=gpio-fan,gpiopin=12,temp=45000"
+ *	 or
+ *	- sudo sh -c 'printf "\n# Enable PI GPIO-Fan Default\ndtoverlay=gpio-fan\n" >> /boot/config.txt'
+ *	- sudo sh -c 'printf "\n# Enable PI GPIO-Fan Custom\ndtoverlay=gpio-fan,gpiopin=12,temp=45000\n" >> /boot/config.txt'
+ *
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			fan0: gpio-fan@0 {
+				compatible = "gpio-fan";
+				gpios = <&gpio 12 0>;
+				gpio-fan,speed-map = <0    0>,
+									 <5000 1>;
+				#cooling-cells = <2>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&cpu_thermal>;
+		polling-delay = <2000>;	/* milliseconds */
+		__overlay__ {
+			trips {
+				cpu_hot: trip-point@0 {
+					temperature = <55000>;	/* (millicelsius) Fan started at 55°C */
+					hysteresis = <10000>;	/* (millicelsius) Fan stopped at 45°C */
+					type = "active";
+				};
+			};
+			cooling-maps {
+				map0 {
+					trip = <&cpu_hot>;
+					cooling-device = <&fan0 1 1>;
+				};
+			};
+		};
+	};
+	__overrides__ {
+		gpiopin = <&fan0>,"gpios:4", <&fan0>,"brcm,pins:0";
+		temp = <&cpu_hot>,"temperature:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for ir-gpio module
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "brcm,bcm2835";
+
+        fragment@0 {
+                target-path = "/";
+                __overlay__ {
+                        gpio_ir: ir-receiver@12 {
+                                compatible = "gpio-ir-receiver";
+                                pinctrl-names = "default";
+                                pinctrl-0 = <&gpio_ir_pins>;
+
+                                // pin number, high or low
+                                gpios = <&gpio 18 1>;
+
+                                // parameter for keymap name
+                                linux,rc-map-name = "rc-rc6-mce";
+
+                                status = "okay";
+                        };
+                };
+        };
+
+        fragment@1 {
+                target = <&gpio>;
+                __overlay__ {
+                        gpio_ir_pins: gpio_ir_pins@12 {
+                                brcm,pins = <18>;                       // pin 18
+                                brcm,function = <0>;                    // in
+                                brcm,pull = <2>;                        // up
+                        };
+                };
+        };
+
+        __overrides__ {
+                // parameters
+                gpio_pin =      <&gpio_ir>,"gpios:4",           // pin number
+                                <&gpio_ir>,"reg:0",
+                                <&gpio_ir_pins>,"brcm,pins:0",
+                                <&gpio_ir_pins>,"reg:0";
+                gpio_pull = <&gpio_ir_pins>,"brcm,pull:0";              // pull-up/down state
+                invert = <&gpio_ir>,"gpios:8";                          // 0 = active high input
+
+                rc-map-name = <&gpio_ir>,"linux,rc-map-name";           // default rc map
+        };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			gpio_ir_tx_pins: gpio_ir_tx_pins@12 {
+				brcm,pins = <18>;
+				brcm,function = <1>;	// out
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			gpio_ir_tx: gpio-ir-transmitter@12 {
+				compatible = "gpio-ir-tx";
+				pinctrl-names = "default";
+				pinctrl-0 = <&gpio_ir_tx_pins>;
+				gpios = <&gpio 18 0>;
+			};
+		};
+	};
+
+	__overrides__ {
+		gpio_pin = <&gpio_ir_tx>, "gpios:4",           	// pin number
+			   <&gpio_ir_tx>, "reg:0",
+			   <&gpio_ir_tx_pins>, "brcm,pins:0",
+			   <&gpio_ir_tx_pins>, "reg:0";
+		invert = <&gpio_ir_tx>, "gpios:8";		// 1 = active low
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-key-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-key-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-key-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-key-overlay.dts	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for gpio-key module
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		// Configure the gpio pin controller
+		target = <&gpio>;
+		__overlay__ {
+			pin_state: button_pins@0 {
+				brcm,pins = <3>; // gpio number
+				brcm,function = <0>; // 0 = input, 1 = output
+				brcm,pull = <2>; // 0 = none, 1 = pull down, 2 = pull up
+			};
+		};
+	};
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			button: button@0 {
+				compatible = "gpio-keys";
+				pinctrl-names = "default";
+				pinctrl-0 = <&pin_state>;
+				status = "okay";
+
+				key: key {
+					linux,code = <116>;
+					gpios = <&gpio 3 1>;
+					label = "KEY_POWER";
+				};
+			};
+		};
+	};
+
+	__overrides__ {
+		gpio =       <&key>,"gpios:4",
+		             <&button>,"reg:0",
+		             <&pin_state>,"brcm,pins:0",
+		             <&pin_state>,"reg:0";
+		label =      <&key>,"label";
+		keycode =    <&key>,"linux,code:0";
+		gpio_pull =  <&pin_state>,"brcm,pull:0";
+		active_low = <&key>,"gpios:8";
+	};
+
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-led-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-led-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-led-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-led-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * gpio-led - generic connection of kernel's LED framework to the RPI's GPIO.
+ * Copyright (C) 2021 House Gordon Software Company Ltd. <assafgordon@gmail.com>
+ *
+ * Based on information from:
+ *   https://mjoldfield.com/atelier/2017/03/rpi-devicetree.html
+ *   https://www.raspberrypi.org/documentation/configuration/device-tree.md
+ *   https://www.kernel.org/doc/html/latest/leds/index.html
+ *
+ * compile with:
+ *   dtc -@ -Hepapr -I dts -O dtb -o gpio-led.dtbo gpio-led-overlay.dts
+ *
+ * There will be some warnings (can be ignored):
+ *  Warning (label_is_string): /__overrides__:label: property is not a string
+ *  Warning (unit_address_vs_reg): /fragment@0/__overlay__/led_pins@0:
+ *                                 node has a unit name, but no reg property
+ *  Warning (unit_address_vs_reg): /fragment@1/__overlay__/leds@0:
+ *                                 node has a unit name, but no reg property
+ *  Warning (gpios_property): /__overrides__: Missing property
+ *                 '#gpio-cells' in node /fragment@1/__overlay__/leds@0/led
+ *                  or bad phandle (referred from gpio[0])
+ *
+ * Typical electrical connection is:
+ *    RPI-GPIO.19  ->  LED  -> 300ohm resister  -> RPI-GND
+ *    The GPIO pin number can be changed with the 'gpio=' parameter.
+ *
+ * Test from user-space with:
+ *   # if nothing is shown, the overlay file isn't found in /boot/overlays
+ *   dtoverlay -a | grep gpio-led
+ *
+ *   # Load the overlay
+ *   dtoverlay gpio-led label=moo gpio=19
+ *
+ *   # if nothing is shown, the overlay wasn't loaded successfully
+ *   dtoverlay -l | grep gpio-led
+ *
+ *   echo 1 > /sys/class/leds/moo/brightness
+ *   echo 0 > /sys/class/leds/moo/brightness
+ *   echo cpu > /sys/class/leds/moo/trigger
+ *   echo heartbeat > /sys/class/leds/moo/trigger
+ *
+ *   # unload the overlay
+ *   dtoverlay -r gpio-led
+ *
+ * To load in /boot/config.txt add lines such as:
+ *   dtoverlay=gpio-led,gpio=19,label=heart,trigger=heartbeat
+ *   dtoverlay=gpio-led,gpio=26,label=brain,trigger=cpu
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		// Configure the gpio pin controller
+		target = <&gpio>;
+		__overlay__ {
+			led_pin: led_pins@19 {
+				brcm,pins = <19>; // gpio number
+				brcm,function = <1>; // 0 = input, 1 = output
+				brcm,pull = <0>; // 0 = none, 1 = pull down, 2 = pull up
+			};
+		};
+	};
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			leds: leds@0 {
+				compatible = "gpio-leds";
+				pinctrl-names = "default";
+				pinctrl-0 = <&led_pin>;
+				status = "okay";
+
+				led: led {
+			                label = "myled1";
+					gpios = <&gpio 19 0>;
+			                linux,default-trigger = "none";
+				};
+			};
+		};
+	};
+
+	__overrides__ {
+		gpio =       <&led>,"gpios:4",
+		             <&leds>,"reg:0",
+		             <&led_pin>,"brcm,pins:0",
+		             <&led_pin>,"reg:0";
+		label =      <&led>,"label";
+		active_low = <&led>,"gpios:8";
+		trigger =    <&led>,"linux,default-trigger";
+	};
+
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-no-bank0-irq-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-no-bank0-irq-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-no-bank0-irq-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-no-bank0-irq-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		// Configure the gpio pin controller
+		target = <&gpio>;
+		__overlay__ {
+			    interrupts = <255 255>, <2 18>;
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-no-irq-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-no-irq-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-no-irq-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-no-irq-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		// Configure the gpio pin controller
+		target = <&gpio>;
+		__overlay__ {
+			    interrupts;
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for gpio-poweroff module
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			power_ctrl: power_ctrl {
+				compatible = "gpio-poweroff";
+				gpios = <&gpio 26 0>;
+				force;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			power_ctrl_pins: power_ctrl_pins {
+				brcm,pins = <26>;
+				brcm,function = <1>; // out
+			};
+		};
+	};
+
+	__overrides__ {
+		gpiopin =       <&power_ctrl>,"gpios:4",
+				<&power_ctrl_pins>,"brcm,pins:0";
+		active_low =    <&power_ctrl>,"gpios:8";
+		input =         <&power_ctrl>,"input?";
+		export =        <&power_ctrl>,"export?";
+		timeout_ms =    <&power_ctrl>,"timeout-ms:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for gpio-poweroff module
+/dts-v1/;
+/plugin/;
+
+// This overlay sets up an input device that generates KEY_POWER events
+// when a given GPIO pin changes. It defaults to using GPIO3, which can
+// also be used to wake up (start) the Rpi again after shutdown.
+// Raspberry Pi 1 Model B rev 1 can be wake up only by GPIO1 pin, so for
+// these boards change default GPIO pin to 1 via gpio_pin parameter. Since
+// wakeup is active-low, this defaults to active-low with a pullup
+// enabled, but all of this can be changed using overlay parameters (but
+// note that GPIO3 has an external pullup on at least some boards).
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		// Configure the gpio pin controller
+		target = <&gpio>;
+		__overlay__ {
+			// Define a pinctrl state, that sets up the gpio
+			// as an input with a pullup enabled. This does
+			// not take effect by itself, only when referenced
+			// by a "pinctrl client", as is done below. See:
+			//   https://www.kernel.org/doc/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+			//   https://www.kernel.org/doc/Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt
+			pin_state: shutdown_button_pins@3 {
+				brcm,pins = <3>; // gpio number
+				brcm,function = <0>; // 0 = input, 1 = output
+				brcm,pull = <2>; // 0 = none, 1 = pull down, 2 = pull up
+			};
+		};
+	};
+	fragment@1 {
+		// Add a new device to the /soc devicetree node
+		target-path = "/soc";
+		__overlay__ {
+			shutdown_button: shutdown_button@3 {
+				// Let the gpio-keys driver handle this device. See:
+				// https://www.kernel.org/doc/Documentation/devicetree/bindings/input/gpio-keys.txt
+				compatible = "gpio-keys";
+
+				// Declare a single pinctrl state (referencing the one declared above) and name it
+				// default, so it is activated automatically.
+				pinctrl-names = "default";
+				pinctrl-0 = <&pin_state>;
+
+				// Enable this device
+				status = "okay";
+
+				// Define a single key, called "shutdown" that monitors the gpio and sends KEY_POWER
+				// (keycode 116, see
+				// https://github.com/torvalds/linux/blob/v4.12/include/uapi/linux/input-event-codes.h#L190)
+				button: shutdown {
+					label = "shutdown";
+					linux,code = <116>; // KEY_POWER
+					gpios = <&gpio 3 1>;
+					debounce-interval = <100>; // ms
+				};
+			};
+		};
+	};
+
+	// This defines parameters that can be specified when loading
+	// the overlay. Each foo = line specifies one parameter, named
+	// foo. The rest of the specification gives properties where the
+	// parameter value is inserted into (changing the values above
+	// or adding new ones).
+	__overrides__ {
+		// Allow overriding the GPIO number.
+		gpio_pin = <&button>,"gpios:4",
+			   <&shutdown_button>,"reg:0",
+			   <&pin_state>,"reg:0",
+		           <&pin_state>,"brcm,pins:0";
+
+		// Allow changing the internal pullup/down state. 0 = none, 1 = pulldown, 2 = pullup
+		// Note that GPIO3 and GPIO2 are the I2c pins and have an external pullup (at least
+		// on some boards). Same applies for GPIO1 on Raspberry Pi 1 Model B rev 1.
+		gpio_pull = <&pin_state>,"brcm,pull:0";
+
+		// Allow setting the active_low flag. 0 = active high, 1 = active low
+		active_low = <&button>,"gpios:8";
+		debounce = <&button>,"debounce-interval:0";
+	};
+
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+
+    fragment@0 {
+        target-path = "/";
+        __overlay__ {
+            lcd_screen: auxdisplay {
+                compatible = "hit,hd44780";
+
+                data-gpios = <&gpio 6 0>,
+                             <&gpio 13 0>,
+                             <&gpio 19 0>,
+                             <&gpio 26 0>;
+                enable-gpios = <&gpio 21 0>;
+                rs-gpios = <&gpio 20 0>;
+
+                display-height-chars = <2>;
+                display-width-chars = <16>;
+            };
+
+        };
+    };
+
+    fragment@1 {
+       target = <&lcd_screen>;
+        __dormant__ {
+            backlight-gpios = <&gpio 12 0>;
+        };
+    };
+
+    __overrides__ {
+        pin_d4 = <&lcd_screen>,"data-gpios:4";
+        pin_d5 = <&lcd_screen>,"data-gpios:16";
+        pin_d6 = <&lcd_screen>,"data-gpios:28";
+        pin_d7 = <&lcd_screen>,"data-gpios:40";
+        pin_en = <&lcd_screen>,"enable-gpios:4";
+        pin_rs = <&lcd_screen>,"rs-gpios:4";
+        pin_bl = <0>,"+1", <&lcd_screen>,"backlight-gpios:4";
+        display_height = <&lcd_screen>,"display-height-chars:0";
+        display_width = <&lcd_screen>,"display-width-chars:0";
+    };
+
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Devicetree overlay for GPIO based backlight on/off capability.
+ *
+ * Use this if you have one of those HDMI displays whose backlight cannot be
+ * controlled via DPMS over HDMI and plan to do a little soldering to use an
+ * RPi gpio pin for on/off switching.
+ *
+ * See: https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control
+ *
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			hdmi_backlight_hwhack_gpio_pins: hdmi_backlight_hwhack_gpio_pins {
+				brcm,pins = <17>;
+				brcm,function = <1>; /* out */
+			};
+		};
+	};
+
+	fragment@2 {
+		target-path = "/";
+		__overlay__ {
+			hdmi_backlight_hwhack_gpio: hdmi_backlight_hwhack_gpio {
+				compatible = "gpio-backlight";
+
+				pinctrl-names = "default";
+				pinctrl-0 = <&hdmi_backlight_hwhack_gpio_pins>;
+
+				gpios = <&gpio 17 0>;
+				default-on;
+			};
+		};
+	};
+
+	__overrides__ {
+		gpio_pin   = <&hdmi_backlight_hwhack_gpio>,"gpios:4",
+		             <&hdmi_backlight_hwhack_gpio_pins>,"brcm,pins:0";
+		active_low = <&hdmi_backlight_hwhack_gpio>,"gpios:8";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for HiFiBerry AMP100
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			dacpro_osc: dacpro_osc {
+				compatible = "hifiberry,dacpro-clk";
+				#clock-cells = <0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4d {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4d>;
+				clocks = <&dacpro_osc>;
+				AVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		hifiberry_dacplus: __overlay__ {
+			compatible = "hifiberry,hifiberry-dacplus";
+			i2s-controller = <&i2s>;
+			status = "okay";
+			mute-gpio = <&gpio 4 0>;
+			reset-gpio = <&gpio 17 0x11>;
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain =
+			<&hifiberry_dacplus>,"hifiberry,24db_digital_gain?";
+		slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?";
+		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?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for HiFiBerry Amp/Amp+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			tas5713@1b {
+				#sound-dai-cells = <0>;
+				compatible = "ti,tas5713";
+				reg = <0x1b>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "hifiberry,hifiberry-amp";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for HiFiBerry DAC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			pcm5102a-codec {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5102a";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "hifiberry,hifiberry-dac";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for HiFiBerry DAC+ADC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			dacpro_osc: dacpro_osc {
+				compatible = "hifiberry,dacpro-clk";
+				#clock-cells = <0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm_codec: pcm5122@4d {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4d>;
+				clocks = <&dacpro_osc>;
+				AVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target-path = "/";
+		__overlay__ {
+			dmic {
+				#sound-dai-cells = <0>;
+				compatible = "dmic-codec";
+				num-channels = <2>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&sound>;
+		hifiberry_dacplusadc: __overlay__ {
+			compatible = "hifiberry,hifiberry-dacplusadc";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain =
+			<&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?";
+		slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?";
+		leds_off = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,leds_off?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for HiFiBerry DAC+ADC PRO
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			dacpro_osc: dacpro_osc {
+				compatible = "hifiberry,dacpro-clk";
+				#clock-cells = <0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			hb_dac: pcm5122@4d {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4d>;
+				clocks = <&dacpro_osc>;
+				status = "okay";
+			};
+			hb_adc: pcm186x@4a {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm1863";
+				reg = <0x4a>;
+				clocks = <&dacpro_osc>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		hifiberry_dacplusadcpro: __overlay__ {
+			compatible = "hifiberry,hifiberry-dacplusadcpro";
+			audio-codec = <&hb_dac &hb_adc>;
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain =
+			<&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?";
+		slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?";
+		leds_off = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,leds_off?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for hifiberry DAC+DSP soundcard overlay
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			dacplusdsp-codec {
+				#sound-dai-cells = <0>;
+				compatible = "hifiberry,dacplusdsp";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for HiFiBerry DAC+ HD
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			dachd_osc: pll_dachd_osc {
+				compatible = "hifiberry,dachd-clk";
+				#clock-cells = <0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm1792a@4c {
+				compatible = "ti,pcm1792a";
+				#sound-dai-cells = <0>;
+				#clock-cells = <0>;
+				clocks = <&dachd_osc>;
+				reg = <0x4c>;
+				status = "okay";
+			};
+			pll: pll@62 {
+				compatible = "hifiberry,dachd-clk";
+				#clock-cells = <0>;
+				reg = <0x62>;
+				clocks = <&dachd_osc>;
+				status = "okay";
+				common_pll_regs = [
+					02 53 03 00 07 20 0F 00
+					10 0D 11 1D 12 0D 13 8C
+					14 8C 15 8C 16 8C 17 8C
+					18 2A 1C 00 1D 0F 1F 00
+					2A 00 2C 00 2F 00 30 00
+					31 00 32 00 34 00 37 00
+					38 00 39 00 3A 00 3B 01
+					3E 00 3F 00 40 00 41 00
+					5A 00 5B 00 95 00 96 00
+					97 00 98 00 99 00 9A 00
+					9B 00 A2 00 A3 00 A4 00
+					B7 92 ];
+				192k_pll_regs = [
+					1A 0C 1B 35 1E F0 20 09
+					21 50 2B 02 2D 10 2E 40
+					33 01 35 22 36 80 3C 22
+					3D 46 ];
+				96k_pll_regs = [
+					1A 0C 1B 35 1E F0 20 09
+					21 50 2B 02 2D 10 2E 40
+					33 01 35 47 36 00 3C 32
+					3D 46 ];
+				48k_pll_regs = [
+					1A 0C 1B 35 1E F0 20 09
+					21 50 2B 02 2D 10 2E 40
+					33 01 35 90 36 00 3C 42
+					3D 46 ];
+				176k4_pll_regs = [
+					1A 3D 1B 09 1E F3 20 13
+					21 75 2B 04 2D 11 2E E0
+					33 02 35 25 36 C0 3C 22
+					3D 7A ];
+				88k2_pll_regs = [
+					1A 3D 1B 09 1E F3 20 13
+					21 75 2B 04 2D 11 2E E0
+					33 01 35 4D 36 80 3C 32
+					3D 7A ];
+				44k1_pll_regs = [
+					1A 3D 1B 09 1E F3 20 13
+					21 75 2B 04 2D 11 2E E0
+					33 01 35 9D 36 00 3C 42
+					3D 7A ];
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "hifiberry,hifiberry-dacplushd";
+			i2s-controller = <&i2s>;
+			clocks = <&pll 0>;
+			reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>;
+			status = "okay";
+		};
+	};
+
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for HiFiBerry DAC+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			dacpro_osc: dacpro_osc {
+				compatible = "hifiberry,dacpro-clk";
+				#clock-cells = <0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4d {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4d>;
+				clocks = <&dacpro_osc>;
+				AVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+			hpamp: hpamp@60 {
+				compatible = "ti,tpa6130a2";
+				reg = <0x60>;
+				status = "disabled";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		hifiberry_dacplus: __overlay__ {
+			compatible = "hifiberry,hifiberry-dacplus";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain =
+			<&hifiberry_dacplus>,"hifiberry,24db_digital_gain?";
+		slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?";
+		leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for HiFiBerry Digi
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8804@3b {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8804";
+				reg = <0x3b>;
+				PVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "hifiberry,hifiberry-digi";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for HiFiBerry Digi Pro
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8804@3b {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8804";
+				reg = <0x3b>;
+				PVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "hifiberry,hifiberry-digi";
+			i2s-controller = <&i2s>;
+			status = "okay";
+			clock44-gpio = <&gpio 5 0>;
+			clock48-gpio = <&gpio 6 0>;
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/highperi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/highperi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/highperi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/highperi-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * highperi.dts
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&soc>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x7c000000  0x4 0x7c000000  0x04000000>,
+				 <0x40000000  0x4 0xc0000000  0x00800000>;
+		};
+	};
+
+	fragment@1 {
+		target = <&scb>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges = <0x0 0x7c000000  0x4 0x7c000000  0x0 0x04000000>,
+				 <0x0 0x40000000  0x4 0xc0000000  0x0 0x00800000>,
+				 <0x6 0x00000000  0x6 0x00000000  0x0 0x40000000>;
+			dma-ranges = <0x0 0x00000000  0x0 0x00000000  0x2 0x00000000>;
+		};
+	};
+
+	fragment@2 {
+		target = <&v3dbus>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <2>;
+			ranges = <0x7c500000  0x4 0x7c500000  0x0 0x03300000>,
+				 <0x40000000  0x4 0xc0000000  0x0 0x00800000>;
+		};
+	};
+
+	fragment@3 {
+		target = <&emmc2bus>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <1>;
+			ranges = <0x0 0x7e000000  0x4 0x7e000000  0x01800000>;
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hy28a-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hy28a-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hy28a-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hy28a-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for HY28A display
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			hy28a_pins: hy28a_pins {
+				brcm,pins = <17 25 18>;
+				brcm,function = <0 1 1>; /* in out out */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			hy28a: hy28a@0{
+				compatible = "ilitek,ili9320";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&hy28a_pins>;
+
+				spi-max-frequency = <32000000>;
+				spi-cpol;
+				spi-cpha;
+				rotate = <270>;
+				bgr;
+				fps = <50>;
+				buswidth = <8>;
+				startbyte = <0x70>;
+				reset-gpios = <&gpio 25 1>;
+				led-gpios = <&gpio 18 1>;
+				debug = <0>;
+			};
+
+			hy28a_ts: hy28a-ts@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+
+				spi-max-frequency = <2000000>;
+				interrupts = <17 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 17 0>;
+				ti,x-plate-ohms = /bits/ 16 <100>;
+				ti,pressure-max = /bits/ 16 <255>;
+			};
+		};
+	};
+	__overrides__ {
+		speed =		<&hy28a>,"spi-max-frequency:0";
+		rotate =	<&hy28a>,"rotate:0";
+		fps =		<&hy28a>,"fps:0";
+		debug =		<&hy28a>,"debug:0";
+		xohms =		<&hy28a_ts>,"ti,x-plate-ohms;0";
+		resetgpio =	<&hy28a>,"reset-gpios:4",
+				<&hy28a_pins>, "brcm,pins:4";
+		ledgpio =	<&hy28a>,"led-gpios:4",
+				<&hy28a_pins>, "brcm,pins:8";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for HY28b display shield by Texy.
+ * Modified for 2017 version with ILI9325 D chip
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			hy28b_pins: hy28b_pins {
+				brcm,pins = <17 25 18>;
+				brcm,function = <0 1 1>; /* in out out */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			hy28b: hy28b@0{
+				compatible = "ilitek,ili9325";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&hy28b_pins>;
+
+				spi-max-frequency = <48000000>;
+				spi-cpol;
+				spi-cpha;
+				rotate = <270>;
+				bgr;
+				fps = <50>;
+				buswidth = <8>;
+				startbyte = <0x70>;
+				reset-gpios = <&gpio 25 1>;
+				led-gpios = <&gpio 18 1>;
+
+				init = <0x10000e5 0x78F0
+					0x1000001 0x0100
+					0x1000002 0x0700
+				        0x1000003 0x1030
+					0x1000004 0x0000
+					0x1000008 0x0207
+					0x1000009 0x0000
+				        0x100000a 0x0000
+					0x100000c 0x0000
+					0x100000d 0x0000
+					0x100000f 0x0000
+				        0x1000010 0x0000
+					0x1000011 0x0007
+					0x1000012 0x0000
+					0x1000013 0x0000
+					0x1000007 0x0001
+				        0x2000032
+				        0x2000032
+				        0x2000032
+				        0x2000032
+					0x1000010 0x1090
+					0x1000011 0x0227
+				        0x2000032
+					0x1000012 0x001f
+				        0x2000032
+				        0x1000013 0x1500
+					0x1000029 0x0027
+					0x100002b 0x000d
+				        0x2000032
+				        0x1000020 0x0000
+					0x1000021 0x0000
+				        0x2000032
+					0x1000030 0x0000
+					0x1000031 0x0707
+					0x1000032 0x0307
+					0x1000035 0x0200
+					0x1000036 0x0008
+					0x1000037 0x0004
+					0x1000038 0x0000
+					0x1000039 0x0707
+					0x100003c 0x0002
+					0x100003d 0x1d04
+					0x1000050 0x0000
+				        0x1000051 0x00ef
+					0x1000052 0x0000
+					0x1000053 0x013f
+					0x1000060 0xa700
+				        0x1000061 0x0001
+					0x100006a 0x0000
+					0x1000080 0x0000
+					0x1000081 0x0000
+				        0x1000082 0x0000
+					0x1000083 0x0000
+					0x1000084 0x0000
+					0x1000085 0x0000
+				        0x1000090 0x0010
+					0x1000092 0x0600
+					0x1000007 0x0133>;
+				debug = <0>;
+			};
+
+			hy28b_ts: hy28b-ts@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+
+				spi-max-frequency = <2000000>;
+				interrupts = <17 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 17 0>;
+				ti,x-plate-ohms = /bits/ 16 <100>;
+				ti,pressure-max = /bits/ 16 <255>;
+			};
+		};
+	};
+	__overrides__ {
+		speed = 	<&hy28b>,"spi-max-frequency:0";
+		rotate = 	<&hy28b>,"rotate:0";
+		fps = 		<&hy28b>,"fps:0";
+		debug = 	<&hy28b>,"debug:0";
+		xohms =		<&hy28b_ts>,"ti,x-plate-ohms;0";
+		resetgpio =	<&hy28b>,"reset-gpios:4",
+				<&hy28b_pins>, "brcm,pins:4";
+		ledgpio =	<&hy28b>,"led-gpios:4",
+				<&hy28b_pins>, "brcm,pins:8";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/hy28b-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hy28b-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/hy28b-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/hy28b-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for HY28b display shield by Texy
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			hy28b_pins: hy28b_pins {
+				brcm,pins = <17 25 18>;
+				brcm,function = <0 1 1>; /* in out out */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			hy28b: hy28b@0{
+				compatible = "ilitek,ili9325";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&hy28b_pins>;
+
+				spi-max-frequency = <48000000>;
+				spi-cpol;
+				spi-cpha;
+				rotate = <270>;
+				bgr;
+				fps = <50>;
+				buswidth = <8>;
+				startbyte = <0x70>;
+				reset-gpios = <&gpio 25 1>;
+				led-gpios = <&gpio 18 1>;
+
+				gamma = "04 1F 4 7 7 0 7 7 6 0\n0F 00 1 7 4 0 0 0 6 7";
+
+				init = <0x10000e7 0x0010
+					0x1000000 0x0001
+					0x1000001 0x0100
+					0x1000002 0x0700
+				        0x1000003 0x1030
+					0x1000004 0x0000
+					0x1000008 0x0207
+					0x1000009 0x0000
+				        0x100000a 0x0000
+					0x100000c 0x0001
+					0x100000d 0x0000
+					0x100000f 0x0000
+				        0x1000010 0x0000
+					0x1000011 0x0007
+					0x1000012 0x0000
+					0x1000013 0x0000
+				        0x2000032
+					0x1000010 0x1590
+					0x1000011 0x0227
+				        0x2000032
+					0x1000012 0x009c
+				        0x2000032
+				        0x1000013 0x1900
+					0x1000029 0x0023
+					0x100002b 0x000e
+				        0x2000032
+				        0x1000020 0x0000
+					0x1000021 0x0000
+				        0x2000032
+					0x1000050 0x0000
+				        0x1000051 0x00ef
+					0x1000052 0x0000
+					0x1000053 0x013f
+					0x1000060 0xa700
+				        0x1000061 0x0001
+					0x100006a 0x0000
+					0x1000080 0x0000
+					0x1000081 0x0000
+				        0x1000082 0x0000
+					0x1000083 0x0000
+					0x1000084 0x0000
+					0x1000085 0x0000
+				        0x1000090 0x0010
+					0x1000092 0x0000
+					0x1000093 0x0003
+					0x1000095 0x0110
+				        0x1000097 0x0000
+					0x1000098 0x0000
+					0x1000007 0x0133
+					0x1000020 0x0000
+				        0x1000021 0x0000
+				        0x2000064>;
+				debug = <0>;
+			};
+
+			hy28b_ts: hy28b-ts@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+
+				spi-max-frequency = <2000000>;
+				interrupts = <17 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 17 0>;
+				ti,x-plate-ohms = /bits/ 16 <100>;
+				ti,pressure-max = /bits/ 16 <255>;
+			};
+		};
+	};
+	__overrides__ {
+		speed = 	<&hy28b>,"spi-max-frequency:0";
+		rotate = 	<&hy28b>,"rotate:0";
+		fps = 		<&hy28b>,"fps:0";
+		debug = 	<&hy28b>,"debug:0";
+		xohms =		<&hy28b_ts>,"ti,x-plate-ohms;0";
+		resetgpio =	<&hy28b>,"reset-gpios:4",
+				<&hy28b_pins>, "brcm,pins:4";
+		ledgpio =	<&hy28b>,"led-gpios:4",
+				<&hy28b_pins>, "brcm,pins:8";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c0-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c0-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c0-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c0-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c0_pins>;
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c0_pins>;
+		pins1: __overlay__ {
+			brcm,pins = <0 1>;
+			brcm,function = <4>; /* alt0 */
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0_pins>;
+		pins2: __dormant__ {
+			brcm,pins = <28 29>;
+			brcm,function = <4>; /* alt0 */
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c0_pins>;
+		pins3: __dormant__ {
+			brcm,pins = <44 45>;
+			brcm,function = <5>; /* alt1 */
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c0_pins>;
+		pins4: __dormant__ {
+			brcm,pins = <46 47>;
+			brcm,function = <4>; /* alt0 */
+		};
+	};
+
+	fragment@5 {
+		target = <&i2c0>;
+		__dormant__ {
+			compatible = "brcm,bcm2708-i2c";
+		};
+	};
+
+	fragment@6 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@7 {
+		target-path = "/aliases";
+		__overlay__ {
+			i2c0 = "/soc/i2c@7e205000";
+		};
+	};
+
+	fragment@8 {
+		target-path = "/__symbols__";
+		__overlay__ {
+			i2c0 = "/soc/i2c@7e205000";
+		};
+	};
+
+	__overrides__ {
+		pins_0_1   = <0>,"+1-2-3-4";
+		pins_28_29 = <0>,"-1+2-3-4";
+		pins_44_45 = <0>,"-1-2+3-4";
+		pins_46_47 = <0>,"-1-2-3+4";
+		combine = <0>, "!5";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c1-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c1-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c1-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c1-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c1>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c1_pins>;
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1_pins>;
+		pins1: __overlay__ {
+			brcm,pins = <2 3>;
+			brcm,function = <4>; /* alt 0 */
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1_pins>;
+		pins2: __dormant__ {
+			brcm,pins = <44 45>;
+			brcm,function = <6>; /* alt 2 */
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c1>;
+		__dormant__ {
+			compatible = "brcm,bcm2708-i2c";
+		};
+	};
+
+	__overrides__ {
+		pins_2_3   = <0>,"=1!2";
+		pins_44_45 = <0>,"!1=2";
+		combine = <0>, "!3";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c3-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c3-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c3-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c3-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&i2c3>;
+		frag0: __overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c3_pins>;
+			clock-frequency = <100000>;
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c3_pins>;
+		__dormant__ {
+			brcm,pins = <2 3>;
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c3_pins>;
+		__overlay__ {
+			brcm,pins = <4 5>;
+		};
+	};
+
+	__overrides__ {
+		pins_2_3 = <0>,"=1!2";
+		pins_4_5 = <0>,"!1=2";
+		baudrate = <&frag0>, "clock-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c4-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c4-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c4-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c4-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&i2c4>;
+		frag0: __overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c4_pins>;
+			clock-frequency = <100000>;
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c4_pins>;
+		__dormant__ {
+			brcm,pins = <6 7>;
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c4_pins>;
+		__overlay__ {
+			brcm,pins = <8 9>;
+		};
+	};
+
+	__overrides__ {
+		pins_6_7 = <0>,"=1!2";
+		pins_8_9 = <0>,"!1=2";
+		baudrate = <&frag0>, "clock-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c5-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c5-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c5-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c5-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&i2c5>;
+		frag0: __overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c5_pins>;
+			clock-frequency = <100000>;
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c5_pins>;
+		__dormant__ {
+			brcm,pins = <10 11>;
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c5_pins>;
+		__overlay__ {
+			brcm,pins = <12 13>;
+		};
+	};
+
+	__overrides__ {
+		pins_10_11 = <0>,"=1!2";
+		pins_12_13 = <0>,"!1=2";
+		baudrate = <&frag0>, "clock-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c6-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c6-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c6-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c6-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&i2c6>;
+		frag0: __overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c6_pins>;
+			clock-frequency = <100000>;
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c6_pins>;
+		__dormant__ {
+			brcm,pins = <0 1>;
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c6_pins>;
+		__overlay__ {
+			brcm,pins = <22 23>;
+		};
+	};
+
+	__overrides__ {
+		pins_0_1 = <0>,"=1!2";
+		pins_22_23 = <0>,"!1=2";
+		baudrate = <&frag0>, "clock-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__overlay__ {
+			compatible = "brcm,bcm2708-i2c";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for i2c_gpio bitbanging host bus.
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+
+		__overlay__ {
+			i2c_gpio: i2c@0 {
+				reg = <0xffffffff>;
+				compatible = "i2c-gpio";
+				gpios = <&gpio 23 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) /* sda */
+					 &gpio 24 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) /* scl */
+					>;
+				i2c-gpio,delay-us = <2>;        /* ~100 kHz */
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/aliases";
+		__overlay__ {
+			i2c_gpio = "/i2c@0";
+		};
+	};
+
+	fragment@2 {
+		target-path = "/__symbols__";
+		__overlay__ {
+			i2c_gpio = "/i2c@0";
+		};
+	};
+
+	__overrides__ {
+		i2c_gpio_sda = <&i2c_gpio>,"gpios:4";
+		i2c_gpio_scl = <&i2c_gpio>,"gpios:16";
+		i2c_gpio_delay_us = <&i2c_gpio>,"i2c-gpio,delay-us:0";
+		bus = <&i2c_gpio>, "reg:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Umbrella I2C Mux overlay
+
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pca9542: mux@70 {
+				compatible = "nxp,pca9542";
+				reg = <0x70>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				i2c@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+				};
+				i2c@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pca9545: mux@70 {
+				compatible = "nxp,pca9545";
+				reg = <0x70>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				i2c@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+				};
+				i2c@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+				};
+				i2c@2 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <2>;
+				};
+				i2c@3 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <3>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pca9548: mux@70 {
+				compatible = "nxp,pca9548";
+				reg = <0x70>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				i2c@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+				};
+				i2c@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+				};
+				i2c@2 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <2>;
+				};
+				i2c@3 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <3>;
+				};
+				i2c@4 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <4>;
+				};
+				i2c@5 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <5>;
+				};
+				i2c@6 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <6>;
+				};
+				i2c@7 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <7>;
+				};
+			};
+		};
+	};
+
+	__overrides__ {
+		pca9542 = <0>, "+0";
+		pca9545 = <0>, "+1";
+		pca9548 = <0>, "+2";
+
+		addr =  <&pca9542>,"reg:0",
+			<&pca9545>,"reg:0",
+			<&pca9548>,"reg:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for NXP PCA9685A I2C PWM controller on ARM I2C bus.
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pca: pca@40 {
+				compatible = "nxp,pca9685-pwm";
+				#pwm-cells = <2>;
+				reg = <0x40>;
+				status = "okay";
+			};
+		};
+	};
+	__overrides__ {
+		addr = <&pca>,"reg:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for several I2C based Real Time Clocks
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			abx80x: abx80x@69 {
+				compatible = "abracon,abx80x";
+				reg = <0x69>;
+				abracon,tc-diode = "standard";
+				abracon,tc-resistor = <0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ds1307: ds1307@68 {
+				compatible = "dallas,ds1307";
+				reg = <0x68>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ds1339: ds1339@68 {
+				compatible = "dallas,ds1339";
+				trickle-resistor-ohms = <0>;
+				reg = <0x68>;
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ds3231: ds3231@68 {
+				compatible = "maxim,ds3231";
+				reg = <0x68>;
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp7940x: mcp7940x@6f {
+				compatible = "microchip,mcp7940x";
+				reg = <0x6f>;
+			};
+		};
+	};
+
+	fragment@5 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp7941x: mcp7941x@6f {
+				compatible = "microchip,mcp7941x";
+				reg = <0x6f>;
+			};
+		};
+	};
+
+	fragment@6 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pcf2127@51 {
+				compatible = "nxp,pcf2127";
+				reg = <0x51>;
+			};
+		};
+	};
+
+	fragment@7 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pcf8523: pcf8523@68 {
+				compatible = "nxp,pcf8523";
+				reg = <0x68>;
+			};
+		};
+	};
+
+	fragment@8 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pcf8563: pcf8563@51 {
+				compatible = "nxp,pcf8563";
+				reg = <0x51>;
+			};
+		};
+	};
+
+	fragment@9 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			m41t62: m41t62@68 {
+				compatible = "st,m41t62";
+				reg = <0x68>;
+			};
+		};
+	};
+
+	fragment@10 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			rv3028: rv3028@52 {
+				compatible = "microcrystal,rv3028";
+				reg = <0x52>;
+			};
+		};
+	};
+
+	fragment@11 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pcf2129@51 {
+				compatible = "nxp,pcf2129";
+				reg = <0x51>;
+			};
+		};
+	};
+
+	fragment@12 {
+		target = <&i2cbus>;
+	       __dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pcf85363@51 {
+				compatible = "nxp,pcf85363";
+				reg = <0x51>;
+			};
+		};
+	};
+
+	fragment@13 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			rv1805: rv1805@69 {
+				compatible = "microcrystal,rv1805";
+				reg = <0x69>;
+				abracon,tc-diode = "standard";
+				abracon,tc-resistor = <0>;
+			};
+		};
+	};
+
+	fragment@14 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sd3078: sd3078@32 {
+				compatible = "whwave,sd3078";
+				reg = <0x32>;
+			};
+		};
+	};
+
+	fragment@15 {
+		target = <&i2cbus>;
+	       __dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pcf85063@51 {
+				compatible = "nxp,pcf85063";
+				reg = <0x51>;
+			};
+		};
+	};
+
+	fragment@16 {
+		target = <&i2cbus>;
+	       __dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pcf85063a@51 {
+				compatible = "nxp,pcf85063a";
+				reg = <0x51>;
+			};
+		};
+	};
+
+	fragment@17 {
+		target = <&i2cbus>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ds1340: ds1340@68 {
+				compatible = "dallas,ds1340";
+				trickle-resistor-ohms = <0>;
+				reg = <0x68>;
+			};
+		};
+	};
+
+	__overrides__ {
+		abx80x = <0>,"+0";
+		ds1307 = <0>,"+1";
+		ds1339 = <0>,"+2";
+		ds1340 = <0>,"+17";
+		ds3231 = <0>,"+3";
+		mcp7940x = <0>,"+4";
+		mcp7941x = <0>,"+5";
+		pcf2127 = <0>,"+6";
+		pcf8523 = <0>,"+7";
+		pcf8563 = <0>,"+8";
+		m41t62 = <0>,"+9";
+		rv3028 = <0>,"+10";
+		pcf2129 = <0>,"+11";
+		pcf85363 = <0>,"+12";
+		rv1805 = <0>,"+13";
+		sd3078 = <0>,"+14";
+		pcf85063 = <0>,"+15";
+		pcf85063a = <0>,"+16";
+
+		addr = <&abx80x>, "reg:0",
+		       <&ds1307>, "reg:0",
+		       <&ds1339>, "reg:0",
+		       <&ds3231>, "reg:0",
+		       <&mcp7940x>, "reg:0",
+		       <&mcp7941x>, "reg:0",
+		       <&pcf8523>, "reg:0",
+		       <&pcf8563>, "reg:0",
+		       <&m41t62>, "reg:0",
+		       <&rv1805>, "reg:0";
+		trickle-diode-type = <&abx80x>,"abracon,tc-diode",
+				     <&rv1805>,"abracon,tc-diode";
+		trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0",
+					<&ds1340>,"trickle-resistor-ohms:0",
+					<&abx80x>,"abracon,tc-resistor:0",
+					<&rv3028>,"trickle-resistor-ohms:0",
+					<&rv1805>,"abracon,tc-resistor:0";
+		backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0";
+		wakeup-source = <&ds1339>,"wakeup-source?",
+				<&ds3231>,"wakeup-source?",
+				<&mcp7940x>,"wakeup-source?",
+				<&mcp7941x>,"wakeup-source?",
+				<&m41t62>,"wakeup-source?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for several I2C based Real Time Clocks
+// Available through i2c-gpio
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "i2c-rtc-common.dtsi"
+
+/ {
+	fragment@100 {
+		target-path = "/";
+		__overlay__ {
+			i2cbus: i2c-gpio-rtc@0 {
+				compatible = "i2c-gpio";
+				gpios = <&gpio 23 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) /* sda */
+					 &gpio 24 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) /* scl */
+					>;
+				i2c-gpio,delay-us = <2>;        /* ~100 kHz */
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+	};
+
+	__overrides__ {
+		i2c_gpio_sda = <&i2cbus>,"gpios:4";
+		i2c_gpio_scl = <&i2cbus>,"gpios:16";
+		i2c_gpio_delay_us = <&i2cbus>,"i2c-gpio,delay-us:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for several I2C based Real Time Clocks
+/dts-v1/;
+/plugin/;
+
+#include "i2c-rtc-common.dtsi"
+
+/ {
+	frag100: fragment@100 {
+		target = <&i2c_arm>;
+		i2cbus: __overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@101 {
+		target = <&i2c0if>;
+		__dormant__ {
+			status = "okay";
+		};
+	};
+
+	fragment@102 {
+		target = <&i2c0mux>;
+		__dormant__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		i2c0 = <&frag100>, "target:0=",<&i2c0>;
+		i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>,
+			      <0>,"+101+102";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for I2C based sensors using the Industrial IO or HWMON interface.
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			bme280: bme280@76 {
+				compatible = "bosch,bme280";
+				reg = <0x76>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			bmp085: bmp085@77 {
+				compatible = "bosch,bmp085";
+				reg = <0x77>;
+				default-oversampling = <3>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			bmp180: bmp180@77 {
+				compatible = "bosch,bmp180";
+				reg = <0x77>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			bmp280: bmp280@76 {
+				compatible = "bosch,bmp280";
+				reg = <0x76>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			htu21: htu21@40 {
+				compatible = "htu21";
+				reg = <0x40>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@5 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			lm75: lm75@4f {
+				compatible = "lm75";
+				reg = <0x4f>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@6 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			si7020: si7020@40 {
+				compatible = "si7020";
+				reg = <0x40>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@7 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			tmp102: tmp102@48 {
+				compatible = "ti,tmp102";
+				reg = <0x48>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@8 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			hdc100x: hdc100x@40 {
+				compatible = "hdc100x";
+				reg = <0x40>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@9 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			tsl4531: tsl4531@29 {
+				compatible = "tsl4531";
+				reg = <0x29>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@10 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			veml6070: veml6070@38 {
+				compatible = "veml6070";
+				reg = <0x38>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@11 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			sht3x: sht3x@44 {
+				compatible = "sht3x";
+				reg = <0x44>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@12 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ds1621: ds1621@48 {
+				compatible = "ds1621";
+				reg = <0x48>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@13 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			max17040: max17040@36 {
+				compatible = "maxim,max17040";
+				reg = <0x36>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@14 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			bme680: bme680@76 {
+				compatible = "bosch,bme680";
+				reg = <0x76>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@15 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			sps30: sps30@69 {
+				compatible = "sensirion,sps30";
+				reg = <0x69>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@16 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			sgp30: sgp30@58 {
+				compatible = "sensirion,sgp30";
+				reg = <0x58>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@17 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ccs811: ccs811@5b {
+				compatible = "ccs811";
+				reg = <0x5b>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@18 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			bh1750: bh1750@23 {
+				compatible = "bh1750";
+				reg = <0x23>;
+				status = "okay";
+			};
+		};
+	};
+
+	__overrides__ {
+		addr =  <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0",
+			<&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0",
+			<&ds1621>,"reg:0", <&bme680>,"reg:0", <&ccs811>,"reg:0",
+			<&bh1750>,"reg:0";
+		bme280 = <0>,"+0";
+		bmp085 = <0>,"+1";
+		bmp180 = <0>,"+2";
+		bmp280 = <0>,"+3";
+		htu21 = <0>,"+4";
+		lm75 = <0>,"+5";
+		lm75addr = <&lm75>,"reg:0";
+		si7020 = <0>,"+6";
+		tmp102 = <0>,"+7";
+		hdc100x = <0>,"+8";
+		tsl4531 = <0>,"+9";
+		veml6070 = <0>,"+10";
+		sht3x = <0>,"+11";
+		ds1621 = <0>,"+12";
+		max17040 = <0>,"+13";
+		bme680 = <0>,"+14";
+		sps30 = <0>,"+15";
+		sgp30 = <0>,"+16";
+		ccs811 = <0>, "+17";
+		bh1750 = <0>, "+18";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device tree overlay to move i2s to gpio 28 to 31 on CM
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s_pins>;
+		__overlay__ {
+			brcm,pins = <28 29 30 31>;
+			brcm,function = <6>; /* alt2 */
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Device tree overlay for I2C connected Ilitek multiple touch controller
+/dts-v1/;
+/plugin/;
+
+ / {
+	compatible = "brcm,bcm2835";
+
+ 	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {		
+			ili251x_pins: ili251x_pins {
+				brcm,pins = <4>; // interrupt
+				brcm,function = <0>; // in
+				brcm,pull = <2>; // pull-up //
+			};
+		};
+	};
+
+ 	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+ 			ili251x: ili251x@41 {
+				compatible = "ilitek,ili251x";
+				reg = <0x41>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&ili251x_pins>;
+				interrupt-parent = <&gpio>;
+				interrupts = <4 8>; // high-to-low edge triggered
+				touchscreen-size-x = <16384>;
+				touchscreen-size-y = <9600>;
+			};
+		};
+	};
+
+ 	__overrides__ {
+		interrupt = <&ili251x_pins>,"brcm,pins:0",
+			<&ili251x>,"interrupts:0";
+		sizex = <&ili251x>,"touchscreen-size-x:0";
+		sizey = <&ili251x>,"touchscreen-size-y:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx219-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx219-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx219-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx219-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for IMX219 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			imx219: imx219@10 {
+				compatible = "sony,imx219";
+				reg = <0x10>;
+				status = "okay";
+
+				clocks = <&imx219_clk>;
+				clock-names = "xclk";
+
+				VANA-supply = <&cam1_reg>;	/* 2.8v */
+				VDIG-supply = <&imx219_vdig>;	/* 1.8v */
+				VDDL-supply = <&imx219_vddl>;	/* 1.2v */
+
+				rotation = <180>;
+
+				port {
+					imx219_0: endpoint {
+						remote-endpoint = <&csi1_ep>;
+						clock-lanes = <0>;
+						data-lanes = <1 2>;
+						clock-noncontinuous;
+						link-frequencies =
+							/bits/ 64 <456000000>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&csi1>;
+		__overlay__ {
+			status = "okay";
+
+			port {
+				csi1_ep: endpoint {
+					remote-endpoint = <&imx219_0>;
+					clock-lanes = <0>;
+					data-lanes = <1 2>;
+					clock-noncontinuous;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target-path="/";
+		__overlay__ {
+			imx219_vdig: fixedregulator@1 {
+				compatible = "regulator-fixed";
+				regulator-name = "imx219_vdig";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			imx219_vddl: fixedregulator@2 {
+				compatible = "regulator-fixed";
+				regulator-name = "imx219_vddl";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+
+			imx219_clk: camera-clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <24000000>;
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&cam1_reg>;
+		__overlay__ {
+			status = "okay";
+			regulator-name = "imx219_vana";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+		};
+	};
+
+	__overrides__ {
+		rotation = <&imx219>,"rotation:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Partial definitions for IMX290 or IMX327 camera module on VC I2C bus
+// The compatible string should be set in an overlay that then includes this one
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			imx290: imx290@1a {
+				reg = <0x1a>;
+				status = "okay";
+
+				clocks = <&imx290_clk>;
+				clock-names = "xclk";
+				clock-frequency = <37125000>;
+
+				vdda-supply = <&cam1_reg>;	/* 2.8v */
+				vdddo-supply = <&imx290_vdddo>;	/* 1.8v */
+				vddd-supply = <&imx290_vddd>;	/* 1.5v */
+
+				port {
+					imx290_0: endpoint {
+						remote-endpoint = <&csi1_ep>;
+						clock-lanes = <0>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&csi1>;
+		__overlay__ {
+			status = "okay";
+
+			port {
+				csi1_ep: endpoint {
+					remote-endpoint = <&imx290_0>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target-path="/";
+		__overlay__ {
+			imx290_vdddo: fixedregulator@1 {
+				compatible = "regulator-fixed";
+				regulator-name = "imx290_vdddo";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			imx290_vddd: fixedregulator@2 {
+				compatible = "regulator-fixed";
+				regulator-name = "imx290_vddd";
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <1500000>;
+			};
+
+			imx290_clk: camera-clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <37125000>;
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&cam1_reg>;
+		__overlay__ {
+			status = "okay";
+			regulator-name = "imx290_vdda";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+		};
+	};
+
+	fragment@6 {
+		target = <&imx290_0>;
+		__overlay__ {
+			data-lanes = <1 2>;
+			link-frequencies =
+				/bits/ 64 <445500000 297000000>;
+		};
+	};
+
+	fragment@7 {
+		target = <&imx290_0>;
+		__dormant__ {
+			data-lanes = <1 2 3 4>;
+			link-frequencies =
+				/bits/ 64 <222750000 148500000>;
+		};
+	};
+
+	fragment@8 {
+		target = <&csi1_ep>;
+		__overlay__ {
+			data-lanes = <1 2>;
+		};
+	};
+
+	fragment@9 {
+		target = <&csi1_ep>;
+		__dormant__ {
+			data-lanes = <1 2 3 4>;
+		};
+	};
+
+	__overrides__ {
+		4lane = <0>, "-6+7-8+9";
+		clock-frequency = <&imx290_clk>,"clock-frequency:0",
+				  <&imx290>,"clock-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx290-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx290-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx290-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx290-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for IMX290 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "imx290_327-overlay.dtsi"
+
+/{
+	compatible = "brcm,bcm2835";
+
+	// Fragment numbers deliberately high to avoid conflicts with the
+	// included imx290_327 overlay file.
+
+	fragment@101 {
+		target = <&imx290>;
+		__overlay__ {
+			compatible = "sony,imx290";
+		};
+	};
+
+	fragment@102 {
+		target = <&imx290>;
+		__dormant__ {
+			compatible = "sony,imx290-mono";
+		};
+	};
+
+	__overrides__ {
+		mono = <0>, "-101+102";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx378-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx378-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx378-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx378-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for IMX378 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+#include "imx477_378-overlay.dtsi"
+
+&imx477 {
+	compatible = "sony,imx378";
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for IMX477 camera module on VC I2C bus
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			imx477: imx477@1a {
+				reg = <0x1a>;
+				status = "okay";
+
+				clocks = <&imx477_clk>;
+				clock-names = "xclk";
+
+				VANA-supply = <&cam1_reg>;	/* 2.8v */
+				VDIG-supply = <&imx477_vdig>;	/* 1.05v */
+				VDDL-supply = <&imx477_vddl>;	/* 1.8v */
+
+				rotation = <180>;
+
+				port {
+					imx477_0: endpoint {
+						remote-endpoint = <&csi1_ep>;
+						clock-lanes = <0>;
+						data-lanes = <1 2>;
+						clock-noncontinuous;
+						link-frequencies =
+							/bits/ 64 <450000000>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&csi1>;
+		__overlay__ {
+			status = "okay";
+
+			port {
+				csi1_ep: endpoint {
+					remote-endpoint = <&imx477_0>;
+					clock-lanes = <0>;
+					data-lanes = <1 2>;
+					clock-noncontinuous;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target-path="/";
+		__overlay__ {
+			imx477_vdig: fixedregulator@0 {
+				compatible = "regulator-fixed";
+				regulator-name = "imx477_vdig";
+				regulator-min-microvolt = <1050000>;
+				regulator-max-microvolt = <1050000>;
+			};
+			imx477_vddl: fixedregulator@1 {
+				compatible = "regulator-fixed";
+				regulator-name = "imx477_vddl";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			imx477_clk: camera-clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <24000000>;
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&cam1_reg>;
+		__overlay__ {
+			status = "okay";
+			regulator-name = "imx477_vana";
+			startup-delay-us = <300000>;
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+		};
+	};
+
+	__overrides__ {
+		rotation = <&imx477>,"rotation:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx477-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx477-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/imx477-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/imx477-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for IMX477 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+#include "imx477_378-overlay.dtsi"
+
+&imx477 {
+	compatible = "sony,imx477";
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for IQaudIO CODEC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			da2713@1a {
+				#sound-dai-cells = <0>;
+				compatible = "dlg,da7213";
+				reg = <0x1a>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		iqaudio_dac: __overlay__ {
+			compatible = "iqaudio,iqaudio-codec";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for IQaudIO DAC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4c>;
+				AVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		frag2: __overlay__ {
+			compatible = "iqaudio,iqaudio-dac";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain = <&frag2>,"iqaudio,24db_digital_gain?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for IQaudIO DAC+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4c>;
+				AVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		iqaudio_dac: __overlay__ {
+			compatible = "iqaudio,iqaudio-dac";
+			i2s-controller = <&i2s>;
+			mute-gpios = <&gpio 22 0>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain = <&iqaudio_dac>,"iqaudio,24db_digital_gain?";
+		auto_mute_amp = <&iqaudio_dac>,"iqaudio-dac,auto-mute-amp?";
+		unmute_amp = <&iqaudio_dac>,"iqaudio-dac,unmute-amp?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for IQAudIO Digi WM8804 audio board
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8804@3b {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8804";
+				reg = <0x3b>;
+				status = "okay";
+				DVDD-supply = <&vdd_3v3_reg>;
+				PVDD-supply = <&vdd_3v3_reg>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		wm8804_digi: __overlay__ {
+			compatible = "iqaudio,wm8804-digi";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		card_name = <&wm8804_digi>,"wm8804-digi,card-name";
+		dai_name = <&wm8804_digi>,"wm8804-digi,dai-name";
+		dai_stream_name = <&wm8804_digi>,"wm8804-digi,dai-stream-name";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/irs1125-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/irs1125-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/irs1125-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/irs1125-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for IRS1125 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			irs1125: irs1125@3D {
+				compatible = "infineon,irs1125";
+				reg = <0x3D>;
+				status = "okay";
+
+				pwdn-gpios = <&gpio 5 0>;
+				clocks = <&irs1125_clk>;
+
+				port {
+					irs1125_0: endpoint {
+						remote-endpoint = <&csi1_ep>;
+						clock-lanes = <0>;
+						data-lanes = <1 2>;
+						clock-noncontinuous;
+						link-frequencies =
+							/bits/ 64 <297000000>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&csi1>;
+		__overlay__ {
+			status = "okay";
+
+			port {
+				csi1_ep: endpoint {
+					remote-endpoint = <&irs1125_0>;
+					data-lanes = <1 2>;
+					clock-noncontinuous;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target-path="/__overrides__";
+		__overlay__ {
+			cam0-pwdn-ctrl = <&irs1125>,"pwdn-gpios:0";
+			cam0-pwdn      = <&irs1125>,"pwdn-gpios:4";
+		};
+	};
+
+	fragment@5 {
+		target-path = "/";
+		__overlay__ {
+			irs1125_clk: camera-clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <26000000>;
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for I-Sabre Q2M
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&sound>;
+		frag0: __overlay__ {
+			compatible = "audiophonics,i-sabre-q2m";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			i-sabre-codec@48 {
+				#sound-dai-cells = <0>;
+				compatible = "audiophonics,i-sabre-codec";
+				reg = <0x48>;
+				status = "okay";
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for JEDEC SPI-NOR Flash Devices (aka m25p80)
+
+// dtparams:
+//     flash-spi<n>-<m>        - Enables flash device on SPI<n>, CS#<m>.
+//     flash-fastr-spi<n>-<m>  - Enables flash device with fast read capability on SPI<n>, CS#<m>.
+//
+// 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.
+//
+// Example: A single flash device with fast read capability on SPI0, CS#0:
+// dtoverlay=jedec-spi-nor:flash-fastr-spi0-0
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	// disable spi-dev on spi0.0
+	fragment@0 {
+		target = <&spidev0>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi0.1
+	fragment@1 {
+		target = <&spidev1>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi1.0
+	fragment@2 {
+		target-path = "spi1/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi1.1
+	fragment@3 {
+		target-path = "spi1/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi1.2
+	fragment@4 {
+		target-path = "spi1/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi2.0
+	fragment@5 {
+		target-path = "spi2/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi2.1
+	fragment@6 {
+		target-path = "spi2/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi2.2
+	fragment@7 {
+		target-path = "spi2/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// enable flash on spi0.0
+	fragment@8 {
+		target = <&spi0>;
+		__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>;
+			};
+		};
+	};
+
+	// enable flash on spi0.1
+	fragment@9 {
+		target = <&spi0>;
+		__dormant__ {
+			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>;
+			};
+		};
+	};
+
+	// 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>;
+				compatible = "jedec,spi-nor";
+				reg = <0>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	// 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";
+	};
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/justboom-both-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/justboom-both-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/justboom-both-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/justboom-both-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+// Definitions for JustBoom Both (Digi+DAC)
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8804@3b {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8804";
+				reg = <0x3b>;
+				PVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4d {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4d>;
+				AVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		frag3: __overlay__ {
+			compatible = "justboom,justboom-both";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain = <&frag3>,"justboom,24db_digital_gain?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for JustBoom DAC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4d {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4d>;
+				AVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		frag2: __overlay__ {
+			compatible = "justboom,justboom-dac";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		24db_digital_gain = <&frag2>,"justboom,24db_digital_gain?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for JustBoom Digi
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8804@3b {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8804";
+				reg = <0x3b>;
+				PVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "justboom,justboom-digi";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ltc294x-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ltc294x-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ltc294x-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ltc294x-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ltc2941: ltc2941@64 {
+				compatible = "lltc,ltc2941";
+				reg = <0x64>;
+				lltc,resistor-sense = <50>;
+				lltc,prescaler-exponent = <7>; 
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ltc2942: ltc2942@64 {
+				compatible = "lltc,ltc2942";
+				reg = <0x64>;
+				lltc,resistor-sense = <50>;
+				lltc,prescaler-exponent = <7>; 
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ltc2943: ltc2943@64 {
+				compatible = "lltc,ltc2943";
+				reg = <0x64>;
+				lltc,resistor-sense = <50>;
+				lltc,prescaler-exponent = <7>; 
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c_arm>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ltc2944: ltc2944@64 {
+				compatible = "lltc,ltc2944";
+				reg = <0x64>;
+				lltc,resistor-sense = <50>;
+				lltc,prescaler-exponent = <7>; 
+			};
+		};
+	};
+
+	__overrides__ {
+		ltc2941 = <0>,"+0";
+		ltc2942 = <0>,"+1";
+		ltc2943 = <0>,"+2";
+		ltc2944 = <0>,"+3";
+		resistor-sense = <&ltc2941>, "lltc,resistor-sense:0",
+			         <&ltc2942>, "lltc,resistor-sense:0",
+				 <&ltc2943>, "lltc,resistor-sense:0",
+				 <&ltc2944>, "lltc,resistor-sense:0";
+		prescaler-exponent = <&ltc2941>, "lltc,prescaler-exponent:0",
+			         <&ltc2942>, "lltc,prescaler-exponent:0",
+				 <&ltc2943>, "lltc,prescaler-exponent:0",
+				 <&ltc2944>, "lltc,prescaler-exponent:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/Makefile linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/Makefile
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/Makefile	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# Overlays for the Raspberry Pi platform
+
+dtb-$(CONFIG_ARCH_BCM2835) += overlay_map.dtb
+
+dtbo-$(CONFIG_ARCH_BCM2835) += \
+	act-led.dtbo \
+	adafruit18.dtbo \
+	adau1977-adc.dtbo \
+	adau7002-simple.dtbo \
+	ads1015.dtbo \
+	ads1115.dtbo \
+	ads7846.dtbo \
+	adv7282m.dtbo \
+	adv728x-m.dtbo \
+	akkordion-iqdacplus.dtbo \
+	allo-boss-dac-pcm512x-audio.dtbo \
+	allo-boss2-dac-audio.dtbo \
+	allo-digione.dtbo \
+	allo-katana-dac-audio.dtbo \
+	allo-piano-dac-pcm512x-audio.dtbo \
+	allo-piano-dac-plus-pcm512x-audio.dtbo \
+	anyspi.dtbo \
+	apds9960.dtbo \
+	applepi-dac.dtbo \
+	at86rf233.dtbo \
+	audioinjector-addons.dtbo \
+	audioinjector-isolated-soundcard.dtbo \
+	audioinjector-ultra.dtbo \
+	audioinjector-wm8731-audio.dtbo \
+	audiosense-pi.dtbo \
+	audremap.dtbo \
+	balena-fin.dtbo \
+	cap1106.dtbo \
+	chipdip-i2s-master-dac.dtbo \
+	cma.dtbo \
+	dht11.dtbo \
+	dionaudio-loco.dtbo \
+	dionaudio-loco-v2.dtbo \
+	disable-bt.dtbo \
+	disable-wifi.dtbo \
+	dpi18.dtbo \
+	dpi18cpadhi.dtbo \
+	dpi24.dtbo \
+	draws.dtbo \
+	dwc-otg.dtbo \
+	dwc2.dtbo \
+	edt-ft5406.dtbo \
+	enc28j60.dtbo \
+	enc28j60-spi2.dtbo \
+	exc3000.dtbo \
+	fe-pi-audio.dtbo \
+	fsm-demo.dtbo \
+	ghost-amp.dtbo \
+	goodix.dtbo \
+	googlevoicehat-soundcard.dtbo \
+	gpio-fan.dtbo \
+	gpio-ir.dtbo \
+	gpio-ir-tx.dtbo \
+	gpio-key.dtbo \
+	gpio-led.dtbo \
+	gpio-no-bank0-irq.dtbo \
+	gpio-no-irq.dtbo \
+	gpio-poweroff.dtbo \
+	gpio-shutdown.dtbo \
+	hd44780-lcd.dtbo \
+	hdmi-backlight-hwhack-gpio.dtbo \
+	hifiberry-amp.dtbo \
+	hifiberry-amp100.dtbo \
+	hifiberry-dac.dtbo \
+	hifiberry-dacplus.dtbo \
+	hifiberry-dacplusadc.dtbo \
+	hifiberry-dacplusadcpro.dtbo \
+	hifiberry-dacplusdsp.dtbo \
+	hifiberry-dacplushd.dtbo \
+	hifiberry-digi.dtbo \
+	hifiberry-digi-pro.dtbo \
+	highperi.dtbo \
+	hy28a.dtbo \
+	hy28b.dtbo \
+	hy28b-2017.dtbo \
+	i-sabre-q2m.dtbo \
+	i2c-bcm2708.dtbo \
+	i2c-gpio.dtbo \
+	i2c-mux.dtbo \
+	i2c-pwm-pca9685a.dtbo \
+	i2c-rtc.dtbo \
+	i2c-rtc-gpio.dtbo \
+	i2c-sensor.dtbo \
+	i2c0.dtbo \
+	i2c1.dtbo \
+	i2c3.dtbo \
+	i2c4.dtbo \
+	i2c5.dtbo \
+	i2c6.dtbo \
+	i2s-gpio28-31.dtbo \
+	ilitek251x.dtbo \
+	imx219.dtbo \
+	imx290.dtbo \
+	imx378.dtbo \
+	imx477.dtbo \
+	iqaudio-codec.dtbo \
+	iqaudio-dac.dtbo \
+	iqaudio-dacplus.dtbo \
+	iqaudio-digi-wm8804-audio.dtbo \
+	irs1125.dtbo \
+	jedec-spi-nor.dtbo \
+	justboom-both.dtbo \
+	justboom-dac.dtbo \
+	justboom-digi.dtbo \
+	ltc294x.dtbo \
+	max98357a.dtbo \
+	maxtherm.dtbo \
+	mbed-dac.dtbo \
+	mcp23017.dtbo \
+	mcp23s17.dtbo \
+	mcp2515-can0.dtbo \
+	mcp2515-can1.dtbo \
+	mcp251xfd.dtbo \
+	mcp3008.dtbo \
+	mcp3202.dtbo \
+	mcp342x.dtbo \
+	media-center.dtbo \
+	merus-amp.dtbo \
+	midi-uart0.dtbo \
+	midi-uart1.dtbo \
+	minipitft13.dtbo \
+	miniuart-bt.dtbo \
+	mmc.dtbo \
+	mpu6050.dtbo \
+	mz61581.dtbo \
+	ov5647.dtbo \
+	ov7251.dtbo \
+	ov9281.dtbo \
+	papirus.dtbo \
+	pca953x.dtbo \
+	pcie-32bit-dma.dtbo \
+	pibell.dtbo \
+	pifacedigital.dtbo \
+	pifi-40.dtbo \
+	pifi-dac-hd.dtbo \
+	pifi-dac-zero.dtbo \
+	pifi-mini-210.dtbo \
+	piglow.dtbo \
+	piscreen.dtbo \
+	piscreen2r.dtbo \
+	pisound.dtbo \
+	pitft22.dtbo \
+	pitft28-capacitive.dtbo \
+	pitft28-resistive.dtbo \
+	pitft35-resistive.dtbo \
+	pps-gpio.dtbo \
+	pwm.dtbo \
+	pwm-2chan.dtbo \
+	pwm-ir-tx.dtbo \
+	qca7000.dtbo \
+	rotary-encoder.dtbo \
+	rpi-backlight.dtbo \
+	rpi-cirrus-wm5102.dtbo \
+	rpi-dac.dtbo \
+	rpi-display.dtbo \
+	rpi-ft5406.dtbo \
+	rpi-poe.dtbo \
+	rpi-poe-plus.dtbo \
+	rpi-proto.dtbo \
+	rpi-sense.dtbo \
+	rpi-tv.dtbo \
+	rpivid-v4l2.dtbo \
+	rra-digidac1-wm8741-audio.dtbo \
+	sainsmart18.dtbo \
+	sc16is750-i2c.dtbo \
+	sc16is752-i2c.dtbo \
+	sc16is752-spi0.dtbo \
+	sc16is752-spi1.dtbo \
+	sdhost.dtbo \
+	sdio.dtbo \
+	seeed-can-fd-hat-v1.dtbo \
+	seeed-can-fd-hat-v2.dtbo \
+	sh1106-spi.dtbo \
+	si446x-spi0.dtbo \
+	smi.dtbo \
+	smi-dev.dtbo \
+	smi-nand.dtbo \
+	spi-gpio35-39.dtbo \
+	spi-gpio40-45.dtbo \
+	spi-rtc.dtbo \
+	spi0-1cs.dtbo \
+	spi0-2cs.dtbo \
+	spi1-1cs.dtbo \
+	spi1-2cs.dtbo \
+	spi1-3cs.dtbo \
+	spi2-1cs.dtbo \
+	spi2-2cs.dtbo \
+	spi2-3cs.dtbo \
+	spi3-1cs.dtbo \
+	spi3-2cs.dtbo \
+	spi4-1cs.dtbo \
+	spi4-2cs.dtbo \
+	spi5-1cs.dtbo \
+	spi5-2cs.dtbo \
+	spi6-1cs.dtbo \
+	spi6-2cs.dtbo \
+	ssd1306.dtbo \
+	ssd1306-spi.dtbo \
+	ssd1331-spi.dtbo \
+	ssd1351-spi.dtbo \
+	superaudioboard.dtbo \
+	sx150x.dtbo \
+	tc358743.dtbo \
+	tc358743-audio.dtbo \
+	tinylcd35.dtbo \
+	tpm-slb9670.dtbo \
+	uart0.dtbo \
+	uart1.dtbo \
+	uart2.dtbo \
+	uart3.dtbo \
+	uart4.dtbo \
+	uart5.dtbo \
+	udrc.dtbo \
+	ugreen-dabboard.dtbo \
+	upstream.dtbo \
+	upstream-pi4.dtbo \
+	vc4-fkms-v3d.dtbo \
+	vc4-kms-dpi-at056tn53v1.dtbo \
+	vc4-kms-dsi-7inch.dtbo \
+	vc4-kms-dsi-lt070me05000.dtbo \
+	vc4-kms-dsi-lt070me05000-v2.dtbo \
+	vc4-kms-kippah-7inch.dtbo \
+	vc4-kms-v3d.dtbo \
+	vc4-kms-v3d-pi4.dtbo \
+	vc4-kms-vga666.dtbo \
+	vga666.dtbo \
+	w1-gpio.dtbo \
+	w1-gpio-pullup.dtbo \
+	w5500.dtbo \
+	wittypi.dtbo \
+	wm8960-soundcard.dtbo
+
+targets += dtbs dtbs_install
+targets += $(dtbo-y)
+
+always-y	:= $(dtbo-y)
+clean-files	:= *.dtbo
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/max98357a-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/max98357a-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/max98357a-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/max98357a-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for Maxim MAX98357A audio DAC
+
+// dtparams:
+//     no-sdmode  - SD_MODE pin not managed by driver.
+//     sdmode-pin - Specify GPIO pin to which SD_MODE is connected (default 4).
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	/* Enable I2S */
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	/* DAC whose SD_MODE pin is managed by driver (via GPIO pin) */
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			max98357a_dac: max98357a {
+				compatible = "maxim,max98357a";
+				#sound-dai-cells = <0>;
+				sdmode-gpios = <&gpio 4 0>;   /* 2nd word overwritten by sdmode-pin parameter */
+				status = "okay";
+			};
+		};
+	};
+
+	/* DAC whose SD_MODE pin is not managed by driver */
+	fragment@2 {
+		target-path = "/";
+		__dormant__ {
+			max98357a_nsd: max98357a {
+				compatible = "maxim,max98357a";
+				#sound-dai-cells = <0>;
+				status = "okay";
+			};
+		};
+	};
+
+	/* Soundcard connecting I2S to DAC with SD_MODE */
+	fragment@3 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "simple-audio-card";
+			simple-audio-card,format = "i2s";
+			simple-audio-card,name = "MAX98357A";
+			status = "okay";
+			simple-audio-card,cpu {
+				sound-dai = <&i2s>;
+			};
+			simple-audio-card,codec {
+				sound-dai = <&max98357a_dac>;
+			};
+		};
+	};
+
+	/* Soundcard connecting I2S to DAC without SD_MODE */
+	fragment@4 {
+		target = <&sound>;
+		__dormant__ {
+			compatible = "simple-audio-card";
+			simple-audio-card,format = "i2s";
+			simple-audio-card,name = "MAX98357A";
+			status = "okay";
+			simple-audio-card,cpu {
+				sound-dai = <&i2s>;
+			};
+			simple-audio-card,codec {
+				sound-dai = <&max98357a_nsd>;
+			};
+		};
+	};
+
+	__overrides__ {
+		no-sdmode  = <0>,"-1+2-3+4";
+		sdmode-pin = <&max98357a_dac>,"sdmode-gpios:4";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/maxtherm-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/maxtherm-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/maxtherm-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/maxtherm-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Universal device tree overlay for SPI devices
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/iio/temperature/thermocouple.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev1>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target-path = "spi1/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target-path = "spi1/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@4 {
+		target-path = "spi1/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@5 {
+		target-path = "spi2/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@6 {
+		target-path = "spi2/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@7 {
+		target-path = "spi2/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	maxfrag: fragment@8 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			max: maxtherm@0 {
+				compatible = "maxim,max6675";
+				reg = <0>;
+				spi-max-frequency = <500000>;
+			};
+		};
+	};
+
+	fragment@9 {
+		target = <&max>;
+		__dormant__ {
+			compatible = "maxim,max31855e", "maxim,max31855";
+		};
+	};
+
+	fragment@10 {
+		target = <&max>;
+		__dormant__ {
+			compatible = "maxim,max31855j", "maxim,max31855";
+		};
+	};
+
+	fragment@11 {
+		target = <&max>;
+		__dormant__ {
+			compatible = "maxim,max31855k", "maxim,max31855";
+		};
+	};
+
+	fragment@12 {
+		target = <&max>;
+		__dormant__ {
+			compatible = "maxim,max31855n", "maxim,max31855";
+		};
+	};
+
+	fragment@13 {
+		target = <&max>;
+		__dormant__ {
+			compatible = "maxim,max31855r", "maxim,max31855";
+		};
+	};
+
+	fragment@14 {
+		target = <&max>;
+		__dormant__ {
+			compatible = "maxim,max31855s", "maxim,max31855";
+		};
+	};
+
+	fragment@15 {
+		target = <&max>;
+		__dormant__ {
+			compatible = "maxim,max31855t", "maxim,max31855";
+		};
+	};
+
+	fragment@16 {
+		target = <&max>;
+		__dormant__ {
+			compatible = "maxim,max31856";
+			spi-cpha;
+			thermocouple-type = <THERMOCOUPLE_TYPE_K>;
+		};
+	};
+
+	__overrides__ {
+		spi0-0 = <0>, "+0",
+			 <&maxfrag>,"target:0=",<&spi0>,
+			 <&max>,"reg:0=0";
+		spi0-1 = <0>, "+1",
+			 <&maxfrag>,"target:0=",<&spi0>,
+			 <&max>,"reg:0=1";
+		spi1-0 = <0>, "+2",
+			 <&maxfrag>,"target:0=",<&spi1>,
+			 <&max>,"reg:0=0";
+		spi1-1 = <0>, "+3",
+			 <&maxfrag>,"target:0=",<&spi1>,
+			 <&max>,"reg:0=1";
+		spi1-2 = <0>, "+4",
+			 <&maxfrag>,"target:0=",<&spi1>,
+			 <&max>,"reg:0=2";
+		spi2-0 = <0>, "+5",
+			 <&maxfrag>,"target:0=",<&spi2>,
+			 <&max>,"reg:0=0";
+		spi2-1 = <0>, "+6",
+			 <&maxfrag>,"target:0=",<&spi2>,
+			 <&max>,"reg:0=1";
+		spi2-2 = <0>, "+7",
+			 <&maxfrag>,"target:0=",<&spi2>,
+			 <&max>,"reg:0=2";
+		max6675 = <&max>,"compatible=maxim,max6675";
+		max31855 = <&max>,"compatible=maxim,max31855";
+		max31855e = <0>,"+9";
+		max31855j = <0>,"+10";
+		max31855k = <0>,"+11";
+		max31855n = <0>,"+12";
+		max31855r = <0>,"+13";
+		max31855s = <0>,"+14";
+		max31855t = <0>,"+15";
+		max31856  = <0>,"+16";
+		type_b    = <&max>,"thermocouple-type:0=",<THERMOCOUPLE_TYPE_B>;
+		type_e    = <&max>,"thermocouple-type:0=",<THERMOCOUPLE_TYPE_E>;
+		type_j    = <&max>,"thermocouple-type:0=",<THERMOCOUPLE_TYPE_J>;
+		type_k    = <&max>,"thermocouple-type:0=",<THERMOCOUPLE_TYPE_K>;
+		type_n    = <&max>,"thermocouple-type:0=",<THERMOCOUPLE_TYPE_N>;
+		type_r    = <&max>,"thermocouple-type:0=",<THERMOCOUPLE_TYPE_R>;
+		type_s    = <&max>,"thermocouple-type:0=",<THERMOCOUPLE_TYPE_S>;
+		type_t    = <&max>,"thermocouple-type:0=",<THERMOCOUPLE_TYPE_T>;
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for mbed DAC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+                        #size-cells = <0>;
+			status = "okay";
+
+			tlv320aic23: codec@1a {
+				#sound-dai-cells = <0>;
+				reg = <0x1a>;
+				compatible = "ti,tlv320aic23";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "simple-audio-card";
+			i2s-controller = <&i2s>;
+			status = "okay";
+
+			simple-audio-card,name = "mbed-DAC";
+
+			simple-audio-card,widgets =
+				"Microphone", "Mic Jack",
+				"Line", "Line In",
+				"Headphone", "Headphone Jack";
+
+			simple-audio-card,routing =
+				"Headphone Jack", "LHPOUT",
+				"Headphone Jack", "RHPOUT",
+				"LLINEIN", "Line In",
+				"RLINEIN", "Line In",
+				"MICIN", "Mic Jack";
+
+			simple-audio-card,format = "i2s";
+
+			simple-audio-card,cpu {
+				sound-dai = <&i2s>;
+			};
+
+			sound_master: simple-audio-card,codec {
+				sound-dai = <&tlv320aic23>;
+				system-clock-frequency = <12288000>;
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp23017-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp23017-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp23017-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for MCP23017 Gpio Extender from Microchip Semiconductor
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			mcp23017_pins: mcp23017_pins@20 {
+				brcm,pins = <4>;
+				brcm,function = <0>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__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 {
+		target = <&mcp23017>;
+		mcp23017_irq: __overlay__ {
+			#interrupt-cells=<2>;
+			interrupt-parent = <&gpio>;
+			interrupts = <4 2>;
+			interrupt-controller;
+			microchip,irq-mirror;
+		};
+	};
+
+	__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";
+	};
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp23s17-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp23s17-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp23s17-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp23s17-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for MCP23S08/17 GPIO Extenders from Microchip Semiconductor
+
+// dtparams:
+//     s08-spi<n>-<m>-present  - 4-bit integer, bitmap indicating MCP23S08 devices present on SPI<n>, CS#<m>.
+//     s17-spi<n>-<m>-present  - 8-bit integer, bitmap indicating MCP23S17 devices present on SPI<n>, CS#<m>.
+//     s08-spi<n>-<m>-int-gpio - integer, enables interrupts on a single MCP23S08 device on SPI<n>, CS#<m>, specifies the GPIO pin to which INT output is connected.
+//     s17-spi<n>-<m>-int-gpio - integer, enables mirrored interrupts on a single MCP23S17 device on SPI<n>, CS#<m>, specifies the GPIO pin to which either INTA or INTB output is connected.
+//
+// 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.
+// If interrupts are enabled for a device on a given CS# on a SPI bus, that device must be the only one present on that SPI bus/CS#.
+//
+// Example 1: A single MCP23S17 device on SPI0, CS#0 with its SPI addr set to 0 and INTA output connected to GPIO25:
+// dtoverlay=mcp23s17:s17-spi0-0-present=1,s17-spi0-0-int-gpio=25
+//
+// Example 2: Two MCP23S08 devices on SPI1, CS#0 with their addrs set to 2 and 3. Three MCP23S17 devices on SPI1, CS#1 with their addrs set to 0, 1 and 7:
+// dtoverlay=spi1-2cs
+// dtoverlay=mcp23s17:s08-spi1-0-present=12,s17-spi1-1-present=131
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	// disable spi-dev on spi0.0
+	fragment@0 {
+		target = <&spidev0>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi0.1
+	fragment@1 {
+		target = <&spidev1>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi1.0
+	fragment@2 {
+		target-path = "spi1/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi1.1
+	fragment@3 {
+		target-path = "spi1/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi1.2
+	fragment@4 {
+		target-path = "spi1/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi2.0
+	fragment@5 {
+		target-path = "spi2/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi2.1
+	fragment@6 {
+		target-path = "spi2/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// disable spi-dev on spi2.2
+	fragment@7 {
+		target-path = "spi2/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	// enable one or more mcp23s08s on spi0.0
+	fragment@8 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s08_00: mcp23s08@0 {
+				compatible = "microchip,mcp23s08";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s08-spi0-0-present parameter */
+     				reg = <0>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s08-spi0-0-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s08s on spi0.1
+	fragment@9 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s08_01: mcp23s08@1 {
+				compatible = "microchip,mcp23s08";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s08-spi0-1-present parameter */
+     				reg = <1>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s08-spi0-1-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s08s on spi1.0
+	fragment@10 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s08_10: mcp23s08@0 {
+				compatible = "microchip,mcp23s08";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s08-spi1-0-present parameter */
+     				reg = <0>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s08-spi1-0-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s08s on spi1.1
+	fragment@11 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s08_11: mcp23s08@1 {
+				compatible = "microchip,mcp23s08";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s08-spi1-1-present parameter */
+     				reg = <1>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s08-spi1-1-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s08s on spi1.2
+	fragment@12 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s08_12: mcp23s08@2 {
+				compatible = "microchip,mcp23s08";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s08-spi1-2-present parameter */
+     				reg = <2>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s08-spi1-2-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s08s on spi2.0
+	fragment@13 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s08_20: mcp23s08@0 {
+				compatible = "microchip,mcp23s08";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s08-spi2-0-present parameter */
+     				reg = <0>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s08-spi2-0-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s08s on spi2.1
+	fragment@14 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s08_21: mcp23s08@1 {
+				compatible = "microchip,mcp23s08";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s08-spi2-1-present parameter */
+     				reg = <1>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s08-spi2-1-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s08s on spi2.2
+	fragment@15 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s08_22: mcp23s08@2 {
+				compatible = "microchip,mcp23s08";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s08-spi2-2-present parameter */
+     				reg = <2>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s08-spi2-2-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s17s on spi0.0
+	fragment@16 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s17_00: mcp23s17@0 {
+				compatible = "microchip,mcp23s17";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s17-spi0-0-present parameter */
+     				reg = <0>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s17-spi0-0-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s17s on spi0.1
+	fragment@17 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s17_01: mcp23s17@1 {
+				compatible = "microchip,mcp23s17";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s17-spi0-1-present parameter */
+     				reg = <1>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s17-spi0-1-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s17s on spi1.0
+	fragment@18 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s17_10: mcp23s17@0 {
+				compatible = "microchip,mcp23s17";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s17-spi1-0-present parameter */
+     				reg = <0>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s17-spi1-0-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s17s on spi1.1
+	fragment@19 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s17_11: mcp23s17@1 {
+				compatible = "microchip,mcp23s17";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s17-spi1-1-present parameter */
+     				reg = <1>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s17-spi1-1-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s17s on spi1.2
+	fragment@20 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s17_12: mcp23s17@2 {
+				compatible = "microchip,mcp23s17";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s17-spi1-2-present parameter */
+     				reg = <2>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s17-spi1-2-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s17s on spi2.0
+	fragment@21 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s17_20: mcp23s17@0 {
+				compatible = "microchip,mcp23s17";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s17-spi2-0-present parameter */
+     				reg = <0>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s17-spi2-0-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s17s on spi2.1
+	fragment@22 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s17_21: mcp23s17@1 {
+				compatible = "microchip,mcp23s17";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s17-spi2-1-present parameter */
+     				reg = <1>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s17-spi2-1-int-gpio parameter */
+			};
+		};
+	};
+
+	// enable one or more mcp23s17s on spi2.2
+	fragment@23 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+			mcp23s17_22: mcp23s17@2 {
+				compatible = "microchip,mcp23s17";
+  				gpio-controller;
+  				#gpio-cells = <2>;
+    				microchip,spi-present-mask = <0x00>;  /* overwritten by mcp23s17-spi2-2-present parameter */
+     				reg = <2>;
+    				spi-max-frequency = <500000>;
+				status = "okay";
+				#interrupt-cells=<2>;
+				interrupts = <0 2>;  /* 1st word overwritten by mcp23s17-spi2-2-int-gpio parameter */
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to INT(A/B) output of mcp23s08/17 on spi0.0 as a input with no pull-up/down
+	fragment@24 {
+		target = <&gpio>;
+		__dormant__ {
+			spi0_0_int_pins: spi0_0_int_pins {
+				brcm,pins = <0>;  /* overwritten by mcp23s08/17-spi0-0-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to INT(A/B) output of mcp23s08/17 on spi0.1 as a input with no pull-up/down
+	fragment@25 {
+		target = <&gpio>;
+		__dormant__ {
+			spi0_1_int_pins: spi0_1_int_pins {
+				brcm,pins = <0>;  /* overwritten by mcp23s08/17-spi0-1-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to INT(A/B) output of mcp23s08/17 on spi1.0 as a input with no pull-up/down
+	fragment@26 {
+		target = <&gpio>;
+		__dormant__ {
+			spi1_0_int_pins: spi1_0_int_pins {
+				brcm,pins = <0>;  /* overwritten by mcp23s08/17-spi1-0-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to INT(A/B) output of mcp23s08/17 on spi1.1 as a input with no pull-up/down
+	fragment@27 {
+		target = <&gpio>;
+		__dormant__ {
+			spi1_1_int_pins: spi1_1_int_pins {
+				brcm,pins = <0>;  /* overwritten by mcp23s08/17-spi1-1-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to INT(A/B) output of mcp23s08/17 on spi1.2 as a input with no pull-up/down
+	fragment@28 {
+		target = <&gpio>;
+		__dormant__ {
+			spi1_2_int_pins: spi1_2_int_pins {
+				brcm,pins = <0>;  /* overwritten by mcp23s08/17-spi1-2-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to INT(A/B) output of mcp23s08/17 on spi2.0 as a input with no pull-up/down
+	fragment@29 {
+		target = <&gpio>;
+		__dormant__ {
+			spi2_0_int_pins: spi2_0_int_pins {
+				brcm,pins = <0>;  /* overwritten by mcp23s08/17-spi2-0-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to INT(A/B) output of mcp23s08/17 on spi2.1 as a input with no pull-up/down
+	fragment@30 {
+		target = <&gpio>;
+		__dormant__ {
+			spi2_1_int_pins: spi2_1_int_pins {
+				brcm,pins = <0>;  /* overwritten by mcp23s08/17-spi2-1-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to INT(A/B) output of mcp23s08/17 on spi2.2 as a input with no pull-up/down
+	fragment@31 {
+		target = <&gpio>;
+		__dormant__ {
+			spi2_2_int_pins: spi2_2_int_pins {
+				brcm,pins = <0>;  /* overwritten by mcp23s08/17-spi2-2-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Enable interrupts for a mcp23s08 on spi0.0.
+	// Use default active low interrupt signalling.
+	fragment@32 {
+		target = <&mcp23s08_00>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+		};
+	};
+
+	// Enable interrupts for a mcp23s08 on spi0.1.
+	// Use default active low interrupt signalling.
+	fragment@33 {
+		target = <&mcp23s08_01>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+		};
+	};
+
+	// Enable interrupts for a mcp23s08 on spi1.0.
+	// Use default active low interrupt signalling.
+	fragment@34 {
+		target = <&mcp23s08_10>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+		};
+	};
+
+	// Enable interrupts for a mcp23s08 on spi1.1.
+	// Use default active low interrupt signalling.
+	fragment@35 {
+		target = <&mcp23s08_11>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+		};
+	};
+
+	// Enable interrupts for a mcp23s08 on spi1.2.
+	// Use default active low interrupt signalling.
+	fragment@36 {
+		target = <&mcp23s08_12>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+		};
+	};
+
+	// Enable interrupts for a mcp23s08 on spi2.0.
+	// Use default active low interrupt signalling.
+	fragment@37 {
+		target = <&mcp23s08_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+		};
+	};
+
+	// Enable interrupts for a mcp23s08 on spi2.1.
+	// Use default active low interrupt signalling.
+	fragment@38 {
+		target = <&mcp23s08_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+		};
+	};
+
+	// Enable interrupts for a mcp23s08 on spi2.2.
+	// Use default active low interrupt signalling.
+	fragment@39 {
+		target = <&mcp23s08_22>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+		};
+	};
+
+	// Enable interrupts for a mcp23s17 on spi0.0.
+	// Enable mirroring so that either INTA or INTB output of mcp23s17 can be connected to the GPIO pin.
+	// Use default active low interrupt signalling.
+	fragment@40 {
+		target = <&mcp23s17_00>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			microchip,irq-mirror;
+		};
+	};
+
+	// Enable interrupts for a mcp23s17 on spi0.1.
+	// Enable mirroring so that either INTA or INTB output of mcp23s17 can be connected to the GPIO pin.
+	// Configure INTA/B outputs of mcp23s08/17 as active low.
+	fragment@41 {
+		target = <&mcp23s17_01>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			microchip,irq-mirror;
+		};
+	};
+
+	// Enable interrupts for a mcp23s17 on spi1.0.
+	// Enable mirroring so that either INTA or INTB output of mcp23s17 can be connected to the GPIO pin.
+	// Configure INTA/B outputs of mcp23s08/17 as active low.
+	fragment@42 {
+		target = <&mcp23s17_10>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			microchip,irq-mirror;
+		};
+	};
+
+	// Enable interrupts for a mcp23s17 on spi1.1.
+	// Enable mirroring so that either INTA or INTB output of mcp23s17 can be connected to the GPIO pin.
+	// Configure INTA/B outputs of mcp23s08/17 as active low.
+	fragment@43 {
+		target = <&mcp23s17_11>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			microchip,irq-mirror;
+		};
+	};
+
+	// Enable interrupts for a mcp23s17 on spi1.2.
+	// Enable mirroring so that either INTA or INTB output of mcp23s17 can be connected to the GPIO pin.
+	// Configure INTA/B outputs of mcp23s08/17 as active low.
+	fragment@44 {
+		target = <&mcp23s17_12>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			microchip,irq-mirror;
+		};
+	};
+
+	// Enable interrupts for a mcp23s17 on spi2.0.
+	// Enable mirroring so that either INTA or INTB output of mcp23s17 can be connected to the GPIO pin.
+	// Configure INTA/B outputs of mcp23s08/17 as active low.
+	fragment@45 {
+		target = <&mcp23s17_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			microchip,irq-mirror;
+		};
+	};
+
+	// Enable interrupts for a mcp23s17 on spi2.1.
+	// Enable mirroring so that either INTA or INTB output of mcp23s17 can be connected to the GPIO pin.
+	// Configure INTA/B outputs of mcp23s08/17 as active low.
+	fragment@46 {
+		target = <&mcp23s17_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			microchip,irq-mirror;
+		};
+	};
+
+	// Enable interrupts for a mcp23s17 on spi2.2.
+	// Enable mirroring so that either INTA or INTB output of mcp23s17 can be connected to the GPIO pin.
+	// Configure INTA/B outputs of mcp23s08/17 as active low.
+	fragment@47 {
+		target = <&mcp23s17_22>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			microchip,irq-mirror;
+		};
+	};
+
+	__overrides__ {
+		s08-spi0-0-present = <0>,"+0+8",  <&mcp23s08_00>,"microchip,spi-present-mask:0";
+		s08-spi0-1-present = <0>,"+1+9",  <&mcp23s08_01>,"microchip,spi-present-mask:0";
+		s08-spi1-0-present = <0>,"+2+10", <&mcp23s08_10>,"microchip,spi-present-mask:0";
+		s08-spi1-1-present = <0>,"+3+11", <&mcp23s08_11>,"microchip,spi-present-mask:0";
+		s08-spi1-2-present = <0>,"+4+12", <&mcp23s08_12>,"microchip,spi-present-mask:0";
+		s08-spi2-0-present = <0>,"+5+13", <&mcp23s08_20>,"microchip,spi-present-mask:0";
+		s08-spi2-1-present = <0>,"+6+14", <&mcp23s08_21>,"microchip,spi-present-mask:0";
+		s08-spi2-2-present = <0>,"+7+15", <&mcp23s08_22>,"microchip,spi-present-mask:0";
+		s17-spi0-0-present = <0>,"+0+16", <&mcp23s17_00>,"microchip,spi-present-mask:0";
+		s17-spi0-1-present = <0>,"+1+17", <&mcp23s17_01>,"microchip,spi-present-mask:0";
+		s17-spi1-0-present = <0>,"+2+18", <&mcp23s17_10>,"microchip,spi-present-mask:0";
+		s17-spi1-1-present = <0>,"+3+19", <&mcp23s17_11>,"microchip,spi-present-mask:0";
+		s17-spi1-2-present = <0>,"+4+20", <&mcp23s17_12>,"microchip,spi-present-mask:0";
+		s17-spi2-0-present = <0>,"+5+21", <&mcp23s17_20>,"microchip,spi-present-mask:0";
+		s17-spi2-1-present = <0>,"+6+22", <&mcp23s17_21>,"microchip,spi-present-mask:0";
+		s17-spi2-2-present = <0>,"+7+23", <&mcp23s17_22>,"microchip,spi-present-mask:0";
+		s08-spi0-0-int-gpio = <0>,"+24+32", <&spi0_0_int_pins>,"brcm,pins:0", <&mcp23s08_00>,"interrupts:0";
+		s08-spi0-1-int-gpio = <0>,"+25+33", <&spi0_1_int_pins>,"brcm,pins:0", <&mcp23s08_01>,"interrupts:0";
+		s08-spi1-0-int-gpio = <0>,"+26+34", <&spi1_0_int_pins>,"brcm,pins:0", <&mcp23s08_10>,"interrupts:0";
+		s08-spi1-1-int-gpio = <0>,"+27+35", <&spi1_1_int_pins>,"brcm,pins:0", <&mcp23s08_11>,"interrupts:0";
+		s08-spi1-2-int-gpio = <0>,"+28+36", <&spi1_2_int_pins>,"brcm,pins:0", <&mcp23s08_12>,"interrupts:0";
+		s08-spi2-0-int-gpio = <0>,"+29+37", <&spi2_0_int_pins>,"brcm,pins:0", <&mcp23s08_20>,"interrupts:0";
+		s08-spi2-1-int-gpio = <0>,"+30+38", <&spi2_1_int_pins>,"brcm,pins:0", <&mcp23s08_21>,"interrupts:0";
+		s08-spi2-2-int-gpio = <0>,"+31+39", <&spi2_2_int_pins>,"brcm,pins:0", <&mcp23s08_22>,"interrupts:0";
+		s17-spi0-0-int-gpio = <0>,"+24+40", <&spi0_0_int_pins>,"brcm,pins:0", <&mcp23s17_00>,"interrupts:0";
+		s17-spi0-1-int-gpio = <0>,"+25+41", <&spi0_1_int_pins>,"brcm,pins:0", <&mcp23s17_01>,"interrupts:0";
+		s17-spi1-0-int-gpio = <0>,"+26+42", <&spi1_0_int_pins>,"brcm,pins:0", <&mcp23s17_10>,"interrupts:0";
+		s17-spi1-1-int-gpio = <0>,"+27+43", <&spi1_1_int_pins>,"brcm,pins:0", <&mcp23s17_11>,"interrupts:0";
+		s17-spi1-2-int-gpio = <0>,"+28+44", <&spi1_2_int_pins>,"brcm,pins:0", <&mcp23s17_12>,"interrupts:0";
+		s17-spi2-0-int-gpio = <0>,"+29+45", <&spi2_0_int_pins>,"brcm,pins:0", <&mcp23s17_20>,"interrupts:0";
+		s17-spi2-1-int-gpio = <0>,"+30+46", <&spi2_1_int_pins>,"brcm,pins:0", <&mcp23s17_21>,"interrupts:0";
+		s17-spi2-2-int-gpio = <0>,"+31+47", <&spi2_2_int_pins>,"brcm,pins:0", <&mcp23s17_22>,"interrupts:0";
+	};
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device tree overlay for mcp251x/can0 on spi0.0
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+    /* disable spi-dev for spi0.0 */
+    fragment@0 {
+        target = <&spi0>;
+        __overlay__ {
+            status = "okay";
+        };
+    };
+
+    fragment@1 {
+	target = <&spidev0>;
+	__overlay__ {
+	    status = "disabled";
+	};
+    };
+
+    /* the interrupt pin of the can-controller */
+    fragment@2 {
+        target = <&gpio>;
+        __overlay__ {
+            can0_pins: can0_pins {
+                brcm,pins = <25>;
+                brcm,function = <0>; /* input */
+            };
+        };
+    };
+
+    /* the clock/oscillator of the can-controller */
+    fragment@3 {
+        target-path = "/";
+        __overlay__ {
+            /* external oscillator of mcp2515 on SPI0.0 */
+            can0_osc: can0_osc {
+                compatible = "fixed-clock";
+                #clock-cells = <0>;
+                clock-frequency  = <16000000>;
+            };
+        };
+    };
+
+    /* the spi config of the can-controller itself binding everything together */
+    fragment@4 {
+        target = <&spi0>;
+        __overlay__ {
+            /* needed to avoid dtc warning */
+            #address-cells = <1>;
+            #size-cells = <0>;
+            can0: mcp2515@0 {
+                reg = <0>;
+                compatible = "microchip,mcp2515";
+                pinctrl-names = "default";
+                pinctrl-0 = <&can0_pins>;
+                spi-max-frequency = <10000000>;
+                interrupt-parent = <&gpio>;
+                interrupts = <25 8>; /* IRQ_TYPE_LEVEL_LOW */
+                clocks = <&can0_osc>;
+            };
+        };
+    };
+    __overrides__ {
+        oscillator = <&can0_osc>,"clock-frequency:0";
+        spimaxfrequency = <&can0>,"spi-max-frequency:0";
+        interrupt = <&can0_pins>,"brcm,pins:0",<&can0>,"interrupts:0";
+    };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device tree overlay for mcp251x/can1 on spi0.1 edited by petit_miner
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+    /* disable spi-dev for spi0.1 */
+    fragment@0 {
+        target = <&spi0>;
+        __overlay__ {
+            status = "okay";
+        };
+    };
+
+    fragment@1 {
+	target = <&spidev1>;
+	__overlay__ {
+	    status = "disabled";
+	};
+    };
+
+    /* the interrupt pin of the can-controller */
+    fragment@2 {
+        target = <&gpio>;
+        __overlay__ {
+            can1_pins: can1_pins {
+                brcm,pins = <25>;
+                brcm,function = <0>; /* input */
+            };
+        };
+    };
+
+    /* the clock/oscillator of the can-controller */
+    fragment@3 {
+        target-path = "/";
+        __overlay__ {
+            /* external oscillator of mcp2515 on spi0.1 */
+            can1_osc: can1_osc {
+                compatible = "fixed-clock";
+                #clock-cells = <0>;
+                clock-frequency  = <16000000>;
+            };
+        };
+    };
+
+    /* the spi config of the can-controller itself binding everything together */
+    fragment@4 {
+        target = <&spi0>;
+        __overlay__ {
+            /* needed to avoid dtc warning */
+            #address-cells = <1>;
+            #size-cells = <0>;
+            can1: mcp2515@1 {
+                reg = <1>;
+                compatible = "microchip,mcp2515";
+                pinctrl-names = "default";
+                pinctrl-0 = <&can1_pins>;
+                spi-max-frequency = <10000000>;
+                interrupt-parent = <&gpio>;
+                interrupts = <25 8>; /* IRQ_TYPE_LEVEL_LOW */
+                clocks = <&can1_osc>;
+            };
+        };
+    };
+    __overrides__ {
+        oscillator = <&can1_osc>,"clock-frequency:0";
+        spimaxfrequency = <&can1>,"spi-max-frequency:0";
+        interrupt = <&can1_pins>,"brcm,pins:0",<&can1>,"interrupts:0";
+    };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp251xfd-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp251xfd-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp251xfd-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp251xfd-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/bcm2835.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev1>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target-path = "spi1/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target-path = "spi1/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@4 {
+		target-path = "spi1/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@5 {
+		target-path = "spi2/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@6 {
+		target-path = "spi2/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@7 {
+		target-path = "spi2/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@8 {
+		target = <&gpio>;
+		__overlay__ {
+			mcp251xfd_pins: mcp251xfd_pins {
+				brcm,pins = <25>;
+				brcm,function = <BCM2835_FSEL_GPIO_IN>;
+			};
+		};
+	};
+
+	fragment@9 {
+		target-path = "/clocks";
+		__overlay__ {
+			clk_mcp251xfd_osc: mcp251xfd-osc {
+				#clock-cells = <0>;
+				compatible = "fixed-clock";
+				clock-frequency = <40000000>;
+			};
+		};
+	};
+
+	mcp251xfd_frag: fragment@10 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp251xfd: mcp251xfd@0 {
+				compatible = "microchip,mcp251xfd";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&mcp251xfd_pins>;
+				spi-max-frequency = <20000000>;
+				interrupt-parent = <&gpio>;
+				interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+				clocks = <&clk_mcp251xfd_osc>;
+			};
+		};
+	};
+
+	fragment@11 {
+		target = <&mcp251xfd>;
+		mcp251xfd_rx_int_gpios: __dormant__ {
+			microchip,rx-int-gpios = <&gpio 255 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	fragment@12 {
+		target = <&gpio>;
+		__dormant__ {
+			mcp251xfd_xceiver_pins: mcp251xfd_xceiver_pins {
+				brcm,pins = <255>;
+				brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+			};
+		};
+	};
+
+	fragment@13 {
+		target-path = "/";
+		__dormant__ {
+			reg_mcp251xfd_xceiver: reg_mcp251xfd_xceiver {
+				compatible = "regulator-fixed";
+				regulator-name = "mcp251xfd_xceiver";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				gpio = <&gpio 4 GPIO_ACTIVE_HIGH>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&mcp251xfd_xceiver_pins>;
+			};
+		};
+	};
+
+	fragment@14 {
+		target = <&mcp251xfd>;
+		__dormant__ {
+			xceiver-supply = <&reg_mcp251xfd_xceiver>;
+		};
+	};
+
+	__overrides__ {
+		spi0-0 = <0>, "+0",
+			<&mcp251xfd_frag>, "target:0=", <&spi0>,
+			<&mcp251xfd>, "reg:0=0",
+			<&mcp251xfd_pins>, "name=mcp251xfd_spi0_0_pins",
+			<&clk_mcp251xfd_osc>, "name=mcp251xfd-spi0-0-osc",
+			<&mcp251xfd_xceiver_pins>, "name=mcp251xfd_spi0_0_xceiver_pins",
+			<&reg_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi0-0-xceiver",
+			<&reg_mcp251xfd_xceiver>, "regulator-name=mcp251xfd-spi0-0-xceiver";
+		spi0-1 = <0>, "+1",
+			<&mcp251xfd_frag>, "target:0=", <&spi0>,
+			<&mcp251xfd>, "reg:0=1",
+			<&mcp251xfd_pins>, "name=mcp251xfd_spi0_1_pins",
+			<&clk_mcp251xfd_osc>, "name=mcp251xfd-spi0-1-osc",
+			<&mcp251xfd_xceiver_pins>, "name=mcp251xfd_spi0_1_xceiver_pins",
+			<&reg_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi0-1-xceiver",
+			<&reg_mcp251xfd_xceiver>, "regulator-name=mcp251xfd-spi0-1-xceiver";
+		spi1-0 = <0>, "+2",
+			<&mcp251xfd_frag>, "target:0=", <&spi1>,
+			<&mcp251xfd>, "reg:0=0",
+			<&mcp251xfd_pins>, "name=mcp251xfd_spi1_0_pins",
+			<&clk_mcp251xfd_osc>, "name=mcp251xfd-spi1-0-osc",
+			<&mcp251xfd_xceiver_pins>, "name=mcp251xfd_spi1_0_xceiver_pins",
+			<&reg_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi1-0-xceiver",
+			<&reg_mcp251xfd_xceiver>, "regulator-name=mcp251xfd-spi1-0-xceiver";
+		spi1-1 = <0>, "+3",
+			<&mcp251xfd_frag>, "target:0=", <&spi1>,
+			<&mcp251xfd>, "reg:0=1",
+			<&mcp251xfd_pins>, "name=mcp251xfd_spi1_1_pins",
+			<&clk_mcp251xfd_osc>, "name=mcp251xfd-spi1-1-osc",
+			<&mcp251xfd_xceiver_pins>, "name=mcp251xfd_spi1_1_xceiver_pins",
+			<&reg_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi1-1-xceiver",
+			<&reg_mcp251xfd_xceiver>, "regulator-name=mcp251xfd-spi1-1-xceiver";
+		spi1-2 = <0>, "+4",
+			<&mcp251xfd_frag>, "target:0=", <&spi1>,
+			<&mcp251xfd>, "reg:0=2",
+			<&mcp251xfd_pins>, "name=mcp251xfd_spi1_2_pins",
+			<&clk_mcp251xfd_osc>, "name=mcp251xfd-spi1-2-osc",
+			<&mcp251xfd_xceiver_pins>, "name=mcp251xfd_spi1_2_xceiver_pins",
+			<&reg_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi1-2-xceiver",
+			<&reg_mcp251xfd_xceiver>, "regulator-name=mcp251xfd-spi1-2-xceiver";
+		spi2-0 = <0>, "+5",
+			<&mcp251xfd_frag>, "target:0=", <&spi2>,
+			<&mcp251xfd>, "reg:0=0",
+			<&mcp251xfd_pins>, "name=mcp251xfd_spi2_0_pins",
+			<&clk_mcp251xfd_osc>, "name=mcp251xfd-spi2-0-osc",
+			<&mcp251xfd_xceiver_pins>, "name=mcp251xfd_spi2_0_xceiver_pins",
+			<&reg_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi2-0-xceiver",
+			<&reg_mcp251xfd_xceiver>, "regulator-name=mcp251xfd-spi2-0-xceiver";
+		spi2-1 = <0>, "+6",
+			<&mcp251xfd_frag>, "target:0=", <&spi2>,
+			<&mcp251xfd>, "reg:0=1",
+			<&mcp251xfd_pins>, "name=mcp251xfd_spi2_1_pins",
+			<&clk_mcp251xfd_osc>, "name=mcp251xfd-spi2-1-osc",
+			<&mcp251xfd_xceiver_pins>, "name=mcp251xfd_spi2_1_xceiver_pins",
+			<&reg_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi2-1-xceiver",
+			<&reg_mcp251xfd_xceiver>, "regulator-name=mcp251xfd-spi2-1-xceiver";
+		spi2-2 = <0>, "+7",
+			<&mcp251xfd_frag>, "target:0=", <&spi2>,
+			<&mcp251xfd>, "reg:0=2",
+			<&mcp251xfd_pins>, "name=mcp251xfd_spi2_2_pins",
+			<&clk_mcp251xfd_osc>, "name=mcp251xfd-spi2-2-osc",
+			<&mcp251xfd_xceiver_pins>, "name=mcp251xfd_spi2_2_xceiver_pins",
+			<&reg_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi2-2-xceiver",
+			<&reg_mcp251xfd_xceiver>, "regulator-name=mcp251xfd-spi2-2-xceiver";
+		oscillator = <&clk_mcp251xfd_osc>, "clock-frequency:0";
+		speed = <&mcp251xfd>, "spi-max-frequency:0";
+		interrupt = <&mcp251xfd_pins>, "brcm,pins:0",
+			<&mcp251xfd>, "interrupts:0";
+		rx_interrupt = <0>, "+11",
+			<&mcp251xfd_pins>, "brcm,pins:4",
+			<&mcp251xfd_rx_int_gpios>, "microchip,rx-int-gpios:4";
+		xceiver_enable = <0>, "+12+13+14",
+			<&mcp251xfd_xceiver_pins>, "brcm,pins:0",
+			<&reg_mcp251xfd_xceiver>, "gpio:4";
+		xceiver_active_high = <&reg_mcp251xfd_xceiver>, "enable-active-high?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp3008-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp3008-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp3008-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp3008-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device tree overlay for Microchip mcp3008 10-Bit A/D Converters
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev1>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target-path = "spi1/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target-path = "spi1/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@4 {
+		target-path = "spi1/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@5 {
+		target-path = "spi2/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@6 {
+		target-path = "spi2/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@7 {
+		target-path = "spi2/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@8 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3008_00: mcp3008@0 {
+				compatible = "microchip,mcp3008";
+				reg = <0>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@9 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3008_01: mcp3008@1 {
+				compatible = "microchip,mcp3008";
+				reg = <1>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@10 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3008_10: mcp3008@0 {
+				compatible = "microchip,mcp3008";
+				reg = <0>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@11 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3008_11: mcp3008@1 {
+				compatible = "microchip,mcp3008";
+				reg = <1>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@12 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3008_12: mcp3008@2 {
+				compatible = "microchip,mcp3008";
+				reg = <2>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@13 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3008_20: mcp3008@0 {
+				compatible = "microchip,mcp3008";
+				reg = <0>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@14 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3008_21: mcp3008@1 {
+				compatible = "microchip,mcp3008";
+				reg = <1>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@15 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3008_22: mcp3008@2 {
+				compatible = "microchip,mcp3008";
+				reg = <2>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	__overrides__ {
+		spi0-0-present = <0>, "+0+8";
+		spi0-1-present = <0>, "+1+9";
+		spi1-0-present = <0>, "+2+10";
+		spi1-1-present = <0>, "+3+11";
+		spi1-2-present = <0>, "+4+12";
+		spi2-0-present = <0>, "+5+13";
+		spi2-1-present = <0>, "+6+14";
+		spi2-2-present = <0>, "+7+15";
+		spi0-0-speed = <&mcp3008_00>, "spi-max-frequency:0";
+		spi0-1-speed = <&mcp3008_01>, "spi-max-frequency:0";
+		spi1-0-speed = <&mcp3008_10>, "spi-max-frequency:0";
+		spi1-1-speed = <&mcp3008_11>, "spi-max-frequency:0";
+		spi1-2-speed = <&mcp3008_12>, "spi-max-frequency:0";
+		spi2-0-speed = <&mcp3008_20>, "spi-max-frequency:0";
+		spi2-1-speed = <&mcp3008_21>, "spi-max-frequency:0";
+		spi2-2-speed = <&mcp3008_22>, "spi-max-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp3202-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp3202-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp3202-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp3202-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device tree overlay for Microchip mcp3202 12-Bit A/D Converters
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev1>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target-path = "spi1/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target-path = "spi1/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@4 {
+		target-path = "spi1/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@5 {
+		target-path = "spi2/spidev@0";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@6 {
+		target-path = "spi2/spidev@1";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@7 {
+		target-path = "spi2/spidev@2";
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@8 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3202_00: mcp3202@0 {
+				compatible = "mcp3202";
+				reg = <0>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@9 {
+		target = <&spi0>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3202_01: mcp3202@1 {
+				compatible = "mcp3202";
+				reg = <1>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@10 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3202_10: mcp3202@0 {
+				compatible = "mcp3202";
+				reg = <0>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@11 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3202_11: mcp3202@1 {
+				compatible = "mcp3202";
+				reg = <1>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@12 {
+		target = <&spi1>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3202_12: mcp3202@2 {
+				compatible = "mcp3202";
+				reg = <2>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@13 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3202_20: mcp3202@0 {
+				compatible = "mcp3202";
+				reg = <0>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@14 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3202_21: mcp3202@1 {
+				compatible = "mcp3202";
+				reg = <1>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	fragment@15 {
+		target = <&spi2>;
+		__dormant__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mcp3202_22: mcp3202@2 {
+				compatible = "mcp3202";
+				reg = <2>;
+				spi-max-frequency = <1600000>;
+			};
+		};
+	};
+
+	__overrides__ {
+		spi0-0-present = <0>, "+0+8";
+		spi0-1-present = <0>, "+1+9";
+		spi1-0-present = <0>, "+2+10";
+		spi1-1-present = <0>, "+3+11";
+		spi1-2-present = <0>, "+4+12";
+		spi2-0-present = <0>, "+5+13";
+		spi2-1-present = <0>, "+6+14";
+		spi2-2-present = <0>, "+7+15";
+		spi0-0-speed = <&mcp3202_00>, "spi-max-frequency:0";
+		spi0-1-speed = <&mcp3202_01>, "spi-max-frequency:0";
+		spi1-0-speed = <&mcp3202_10>, "spi-max-frequency:0";
+		spi1-1-speed = <&mcp3202_11>, "spi-max-frequency:0";
+		spi1-2-speed = <&mcp3202_12>, "spi-max-frequency:0";
+		spi2-0-speed = <&mcp3202_20>, "spi-max-frequency:0";
+		spi2-1-speed = <&mcp3202_21>, "spi-max-frequency:0";
+		spi2-2-speed = <&mcp3202_22>, "spi-max-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp342x-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mcp342x-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mcp342x-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for MCP3421-8 ADCs from Microchip Semiconductor
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			mcp3421: mcp@68 {
+				reg = <0x68>;
+				compatible = "microchip,mcp3421";
+
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			mcp3422: mcp@68 {
+				reg = <0x68>;
+				compatible = "microchip,mcp3422";
+
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			mcp3423: mcp@68 {
+				reg = <0x68>;
+				compatible = "microchip,mcp3423";
+
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			mcp3424: mcp@68 {
+				reg = <0x68>;
+				compatible = "microchip,mcp3424";
+
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			mcp3425: mcp@68 {
+				reg = <0x68>;
+				compatible = "microchip,mcp3425","mcp3425";
+
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@5 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			mcp3426: mcp@68 {
+				reg = <0x68>;
+				compatible = "microchip,mcp3426";
+
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@6 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			mcp3427: mcp@68 {
+				reg = <0x68>;
+				compatible = "microchip,mcp3427";
+
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@7 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			mcp3428: mcp@68 {
+				reg = <0x68>;
+				compatible = "microchip,mcp3428";
+
+				status = "okay";
+			};
+		};
+	};
+
+	__overrides__ {
+		addr = <&mcp3421>,"reg:0",
+		       <&mcp3422>,"reg:0",
+		       <&mcp3423>,"reg:0",
+		       <&mcp3424>,"reg:0",
+		       <&mcp3425>,"reg:0",
+		       <&mcp3426>,"reg:0",
+		       <&mcp3427>,"reg:0",
+		       <&mcp3428>,"reg:0";
+		mcp3421 = <0>,"=0";
+		mcp3422 = <0>,"=1";
+		mcp3423 = <0>,"=2";
+		mcp3424 = <0>,"=3";
+		mcp3425 = <0>,"=4";
+		mcp3426 = <0>,"=5";
+		mcp3427 = <0>,"=6";
+		mcp3428 = <0>,"=7";
+	};
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/media-center-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/media-center-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/media-center-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/media-center-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for Media Center HAT by Pi Supply
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+
+			spidev@0{
+				status = "disabled";
+			};
+
+			spidev@1{
+				status = "disabled";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			rpi_display_pins: rpi_display_pins {
+				brcm,pins = <12 23 24 25>;
+				brcm,function = <1 1 1 0>; /* out out out in */
+				brcm,pull = <0 0 0 2>; /* - - - up */
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			rpidisplay: rpi-display@0{
+				compatible = "ilitek,ili9341";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&rpi_display_pins>;
+
+				spi-max-frequency = <32000000>;
+				rotate = <90>;
+				bgr;
+				fps = <30>;
+				buswidth = <8>;
+				reset-gpios = <&gpio 23 1>;
+				dc-gpios = <&gpio 24 0>;
+				led-gpios = <&gpio 12 0>;
+				debug = <0>;
+			};
+
+			rpidisplay_ts: rpi-display-ts@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+
+				spi-max-frequency = <2000000>;
+				interrupts = <25 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 25 1>;
+				ti,x-plate-ohms = /bits/ 16 <60>;
+				ti,pressure-max = /bits/ 16 <255>;
+			};
+		};
+	};
+
+	fragment@3 {
+		target-path = "/";
+		__overlay__ {
+			lirc_rpi: lirc_rpi {
+				compatible = "rpi,lirc-rpi";
+				pinctrl-names = "default";
+				pinctrl-0 = <&lirc_pins>;
+				status = "okay";
+
+				// Override autodetection of IR receiver circuit
+				// (0 = active high, 1 = active low, -1 = no override )
+				rpi,sense = <0xffffffff>;
+
+				// Software carrier
+				// (0 = off, 1 = on)
+				rpi,softcarrier = <1>;
+
+				// Invert output
+				// (0 = off, 1 = on)
+				rpi,invert = <0>;
+
+				// Enable debugging messages
+				// (0 = off, 1 = on)
+				rpi,debug = <0>;
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&gpio>;
+		__overlay__ {
+			lirc_pins: lirc_pins {
+				brcm,pins = <6 5>;
+				brcm,function = <1 0>; // out in
+				brcm,pull = <0 1>; // off down
+			};
+		};
+	};
+
+	__overrides__ {
+		speed =     <&rpidisplay>,"spi-max-frequency:0";
+		rotate =    <&rpidisplay>,"rotate:0";
+		fps =       <&rpidisplay>,"fps:0";
+		debug =     <&rpidisplay>,"debug:0", 
+		            <&lirc_rpi>,"rpi,debug:0";
+		xohms =     <&rpidisplay_ts>,"ti,x-plate-ohms;0";
+		swapxy =    <&rpidisplay_ts>,"ti,swap-xy?";
+		backlight = <&rpidisplay>,"led-gpios:4",
+		            <&rpi_display_pins>,"brcm,pins:0";
+
+		gpio_out_pin =  <&lirc_pins>,"brcm,pins:0";
+		gpio_in_pin =   <&lirc_pins>,"brcm,pins:4";
+		gpio_in_pull =  <&lirc_pins>,"brcm,pull:4";
+
+		sense =         <&lirc_rpi>,"rpi,sense:0";
+		softcarrier =   <&lirc_rpi>,"rpi,softcarrier:0";
+		invert =        <&lirc_rpi>,"rpi,invert:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/merus-amp-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/merus-amp-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/merus-amp-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/merus-amp-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for Infineon Merus-Amp
+/dts-v1/;
+/plugin/;
+#include <dt-bindings/pinctrl/bcm2835.h>
+#include <dt-bindings/gpio/gpio.h>
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			merus_amp_pins: merus_amp_pins {
+				brcm,pins = <23>;
+				brcm,function = <0>; /* in */
+				brcm,pull = <2>; /* up */
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			merus_amp: ma120x0p@20 {
+				#sound-dai-cells = <0>;
+				compatible = "ma,ma120x0p";
+				reg = <0x20>;
+				status = "okay";
+				pinctrl-names = "default";
+				pinctrl-0 = <&merus_amp_pins>;
+				enable_gp-gpios = <&gpio 14 GPIO_ACTIVE_HIGH>;
+				mute_gp-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>;
+				booster_gp-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
+				error_gp-gpios = <&gpio 23 GPIO_ACTIVE_HIGH>;
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "merus,merus-amp";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/midi-uart0-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/midi-uart0-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/midi-uart0-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/midi-uart0-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/bcm2835.h>
+
+/*
+ * Fake a higher clock rate to get a larger divisor, and thereby a lower
+ * baudrate. The real clock is 48MHz, which we scale so that requesting
+ * 38.4kHz results in an actual 31.25kHz.
+ *
+ *   48000000*38400/31250 = 58982400
+ */
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			midi_clk: midi_clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-output-names = "uart0_pclk";
+				clock-frequency = <58982400>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&uart0>;
+		__overlay__ {
+			clocks = <&midi_clk>,
+			         <&clocks BCM2835_CLOCK_VPU>;
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/midi-uart1-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/midi-uart1-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/midi-uart1-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/midi-uart1-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/bcm2835-aux.h>
+
+/*
+ * Fake a higher clock rate to get a larger divisor, and thereby a lower
+ * baudrate. The real clock is 48MHz, which we scale so that requesting
+ * 38.4kHz results in an actual 31.25kHz.
+ *
+ *   48000000*38400/31250 = 58982400
+ */
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/clocks";
+		__overlay__ {
+			midi_clk: clock@5 {
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&aux BCM2835_AUX_CLOCK_UART>;
+				clock-mult = <38400>;
+				clock-div  = <31250>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&uart1>;
+		__overlay__ {
+			clocks = <&midi_clk>;
+		};
+	};
+
+	fragment@2 {
+		target = <&aux>;
+		__overlay__ {
+			clock-output-names = "aux_uart", "aux_spi1", "aux_spi2";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/minipitft13-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/minipitft13-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/minipitft13-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/minipitft13-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for Adafruit Mini PiTFT 1.3" and 1.5" 240x240 Display
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "brcm,bcm2835";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+        fragment@1 {
+                target = <&gpio>;
+                __overlay__ {
+                        pitft_pins: pitft_pins {
+                                brcm,pins = <25>;
+                                brcm,function = <1>; /* out */
+                                brcm,pull = <0>; /* none */
+                        };
+                };
+        };
+
+        fragment@2 {
+                target = <&spi0>;
+                __overlay__ {
+                        /* needed to avoid dtc warning */
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+
+                        pitft: pitft@0 {
+                                compatible = "fbtft,minipitft13";
+                                reg = <0>;
+                                pinctrl-names = "default";
+                                pinctrl-0 = <&pitft_pins>;
+                                spi-max-frequency = <32000000>;
+                                rotate = <0>;
+                                width = <240>;
+                                height = <240>;
+                                buswidth = <8>;
+                                dc-gpios = <&gpio 25 0>;
+                                led-gpios = <&gpio 26 0>;
+                                debug = <0>;
+                        };
+                };
+        };
+
+        __overrides__ {
+                speed =   <&pitft>,"spi-max-frequency:0";
+                rotate =  <&pitft>,"rotate:0";
+                width =   <&pitft>,"width:0";
+                height =  <&pitft>,"height:0";
+                fps =     <&pitft>,"fps:0";
+                debug =   <&pitft>,"debug:0";
+        };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/* Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
+   UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
+   usable baudrate.
+
+   It is also necessary to edit /lib/systemd/system/hciuart.service and
+   replace ttyAMA0 with ttyS0, unless you have a system with udev rules
+   that create /dev/serial0 and /dev/serial1, in which case use /dev/serial1
+   instead because it will always be correct.
+
+   If cmdline.txt uses the alias serial0 to refer to the user-accessable port
+   then the firmware will replace with the appropriate port whether or not
+   this overlay is used.
+*/
+
+#include <dt-bindings/gpio/gpio.h>
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&uart0>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart0_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&bt>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart1_pins &bt_pins &fake_bt_cts>;
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&uart0_pins>;
+		__overlay__ {
+			brcm,pins;
+			brcm,function;
+			brcm,pull;
+		};
+	};
+
+	fragment@4 {
+		target = <&uart1_pins>;
+		__overlay__ {
+			brcm,pins = <32 33>;
+			brcm,function = <2>; /* alt5=UART1 */
+			brcm,pull = <0 2>;
+		};
+	};
+
+	fragment@5 {
+		target = <&gpio>;
+		__overlay__ {
+			fake_bt_cts: fake_bt_cts {
+				brcm,pins = <31>;
+				brcm,function = <1>; /* output */
+			};
+		};
+	};
+
+	fragment@6 {
+		target-path = "/aliases";
+		__overlay__ {
+			serial0 = "/soc/serial@7e201000";
+			serial1 = "/soc/serial@7e215040";
+		};
+	};
+
+	fragment@7 {
+		target = <&minibt>;
+		minibt_frag: __overlay__ {
+		};
+	};
+
+	__overrides__ {
+		krnbt = <&minibt_frag>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mmc-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mmc-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mmc-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mmc-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&mmc>;
+		frag0: __overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc_pins>;
+			bus-width = <4>;
+			brcm,overclock-50 = <0>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			mmc_pins: mmc_pins {
+				brcm,pins = <48 49 50 51 52 53>;
+				brcm,function = <7>; /* alt3 */
+				brcm,pull = <0 2 2 2 2 2>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sdhost>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&mmcnr>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	__overrides__ {
+		overclock_50     = <&frag0>,"brcm,overclock-50:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mpu6050-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mpu6050-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mpu6050-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mpu6050-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for MPU6050
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "brcm,bcm2835";
+
+        fragment@0 {
+                target = <&i2c1>;
+                __overlay__ {
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+                        status = "okay";
+                        clock-frequency = <400000>;
+
+                        mpu6050: mpu6050@68 {
+                                compatible = "invensense,mpu6050";
+                                reg = <0x68>;
+                                interrupt-parent = <&gpio>;
+                                interrupts = <4 1>;
+                        };
+                };
+        };
+
+        __overrides__ {
+                interrupt = <&mpu6050>,"interrupts:0";
+                addr = <&mpu6050>,"reg:0";
+        };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/mz61581-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mz61581-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/mz61581-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/mz61581-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for MZ61581-PI-EXT 2014.12.28 by Tontec
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			mz61581_pins: mz61581_pins {
+				brcm,pins = <4 15 18 25>;
+				brcm,function = <0 1 1 1>; /* in out out out */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mz61581: mz61581@0{
+				compatible = "samsung,s6d02a1";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&mz61581_pins>;
+
+				spi-max-frequency = <128000000>;
+				spi-cpol;
+				spi-cpha;
+
+				width = <320>;
+				height = <480>;
+				rotate = <270>;
+				bgr;
+				fps = <30>;
+				buswidth = <8>;
+				txbuflen = <32768>;
+
+				reset-gpios = <&gpio 15 1>;
+				dc-gpios = <&gpio 25 0>;
+				led-gpios = <&gpio 18 0>;
+
+				init = <0x10000b0 00
+					0x1000011
+					0x20000ff
+					0x10000b3 0x02 0x00 0x00 0x00
+					0x10000c0 0x13 0x3b 0x00 0x02 0x00 0x01 0x00 0x43
+					0x10000c1 0x08 0x16 0x08 0x08
+					0x10000c4 0x11 0x07 0x03 0x03
+					0x10000c6 0x00
+					0x10000c8 0x03 0x03 0x13 0x5c 0x03 0x07 0x14 0x08 0x00 0x21 0x08 0x14 0x07 0x53 0x0c 0x13 0x03 0x03 0x21 0x00
+					0x1000035 0x00
+					0x1000036 0xa0
+					0x100003a 0x55
+					0x1000044 0x00 0x01
+					0x10000d0 0x07 0x07 0x1d 0x03
+					0x10000d1 0x03 0x30 0x10
+					0x10000d2 0x03 0x14 0x04
+					0x1000029
+					0x100002c>;
+
+				/* This is a workaround to make sure the init sequence slows down and doesn't fail */
+				debug = <3>;
+			};
+
+			mz61581_ts: mz61581_ts@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+
+				spi-max-frequency = <2000000>;
+				interrupts = <4 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 4 0>;
+
+				ti,x-plate-ohms = /bits/ 16 <60>;
+				ti,pressure-max = /bits/ 16 <255>;
+			};
+		};
+	};
+	__overrides__ {
+		speed =   <&mz61581>, "spi-max-frequency:0";
+		rotate =  <&mz61581>, "rotate:0";
+		fps =     <&mz61581>, "fps:0";
+		txbuflen = <&mz61581>, "txbuflen:0";
+		debug =   <&mz61581>, "debug:0";
+		xohms =   <&mz61581_ts>,"ti,x-plate-ohms;0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ov5647-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ov5647-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ov5647-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ov5647-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for OV5647 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ov5647: ov5647@36 {
+				compatible = "ovti,ov5647";
+				reg = <0x36>;
+				status = "okay";
+
+				pwdn-gpios = <&gpio 41 1>, <&gpio 32 1>;
+				clocks = <&ov5647_clk>;
+
+				rotation = <0>;
+
+				port {
+					ov5647_0: endpoint {
+						remote-endpoint = <&csi1_ep>;
+						clock-lanes = <0>;
+						data-lanes = <1 2>;
+						clock-noncontinuous;
+						link-frequencies =
+							/bits/ 64 <297000000>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&csi1>;
+		__overlay__ {
+			status = "okay";
+
+			port {
+				csi1_ep: endpoint {
+					remote-endpoint = <&ov5647_0>;
+					data-lanes = <1 2>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target-path="/__overrides__";
+		__overlay__ {
+			cam0-pwdn-ctrl = <&ov5647>,"pwdn-gpios:0";
+			cam0-pwdn      = <&ov5647>,"pwdn-gpios:4";
+			cam0-led-ctrl  = <&ov5647>,"pwdn-gpios:12";
+			cam0-led       = <&ov5647>,"pwdn-gpios:16";
+		};
+	};
+
+	fragment@5 {
+		target-path = "/";
+		__overlay__ {
+			ov5647_clk: camera-clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <25000000>;
+			};
+		};
+	};
+
+	__overrides__ {
+		rotation = <&ov5647>,"rotation:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ov7251-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ov7251-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ov7251-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ov7251-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for OV7251 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ov7251: ov7251@60 {
+				compatible = "ovti,ov7251";
+				reg = <0x60>;
+				status = "okay";
+
+				clocks = <&ov7251_clk>;
+				clock-names = "xclk";
+				clock-frequency = <24000000>;
+
+				vdddo-supply = <&ov7251_dovdd>;
+				vdda-supply = <&cam1_reg>;
+				vddd-supply = <&ov7251_dvdd>;
+
+				port {
+					ov7251_0: endpoint {
+						remote-endpoint = <&csi1_ep>;
+						clock-lanes = <0>;
+						data-lanes = <1>;
+						clock-noncontinuous;
+						link-frequencies =
+							/bits/ 64 <456000000>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&csi1>;
+		__overlay__ {
+			status = "okay";
+
+			port {
+				csi1_ep: endpoint {
+					remote-endpoint = <&ov7251_0>;
+					data-lanes = <1>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target-path="/";
+		__overlay__ {
+			ov7251_dovdd: fixedregulator@1 {
+				compatible = "regulator-fixed";
+				regulator-name = "ov7251_dovdd";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ov7251_dvdd: fixedregulator@2 {
+				compatible = "regulator-fixed";
+				regulator-name = "ov7251_dvdd";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ov7251_clk: ov7251-clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <24000000>;
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&cam1_reg>;
+		__overlay__ {
+			status = "okay";
+			regulator-name = "ov7251_avdd";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ov9281-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ov9281-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ov9281-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ov9281-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for OV9281 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ov9281: ov9281@60 {
+				compatible = "ovti,ov9281";
+				reg = <0x60>;
+				status = "okay";
+
+				clocks = <&ov9281_clk>;
+				clock-names = "xvclk";
+
+				avdd-supply = <&cam1_reg>;
+				dovdd-supply = <&ov9281_dovdd>;
+				dvdd-supply = <&ov9281_dvdd>;
+
+				port {
+					ov9281_0: endpoint {
+						remote-endpoint = <&csi1_ep>;
+						clock-lanes = <0>;
+						data-lanes = <1 2>;
+						clock-noncontinuous;
+						link-frequencies =
+							/bits/ 64 <400000000>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&csi1>;
+		__overlay__ {
+			status = "okay";
+
+			port {
+				csi1_ep: endpoint {
+					remote-endpoint = <&ov9281_0>;
+					data-lanes = <1 2>;
+					clock-noncontinuous;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target-path="/";
+		__overlay__ {
+			ov9281_dovdd: fixedregulator@1 {
+				compatible = "regulator-fixed";
+				regulator-name = "ov9281_dovdd";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ov9281_dvdd: fixedregulator@2 {
+				compatible = "regulator-fixed";
+				regulator-name = "ov9281_dvdd";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ov9281_clk: ov9281-clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <24000000>;
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&cam1_reg>;
+		__overlay__ {
+			status = "okay";
+			regulator-name = "ov9281_avdd";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+		};
+	};
+
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/overlay_map.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/overlay_map.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/overlay_map.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/overlay_map.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+
+/ {
+	bmp085_i2c-sensor {
+		deprecated = "use i2c-sensor,bmp085";
+	};
+
+	highperi {
+		bcm2711;
+	};
+
+	i2c0-bcm2708 {
+		deprecated = "use i2c0";
+	};
+
+	i2c1-bcm2708 {
+		deprecated = "use i2c1";
+	};
+
+	i2c3 {
+		bcm2711;
+	};
+
+	i2c4 {
+		bcm2711;
+	};
+
+	i2c5 {
+		bcm2711;
+	};
+
+	i2c6 {
+		bcm2711;
+	};
+
+	lirc-rpi {
+		deprecated = "use gpio-ir";
+	};
+
+	pcie-32bit-dma {
+		bcm2711;
+	};
+
+	pi3-act-led {
+		renamed = "act-led";
+	};
+
+	pi3-disable-bt {
+		renamed = "disable-bt";
+	};
+
+	pi3-disable-wifi {
+		renamed = "disable-wifi";
+	};
+
+	pi3-miniuart-bt {
+		renamed = "miniuart-bt";
+	};
+
+	rpivid-v4l2 {
+		bcm2711;
+	};
+
+	sdio-1bit {
+		deprecated = "use sdio,bus_width=1,gpios_22_25";
+	};
+
+	sdtweak {
+		deprecated = "use 'dtparam=sd_poll_once' etc.";
+	};
+
+	spi0-cs {
+		renamed = "spi0-2cs";
+	};
+
+	spi0-hw-cs {
+		deprecated = "no longer necessary";
+	};
+
+	spi3-1cs {
+		bcm2711;
+	};
+
+	spi3-2cs {
+		bcm2711;
+	};
+
+	spi4-1cs {
+		bcm2711;
+	};
+
+	spi4-2cs {
+		bcm2711;
+	};
+
+	spi5-1cs {
+		bcm2711;
+	};
+
+	spi5-2cs {
+		bcm2711;
+	};
+
+	spi6-1cs {
+		bcm2711;
+	};
+
+	spi6-2cs {
+		bcm2711;
+	};
+
+	uart2 {
+		bcm2711;
+	};
+
+	uart3 {
+		bcm2711;
+	};
+
+	uart4 {
+		bcm2711;
+	};
+
+	uart5 {
+		bcm2711;
+	};
+
+	upstream {
+		bcm2835;
+		bcm2711 = "upstream-pi4";
+	};
+
+	upstream-aux-interrupt {
+		deprecated = "no longer necessary";
+	};
+
+	upstream-pi4 {
+		bcm2711;
+	};
+
+	vc4-kms-v3d {
+		bcm2835;
+		bcm2711 = "vc4-kms-v3d-pi4";
+	};
+
+	vc4-kms-v3d-pi4 {
+		bcm2711;
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/papirus-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/papirus-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/papirus-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/papirus-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* PaPiRus ePaper Screen by Pi Supply */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			display_temp: lm75@48 {
+				compatible = "lm75b";
+				reg = <0x48>;
+				status = "okay";
+				#thermal-sensor-cells = <0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			thermal-zones {
+				display {
+					polling-delay-passive = <0>;
+					polling-delay = <0>;
+					thermal-sensors = <&display_temp>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+
+			spidev@0{
+				status = "disabled";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			repaper_pins: repaper_pins {
+				brcm,pins = <14 15 23 24 25>;
+				brcm,function = <1 1 1 1 0>; /* out out out out in */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			repaper: repaper@0{
+				compatible = "not_set";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&repaper_pins>;
+
+				spi-max-frequency = <8000000>;
+
+				panel-on-gpios = <&gpio 23 0>;
+				border-gpios = <&gpio 14 0>;
+				discharge-gpios = <&gpio 15 0>;
+				reset-gpios = <&gpio 24 0>;
+				busy-gpios = <&gpio 25 0>;
+
+				repaper-thermal-zone = "display";
+			};
+		};
+	};
+
+	__overrides__ {
+		panel = <&repaper>, "compatible";
+		speed = <&repaper>, "spi-max-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pca953x-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pca953x-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pca953x-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pca953x-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for NXP PCA953x family of I2C GPIO controllers on ARM I2C bus.
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pca: pca@20 {
+				compatible = "nxp,pca9534";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca6416";
+		};
+	};
+	fragment@2 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9505";
+		};
+	};
+	fragment@3 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9535";
+		};
+	};
+	fragment@4 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9536";
+		};
+	};
+	fragment@5 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9537";
+		};
+	};
+	fragment@6 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9538";
+		};
+	};
+	fragment@7 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9539";
+		};
+	};
+	fragment@8 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9554";
+		};
+	};
+	fragment@9 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9555";
+		};
+	};
+	fragment@10 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9556";
+		};
+	};
+	fragment@11 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9557";
+		};
+	};
+	fragment@12 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9574";
+		};
+	};
+	fragment@13 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9575";
+		};
+	};
+	fragment@14 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca9698";
+		};
+	};
+	fragment@15 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca16416";
+		};
+	};
+	fragment@16 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca16524";
+		};
+	};
+	fragment@17 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "nxp,pca19555a";
+		};
+	};
+	fragment@18 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "maxim,max7310";
+		};
+	};
+	fragment@19 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "maxim,max7312";
+		};
+	};
+	fragment@20 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "maxim,max7313";
+		};
+	};
+	fragment@21 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "maxim,max7315";
+		};
+	};
+	fragment@22 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "ti,pca6107";
+		};
+	};
+	fragment@23 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "ti,tca6408";
+		};
+	};
+	fragment@24 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "ti,tca6416";
+		};
+	};
+	fragment@25 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "ti,tca6424";
+		};
+	};
+	fragment@26 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "ti,tca9539";
+		};
+	};
+	fragment@27 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "ti,tca9554";
+		};
+	};
+	fragment@28 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "onnn,cat9554";
+		};
+	};
+	fragment@29 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "onnn,pca9654";
+		};
+	};
+	fragment@30 {
+		target = <&pca>;
+		__dormant__ {
+			compatible = "exar,xra1202";
+		};
+	};
+
+	__overrides__ {
+		addr = <&pca>,"reg:0";
+		pca6416 = <0>, "+1";
+		pca9505 = <0>, "+2";
+		pca9535 = <0>, "+3";
+		pca9536 = <0>, "+4";
+		pca9537 = <0>, "+5";
+		pca9538 = <0>, "+6";
+		pca9539 = <0>, "+7";
+		pca9554 = <0>, "+8";
+		pca9555 = <0>, "+9";
+		pca9556 = <0>, "+10";
+		pca9557 = <0>, "+11";
+		pca9574 = <0>, "+12";
+		pca9575 = <0>, "+13";
+		pca9698 = <0>, "+14";
+		pca16416 = <0>, "+15";
+		pca16524 = <0>, "+16";
+		pca19555a = <0>, "+17";
+		max7310 = <0>, "+18";
+		max7312 = <0>, "+19";
+		max7313 = <0>, "+20";
+		max7315 = <0>, "+21";
+		pca6107 = <0>, "+22";
+		tca6408 = <0>, "+23";
+		tca6416 = <0>, "+24";
+		tca6424 = <0>, "+25";
+		tca9539 = <0>, "+26";
+		tca9554 = <0>, "+27";
+		cat9554 = <0>, "+28";
+		pca9654 = <0>, "+29";
+		xra1202 = <0>, "+30";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pcie-32bit-dma-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pcie-32bit-dma-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pcie-32bit-dma-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pcie-32bit-dma-overlay.dts	2021-07-25 16:45:35.148807558 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * pcie-32bit-dma-overlay.dts
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target-path = "/aliases";
+		__overlay__ {
+			pcie0 = "";
+		};
+	};
+
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pibell-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pibell-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pibell-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pibell-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+
+    fragment@0 {
+        target-path = "/";
+        __overlay__ {
+            codec_out: spdif-transmitter {
+                #address-cells = <0>;
+                #size-cells = <0>;
+                #sound-dai-cells = <0>;
+                compatible = "linux,spdif-dit";
+                status = "okay";
+            };
+
+            codec_in: card-codec {
+                #sound-dai-cells = <0>;
+                compatible = "invensense,ics43432";
+                status = "okay";
+            };
+        };
+    };
+
+    fragment@1 {
+        target = <&i2s>;
+        __overlay__ {
+            #sound-dai-cells = <0>;
+            status = "okay";
+        };
+    };
+
+    fragment@2 {
+        target = <&sound>;
+        snd: __overlay__ {
+            compatible = "simple-audio-card";
+            simple-audio-card,name = "PiBell";
+
+            status="okay";
+
+            capture_link: simple-audio-card,dai-link@0 {
+                format = "i2s";
+
+                r_cpu_dai: cpu {
+                    sound-dai = <&i2s>;
+
+/* example TDM slot configuration
+                    dai-tdm-slot-num = <2>;
+                    dai-tdm-slot-width = <32>;
+*/
+                };
+
+                r_codec_dai: codec {
+                    sound-dai = <&codec_in>;
+                };
+            };
+
+            playback_link: simple-audio-card,dai-link@1 {
+                format = "i2s";
+
+                p_cpu_dai: cpu {
+                    sound-dai = <&i2s>;
+
+/* example TDM slot configuration
+                    dai-tdm-slot-num = <2>;
+                    dai-tdm-slot-width = <32>;
+*/
+                };
+
+                p_codec_dai: codec {
+                    sound-dai = <&codec_out>;
+                };
+            };
+        };
+    };
+
+    __overrides__ {
+        alsaname = <&snd>, "simple-audio-card,name";
+    };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifacedigital-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifacedigital-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifacedigital-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifacedigital-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PiFace Digital, Device Tree Overlay.
+ * Copyright (C) 2020 Thomas Preston <thomas.preston@codethink.co.uk>
+ *
+ * The PiFace Digital is a convenient breakout board for the Microchip mcp23s17
+ * SPI GPIO port expander.
+ *
+ * The first eight GPIOs 0..7 (bank A) are connected to eight output terminals
+ * and LEDs, plus two relays on the first two outputs. These output loads are
+ * active-high.
+ *
+ * The next eight GPIOs 8..15 (bank B) are connected to eight input terminals
+ * with four on-board switches connecting them to ground. Inputs devices are
+ * therefore expected to bridge terminals to ground, so the mcp23s17 pullups are
+ * activated for GPIO bank B.
+ *
+ * On PiFace Digital, the mcp23s17 is connected to the Raspberry Pi's SPI0 CS0
+ * bus. Each SPI bus supports up to eight addressable child devices. The PiFace
+ * Digital only supports addresses 0-4, which can be configured by jumpers JP1
+ * and JP2.
+ *
+ * You can tell the driver about these jumper configurations with the
+ * spi-present-mask bitmask:
+ *
+ *     | JP1 | JP2 | dtoverlay line in /boot/config.txt         |
+ *     | --- | --- | ------------------------------------------ |
+ *     |  0  |  0  | dtoverlay=pifacedigital                    |
+ *     |  0  |  0  | dtoverlay=pifacedigital:spi-present-mask=1 |
+ *     |  0  |  1  | dtoverlay=pifacedigital:spi-present-mask=2 |
+ *     |  1  |  0  | dtoverlay=pifacedigital:spi-present-mask=4 |
+ *     |  1  |  1  | dtoverlay=pifacedigital:spi-present-mask=8 |
+ *
+ * # Example
+ * Set the dtoverlay config in /boot/config.txt and power off the Raspberry Pi:
+ *
+ *     $ grep pifacedigital /boot/config.txt
+ *     dtoverlay=pifacedigital
+ *     $ sudo systemctl poweroff
+ *
+ * Attach the PiFace Digital and power on the Raspberry Pi.
+ * Then use the libgpiod tools to query the device:
+ *
+ *     $ sudo apt install gpiod
+ *     $ gpiodetect | grep mcp23s17
+ *     gpiochip2 [mcp23s17.0] (16 lines)
+ *
+ * Set GPIO outputs 0, 2 and 5:
+ *
+ *     $ gpioset gpiochip2 0=1 2=1 5=1
+ *
+ * Get GPIO status (input GPIO 8..15 are high, because they are active-low):
+ *
+ *     $ gpioget gpiochip2 {8..15}
+ *     1 1 1 1 1 1 1 1
+ *
+ * And even monitor interrupts:
+ *
+ *     $ gpiomon gpiochip2 {8..15}
+ *     event: FALLING EDGE offset: 11 timestamp: [1597361662.926741667]
+ *     event:  RISING EDGE offset: 11 timestamp: [1597361663.062555051]
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	/* Disable exposing /dev/spidev0.0 */
+	fragment@0 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	/* Add the PiFace Digital device node to the spi0.0 device. */
+	fragment@1 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pfdigital: pifacedigital@0 {
+				compatible = "microchip,mcp23s17";
+				reg = <0>;
+
+				/* Set devices present with 8-bit mask. */
+				microchip,spi-present-mask = <0x01>;
+				spi-max-frequency = <500000>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				/* This device can pass through interrupts. */
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				/* INTB is connected to GPIO 25.
+				 * 0x8 active-low level-sensitive
+				 */
+				interrupts = <25 0x8>;
+				interrupt-parent = <&gpio>;
+
+				/* Configure pull-ups on bank B GPIOs */
+				pinctrl-0 = <&pfdigital_irq &pfdigital_pullups>;
+				pinctrl-names = "default";
+				pfdigital_pullups: pinmux {
+					pins =
+						"gpio8",
+						"gpio9",
+						"gpio10",
+						"gpio11",
+						"gpio12",
+						"gpio13",
+						"gpio14",
+						"gpio15";
+					bias-pull-up;
+				};
+			};
+		};
+	};
+
+	/* PiFace Digital mcp23s17 INTB pin is connected to GPIO 25. The INTB
+	 * pin is configured active-low (0 on interrupt), so expect to see
+	 * FALLING_EDGE when inputs are bridged to ground (switch is pressed).
+	 */
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			pfdigital_irq: pifacedigital_irq {
+				brcm,pins = <25>;
+				brcm,function = <0>; /* input */
+			};
+		};
+	};
+
+	__overrides__ {
+		spi-present-mask = <&pfdigital>, "microchip,spi-present-mask:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifi-40-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifi-40-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifi-40-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifi-40-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for PiFi-40 Amp
+/dts-v1/;
+/plugin/;
+#include <dt-bindings/gpio/gpio.h>
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			tas5711l: audio-codec@1a {
+				compatible = "ti,tas5711";
+				reg = <0x1a>;
+				#sound-dai-cells = <0>;
+				sound-name-prefix = "Left";
+				status = "okay";
+			};
+
+			tas5711r: audio-codec@1b {
+				compatible = "ti,tas5711";
+				reg = <0x1b>;
+				#sound-dai-cells = <0>;
+				sound-name-prefix = "Right";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		pifi_40: __overlay__ {
+			compatible = "pifi,pifi-40";
+			audio-codec = <&tas5711l &tas5711r>;
+			i2s-controller = <&i2s>;
+			pdn-gpios = <&gpio 23 1>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifi-dac-hd-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifi-dac-hd-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifi-dac-hd-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifi-dac-hd-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for PiFi-DAC-HD
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells =<0>;
+
+			pcm5142: pcm5142@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5142";
+				reg = <0x4c>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "simple-audio-card";
+			simple-audio-card,name = "PiFi-DAC-HD";
+			status = "okay";
+
+			simple-audio-card,dai-link@1 {
+				format = "i2s";
+				cpu {
+					sound-dai = <&i2s>;
+				};
+				codec {
+					sound-dai = <&pcm5142>;
+				};
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifi-dac-zero-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifi-dac-zero-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifi-dac-zero-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifi-dac-zero-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for PiFi-DAC-Zero
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "simple-audio-card";
+			simple-audio-card,name = "PiFi-DAC-Zero";
+			status = "okay";
+
+			simple-audio-card,dai-link@1 {
+				format = "i2s";
+
+				cpu {
+					sound-dai = <&i2s>;
+					dai-tdm-slot-num = <2>;
+					dai-tdm-slot-width = <32>;
+				};
+
+				codec {
+					sound-dai = <&codec_out>;
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			codec_out: pcm5102a-codec {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5102a";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2s>;
+		__overlay__ {
+			#sound-dai-cells = <0>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for PiFi Mini 210
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			tas5711@1a {
+				#sound-dai-cells = <0>;
+				compatible = "ti,tas5711";
+				reg = <0x1a>;
+				status = "okay";
+				pdn-gpios = <&gpio 23 1>;
+				reset-gpios = <&gpio 24 1>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "pifi,pifi-mini-210";
+			i2s-controller = <&i2s>;
+
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/piglow-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/piglow-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/piglow-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/piglow-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for SN3218 LED driver from Si-En Technology on PiGlow
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			sn3218@54 {
+				compatible = "si-en,sn3218";
+				reg = <0x54>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "okay";
+
+				led@1 {
+					reg = <1>;
+					label = "piglow:red:led1";
+				};
+				led@2 {
+					reg = <2>;
+					label = "piglow:orange:led2";
+				};
+				led@3 {
+					reg = <3>;
+					label = "piglow:yellow:led3";
+				};
+				led@4 {
+					reg = <4>;
+					label = "piglow:green:led4";
+				};
+				led@5 {
+					reg = <5>;
+					label = "piglow:blue:led5";
+				};
+				led@6 {
+					reg = <6>;
+					label = "piglow:green:led6";
+				};
+				led@7 {
+					reg = <7>;
+					label = "piglow:red:led7";
+				};
+				led@8 {
+					reg = <8>;
+					label = "piglow:orange:led8";
+				};
+				led@9 {
+					reg = <9>;
+					label = "piglow:yellow:led9";
+				};
+				led@10 {
+					reg = <10>;
+					label = "piglow:white:led10";
+				};
+				led@11 {
+					reg = <11>;
+					label = "piglow:white:led11";
+				};
+				led@12 {
+					reg = <12>;
+					label = "piglow:blue:led12";
+				};
+				led@13 {
+					reg = <13>;
+					label = "piglow:white:led13";
+				};
+				led@14 {
+					reg = <14>;
+					label = "piglow:green:led14";
+				};
+				led@15 {
+					reg = <15>;
+					label = "piglow:blue:led15";
+				};
+				led@16 {
+					reg = <16>;
+					label = "piglow:yellow:led16";
+				};
+				led@17 {
+					reg = <17>;
+					label = "piglow:orange:led17";
+				};
+				led@18 {
+					reg = <18>;
+					label = "piglow:red:led18";
+				};
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+ /*
+ * Device Tree overlay for PiScreen2 3.5" TFT with resistive touch  by Ozzmaker.com
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			piscreen2_pins: piscreen2_pins {
+				brcm,pins = <17 25 24 22>;
+				brcm,function = <0 1 1 1>; /* in out out out */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			piscreen2: piscreen2@0{
+				compatible = "ilitek,ili9486";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&piscreen2_pins>;
+				bgr;
+				spi-max-frequency = <64000000>;
+				rotate = <90>;
+				fps = <30>;
+				buswidth = <8>;
+				regwidth = <16>;
+				txbuflen = <32768>;
+				reset-gpios = <&gpio 25 1>;
+				dc-gpios = <&gpio 24 0>;
+				led-gpios = <&gpio 22 0>;
+				debug = <0>;
+
+                                init = <0x10000b0 0x00
+                                        0x1000011
+                                        0x20000ff
+                                        0x100003a 0x55
+                                        0x1000036 0x28
+                                        0x10000c0 0x11 0x09
+                                        0x10000c1 0x41
+                                        0x10000c5 0x00 0x00 0x00 0x00
+                                        0x10000b6 0x00 0x02
+                                        0x10000f7 0xa9 0x51 0x2c 0x2
+                                        0x10000be 0x00 0x04
+                                        0x10000e9 0x00
+                                        0x1000011
+                                        0x1000029>;
+
+			};
+
+			piscreen2_ts: piscreen2-ts@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+
+				spi-max-frequency = <2000000>;
+				interrupts = <17 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 17 0>;
+				ti,swap-xy;
+				ti,x-plate-ohms = /bits/ 16 <100>;
+				ti,pressure-max = /bits/ 16 <255>;
+			};
+		};
+	};
+	__overrides__ {
+		speed =		<&piscreen2>,"spi-max-frequency:0";
+		rotate =	<&piscreen2>,"rotate:0";
+		fps =		<&piscreen2>,"fps:0";
+		debug =		<&piscreen2>,"debug:0";
+		xohms =		<&piscreen2_ts>,"ti,x-plate-ohms;0";
+	};
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/piscreen-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/piscreen-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/piscreen-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/piscreen-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for PiScreen 3.5" display shield by Ozzmaker
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			piscreen_pins: piscreen_pins {
+				brcm,pins = <17 25 24 22>;
+				brcm,function = <0 1 1 1>; /* in out out out */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			piscreen: piscreen@0{
+				compatible = "ilitek,ili9486";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&piscreen_pins>;
+
+				spi-max-frequency = <24000000>;
+				rotate = <270>;
+				bgr;
+				fps = <30>;
+				buswidth = <8>;
+				regwidth = <16>;
+				reset-gpios = <&gpio 25 1>;
+				dc-gpios = <&gpio 24 0>;
+				led-gpios = <&gpio 22 0>;
+				debug = <0>;
+
+				init = <0x10000b0 0x00
+				        0x1000011
+					0x20000ff
+					0x100003a 0x55
+					0x1000036 0x28
+					0x10000c2 0x44
+					0x10000c5 0x00 0x00 0x00 0x00
+					0x10000e0 0x0f 0x1f 0x1c 0x0c 0x0f 0x08 0x48 0x98 0x37 0x0a 0x13 0x04 0x11 0x0d 0x00
+					0x10000e1 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00
+					0x10000e2 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00
+					0x1000011
+					0x1000029>;
+			};
+
+			piscreen_ts: piscreen-ts@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+
+				spi-max-frequency = <2000000>;
+				interrupts = <17 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 17 0>;
+				ti,swap-xy;
+				ti,x-plate-ohms = /bits/ 16 <100>;
+				ti,pressure-max = /bits/ 16 <255>;
+			};
+		};
+	};
+	__overrides__ {
+		speed =		<&piscreen>,"spi-max-frequency:0";
+		rotate =	<&piscreen>,"rotate:0";
+		fps =		<&piscreen>,"fps:0";
+		debug =		<&piscreen>,"debug:0";
+		xohms =		<&piscreen_ts>,"ti,x-plate-ohms;0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pisound-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pisound-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pisound-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pisound-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Pisound Linux kernel module.
+ * Copyright (C) 2016-2017  Vilniaus Blokas UAB, https://blokas.io/pisound
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&spi0>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pisound_spi: pisound_spi@0{
+				compatible = "blokaslabs,pisound-spi";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&spi0_pins>;
+				spi-max-frequency = <1000000>;
+			};
+		};
+	};
+
+	fragment@4 {
+		target-path = "/";
+		__overlay__ {
+			pcm5102a-codec {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5102a";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@5 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "blokaslabs,pisound";
+			i2s-controller = <&i2s>;
+			status = "okay";
+
+			pinctrl-0 = <&pisound_button_pins>;
+
+			osr-gpios =
+				<&gpio 13 GPIO_ACTIVE_HIGH>,
+				<&gpio 26 GPIO_ACTIVE_HIGH>,
+				<&gpio 16 GPIO_ACTIVE_HIGH>;
+
+			reset-gpios =
+				<&gpio 12 GPIO_ACTIVE_HIGH>,
+				<&gpio 24 GPIO_ACTIVE_HIGH>;
+
+			data_available-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>;
+
+			button-gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	fragment@6 {
+		target = <&gpio>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pisound_button_pins>;
+
+			pisound_button_pins: pisound_button_pins {
+				brcm,pins = <17>;
+				brcm,function = <0>; // Input
+				brcm,pull = <2>; // Pull-Up
+			};
+		};
+	};
+
+	fragment@7 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pitft22-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pitft22-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pitft22-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pitft22-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for pitft by Adafruit
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "brcm,bcm2835";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+
+                        spidev@0{
+                                status = "disabled";
+                        };
+
+                        spidev@1{
+                                status = "disabled";
+                        };
+                };
+        };
+
+        fragment@1 {
+                target = <&gpio>;
+                __overlay__ {
+                        pitft_pins: pitft_pins {
+                                brcm,pins = <25>;
+                                brcm,function = <1>; /* out */
+                                brcm,pull = <0>; /* none */
+                        };
+                };
+        };
+
+        fragment@2 {
+                target = <&spi0>;
+                __overlay__ {
+                        /* needed to avoid dtc warning */
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+
+                        pitft: pitft@0{
+                                compatible = "ilitek,ili9340";
+                                reg = <0>;
+                                pinctrl-names = "default";
+                                pinctrl-0 = <&pitft_pins>;
+
+                                spi-max-frequency = <32000000>;
+                                rotate = <90>;
+                                fps = <25>;
+                                bgr;
+                                buswidth = <8>;
+                                dc-gpios = <&gpio 25 0>;
+                                debug = <0>;
+                        };
+
+                };
+        };
+
+        __overrides__ {
+                speed =   <&pitft>,"spi-max-frequency:0";
+                rotate =  <&pitft>,"rotate:0";
+                fps =     <&pitft>,"fps:0";
+                debug =   <&pitft>,"debug:0";
+        };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for Adafruit PiTFT 2.8" capacitive touch screen
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "brcm,bcm2835";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+                };
+        };
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+        fragment@2 {
+                target = <&gpio>;
+                __overlay__ {
+                        pitft_pins: pitft_pins {
+                                brcm,pins = <24 25>;
+                                brcm,function = <0 1>; /* in out */
+                                brcm,pull = <2 0>; /* pullup none */
+                        };
+                };
+        };
+
+        fragment@3 {
+                target = <&spi0>;
+                __overlay__ {
+                        /* needed to avoid dtc warning */
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+
+                        pitft: pitft@0{
+                                compatible = "ilitek,ili9340";
+                                reg = <0>;
+                                pinctrl-names = "default";
+                                pinctrl-0 = <&pitft_pins>;
+
+                                spi-max-frequency = <32000000>;
+                                rotate = <90>;
+                                fps = <25>;
+                                bgr;
+                                buswidth = <8>;
+                                dc-gpios = <&gpio 25 0>;
+                                debug = <0>;
+                        };
+                };
+        };
+
+        fragment@4 {
+                target = <&i2c1>;
+                __overlay__ {
+                        /* needed to avoid dtc warning */
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+
+                        ft6236: ft6236@38 {
+                                compatible = "focaltech,ft6236";
+                                reg = <0x38>;
+
+                                interrupt-parent = <&gpio>;
+                                interrupts = <24 2>;
+                                touchscreen-size-x = <240>;
+                                touchscreen-size-y = <320>;
+                        };
+                };
+        };
+
+        __overrides__ {
+                speed =   <&pitft>,"spi-max-frequency:0";
+                rotate =  <&pitft>,"rotate:0";
+                fps =     <&pitft>,"fps:0";
+                debug =   <&pitft>,"debug:0";
+                touch-sizex = <&ft6236>,"touchscreen-size-x?";
+                touch-sizey = <&ft6236>,"touchscreen-size-y?";
+                touch-invx  = <&ft6236>,"touchscreen-inverted-x?";
+                touch-invy  = <&ft6236>,"touchscreen-inverted-y?";
+                touch-swapxy = <&ft6236>,"touchscreen-swapped-x-y?";
+        };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for Adafruit PiTFT 2.8" resistive touch screen
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			pitft_pins: pitft_pins {
+				brcm,pins = <24 25>;
+				brcm,function = <0 1>; /* in out */
+				brcm,pull = <2 0>; /* pullup none */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pitft: pitft@0{
+				compatible = "ilitek,ili9340";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&pitft_pins>;
+
+				spi-max-frequency = <32000000>;
+				rotate = <90>;
+				fps = <25>;
+				bgr;
+				buswidth = <8>;
+				dc-gpios = <&gpio 25 0>;
+				debug = <0>;
+			};
+
+			pitft_ts@1 {
+				compatible = "st,stmpe610";
+				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;
+
+				stmpe_touchscreen {
+					compatible = "st,stmpe-ts";
+					st,sample-time = <4>;
+					st,mod-12b = <1>;
+					st,ref-sel = <0>;
+					st,adc-freq = <2>;
+					st,ave-ctrl = <3>;
+					st,touch-det-delay = <4>;
+					st,settling = <2>;
+					st,fraction-z = <7>;
+					st,i-drive = <0>;
+				};
+
+				stmpe_gpio: stmpe_gpio {
+					#gpio-cells = <2>;
+					compatible = "st,stmpe-gpio";
+					/*
+					 * only GPIO2 is wired/available
+					 * and it is wired to the backlight
+					 */
+					st,norequest-mask = <0x7b>;
+				};
+			};
+		};
+	};
+
+	fragment@5 {
+		target-path = "/soc";
+		__overlay__ {
+			backlight {
+				compatible = "gpio-backlight";
+				gpios = <&stmpe_gpio 2 0>;
+				default-on;
+			};
+		};
+	};
+
+	__overrides__ {
+		speed =   <&pitft>,"spi-max-frequency:0";
+		rotate =  <&pitft>,"rotate:0";
+		fps =     <&pitft>,"fps:0";
+		debug =   <&pitft>,"debug:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for Adafruit PiTFT 3.5" resistive touch screen
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			pitft_pins: pitft_pins {
+				brcm,pins = <24 25>;
+				brcm,function = <0 1>; /* in out */
+				brcm,pull = <2 0>; /* pullup none */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pitft: pitft@0{
+				compatible = "himax,hx8357d", "adafruit,yx350hv15";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&pitft_pins>;
+
+				spi-max-frequency = <32000000>;
+				rotate = <90>;
+				fps = <25>;
+				bgr;
+				buswidth = <8>;
+				dc-gpios = <&gpio 25 0>;
+				debug = <0>;
+			};
+
+			pitft_ts@1 {
+				compatible = "st,stmpe610";
+				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;
+
+				stmpe_touchscreen {
+					compatible = "st,stmpe-ts";
+					st,sample-time = <4>;
+					st,mod-12b = <1>;
+					st,ref-sel = <0>;
+					st,adc-freq = <2>;
+					st,ave-ctrl = <3>;
+					st,touch-det-delay = <4>;
+					st,settling = <2>;
+					st,fraction-z = <7>;
+					st,i-drive = <0>;
+				};
+
+				stmpe_gpio: stmpe_gpio {
+					#gpio-cells = <2>;
+					compatible = "st,stmpe-gpio";
+					/*
+					 * only GPIO2 is wired/available
+					 * and it is wired to the backlight
+					 */
+					st,norequest-mask = <0x7b>;
+				};
+			};
+		};
+	};
+
+	fragment@5 {
+		target-path = "/soc";
+		__overlay__ {
+			backlight {
+				compatible = "gpio-backlight";
+				gpios = <&stmpe_gpio 2 0>;
+				default-on;
+			};
+		};
+	};
+
+	__overrides__ {
+		speed =   <&pitft>,"spi-max-frequency:0";
+		rotate =  <&pitft>,"rotate:0";
+		fps =     <&pitft>,"fps:0";
+		debug =   <&pitft>,"debug:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			pps: pps@12 {
+				compatible = "pps-gpio";
+				pinctrl-names = "default";
+				pinctrl-0 = <&pps_pins>;
+				gpios = <&gpio 18 0>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			pps_pins: pps_pins@12 {
+				brcm,pins =     <18>;
+				brcm,function = <0>;    // in
+				brcm,pull =     <0>;    // off
+			};
+		};
+	};
+
+	__overrides__ {
+		gpiopin = <&pps>,"gpios:4",
+			  <&pps>,"reg:0",
+			  <&pps_pins>,"brcm,pins:0",
+			  <&pps_pins>,"reg:0";
+		assert_falling_edge = <&pps>,"assert-falling-edge?";
+		capture_clear = <&pps>,"capture-clear?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/*
+This is the 2-channel overlay - only use it if you need both channels.
+
+Legal pin,function combinations for each channel:
+  PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0)            52,5(Alt1)
+  PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
+
+N.B.:
+  1) Pin 18 is the only one available on all platforms, and
+     it is the one used by the I2S audio interface.
+     Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
+  2) The onboard analogue audio output uses both PWM channels.
+  3) So be careful mixing audio and PWM.
+*/
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			pwm_pins: pwm_pins {
+				brcm,pins = <18 19>;
+				brcm,function = <2 2>; /* Alt5 */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&pwm>;
+		frag1: __overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pwm_pins>;
+			assigned-clock-rates = <100000000>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		pin   = <&pwm_pins>,"brcm,pins:0";
+		pin2  = <&pwm_pins>,"brcm,pins:4";
+		func  = <&pwm_pins>,"brcm,function:0";
+		func2 = <&pwm_pins>,"brcm,function:4";
+		clock = <&frag1>,"assigned-clock-rates:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			pwm0_pins: pwm0_pins {
+				brcm,pins = <18>;
+				brcm,function = <2>; /* Alt5 */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&pwm>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pwm0_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target-path = "/";
+		__overlay__ {
+			pwm-ir-transmitter {
+				compatible = "pwm-ir-tx";
+				pwms = <&pwm 0 100>;
+			};
+		};
+	};
+
+	__overrides__ {
+		gpio_pin = <&pwm0_pins>, "brcm,pins:0";
+		func = <&pwm0_pins>,"brcm,function:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/pwm-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pwm-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/pwm-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/pwm-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/*
+Legal pin,function combinations for each channel:
+  PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0)            52,5(Alt1)
+  PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
+
+N.B.:
+  1) Pin 18 is the only one available on all platforms, and
+     it is the one used by the I2S audio interface.
+     Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
+  2) The onboard analogue audio output uses both PWM channels.
+  3) So be careful mixing audio and PWM.
+*/
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			pwm_pins: pwm_pins {
+				brcm,pins = <18>;
+				brcm,function = <2>; /* Alt5 */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&pwm>;
+		frag1: __overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pwm_pins>;
+			assigned-clock-rates = <100000000>;
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		pin   = <&pwm_pins>,"brcm,pins:0";
+		func  = <&pwm_pins>,"brcm,function:0";
+		clock = <&frag1>,"assigned-clock-rates:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/qca7000-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/qca7000-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/qca7000-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/qca7000-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for the Qualcomm Atheros QCA7000 on I2SE's PLC Stamp micro EVK
+// Visit: https://www.i2se.com/product/plc-stamp-micro-evk for details
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			eth1: qca7000@0 {
+				compatible = "qca,qca7000";
+				reg = <0>; /* CE0 */
+				pinctrl-names = "default";
+				pinctrl-0 = <&eth1_pins>;
+				interrupt-parent = <&gpio>;
+				interrupts = <23 0x1>; /* rising edge */
+				spi-max-frequency = <12000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&gpio>;
+		__overlay__ {
+			eth1_pins: eth1_pins {
+				brcm,pins = <23>;
+				brcm,function = <0>; /* in */
+				brcm,pull = <0>; /* none */
+			};
+		};
+	};
+
+	__overrides__ {
+		int_pin = <&eth1>, "interrupts:0",
+		          <&eth1_pins>, "brcm,pins:0";
+		speed   = <&eth1>, "spi-max-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/README linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/README
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/README	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/README	2021-07-25 16:45:35.138807726 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+Introduction
+============
+
+This directory contains Device Tree overlays. Device Tree makes it possible
+to support many hardware configurations with a single kernel and without the
+need to explicitly load or blacklist kernel modules. Note that this isn't a
+"pure" Device Tree configuration (c.f. MACH_BCM2835) - some on-board devices
+are still configured by the board support code, but the intention is to
+eventually reach that goal.
+
+On Raspberry Pi, Device Tree usage is controlled from /boot/config.txt. By
+default, the Raspberry Pi kernel boots with device tree enabled. You can
+completely disable DT usage (for now) by adding:
+
+    device_tree=
+
+to your config.txt, which should cause your Pi to revert to the old way of
+doing things after a reboot.
+
+In /boot you will find a .dtb for each base platform. This describes the
+hardware that is part of the Raspberry Pi board. The loader (start.elf and its
+siblings) selects the .dtb file appropriate for the platform by name, and reads
+it into memory. At this point, all of the optional interfaces (i2c, i2s, spi)
+are disabled, but they can be enabled using Device Tree parameters:
+
+    dtparam=i2c=on,i2s=on,spi=on
+
+However, this shouldn't be necessary in many use cases because loading an
+overlay that requires one of those interfaces will cause it to be enabled
+automatically, and it is advisable to only enable interfaces if they are
+needed.
+
+Configuring additional, optional hardware is done using Device Tree overlays
+(see below).
+
+GPIO numbering uses the hardware pin numbering scheme (aka BCM scheme) and
+not the physical pin numbers.
+
+raspi-config
+============
+
+The Advanced Options section of the raspi-config utility can enable and disable
+Device Tree use, as well as toggling the I2C and SPI interfaces. Note that it
+is possible to both enable an interface and blacklist the driver, if for some
+reason you should want to defer the loading.
+
+Modules
+=======
+
+As well as describing the hardware, Device Tree also gives enough information
+to allow suitable driver modules to be located and loaded, with the corollary
+that unneeded modules are not loaded. As a result it should be possible to
+remove lines from /etc/modules, and /etc/modprobe.d/raspi-blacklist.conf can
+have its contents deleted (or commented out).
+
+Using Overlays
+==============
+
+Overlays are loaded using the "dtoverlay" config.txt setting. As an example,
+consider I2C Real Time Clock drivers. In the pre-DT world these would be loaded
+by writing a magic string comprising a device identifier and an I2C address to
+a special file in /sys/class/i2c-adapter, having first loaded the driver for
+the I2C interface and the RTC device - something like this:
+
+    modprobe i2c-bcm2835
+    modprobe rtc-ds1307
+    echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
+
+With DT enabled, this becomes a line in config.txt:
+
+    dtoverlay=i2c-rtc,ds1307
+
+This causes the file /boot/overlays/i2c-rtc.dtbo to be loaded and a "node"
+describing the DS1307 I2C device to be added to the Device Tree for the Pi. By
+default it usees address 0x68, but this can be modified with an additional DT
+parameter:
+
+    dtoverlay=i2c-rtc,ds1307,addr=0x68
+
+Parameters usually have default values, although certain parameters are
+mandatory. See the list of overlays below for a description of the parameters
+and their defaults.
+
+Making new Overlays based on existing Overlays
+==============================================
+
+Recent overlays have been designed in a more general way, so that they can be
+adapted to hardware by changing their parameters. When you have additional
+hardware with more than one device of a kind, you end up using the same overlay
+multiple times with other parameters, e.g.
+
+    # 2 CAN FD interfaces on spi but with different pins
+    dtoverlay=mcp251xfd,spi0-0,interrupt=25
+    dtoverlay=mcp251xfd,spi0-1,interrupt=24
+
+    # a realtime clock on i2c
+    dtoverlay=i2c-rtc,pcf85063
+
+While this approach does work, it requires knowledge about the hardware design.
+It is more feasible to simplify things for the end user by providing a single
+overlay as it is done the traditional way.
+
+A new overlay can be generated by using ovmerge utility.
+https://github.com/raspberrypi/utils/blob/master/ovmerge/ovmerge
+
+To generate an overlay for the above configuration we pass the configuration
+to ovmerge and add the -c flag.
+
+    ovmerge -c mcp251xfd-overlay.dts,spi0-0,interrupt=25 \
+               mcp251xfd-overlay.dts,spi0-1,interrupt=24 \
+               i2c-rtc-overlay.dts,pcf85063 \
+    >> merged-overlay.dts
+
+The -c option writes the command above as a comment into the overlay as
+a marker that this overlay is generated and how it was generated.
+After compiling the overlay it can be loaded in a single line.
+
+    dtoverlay=merged
+
+It does the same as the original configuration but without parameters.
+
+The Overlay and Parameter Reference
+===================================
+
+N.B. When editing this file, please preserve the indentation levels to make it
+simple to parse programmatically. NO HARD TABS.
+
+
+Name:   <The base DTB>
+Info:   Configures the base Raspberry Pi hardware
+Load:   <loaded automatically>
+Params:
+        ant1                    Select antenna 1 (default). CM4 only.
+
+        ant2                    Select antenna 2. CM4 only.
+
+        noant                   Disable both antennas. CM4 only.
+
+        audio                   Set to "on" to enable the onboard ALSA audio
+                                interface (default "off")
+
+        axiperf                 Set to "on" to enable the AXI bus performance
+                                monitors.
+                                See /sys/kernel/debug/raspberrypi_axi_monitor
+                                for the results.
+
+        eee                     Enable Energy Efficient Ethernet support for
+                                compatible devices (default "on"). See also
+                                "tx_lpi_timer". Pi3B+ only.
+
+        eth_downshift_after     Set the number of auto-negotiation failures
+                                after which the 1000Mbps modes are disabled.
+                                Legal values are 2, 3, 4, 5 and 0, where
+                                0 means never downshift (default 2). Pi3B+ only.
+
+        eth_led0                Set mode of LED0 - amber on Pi3B+ (default "1"),
+                                green on Pi4 (default "0").
+                                The legal values are:
+
+                                Pi3B+
+
+                                0=link/activity          1=link1000/activity
+                                2=link100/activity       3=link10/activity
+                                4=link100/1000/activity  5=link10/1000/activity
+                                6=link10/100/activity    14=off    15=on
+
+                                Pi4
+
+                                0=Speed/Activity         1=Speed
+                                2=Flash activity         3=FDX
+                                4=Off                    5=On
+                                6=Alt                    7=Speed/Flash
+                                8=Link                   9=Activity
+
+        eth_led1                Set mode of LED1 - green on Pi3B+ (default "6"),
+                                amber on Pi4 (default "8"). See eth_led0 for
+                                legal values.
+
+        eth_max_speed           Set the maximum speed a link is allowed
+                                to negotiate. Legal values are 10, 100 and
+                                1000 (default 1000). Pi3B+ only.
+
+        i2c_arm                 Set to "on" to enable the ARM's i2c interface
+                                (default "off")
+
+        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")
+
+        krnbt                   Set to "on" to enable autoprobing of Bluetooth
+                                driver without need of hciattach/btattach
+                                (default "off")
+
+        krnbt_baudrate          Set the baudrate of the PL011 UART when used
+                                with krnbt=on
+
+        spi                     Set to "on" to enable the spi interfaces
+                                (default "off")
+
+        spi_dma4                Use to enable 40-bit DMA on spi interfaces
+                                (the assigned value doesn't matter)
+                                (2711 only)
+
+        random                  Set to "on" to enable the hardware random
+                                number generator (default "on")
+
+        sd_overclock            Clock (in MHz) to use when the MMC framework
+                                requests 50MHz
+
+        sd_poll_once            Looks for a card once after booting. Useful
+                                for network booting scenarios to avoid the
+                                overhead of continuous polling. N.B. Using
+                                this option restricts the system to using a
+                                single card per boot (or none at all).
+                                (default off)
+
+        sd_force_pio            Disable DMA support for SD driver (default off)
+
+        sd_pio_limit            Number of blocks above which to use DMA for
+                                SD card (default 1)
+
+        sd_debug                Enable debug output from SD driver (default off)
+
+        sdio_overclock          Clock (in MHz) to use when the MMC framework
+                                requests 50MHz for the SDIO/WiFi interface.
+
+        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")
+
+        uart1                   Set to "on" or "off" to enable or disable uart1
+                                (default varies)
+
+        watchdog                Set to "on" to enable the hardware watchdog
+                                (default "off")
+
+        act_led_trigger         Choose which activity the LED tracks.
+                                Use "heartbeat" for a nice load indicator.
+                                (default "mmc")
+
+        act_led_activelow       Set to "on" to invert the sense of the LED
+                                (default "off")
+                                N.B. For Pi 3B, 3B+, 3A+ and 4B, use the act-led
+                                overlay.
+
+        act_led_gpio            Set which GPIO to use for the activity LED
+                                (in case you want to connect it to an external
+                                device)
+                                (default "16" on a non-Plus board, "47" on a
+                                Plus or Pi 2)
+                                N.B. For Pi 3B, 3B+, 3A+ and 4B, use the act-led
+                                overlay.
+
+        pwr_led_trigger
+        pwr_led_activelow
+        pwr_led_gpio
+                                As for act_led_*, but using the PWR LED.
+                                Not available on Model A/B boards.
+
+        N.B. It is recommended to only enable those interfaces that are needed.
+        Leaving all interfaces enabled can lead to unwanted behaviour (i2c_vc
+        interfering with Pi Camera, I2S and SPI hogging GPIO pins, etc.)
+        Note also that i2c, i2c_arm and i2c_vc are aliases for the physical
+        interfaces i2c0 and i2c1. Use of the numeric variants is still possible
+        but deprecated because the ARM/VC assignments differ between board
+        revisions. The same board-specific mapping applies to i2c_baudrate,
+        and the other i2c baudrate parameters.
+
+
+Name:   act-led
+Info:   Pi 3B, 3B+, 3A+ and 4B use a GPIO expander to drive the LEDs which can
+        only be accessed from the VPU. There is a special driver for this with a
+        separate DT node, which has the unfortunate consequence of breaking the
+        act_led_gpio and act_led_activelow dtparams.
+        This overlay changes the GPIO controller back to the standard one and
+        restores the dtparams.
+Load:   dtoverlay=act-led,<param>=<val>
+Params: activelow               Set to "on" to invert the sense of the LED
+                                (default "off")
+
+        gpio                    Set which GPIO to use for the activity LED
+                                (in case you want to connect it to an external
+                                device)
+                                REQUIRED
+
+
+Name:   adafruit18
+Info:   Overlay for the SPI-connected Adafruit 1.8" display (based on the
+        ST7735R chip). It includes support for the "green tab" version.
+Load:   dtoverlay=adafruit18,<param>=<val>
+Params: green                   Use the adafruit18_green variant.
+        rotate                  Display rotation {0,90,180,270}
+        speed                   SPI bus speed in Hz (default 4000000)
+        fps                     Display frame rate in Hz
+        bgr                     Enable BGR mode (default off)
+        debug                   Debug output level {0-7}
+        dc_pin                  GPIO pin for D/C (default 24)
+        reset_pin               GPIO pin for RESET (default 25)
+        led_pin                 GPIO used to control backlight (default 18)
+
+
+Name:   adau1977-adc
+Info:   Overlay for activation of ADAU1977 ADC codec over I2C for control
+        and I2S for data.
+Load:   dtoverlay=adau1977-adc
+Params: <None>
+
+
+Name:   adau7002-simple
+Info:   Overlay for the activation of ADAU7002 stereo PDM to I2S converter.
+Load:   dtoverlay=adau7002-simple,<param>=<val>
+Params: card-name               Override the default, "adau7002", card name.
+
+
+Name:   ads1015
+Info:   Overlay for activation of Texas Instruments ADS1015 ADC over I2C
+Load:   dtoverlay=ads1015,<param>=<val>
+Params: addr                    I2C bus address of device. Set based on how the
+                                addr pin is wired. (default=0x48 assumes addr
+                                is pulled to GND)
+        cha_enable              Enable virtual channel a. (default=true)
+        cha_cfg                 Set the configuration for virtual channel a.
+                                (default=4 configures this channel for the
+                                voltage at A0 with respect to GND)
+        cha_datarate            Set the datarate (samples/sec) for this channel.
+                                (default=4 sets 1600 sps)
+        cha_gain                Set the gain of the Programmable Gain
+                                Amplifier for this channel. (default=2 sets the
+                                full scale of the channel to 2.048 Volts)
+
+        Channel (ch) parameters can be set for each enabled channel.
+        A maximum of 4 channels can be enabled (letters a thru d).
+        For more information refer to the device datasheet at:
+        http://www.ti.com/lit/ds/symlink/ads1015.pdf
+
+
+Name:   ads1115
+Info:   Texas Instruments ADS1115 ADC
+Load:   dtoverlay=ads1115,<param>[=<val>]
+Params: addr                    I2C bus address of device. Set based on how the
+                                addr pin is wired. (default=0x48 assumes addr
+                                is pulled to GND)
+        cha_enable              Enable virtual channel a.
+        cha_cfg                 Set the configuration for virtual channel a.
+                                (default=4 configures this channel for the
+                                voltage at A0 with respect to GND)
+        cha_datarate            Set the datarate (samples/sec) for this channel.
+                                (default=7 sets 860 sps)
+        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)
+
+        Channel parameters can be set for each enabled channel.
+        A maximum of 4 channels can be enabled (letters a thru d).
+        For more information refer to the device datasheet at:
+        http://www.ti.com/lit/ds/symlink/ads1115.pdf
+
+
+Name:   ads7846
+Info:   ADS7846 Touch controller
+Load:   dtoverlay=ads7846,<param>=<val>
+Params: cs                      SPI bus Chip Select (default 1)
+        speed                   SPI bus speed (default 2MHz, max 3.25MHz)
+        penirq                  GPIO used for PENIRQ. REQUIRED
+        penirq_pull             Set GPIO pull (default 0=none, 2=pullup)
+        swapxy                  Swap x and y axis
+        xmin                    Minimum value on the X axis (default 0)
+        ymin                    Minimum value on the Y axis (default 0)
+        xmax                    Maximum value on the X axis (default 4095)
+        ymax                    Maximum value on the Y axis (default 4095)
+        pmin                    Minimum reported pressure value (default 0)
+        pmax                    Maximum reported pressure value (default 65535)
+        xohms                   Touchpanel sensitivity (X-plate resistance)
+                                (default 400)
+
+        penirq is required and usually xohms (60-100) has to be set as well.
+        Apart from that, pmax (255) and swapxy are also common.
+        The rest of the calibration can be done with xinput-calibrator.
+        See: github.com/notro/fbtft/wiki/FBTFT-on-Raspian
+        Device Tree binding document:
+        www.kernel.org/doc/Documentation/devicetree/bindings/input/ads7846.txt
+
+
+Name:   adv7282m
+Info:   Analog Devices ADV7282M analogue video to CSI2 bridge.
+        Uses Unicam1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=adv7282m,<param>=<val>
+Params: addr                    Overrides the I2C address (default 0x21)
+
+
+Name:   adv728x-m
+Info:   Analog Devices ADV728[0|1|2]-M analogue video to CSI2 bridges.
+        This is a wrapper for adv7282m, and defaults to ADV7282M.
+Load:   dtoverlay=adv728x-m,<param>=<val>
+Params: addr                    Overrides the I2C address (default 0x21)
+        adv7280m                Select ADV7280-M.
+        adv7281m                Select ADV7281-M.
+        adv7281ma               Select ADV7281-MA.
+
+
+Name:   akkordion-iqdacplus
+Info:   Configures the Digital Dreamtime Akkordion Music Player (based on the
+        OEM IQAudIO DAC+ or DAC Zero module).
+Load:   dtoverlay=akkordion-iqdacplus,<param>=<val>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                dtoverlay=akkordion-iqdacplus,24db_digital_gain
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24db_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                responsibility of the user to ensure that
+                                the Digital volume control is set to a value
+                                that does not result in clipping/distortion!)
+
+
+Name:   allo-boss-dac-pcm512x-audio
+Info:   Configures the Allo Boss DAC audio cards.
+Load:   dtoverlay=allo-boss-dac-pcm512x-audio,<param>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=allo-boss-dac-pcm512x-audio,
+                                24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24db_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                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 Boss DAC into slave mode, using Pi a
+                                master for bit clock and frame clock. Enable
+                                with "dtoverlay=allo-boss-dac-pcm512x-audio,
+                                slave"
+
+
+Name:   allo-boss2-dac-audio
+Info:   Configures the Allo Boss2 DAC audio card
+Load:   dtoverlay=allo-boss2-dac-audio
+Params: <None>
+
+
+Name:   allo-digione
+Info:   Configures the Allo Digione audio card
+Load:   dtoverlay=allo-digione
+Params: <None>
+
+
+Name:   allo-katana-dac-audio
+Info:   Configures the Allo Katana DAC audio card
+Load:   dtoverlay=allo-katana-dac-audio
+Params: <None>
+
+
+Name:   allo-piano-dac-pcm512x-audio
+Info:   Configures the Allo Piano DAC (2.0/2.1) audio cards.
+        (NB. This initial support is for 2.0 channel audio ONLY! ie. stereo.
+        The subwoofer outputs on the Piano 2.1 are not currently supported!)
+Load:   dtoverlay=allo-piano-dac-pcm512x-audio,<param>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control.
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24db_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                responsibility of the user to ensure that
+                                the Digital volume control is set to a value
+                                that does not result in clipping/distortion!)
+
+
+Name:   allo-piano-dac-plus-pcm512x-audio
+Info:   Configures the Allo Piano DAC (2.1) audio cards.
+Load:   dtoverlay=allo-piano-dac-plus-pcm512x-audio,<param>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control.
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24db_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                responsibility of the user to ensure that
+                                the Digital volume control is set to a value
+                                that does not result in clipping/distortion!)
+        glb_mclk                This option is only with Kali board. If enabled,
+                                MCLK for Kali is used and PLL is disabled for
+                                better voice quality. (default Off)
+
+
+Name:   anyspi
+Info:   Universal device tree overlay for SPI devices
+
+        Just specify the SPI address and device name ("compatible" property).
+        This overlay lacks any device-specific parameter support!
+
+        For devices on spi1 or spi2, the interfaces should be enabled
+        with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.
+
+        Examples:
+        1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz:
+            dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000
+        2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz:
+            dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204"
+Load:   dtoverlay=anyspi,<param>=<val>
+Params: spi<n>-<m>              Configure device at spi<n>, cs<m>
+                                (boolean, required)
+        dev                     Set device name to search compatible module
+                                (string, required)
+        speed                   Set SPI clock frequency in Hz
+                                (integer, optional, default 500000)
+
+
+Name:   apds9960
+Info:   Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and
+        gesture sensor
+Load:   dtoverlay=apds9960,<param>=<val>
+Params: gpiopin                 GPIO used for INT (default 4)
+        noints                  Disable the interrupt GPIO line.
+
+
+Name:   applepi-dac
+Info:   Configures the Orchard Audio ApplePi-DAC audio card
+Load:   dtoverlay=applepi-dac
+Params: <None>
+
+
+Name:   at86rf233
+Info:   Configures the Atmel AT86RF233 802.15.4 low-power WPAN transceiver,
+        connected to spi0.0
+Load:   dtoverlay=at86rf233,<param>=<val>
+Params: interrupt               GPIO used for INT (default 23)
+        reset                   GPIO used for Reset (default 24)
+        sleep                   GPIO used for Sleep (default 25)
+        speed                   SPI bus speed in Hz (default 3000000)
+        trim                    Fine tuning of the internal capacitance
+                                arrays (0=+0pF, 15=+4.5pF, default 15)
+
+
+Name:   audioinjector-addons
+Info:   Configures the audioinjector.net audio add on soundcards
+Load:   dtoverlay=audioinjector-addons,<param>=<val>
+Params: non-stop-clocks         Keeps the clocks running even when the stream
+                                is paused or stopped (default off)
+
+
+Name:   audioinjector-isolated-soundcard
+Info:   Configures the audioinjector.net isolated soundcard
+Load:   dtoverlay=audioinjector-isolated-soundcard
+Params: <None>
+
+
+Name:   audioinjector-ultra
+Info:   Configures the audioinjector.net ultra soundcard
+Load:   dtoverlay=audioinjector-ultra
+Params: <None>
+
+
+Name:   audioinjector-wm8731-audio
+Info:   Configures the audioinjector.net audio add on soundcard
+Load:   dtoverlay=audioinjector-wm8731-audio
+Params: <None>
+
+
+Name:   audiosense-pi
+Info:   Configures the audiosense-pi add on soundcard
+        For more information refer to
+        https://gitlab.com/kakar0t/audiosense-pi
+Load:   dtoverlay=audiosense-pi
+Params: <None>
+
+
+Name:   audremap
+Info:   Switches PWM sound output to GPIOs on the 40-pin header
+Load:   dtoverlay=audremap,<param>=<val>
+Params: swap_lr                 Reverse the channel allocation, which will also
+                                swap the audio jack outputs (default off)
+        enable_jack             Don't switch off the audio jack output
+                                (default off)
+        pins_12_13              Select GPIOs 12 & 13 (default)
+        pins_18_19              Select GPIOs 18 & 19
+
+
+Name:   balena-fin
+Info:   Overlay that enables WiFi, Bluetooth and the GPIO expander on the
+        balenaFin carrier board for the Raspberry Pi Compute Module 3/3+ Lite.
+Load:   dtoverlay=balena-fin
+Params: <None>
+
+
+Name:   bmp085_i2c-sensor
+Info:   This overlay is now deprecated - see i2c-sensor
+Load:   <Deprecated>
+
+
+Name:   cap1106
+Info:   Enables the ability to use the cap1106 touch sensor as a keyboard
+Load:   dtoverlay=cap1106,<param>=<val>
+Params: int_pin                 GPIO pin for interrupt signal (default 23)
+
+
+Name:   chipdip-i2s-master-dac
+Info:   Configures Raspberry PI to work as I2S slave with BCLK=64Fs.
+Load:   dtoverlay=chipdip-i2s-master-dac
+Params: <None>
+
+
+Name:   cma
+Info:   Set custom CMA sizes, only use if you know what you are doing, might
+        clash with other overlays like vc4-fkms-v3d and vc4-kms-v3d.
+Load:   dtoverlay=cma,<param>=<val>
+Params: cma-512                 CMA is 512MB (needs 1GB)
+        cma-448                 CMA is 448MB (needs 1GB)
+        cma-384                 CMA is 384MB (needs 1GB)
+        cma-320                 CMA is 320MB (needs 1GB)
+        cma-256                 CMA is 256MB (needs 1GB)
+        cma-192                 CMA is 192MB (needs 1GB)
+        cma-128                 CMA is 128MB
+        cma-96                  CMA is 96MB
+        cma-64                  CMA is 64MB
+        cma-size                CMA size in bytes, 4MB aligned
+        cma-default             Use upstream's default value
+
+
+Name:   dht11
+Info:   Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors
+        Also sometimes found with the part number(s) AM230x.
+Load:   dtoverlay=dht11,<param>=<val>
+Params: gpiopin                 GPIO connected to the sensor's DATA output.
+                                (default 4)
+
+
+Name:   dionaudio-loco
+Info:   Configures the Dion Audio LOCO DAC-AMP
+Load:   dtoverlay=dionaudio-loco
+Params: <None>
+
+
+Name:   dionaudio-loco-v2
+Info:   Configures the Dion Audio LOCO-V2 DAC-AMP
+Load:   dtoverlay=dionaudio-loco-v2,<param>=<val>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=hifiberry-dacplus,24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24dB_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                responsibility of the user to ensure that
+                                the Digital volume control is set to a value
+                                that does not result in clipping/distortion!)
+
+
+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'.
+Load:   dtoverlay=disable-bt
+Params: <None>
+
+
+Name:   disable-wifi
+Info:   Disable onboard WiFi on Pi 3B, 3B+, 3A+, 4B and Zero W.
+Load:   dtoverlay=disable-wifi
+Params: <None>
+
+
+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
+        2-3 seconds after the kernel has started.
+Load:   dtoverlay=dpi18
+Params: <None>
+
+
+Name:   dpi18cpadhi
+Info:   Overlay for a generic 18-bit DPI display (in 'mode 6' connection scheme)
+        This uses GPIOs 0-9,12-17,20-25 (so no I2C, uart etc.), and activates
+        the output 3-3 seconds after the kernel has started.
+Load:   dtoverlay=dpi18cpadhi
+Params: <None>
+
+
+Name:   dpi24
+Info:   Overlay for a generic 24-bit DPI display
+        This uses GPIOs 0-27 (so no I2C, uart etc.), and activates the output
+        2-3 seconds after the kernel has started.
+Load:   dtoverlay=dpi24
+Params: <None>
+
+
+Name:   draws
+Info:   Configures the NW Digital Radio DRAWS Hat
+
+        The board includes an ADC to measure various board values and also
+        provides two analog user inputs on the expansion header.  The ADC
+        can be configured for various sample rates and gain values to adjust
+        the input range.  Tables describing the two parameters follow.
+
+        ADC Gain Values:
+            0 = +/- 6.144V
+            1 = +/- 4.096V
+            2 = +/- 2.048V
+            3 = +/- 1.024V
+            4 = +/- 0.512V
+            5 = +/- 0.256V
+            6 = +/- 0.256V
+            7 = +/- 0.256V
+
+        ADC Datarate Values:
+            0 = 128sps
+            1 = 250sps
+            2 = 490sps
+            3 = 920sps
+            4 = 1600sps (default)
+            5 = 2400sps
+            6 = 3300sps
+            7 = 3300sps
+Load:   dtoverlay=draws,<param>=<val>
+Params: draws_adc_ch4_gain      Sets the full scale resolution of the ADCs
+                                input voltage sensor (default 1)
+
+        draws_adc_ch4_datarate  Sets the datarate of the ADCs input voltage
+                                sensor
+
+        draws_adc_ch5_gain      Sets the full scale resolution of the ADCs
+                                5V rail voltage sensor (default 1)
+
+        draws_adc_ch5_datarate  Sets the datarate of the ADCs 4V rail voltage
+                                sensor
+
+        draws_adc_ch6_gain      Sets the full scale resolution of the ADCs
+                                AIN2 input (default 2)
+
+        draws_adc_ch6_datarate  Sets the datarate of the ADCs AIN2 input
+
+        draws_adc_ch7_gain      Sets the full scale resolution of the ADCs
+                                AIN3 input (default 2)
+
+        draws_adc_ch7_datarate  Sets the datarate of the ADCs AIN3 input
+
+        alsaname                Name of the ALSA audio device (default "draws")
+
+
+Name:   dwc-otg
+Info:   Selects the dwc_otg USB controller driver which has fiq support. This
+        is the default on all except the Pi Zero which defaults to dwc2.
+Load:   dtoverlay=dwc-otg
+Params: <None>
+
+
+Name:   dwc2
+Info:   Selects the dwc2 USB controller driver
+Load:   dtoverlay=dwc2,<param>=<val>
+Params: dr_mode                 Dual role mode: "host", "peripheral" or "otg"
+
+        g-rx-fifo-size          Size of rx fifo size in gadget mode
+
+        g-np-tx-fifo-size       Size of non-periodic tx fifo size in gadget
+                                mode
+
+
+[ The ds1307-rtc overlay has been deleted. See i2c-rtc. ]
+
+
+Name:   edt-ft5406
+Info:   Overlay for the EDT FT5406 touchscreen on the CSI/DSI I2C interface.
+        This works with the Raspberry Pi 7" touchscreen when not being polled
+        by the firmware.
+        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,<param>=<val>
+Params: sizex                   Touchscreen size x (default 800)
+        sizey                   Touchscreen size y (default 480)
+        invx                    Touchscreen inverted x axis
+        invy                    Touchscreen inverted y axis
+        swapxy                  Touchscreen swapped x y axis
+
+
+Name:   enc28j60
+Info:   Overlay for the Microchip ENC28J60 Ethernet Controller on SPI0
+Load:   dtoverlay=enc28j60,<param>=<val>
+Params: int_pin                 GPIO used for INT (default 25)
+
+        speed                   SPI bus speed (default 12000000)
+
+
+Name:   enc28j60-spi2
+Info:   Overlay for the Microchip ENC28J60 Ethernet Controller on SPI2
+Load:   dtoverlay=enc28j60-spi2,<param>=<val>
+Params: int_pin                 GPIO used for INT (default 39)
+
+        speed                   SPI bus speed (default 12000000)
+
+
+Name:   exc3000
+Info:   Enables I2C connected EETI EXC3000 multiple touch controller using
+        GPIO 4 (pin 7 on GPIO header) for interrupt.
+Load:   dtoverlay=exc3000,<param>=<val>
+Params: interrupt               GPIO used for interrupt (default 4)
+        sizex                   Touchscreen size x (default 4096)
+        sizey                   Touchscreen size y (default 4096)
+        invx                    Touchscreen inverted x axis
+        invy                    Touchscreen inverted y axis
+        swapxy                  Touchscreen swapped x y axis
+
+
+Name:   fe-pi-audio
+Info:   Configures the Fe-Pi Audio Sound Card
+Load:   dtoverlay=fe-pi-audio
+Params: <None>
+
+
+Name:   fsm-demo
+Info:   A demonstration of the gpio-fsm driver. The GPIOs are chosen to work
+        nicely with a "traffic-light" display of red, amber and green LEDs on
+        GPIOs 7, 8 and 25 respectively.
+Load:   dtoverlay=fsm-demo,<param>=<val>
+Params: fsm_debug               Enable debug logging (default off)
+
+
+Name:   ghost-amp
+Info:   An overlay for the Ghost amplifier.
+Load:   dtoverlay=ghost-amp,<param>=<val>
+Params: fsm_debug               Enable debug logging of the GPIO FSM (default
+                                off)
+
+
+Name:   goodix
+Info:   Enables I2C connected Goodix gt9271 multiple touch controller using
+        GPIOs 4 and 17 (pins 7 and 11 on GPIO header) for interrupt and reset.
+Load:   dtoverlay=goodix,<param>=<val>
+Params: interrupt               GPIO used for interrupt (default 4)
+        reset                   GPIO used for reset (default 17)
+
+
+Name:   googlevoicehat-soundcard
+Info:   Configures the Google voiceHAT soundcard
+Load:   dtoverlay=googlevoicehat-soundcard
+Params: <None>
+
+
+Name:   gpio-fan
+Info:   Configure a GPIO pin to control a cooling fan.
+Load:   dtoverlay=gpio-fan,<param>=<val>
+Params: gpiopin                 GPIO used to control the fan (default 12)
+        temp                    Temperature at which the fan switches on, in
+                                millicelcius (default 55000)
+
+
+Name:   gpio-ir
+Info:   Use GPIO pin as rc-core style infrared receiver input. The rc-core-
+        based gpio_ir_recv driver maps received keys directly to a
+        /dev/input/event* device, all decoding is done by the kernel - LIRC is
+        not required! The key mapping and other decoding parameters can be
+        configured by "ir-keytable" tool.
+Load:   dtoverlay=gpio-ir,<param>=<val>
+Params: gpio_pin                Input pin number. Default is 18.
+
+        gpio_pull               Desired pull-up/down state (off, down, up)
+                                Default is "up".
+
+        invert                  "1" = invert the input (active-low signalling).
+                                "0" = non-inverted input (active-high
+                                signalling). Default is "1".
+
+        rc-map-name             Default rc keymap (can also be changed by
+                                ir-keytable), defaults to "rc-rc6-mce"
+
+
+Name:   gpio-ir-tx
+Info:   Use GPIO pin as bit-banged infrared transmitter output.
+        This is an alternative to "pwm-ir-tx". gpio-ir-tx doesn't require
+        a PWM so it can be used together with onboard analog audio.
+Load:   dtoverlay=gpio-ir-tx,<param>=<val>
+Params: gpio_pin                Output GPIO (default 18)
+
+        invert                  "1" = invert the output (make it active-low).
+                                Default is "0" (active-high).
+
+
+Name:   gpio-key
+Info:   This is a generic overlay for activating GPIO keypresses using
+        the gpio-keys library and this dtoverlay. Multiple keys can be
+        set up using multiple calls to the overlay for configuring
+        additional buttons or joysticks. You can see available keycodes
+        at https://github.com/torvalds/linux/blob/v4.12/include/uapi/
+        linux/input-event-codes.h#L64
+Load:   dtoverlay=gpio-key,<param>=<val>
+Params: gpio                    GPIO pin to trigger on (default 3)
+        active_low              When this is 1 (active low), a falling
+                                edge generates a key down event and a
+                                rising edge generates a key up event.
+                                When this is 0 (active high), this is
+                                reversed. The default is 1 (active low)
+        gpio_pull               Desired pull-up/down state (off, down, up)
+                                Default is "up". Note that the default pin
+                                (GPIO3) has an external pullup
+        label                   Set a label for the key
+        keycode                 Set the key code for the button
+
+
+
+Name:   gpio-led
+Info:   This is a generic overlay for activating LEDs (or any other component)
+        by a GPIO pin. Multiple LEDs can be set up using multiple calls to the
+        overlay. While there are many existing methods to activate LEDs on the
+        RPi, this method offers some advantages:
+        1) Does not require any userspace programs.
+        2) LEDs can be connected to the kernel's led-trigger framework,
+           and drive the LED based on triggers such as cpu load, heartbeat,
+           kernel panic, key input, timers and others.
+        3) LED can be tied to the input state of another GPIO pin.
+        4) The LED is setup early during the kernel boot process (useful
+           for cpu/heartbeat/panic triggers).
+
+        Typical electrical connection is:
+           RPI-GPIO.19  ->  LED  -> 300ohm resister  -> RPI-GND
+        The GPIO pin number can be changed with the 'gpio=' parameter.
+
+        To control an LED from userspace, write a 0 or 1 value:
+           echo 1 > /sys/class/leds/myled1/brightness
+        The 'myled1' name can be changed with the 'label=' parameter.
+
+        To connect the LED to a kernel trigger from userspace:
+           echo cpu > /sys/class/leds/myled1/trigger
+           echo heartbeat > /sys/class/leds/myled1/trigger
+           echo none > /sys/class/leds/myled1/trigger
+        To connect the LED to GPIO.26 pin (physical pin 37):
+           echo gpio > /sys/class/leds/myled1/trigger
+           echo 26 > /sys/class/leds/myled1/gpio
+        Available triggers:
+           cat /sys/class/leds/myled1/trigger
+
+        More information about the Linux kernel LED/Trigger system:
+           https://www.kernel.org/doc/Documentation/leds/leds-class.rst
+           https://www.kernel.org/doc/Documentation/leds/ledtrig-oneshot.rst
+Load:   dtoverlay=gpio-led,<param>=<val>
+Params: gpio                    GPIO pin connected to the LED (default 19)
+        label                   The label for this LED. It will appear under
+                                /sys/class/leds/<label> . Default 'myled1'.
+        trigger                 Set the led-trigger to connect to this LED.
+                                default 'none' (LED is user-controlled).
+                                Some possible triggers:
+                                 cpu - CPU load (all CPUs)
+                                 cpu0 - CPU load of first CPU.
+                                 mmc - disk activity (all disks)
+                                 panic - turn on on kernel panic
+                                 heartbeat - indicate system health
+                                 gpio - connect to a GPIO input pin (note:
+                                        currently the GPIO PIN can not be set
+                                        using overlay parameters, must be
+                                        done in userspace, see examples above.
+        active_low              Set to 1 to turn invert the LED control
+                                (writing 0 to /sys/class/leds/XXX/brightness
+                                will turn on the GPIO/LED). Default '0'.
+
+
+Name:   gpio-no-bank0-irq
+Info:   Use this overlay to disable GPIO interrupts for GPIOs in bank 0 (0-27),
+        which can be useful for UIO drivers.
+        N.B. Using this overlay will trigger a kernel WARN during booting, but
+        this can safely be ignored - the system should work as expected.
+Load:   dtoverlay=gpio-no-bank0-irq
+Params: <None>
+
+
+Name:   gpio-no-irq
+Info:   Use this overlay to disable all GPIO interrupts, which can be useful
+        for user-space GPIO edge detection systems.
+Load:   dtoverlay=gpio-no-irq
+Params: <None>
+
+
+Name:   gpio-poweroff
+Info:   Drives a GPIO high or low on poweroff (including halt). Using this
+        overlay interferes with the normal power-down sequence, preventing the
+        kernel from resetting the SoC (a necessary step in a normal power-off
+        or reboot). This also disables the ability to trigger a boot by driving
+        GPIO3 low.
+
+        Users of this overlay are required to provide an external mechanism to
+        switch off the power supply when signalled - failure to do so results
+        in a kernel BUG, increased power consumption and undefined behaviour.
+Load:   dtoverlay=gpio-poweroff,<param>=<val>
+Params: gpiopin                 GPIO for signalling (default 26)
+
+        active_low              Set if the power control device requires a
+                                high->low transition to trigger a power-down.
+                                Note that this will require the support of a
+                                custom dt-blob.bin to prevent a power-down
+                                during the boot process, and that a reboot
+                                will also cause the pin to go low.
+        input                   Set if the gpio pin should be configured as
+                                an input.
+        export                  Set to export the configured pin to sysfs
+        timeout_ms              Specify (in ms) how long the kernel waits for
+                                power-down before issuing a WARN (default 3000).
+
+
+Name:   gpio-shutdown
+Info:   Initiates a shutdown when GPIO pin changes. The given GPIO pin
+        is configured as an input key that generates KEY_POWER events.
+
+        This event is handled by systemd-logind by initiating a
+        shutdown. Systemd versions older than 225 need an udev rule
+        enable listening to the input device:
+
+                ACTION!="REMOVE", SUBSYSTEM=="input", KERNEL=="event*", \
+                        SUBSYSTEMS=="platform", DRIVERS=="gpio-keys", \
+                        ATTRS{keys}=="116", TAG+="power-switch"
+
+        Alternatively this event can be handled also on systems without
+        systemd, just by traditional SysV init daemon. KEY_POWER event
+        (keycode 116) needs to be mapped to KeyboardSignal on console
+        and then kb::kbrequest inittab action which is triggered by
+        KeyboardSignal from console can be configured to issue system
+        shutdown. Steps for this configuration are:
+
+            Add following lines to the /etc/console-setup/remap.inc file:
+
+                # Key Power as special keypress
+                keycode 116 = KeyboardSignal
+
+            Then add following lines to /etc/inittab file:
+
+                # Action on special keypress (Key Power)
+                kb::kbrequest:/sbin/shutdown -t1 -a -h -P now
+
+            And finally reload configuration by calling following commands:
+
+                # dpkg-reconfigure console-setup
+                # service console-setup reload
+                # init q
+
+        This overlay only handles shutdown. After shutdown, the system
+        can be powered up again by driving GPIO3 low. The default
+        configuration uses GPIO3 with a pullup, so if you connect a
+        button between GPIO3 and GND (pin 5 and 6 on the 40-pin header),
+        you get a shutdown and power-up button. Please note that
+        Raspberry Pi 1 Model B rev 1 uses GPIO1 instead of GPIO3.
+Load:   dtoverlay=gpio-shutdown,<param>=<val>
+Params: gpio_pin                GPIO pin to trigger on (default 3)
+                                For Raspberry Pi 1 Model B rev 1 set this
+                                explicitly to value 1, e.g.:
+
+                                    dtoverlay=gpio-shutdown,gpio_pin=1
+
+        active_low              When this is 1 (active low), a falling
+                                edge generates a key down event and a
+                                rising edge generates a key up event.
+                                When this is 0 (active high), this is
+                                reversed. The default is 1 (active low).
+
+        gpio_pull               Desired pull-up/down state (off, down, up)
+                                Default is "up".
+
+                                Note that the default pin (GPIO3) has an
+                                external pullup. Same applies for GPIO1
+                                on Raspberry Pi 1 Model B rev 1.
+
+        debounce                Specify the debounce interval in milliseconds
+                                (default 100)
+
+
+Name:   hd44780-lcd
+Info:   Configures an HD44780 compatible LCD display. Uses 4 gpio pins for
+        data, 2 gpio pins for enable and register select and 1 optional pin
+        for enabling/disabling the backlight display.
+Load:   dtoverlay=hd44780-lcd,<param>=<val>
+Params: pin_d4                  GPIO pin for data pin D4 (default 6)
+
+        pin_d5                  GPIO pin for data pin D5 (default 13)
+
+        pin_d6                  GPIO pin for data pin D6 (default 19)
+
+        pin_d7                  GPIO pin for data pin D7 (default 26)
+
+        pin_en                  GPIO pin for "Enable" (default 21)
+
+        pin_rs                  GPIO pin for "Register Select" (default 20)
+
+        pin_bl                  Optional pin for enabling/disabling the
+                                display backlight. (default disabled)
+
+        display_height          Height of the display in characters
+
+        display_width           Width of the display in characters
+
+
+Name:   hdmi-backlight-hwhack-gpio
+Info:   Devicetree overlay for GPIO based backlight on/off capability.
+        Use this if you have one of those HDMI displays whose backlight cannot
+        be controlled via DPMS over HDMI and plan to do a little soldering to
+        use an RPi gpio pin for on/off switching. See:
+        https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control
+Load:   dtoverlay=hdmi-backlight-hwhack-gpio,<param>=<val>
+Params: gpio_pin                GPIO pin used (default 17)
+        active_low              Set this to 1 if the display backlight is
+                                switched on when the wire goes low.
+                                Leave the default (value 0) if the backlight
+                                expects a high to switch it on.
+
+
+Name:   hifiberry-amp
+Info:   Configures the HifiBerry Amp and Amp+ audio cards
+Load:   dtoverlay=hifiberry-amp
+Params: <None>
+
+
+Name:   hifiberry-amp100
+Info:   Configures the HifiBerry AMP100 audio card
+Load:   dtoverlay=hifiberry-amp100,<param>=<val>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=hifiberry-amp100,24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24dB_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                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
+                                master for bit clock and frame clock.
+        leds_off                If set to 'true' the onboard indicator LEDs
+                                are switched off at all times.
+        auto_mute               If set to 'true' the amplifier is automatically
+                                muted when the DAC is not playing.
+        mute_ext_ctl            The amplifier's HW mute control is enabled
+                                in ALSA mixer and set to <val>.
+                                Will be overwritten by ALSA user settings.
+
+
+Name:   hifiberry-dac
+Info:   Configures the HifiBerry DAC audio cards
+Load:   dtoverlay=hifiberry-dac
+Params: <None>
+
+
+Name:   hifiberry-dacplus
+Info:   Configures the HifiBerry DAC+ audio card
+Load:   dtoverlay=hifiberry-dacplus,<param>=<val>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=hifiberry-dacplus,24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24dB_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                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
+                                master for bit clock and frame clock.
+        leds_off                If set to 'true' the onboard indicator LEDs
+                                are switched off at all times.
+
+
+Name:   hifiberry-dacplusadc
+Info:   Configures the HifiBerry DAC+ADC audio card
+Load:   dtoverlay=hifiberry-dacplusadc,<param>=<val>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=hifiberry-dacplus,24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24dB_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                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
+                                master for bit clock and frame clock.
+        leds_off                If set to 'true' the onboard indicator LEDs
+                                are switched off at all times.
+
+
+Name:   hifiberry-dacplusadcpro
+Info:   Configures the HifiBerry DAC+ADC PRO audio card
+Load:   dtoverlay=hifiberry-dacplusadcpro,<param>=<val>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=hifiberry-dacplusadcpro,24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24dB_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                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+ADC Pro 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.
+
+
+Name:   hifiberry-dacplusdsp
+Info:   Configures the HifiBerry DAC+DSP audio card
+Load:   dtoverlay=hifiberry-dacplusdsp
+Params: <None>
+
+
+Name:   hifiberry-dacplushd
+Info:   Configures the HifiBerry DAC+ HD audio card
+Load:   dtoverlay=hifiberry-dacplushd
+Params: <None>
+
+
+Name:   hifiberry-digi
+Info:   Configures the HifiBerry Digi and Digi+ audio card
+Load:   dtoverlay=hifiberry-digi
+Params: <None>
+
+
+Name:   hifiberry-digi-pro
+Info:   Configures the HifiBerry Digi+ Pro audio card
+Load:   dtoverlay=hifiberry-digi-pro
+Params: <None>
+
+
+Name:   highperi
+Info:   Enables "High Peripheral" mode
+Load:   dtoverlay=highperi
+Params: <None>
+
+
+Name:   hy28a
+Info:   HY28A - 2.8" TFT LCD Display Module by HAOYU Electronics
+        Default values match Texy's display shield
+Load:   dtoverlay=hy28a,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+        xohms                   Touchpanel sensitivity (X-plate resistance)
+
+        resetgpio               GPIO used to reset controller
+
+        ledgpio                 GPIO used to control backlight
+
+
+Name:   hy28b
+Info:   HY28B - 2.8" TFT LCD Display Module by HAOYU Electronics
+        Default values match Texy's display shield
+Load:   dtoverlay=hy28b,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+        xohms                   Touchpanel sensitivity (X-plate resistance)
+
+        resetgpio               GPIO used to reset controller
+
+        ledgpio                 GPIO used to control backlight
+
+
+Name:   hy28b-2017
+Info:   HY28B 2017 version - 2.8" TFT LCD Display Module by HAOYU Electronics
+        Default values match Texy's display shield
+Load:   dtoverlay=hy28b-2017,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+        xohms                   Touchpanel sensitivity (X-plate resistance)
+
+        resetgpio               GPIO used to reset controller
+
+        ledgpio                 GPIO used to control backlight
+
+
+Name:   i-sabre-q2m
+Info:   Configures the Audiophonics I-SABRE Q2M DAC
+Load:   dtoverlay=i-sabre-q2m
+Params: <None>
+
+
+Name:   i2c-bcm2708
+Info:   Fall back to the i2c_bcm2708 driver for the i2c_arm bus.
+Load:   dtoverlay=i2c-bcm2708
+Params: <None>
+
+
+Name:   i2c-gpio
+Info:   Adds support for software i2c controller on gpio pins
+Load:   dtoverlay=i2c-gpio,<param>=<val>
+Params: i2c_gpio_sda            GPIO used for I2C data (default "23")
+
+        i2c_gpio_scl            GPIO used for I2C clock (default "24")
+
+        i2c_gpio_delay_us       Clock delay in microseconds
+                                (default "2" = ~100kHz)
+
+        bus                     Set to a unique, non-zero value if wanting
+                                multiple i2c-gpio busses. If set, will be used
+                                as the preferred bus number (/dev/i2c-<n>). If
+                                not set, the default value is 0, but the bus
+                                number will be dynamically assigned - probably
+                                3.
+
+
+Name:   i2c-mux
+Info:   Adds support for a number of I2C bus multiplexers on i2c_arm
+Load:   dtoverlay=i2c-mux,<param>=<val>
+Params: pca9542                 Select the NXP PCA9542 device
+
+        pca9545                 Select the NXP PCA9545 device
+
+        pca9548                 Select the NXP PCA9548 device
+
+        addr                    Change I2C address of the device (default 0x70)
+
+
+[ The i2c-mux-pca9548a overlay has been deleted. See i2c-mux. ]
+
+
+Name:   i2c-pwm-pca9685a
+Info:   Adds support for an NXP PCA9685A I2C PWM controller on i2c_arm
+Load:   dtoverlay=i2c-pwm-pca9685a,<param>=<val>
+Params: addr                    I2C address of PCA9685A (default 0x40)
+
+
+Name:   i2c-rtc
+Info:   Adds support for a number of I2C Real Time Clock devices
+Load:   dtoverlay=i2c-rtc,<param>=<val>
+Params: abx80x                  Select one of the ABx80x family:
+                                  AB0801, AB0803, AB0804, AB0805,
+                                  AB1801, AB1803, AB1804, AB1805
+
+        ds1307                  Select the DS1307 device
+
+        ds1339                  Select the DS1339 device
+
+        ds1340                  Select the DS1340 device
+
+        ds3231                  Select the DS3231 device
+
+        m41t62                  Select the M41T62 device
+
+        mcp7940x                Select the MCP7940x device
+
+        mcp7941x                Select the MCP7941x device
+
+        pcf2127                 Select the PCF2127 device
+
+        pcf2129                 Select the PCF2129 device
+
+        pcf85063                Select the PCF85063 device
+
+        pcf85063a               Select the PCF85063A device
+
+        pcf8523                 Select the PCF8523 device
+
+        pcf85363                Select the PCF85363 device
+
+        pcf8563                 Select the PCF8563 device
+
+        rv1805                  Select the Micro Crystal RV1805 device
+
+        rv3028                  Select the Micro Crystal RV3028 device
+
+        sd3078                  Select the ZXW Shenzhen whwave SD3078 device
+
+        i2c0                    Choose the I2C0 bus on GPIOs 0&1
+
+        i2c_csi_dsi             Choose the I2C0 bus on GPIOs 44&45
+
+        addr                    Sets the address for the RTC. Note that the
+                                device must be configured to use the specified
+                                address.
+
+        trickle-diode-type      Diode type for trickle charge - "standard" or
+                                "schottky" (ABx80x and RV1805 only)
+
+        trickle-resistor-ohms   Resistor value for trickle charge (DS1339,
+                                ABx80x, RV1805, RV3028)
+
+        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)
+
+
+Name:   i2c-rtc-gpio
+Info:   Adds support for a number of I2C Real Time Clock devices
+        using the software i2c controller
+Load:   dtoverlay=i2c-rtc-gpio,<param>=<val>
+Params: abx80x                  Select one of the ABx80x family:
+                                  AB0801, AB0803, AB0804, AB0805,
+                                  AB1801, AB1803, AB1804, AB1805
+
+        ds1307                  Select the DS1307 device
+
+        ds1339                  Select the DS1339 device
+
+        ds1340                  Select the DS1340 device
+
+        ds3231                  Select the DS3231 device
+
+        m41t62                  Select the M41T62 device
+
+        mcp7940x                Select the MCP7940x device
+
+        mcp7941x                Select the MCP7941x device
+
+        pcf2127                 Select the PCF2127 device
+
+        pcf2129                 Select the PCF2129 device
+
+        pcf85063                Select the PCF85063 device
+
+        pcf85063a               Select the PCF85063A device
+
+        pcf8523                 Select the PCF8523 device
+
+        pcf85363                Select the PCF85363 device
+
+        pcf8563                 Select the PCF8563 device
+
+        rv1805                  Select the Micro Crystal RV1805 device
+
+        rv3028                  Select the Micro Crystal RV3028 device
+
+        sd3078                  Select the ZXW Shenzhen whwave SD3078 device
+
+        addr                    Sets the address for the RTC. Note that the
+                                device must be configured to use the specified
+                                address.
+
+        trickle-diode-type      Diode type for trickle charge - "standard" or
+                                "schottky" (ABx80x and RV1805 only)
+
+        trickle-resistor-ohms   Resistor value for trickle charge (DS1339,
+                                ABx80x, RV1805, RV3028)
+
+        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)
+
+        i2c_gpio_sda            GPIO used for I2C data (default "23")
+
+        i2c_gpio_scl            GPIO used for I2C clock (default "24")
+
+        i2c_gpio_delay_us       Clock delay in microseconds
+                                (default "2" = ~100kHz)
+
+
+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,<param>=<val>
+Params: addr                    Set the address for the BH1750, BME280, BME680,
+                                BMP280, CCS811, DS1621, HDC100X, LM75, SHT3x or
+                                TMP102
+
+        bh1750                  Select the Rohm BH1750 ambient light sensor
+                                Valid addresses 0x23 or 0x5c, default 0x23
+
+        bme280                  Select the Bosch Sensortronic BME280
+                                Valid addresses 0x76-0x77, default 0x76
+
+        bme680                  Select the Bosch Sensortronic BME680
+                                Valid addresses 0x76-0x77, default 0x76
+
+        bmp085                  Select the Bosch Sensortronic BMP085
+
+        bmp180                  Select the Bosch Sensortronic BMP180
+
+        bmp280                  Select the Bosch Sensortronic BMP280
+                                Valid addresses 0x76-0x77, default 0x76
+
+        ccs811                  Select the AMS CCS811 digital gas sensor
+                                Valid addresses 0x5a-0x5b, default 0x5b
+
+        ds1621                  Select the Dallas Semiconductors DS1621 temp
+                                sensor. Valid addresses 0x48-0x4f, default 0x48
+
+        hdc100x                 Select the Texas Instruments HDC100x temp sensor
+                                Valid addresses 0x40-0x43, default 0x40
+
+        htu21                   Select the HTU21 temperature and humidity sensor
+
+        lm75                    Select the Maxim LM75 temperature sensor
+                                Valid addresses 0x48-0x4f, default 0x4f
+
+        lm75addr                Deprecated - use addr parameter instead
+
+        max17040                Select the Maxim Integrated MAX17040 battery
+                                monitor
+
+        sht3x                   Select the Sensiron SHT3x temperature and
+                                humidity sensor. Valid addresses 0x44-0x45,
+                                default 0x44
+
+        si7020                  Select the Silicon Labs Si7013/20/21 humidity/
+                                temperature sensor
+
+        sps30                   Select the Sensirion SPS30 particulate matter
+                                sensor. Fixed address 0x69.
+
+        sgp30                   Select the Sensirion SGP30 VOC sensor.
+                                Fixed address 0x58.
+
+        tmp102                  Select the Texas Instruments TMP102 temp sensor
+                                Valid addresses 0x48-0x4b, default 0x48
+
+        tsl4531                 Select the AMS TSL4531 digital ambient light
+                                sensor
+
+        veml6070                Select the Vishay VEML6070 ultraviolet light
+                                sensor
+
+
+Name:   i2c0
+Info:   Change i2c0 pin usage. Not all pin combinations are usable on all
+        platforms - platforms other then Compute Modules can only use this
+        to disable transaction combining.
+        Do NOT use in conjunction with dtparam=i2c_vc=on. From the 5.4 kernel
+        onwards the base DT includes the use of i2c_mux_pinctrl to expose two
+        muxings of BSC0 - GPIOs 0&1, and whichever combination is used for the
+        camera and display connectors. This overlay disables that mux and
+        configures /dev/i2c0 to point at whichever set of pins is requested.
+        dtparam=i2c_vc=on will try and enable the mux, so combining the two
+        will cause conflicts.
+Load:   dtoverlay=i2c0,<param>=<val>
+Params: pins_0_1                Use pins 0 and 1 (default)
+        pins_28_29              Use pins 28 and 29
+        pins_44_45              Use pins 44 and 45
+        pins_46_47              Use pins 46 and 47
+        combine                 Allow transactions to be combined (default
+                                "yes")
+
+
+Name:   i2c0-bcm2708
+Info:   Deprecated, legacy version of i2c0.
+Load:   <Deprecated>
+
+
+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
+        to disable transaction combining.
+Load:   dtoverlay=i2c1,<param>=<val>
+Params: pins_2_3                Use pins 2 and 3 (default)
+        pins_44_45              Use pins 44 and 45
+        combine                 Allow transactions to be combined (default
+                                "yes")
+
+
+Name:   i2c1-bcm2708
+Info:   Deprecated, legacy version of i2c1.
+Load:   <Deprecated>
+
+
+Name:   i2c3
+Info:   Enable the i2c3 bus. BCM2711 only.
+Load:   dtoverlay=i2c3,<param>
+Params: pins_2_3                Use GPIOs 2 and 3
+        pins_4_5                Use GPIOs 4 and 5 (default)
+        baudrate                Set the baudrate for the interface (default
+                                "100000")
+
+
+Name:   i2c4
+Info:   Enable the i2c4 bus. BCM2711 only.
+Load:   dtoverlay=i2c4,<param>
+Params: pins_6_7                Use GPIOs 6 and 7
+        pins_8_9                Use GPIOs 8 and 9 (default)
+        baudrate                Set the baudrate for the interface (default
+                                "100000")
+
+
+Name:   i2c5
+Info:   Enable the i2c5 bus. BCM2711 only.
+Load:   dtoverlay=i2c5,<param>
+Params: pins_10_11              Use GPIOs 10 and 11
+        pins_12_13              Use GPIOs 12 and 13 (default)
+        baudrate                Set the baudrate for the interface (default
+                                "100000")
+
+
+Name:   i2c6
+Info:   Enable the i2c6 bus. BCM2711 only.
+Load:   dtoverlay=i2c6,<param>
+Params: pins_0_1                Use GPIOs 0 and 1
+        pins_22_23              Use GPIOs 22 and 23 (default)
+        baudrate                Set the baudrate for the interface (default
+                                "100000")
+
+
+Name:   i2s-gpio28-31
+Info:   move I2S function block to GPIO 28 to 31
+Load:   dtoverlay=i2s-gpio28-31
+Params: <None>
+
+
+Name:   ilitek251x
+Info:   Enables I2C connected Ilitek 251x multiple touch controller using
+        GPIO 4 (pin 7 on GPIO header) for interrupt.
+Load:   dtoverlay=ilitek251x,<param>=<val>
+Params: interrupt               GPIO used for interrupt (default 4)
+        sizex                   Touchscreen size x, horizontal resolution of
+                                touchscreen (in pixels)
+        sizey                   Touchscreen size y, vertical resolution of
+                                touchscreen (in pixels)
+
+
+Name:   imx219
+Info:   Sony IMX219 camera module.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=imx219,<param>=<val>
+Params: rotation                Mounting rotation of the camera sensor (0 or
+                                180, default 180)
+
+
+Name:   imx290
+Info:   Sony IMX290 camera module.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants. NB This currently uses 4 CSI2 data lanes and therefore will
+        only work on a CM.
+Load:   dtoverlay=imx290,<param>
+Params: 4lane                   Enable 4 CSI2 lanes. This requires a Compute
+                                Module (1, 3, or 4).
+        clock-frequency         Sets the clock frequency to match that used on
+                                the board.
+                                Modules from Vision Components use 37.125MHz
+                                (the default), whilst those from Innomaker use
+                                74.25MHz.
+        mono                    Denote that the module is a mono sensor.
+
+
+Name:   imx378
+Info:   Sony IMX378 camera module.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=imx378,<param>=<val>
+Params: rotation                Mounting rotation of the camera sensor (0 or
+                                180, default 180)
+
+
+Name:   imx477
+Info:   Sony IMX477 camera module.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=imx477,<param>=<val>
+Params: rotation                Mounting rotation of the camera sensor (0 or
+                                180, default 180)
+
+
+Name:   iqaudio-codec
+Info:   Configures the IQaudio Codec audio card
+Load:   dtoverlay=iqaudio-codec
+Params: <None>
+
+
+Name:   iqaudio-dac
+Info:   Configures the IQaudio DAC audio card
+Load:   dtoverlay=iqaudio-dac,<param>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=iqaudio-dac,24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24db_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                responsibility of the user to ensure that
+                                the Digital volume control is set to a value
+                                that does not result in clipping/distortion!)
+
+
+Name:   iqaudio-dacplus
+Info:   Configures the IQaudio DAC+ audio card
+Load:   dtoverlay=iqaudio-dacplus,<param>=<val>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=iqaudio-dacplus,24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24db_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                responsibility of the user to ensure that
+                                the Digital volume control is set to a value
+                                that does not result in clipping/distortion!)
+        auto_mute_amp           If specified, unmute/mute the IQaudIO amp when
+                                starting/stopping audio playback.
+        unmute_amp              If specified, unmute the IQaudIO amp once when
+                                the DAC driver module loads.
+
+
+Name:   iqaudio-digi-wm8804-audio
+Info:   Configures the IQAudIO Digi WM8804 audio card
+Load:   dtoverlay=iqaudio-digi-wm8804-audio,<param>=<val>
+Params: card_name               Override the default, "IQAudIODigi", card name.
+        dai_name                Override the default, "IQAudIO Digi", dai name.
+        dai_stream_name         Override the default, "IQAudIO Digi HiFi",
+                                dai stream name.
+
+
+Name:   irs1125
+Info:   Infineon irs1125 TOF camera module.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=irs1125
+Params: <None>
+
+
+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,<param>=<val>
+Params: flash-spi<n>-<m>        Enables flash device on SPI<n>, CS#<m>.
+        flash-fastr-spi<n>-<m>  Enables flash device with fast read capability
+                                on SPI<n>, CS#<m>.
+
+
+Name:   justboom-both
+Info:   Simultaneous usage of an justboom-dac and justboom-digi based
+        card
+Load:   dtoverlay=justboom-both,<param>=<val>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=justboom-dac,24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24dB_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                responsibility of the user to ensure that
+                                the Digital volume control is set to a value
+                                that does not result in clipping/distortion!)
+
+
+Name:   justboom-dac
+Info:   Configures the JustBoom DAC HAT, Amp HAT, DAC Zero and Amp Zero audio
+        cards
+Load:   dtoverlay=justboom-dac,<param>=<val>
+Params: 24db_digital_gain       Allow gain to be applied via the PCM512x codec
+                                Digital volume control. Enable with
+                                "dtoverlay=justboom-dac,24db_digital_gain"
+                                (The default behaviour is that the Digital
+                                volume control is limited to a maximum of
+                                0dB. ie. it can attenuate but not provide
+                                gain. For most users, this will be desired
+                                as it will prevent clipping. By appending
+                                the 24dB_digital_gain parameter, the Digital
+                                volume control will allow up to 24dB of
+                                gain. If this parameter is enabled, it is the
+                                responsibility of the user to ensure that
+                                the Digital volume control is set to a value
+                                that does not result in clipping/distortion!)
+
+
+Name:   justboom-digi
+Info:   Configures the JustBoom Digi HAT and Digi Zero audio cards
+Load:   dtoverlay=justboom-digi
+Params: <None>
+
+
+Name:   lirc-rpi
+Info:   This overlay has been deprecated and removed - see gpio-ir
+Load:   <Deprecated>
+
+
+Name:   ltc294x
+Info:   Adds support for the ltc294x family of battery gauges
+Load:   dtoverlay=ltc294x,<param>=<val>
+Params: ltc2941                 Select the ltc2941 device
+
+        ltc2942                 Select the ltc2942 device
+
+        ltc2943                 Select the ltc2943 device
+
+        ltc2944                 Select the ltc2944 device
+
+        resistor-sense          The sense resistor value in milli-ohms.
+                                Can be a 32-bit negative value when the battery
+                                has been connected to the wrong end of the
+                                resistor.
+
+        prescaler-exponent      Range and accuracy of the gauge. The value is
+                                programmed into the chip only if it differs
+                                from the current setting.
+                                For LTC2941 only:
+                                - Default value is 128
+                                - the exponent is in the range 0-7 (default 7)
+                                See the datasheet for more information.
+
+
+Name:   max98357a
+Info:   Configures the Maxim MAX98357A I2S DAC
+Load:   dtoverlay=max98357a,<param>=<val>
+Params: no-sdmode               Driver does not manage the state of the DAC's
+                                SD_MODE pin (i.e. chip is always on).
+        sdmode-pin              integer, GPIO pin connected to the SD_MODE input
+                                of the DAC (default GPIO4 if parameter omitted).
+
+
+Name:   maxtherm
+Info:   Configure a MAX6675, MAX31855 or MAX31856 thermocouple as an IIO device.
+
+        For devices on spi1 or spi2, the interfaces should be enabled
+        with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.
+        The overlay expects to disable the relevant spidev node, so also using
+        e.g. cs0_spidev=off is unnecessary.
+
+        Example:
+        MAX31855 on /dev/spidev0.0
+            dtoverlay=maxtherm,spi0-0,max31855
+        MAX31856 using a type J thermocouple on /dev/spidev2.1
+            dtoverlay=spi2-2cs
+            dtoverlay=maxtherm,spi2-1,max31856,type_j
+
+Load:   dtoverlay=maxtherm,<param>=<val>
+Params: spi<n>-<m>              Configure device at spi<n>, cs<m>
+                                (boolean, required)
+        max6675                 Enable support for the MAX6675 (default)
+        max31855                Enable support for the MAX31855
+        max31855e               Enable support for the MAX31855E
+        max31855j               Enable support for the MAX31855J
+        max31855k               Enable support for the MAX31855K
+        max31855n               Enable support for the MAX31855N
+        max31855r               Enable support for the MAX31855R
+        max31855s               Enable support for the MAX31855S
+        max31855t               Enable support for the MAX31855T
+        max31856                Enable support for the MAX31856 (with type K)
+        type_b                  Select a type B sensor for max31856
+        type_e                  Select a type E sensor for max31856
+        type_j                  Select a type J sensor for max31856
+        type_k                  Select a type K sensor for max31856
+        type_n                  Select a type N sensor for max31856
+        type_r                  Select a type R sensor for max31856
+        type_s                  Select a type S sensor for max31856
+        type_t                  Select a type T sensor for max31856
+
+
+Name:   mbed-dac
+Info:   Configures the mbed AudioCODEC (TLV320AIC23B)
+Load:   dtoverlay=mbed-dac
+Params: <None>
+
+
+Name:   mcp23017
+Info:   Configures the MCP23017 I2C GPIO expander
+Load:   dtoverlay=mcp23017,<param>=<val>
+Params: gpiopin                 Gpio pin connected to the INTA output of the
+                                MCP23017 (default: 4)
+
+        addr                    I2C address of the MCP23017 (default: 0x20)
+
+        mcp23008                Configure an MCP23008 instead.
+        noints                  Disable the interrupt GPIO line.
+
+
+Name:   mcp23s17
+Info:   Configures the MCP23S08/17 SPI GPIO expanders.
+        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.
+        If interrupts are enabled for a device on a given CS# on a SPI bus, that
+        device must be the only one present on that SPI bus/CS#.
+Load:   dtoverlay=mcp23s17,<param>=<val>
+Params: s08-spi<n>-<m>-present  4-bit integer, bitmap indicating MCP23S08
+                                devices present on SPI<n>, CS#<m>
+
+        s17-spi<n>-<m>-present  8-bit integer, bitmap indicating MCP23S17
+                                devices present on SPI<n>, CS#<m>
+
+        s08-spi<n>-<m>-int-gpio integer, enables interrupts on a single
+                                MCP23S08 device on SPI<n>, CS#<m>, specifies
+                                the GPIO pin to which INT output of MCP23S08
+                                is connected.
+
+        s17-spi<n>-<m>-int-gpio integer, enables mirrored interrupts on a
+                                single MCP23S17 device on SPI<n>, CS#<m>,
+                                specifies the GPIO pin to which either INTA
+                                or INTB output of MCP23S17 is connected.
+
+
+Name:   mcp2515-can0
+Info:   Configures the MCP2515 CAN controller on spi0.0
+Load:   dtoverlay=mcp2515-can0,<param>=<val>
+Params: oscillator              Clock frequency for the CAN controller (Hz)
+
+        spimaxfrequency         Maximum SPI frequence (Hz)
+
+        interrupt               GPIO for interrupt signal
+
+
+Name:   mcp2515-can1
+Info:   Configures the MCP2515 CAN controller on spi0.1
+Load:   dtoverlay=mcp2515-can1,<param>=<val>
+Params: oscillator              Clock frequency for the CAN controller (Hz)
+
+        spimaxfrequency         Maximum SPI frequence (Hz)
+
+        interrupt               GPIO for interrupt signal
+
+
+Name:   mcp251xfd
+Info:   Configures the MCP251XFD CAN controller family
+        For devices on spi1 or spi2, the interfaces should be enabled
+        with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.
+Load:   dtoverlay=mcp251xfd,<param>=<val>
+Params: spi<n>-<m>              Configure device at spi<n>, cs<m>
+                                (boolean, required)
+
+        oscillator              Clock frequency for the CAN controller (Hz)
+
+        speed                   Maximum SPI frequence (Hz)
+
+        interrupt               GPIO for interrupt signal
+
+        rx_interrupt            GPIO for RX interrupt signal (nINT1) (optional)
+
+        xceiver_enable          GPIO for CAN transceiver enable (optional)
+
+        xceiver_active_high     specifiy if CAN transceiver enable pin is
+                                active high (optional, default: active low)
+
+
+Name:   mcp3008
+Info:   Configures MCP3008 A/D converters
+        For devices on spi1 or spi2, the interfaces should be enabled
+        with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.
+Load:   dtoverlay=mcp3008,<param>[=<val>]
+Params: spi<n>-<m>-present      boolean, configure device at spi<n>, cs<m>
+        spi<n>-<m>-speed        integer, set the spi bus speed for this device
+
+
+Name:   mcp3202
+Info:   Configures MCP3202 A/D converters
+        For devices on spi1 or spi2, the interfaces should be enabled
+        with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.
+Load:   dtoverlay=mcp3202,<param>[=<val>]
+Params: spi<n>-<m>-present      boolean, configure device at spi<n>, cs<m>
+        spi<n>-<m>-speed        integer, set the spi bus speed for this device
+
+
+Name:   mcp342x
+Info:   Overlay for activation of Microchip MCP3421-3428 ADCs over I2C
+Load:   dtoverlay=mcp342x,<param>=<val>
+Params: addr                    I2C bus address of device, for devices with
+                                addresses that are configurable, e.g. by
+                                hardware links (default=0x68)
+        mcp3421                 The device is an MCP3421
+        mcp3422                 The device is an MCP3422
+        mcp3423                 The device is an MCP3423
+        mcp3424                 The device is an MCP3424
+        mcp3425                 The device is an MCP3425
+        mcp3426                 The device is an MCP3426
+        mcp3427                 The device is an MCP3427
+        mcp3428                 The device is an MCP3428
+
+
+Name:   media-center
+Info:   Media Center HAT - 2.83" Touch Display + extras by Pi Supply
+Load:   dtoverlay=media-center,<param>=<val>
+Params: speed                   Display SPI bus speed
+        rotate                  Display rotation {0,90,180,270}
+        fps                     Delay between frame updates
+        xohms                   Touchpanel sensitivity (X-plate resistance)
+        swapxy                  Swap x and y axis
+        backlight               Change backlight GPIO pin {e.g. 12, 18}
+        gpio_out_pin            GPIO for output (default "17")
+        gpio_in_pin             GPIO for input (default "18")
+        gpio_in_pull            Pull up/down/off on the input pin
+                                (default "down")
+        sense                   Override the IR receive auto-detection logic:
+                                 "0" = force active-high
+                                 "1" = force active-low
+                                 "-1" = use auto-detection
+                                (default "-1")
+        softcarrier             Turn the software carrier "on" or "off"
+                                (default "on")
+        invert                  "on" = invert the output pin (default "off")
+        debug                   "on" = enable additional debug messages
+                                (default "off")
+
+
+Name:   merus-amp
+Info:   Configures the merus-amp audio card
+Load:   dtoverlay=merus-amp
+Params: <None>
+
+
+Name:   midi-uart0
+Info:   Configures UART0 (ttyAMA0) so that a requested 38.4kbaud actually gets
+        31.25kbaud, the frequency required for MIDI
+Load:   dtoverlay=midi-uart0
+Params: <None>
+
+
+Name:   midi-uart1
+Info:   Configures UART1 (ttyS0) so that a requested 38.4kbaud actually gets
+        31.25kbaud, the frequency required for MIDI
+Load:   dtoverlay=midi-uart1
+Params: <None>
+
+
+Name:   minipitft13
+Info:   Overlay for AdaFruit Mini Pi 1.3" TFT via SPI using fbtft driver.
+Load:   dtoverlay=minipitft13,<param>=<val>
+Params: speed                   SPI bus speed (default 32000000)
+        rotate                  Display rotation (0, 90, 180 or 270; default 0)
+        width                   Display width (default 240)
+        height                  Display height (default 240)
+        fps                     Delay between frame updates (default 25)
+        debug                   Debug output level (0-7; default 0)
+
+
+Name:   miniuart-bt
+Info:   Switch the onboard Bluetooth function on Pi 3B, 3B+, 3A+, 4B and Zero W
+        to use the mini-UART (ttyS0) and restore UART0/ttyAMA0 over GPIOs 14 &
+        15. Note that this may reduce the maximum usable baudrate.
+        N.B. It is also necessary to edit /lib/systemd/system/hciuart.service
+        and replace ttyAMA0 with ttyS0, unless using Raspbian or another
+        distribution with udev rules that create /dev/serial0 and /dev/serial1,
+        in which case use /dev/serial1 instead because it will always be
+        correct. Furthermore, you must also set core_freq and core_freq_min to
+        the same value in config.txt or the miniuart will not work.
+Load:   dtoverlay=miniuart-bt,<param>=<val>
+Params: krnbt                   Set to "on" to enable autoprobing of Bluetooth
+                                driver without need of hciattach/btattach
+
+
+Name:   mmc
+Info:   Selects the bcm2835-mmc SD/MMC driver, optionally with overclock
+Load:   dtoverlay=mmc,<param>=<val>
+Params: overclock_50            Clock (in MHz) to use when the MMC framework
+                                requests 50MHz
+
+
+Name:   mpu6050
+Info:   Overlay for i2c connected mpu6050 imu
+Load:   dtoverlay=mpu6050,<param>=<val>
+Params: interrupt               GPIO pin for interrupt (default 4)
+        addr                    I2C address of the device (default 0x68)
+
+
+Name:   mz61581
+Info:   MZ61581 display by Tontec
+Load:   dtoverlay=mz61581,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        txbuflen                Transmit buffer length (default 32768)
+
+        debug                   Debug output level {0-7}
+
+        xohms                   Touchpanel sensitivity (X-plate resistance)
+
+
+Name:   ov5647
+Info:   Omnivision OV5647 camera module.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=ov5647,<param>=<val>
+Params: rotation                Mounting rotation of the camera sensor (0 or
+                                180, default 0)
+
+
+Name:   ov7251
+Info:   Omnivision OV7251 camera module.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=ov7251
+Params: <None>
+
+
+Name:   ov9281
+Info:   Omnivision OV9281 camera module.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=ov9281
+Params: <None>
+
+
+Name:   papirus
+Info:   PaPiRus ePaper Screen by Pi Supply (both HAT and pHAT)
+Load:   dtoverlay=papirus,<param>=<val>
+Params: panel                   Display panel (required):
+                                1.44": e1144cs021
+                                2.0":  e2200cs021
+                                2.7":  e2271cs021
+
+        speed                   Display SPI bus speed
+
+
+Name:   pca953x
+Info:   TI PCA953x family of I2C GPIO expanders. Default is for NXP PCA9534.
+Load:   dtoverlay=pca953x,<param>=<val>
+Params: addr                    I2C address of expander. Default 0x20.
+        pca6416                 Select the NXP PCA6416 (16 bit)
+        pca9505                 Select the NXP PCA9505 (40 bit)
+        pca9535                 Select the NXP PCA9535 (16 bit)
+        pca9536                 Select the NXP PCA9536 or TI PCA9536 (4 bit)
+        pca9537                 Select the NXP PCA9537 (4 bit)
+        pca9538                 Select the NXP PCA9538 (8 bit)
+        pca9539                 Select the NXP PCA9539 (16 bit)
+        pca9554                 Select the NXP PCA9554 (8 bit)
+        pca9555                 Select the NXP PCA9555 (16 bit)
+        pca9556                 Select the NXP PCA9556 (8 bit)
+        pca9557                 Select the NXP PCA9557 (8 bit)
+        pca9574                 Select the NXP PCA9574 (8 bit)
+        pca9575                 Select the NXP PCA9575 (16 bit)
+        pca9698                 Select the NXP PCA9698 (40 bit)
+        pca16416                Select the NXP PCA16416 (16 bit)
+        pca16524                Select the NXP PCA16524 (24 bit)
+        pca19555a               Select the NXP PCA19555A (16 bit)
+        max7310                 Select the Maxim MAX7310 (8 bit)
+        max7312                 Select the Maxim MAX7312 (16 bit)
+        max7313                 Select the Maxim MAX7313 (16 bit)
+        max7315                 Select the Maxim MAX7315 (8 bit)
+        pca6107                 Select the TI PCA6107 (8 bit)
+        tca6408                 Select the TI TCA6408 (8 bit)
+        tca6416                 Select the TI TCA6416 (16 bit)
+        tca6424                 Select the TI TCA6424 (24 bit)
+        tca9539                 Select the TI TCA9539 (16 bit)
+        tca9554                 Select the TI TCA9554 (8 bit)
+        cat9554                 Select the Onnn CAT9554 (8 bit)
+        pca9654                 Select the Onnn PCA9654 (8 bit)
+        xra1202                 Select the Exar XRA1202 (8 bit)
+
+
+Name:   pcie-32bit-dma
+Info:   Force PCIe config to support 32bit DMA addresses at the expense of
+        having to bounce buffers.
+Load:   dtoverlay=pcie-32bit-dma
+Params: <None>
+
+
+[ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ]
+
+
+[ The pcf8523-rtc overlay has been deleted. See i2c-rtc. ]
+
+
+[ The pcf8563-rtc overlay has been deleted. See i2c-rtc. ]
+
+
+Name:   pi3-act-led
+Info:   This overlay has been renamed act-led, keeping pi3-act-led as an alias
+        for backwards compatibility.
+Load:   <Deprecated>
+
+
+Name:   pi3-disable-bt
+Info:   This overlay has been renamed disable-bt, keeping pi3-disable-bt as an
+        alias for backwards compatibility.
+Load:   <Deprecated>
+
+
+Name:   pi3-disable-wifi
+Info:   This overlay has been renamed disable-wifi, keeping pi3-disable-wifi as
+        an alias for backwards compatibility.
+Load:   <Deprecated>
+
+
+Name:   pi3-miniuart-bt
+Info:   This overlay has been renamed miniuart-bt, keeping pi3-miniuart-bt as
+        an alias for backwards compatibility.
+Load:   <Deprecated>
+
+
+Name:   pibell
+Info:   Configures the pibell audio card.
+Load:   dtoverlay=pibell,<param>=<val>
+Params: alsaname                Set the name as it appears in ALSA (default
+                                "PiBell")
+
+
+Name:   pifacedigital
+Info:   Configures the PiFace Digital mcp23s17 GPIO port expander.
+Load:   dtoverlay=pifacedigital,<param>=<val>
+Params: spi-present-mask        8-bit integer, bitmap indicating MCP23S17 SPI0
+                                CS0 address. PiFace Digital supports addresses
+                                0-3, which can be configured with JP1 and JP2.
+
+
+Name:   pifi-40
+Info:   Configures the PiFi 40W stereo amplifier
+Load:   dtoverlay=pifi-40
+Params: <None>
+
+
+Name:   pifi-dac-hd
+Info:   Configures the PiFi DAC HD
+Load:   dtoverlay=pifi-dac-hd
+Params: <None>
+
+
+Name:   pifi-dac-zero
+Info:   Configures the PiFi DAC Zero
+Load:   dtoverlay=pifi-dac-zero
+Params: <None>
+
+
+Name:   pifi-mini-210
+Info:   Configures the PiFi Mini stereo amplifier
+Load:   dtoverlay=pifi-mini-210
+Params: <None>
+
+
+Name:   piglow
+Info:   Configures the PiGlow by pimoroni.com
+Load:   dtoverlay=piglow
+Params: <None>
+
+
+Name:   piscreen
+Info:   PiScreen display by OzzMaker.com
+Load:   dtoverlay=piscreen,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+        xohms                   Touchpanel sensitivity (X-plate resistance)
+
+
+Name:   piscreen2r
+Info:   PiScreen 2 with resistive TP display by OzzMaker.com
+Load:   dtoverlay=piscreen2r,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+        xohms                   Touchpanel sensitivity (X-plate resistance)
+
+
+Name:   pisound
+Info:   Configures the Blokas Labs pisound card
+Load:   dtoverlay=pisound
+Params: <None>
+
+
+Name:   pitft22
+Info:   Adafruit PiTFT 2.2" screen
+Load:   dtoverlay=pitft22,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+
+Name:   pitft28-capacitive
+Info:   Adafruit PiTFT 2.8" capacitive touch screen
+Load:   dtoverlay=pitft28-capacitive,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+        touch-sizex             Touchscreen size x (default 240)
+
+        touch-sizey             Touchscreen size y (default 320)
+
+        touch-invx              Touchscreen inverted x axis
+
+        touch-invy              Touchscreen inverted y axis
+
+        touch-swapxy            Touchscreen swapped x y axis
+
+
+Name:   pitft28-resistive
+Info:   Adafruit PiTFT 2.8" resistive touch screen
+Load:   dtoverlay=pitft28-resistive,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+
+Name:   pitft35-resistive
+Info:   Adafruit PiTFT 3.5" resistive touch screen
+Load:   dtoverlay=pitft35-resistive,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+
+Name:   pps-gpio
+Info:   Configures the pps-gpio (pulse-per-second time signal via GPIO).
+Load:   dtoverlay=pps-gpio,<param>=<val>
+Params: gpiopin                 Input GPIO (default "18")
+        assert_falling_edge     When present, assert is indicated by a falling
+                                edge, rather than by a rising edge (default
+                                off)
+        capture_clear           Generate clear events on the trailing edge
+                                (default off)
+
+
+Name:   pwm
+Info:   Configures a single PWM channel
+        Legal pin,function combinations for each channel:
+          PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0)            52,5(Alt1)
+          PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
+        N.B.:
+          1) Pin 18 is the only one available on all platforms, and
+             it is the one used by the I2S audio interface.
+             Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
+          2) The onboard analogue audio output uses both PWM channels.
+          3) So be careful mixing audio and PWM.
+          4) Currently the clock must have been enabled and configured
+             by other means.
+Load:   dtoverlay=pwm,<param>=<val>
+Params: pin                     Output pin (default 18) - see table
+        func                    Pin function (default 2 = Alt5) - see above
+        clock                   PWM clock frequency (informational)
+
+
+Name:   pwm-2chan
+Info:   Configures both PWM channels
+        Legal pin,function combinations for each channel:
+          PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0)            52,5(Alt1)
+          PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
+        N.B.:
+          1) Pin 18 is the only one available on all platforms, and
+             it is the one used by the I2S audio interface.
+             Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
+          2) The onboard analogue audio output uses both PWM channels.
+          3) So be careful mixing audio and PWM.
+          4) Currently the clock must have been enabled and configured
+             by other means.
+Load:   dtoverlay=pwm-2chan,<param>=<val>
+Params: pin                     Output pin (default 18) - see table
+        pin2                    Output pin for other channel (default 19)
+        func                    Pin function (default 2 = Alt5) - see above
+        func2                   Function for pin2 (default 2 = Alt5)
+        clock                   PWM clock frequency (informational)
+
+
+Name:   pwm-ir-tx
+Info:   Use GPIO pin as pwm-assisted infrared transmitter output.
+        This is an alternative to "gpio-ir-tx". pwm-ir-tx makes use
+        of PWM0 to reduce the CPU load during transmission compared to
+        gpio-ir-tx which uses bit-banging.
+        Legal pin,function combinations are:
+          12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1)
+Load:   dtoverlay=pwm-ir-tx,<param>=<val>
+Params: gpio_pin                Output GPIO (default 18)
+
+        func                    Pin function (default 2 = Alt5)
+
+
+Name:   qca7000
+Info:   I2SE's Evaluation Board for PLC Stamp micro
+Load:   dtoverlay=qca7000,<param>=<val>
+Params: int_pin                 GPIO pin for interrupt signal (default 23)
+
+        speed                   SPI bus speed (default 12 MHz)
+
+
+Name:   rotary-encoder
+Info:   Overlay for GPIO connected rotary encoder.
+Load:   dtoverlay=rotary-encoder,<param>=<val>
+Params: pin_a                   GPIO connected to rotary encoder channel A
+                                (default 4).
+        pin_b                   GPIO connected to rotary encoder channel B
+                                (default 17).
+        relative_axis           register a relative axis rather than an
+                                absolute one. Relative axis will only
+                                generate +1/-1 events on the input device,
+                                hence no steps need to be passed.
+        linux_axis              the input subsystem axis to map to this
+                                rotary encoder. Defaults to 0 (ABS_X / REL_X)
+        rollover                Automatic rollover when the rotary value
+                                becomes greater than the specified steps or
+                                smaller than 0. For absolute axis only.
+        steps-per-period        Number of steps (stable states) per period.
+                                The values have the following meaning:
+                                1: Full-period mode (default)
+                                2: Half-period mode
+                                4: Quarter-period mode
+        steps                   Number of steps in a full turnaround of the
+                                encoder. Only relevant for absolute axis.
+                                Defaults to 24 which is a typical value for
+                                such devices.
+        wakeup                  Boolean, rotary encoder can wake up the
+                                system.
+        encoding                String, the method used to encode steps.
+                                Supported are "gray" (the default and more
+                                common) and "binary".
+
+
+Name:   rpi-backlight
+Info:   Raspberry Pi official display backlight driver
+Load:   dtoverlay=rpi-backlight
+Params: <None>
+
+
+Name:   rpi-cirrus-wm5102
+Info:   Configures the Cirrus Logic Audio Card
+Load:   dtoverlay=rpi-cirrus-wm5102
+Params: <None>
+
+
+Name:   rpi-dac
+Info:   Configures the RPi DAC audio card
+Load:   dtoverlay=rpi-dac
+Params: <None>
+
+
+Name:   rpi-display
+Info:   RPi-Display - 2.8" Touch Display by Watterott
+Load:   dtoverlay=rpi-display,<param>=<val>
+Params: speed                   Display SPI bus speed
+        rotate                  Display rotation {0,90,180,270}
+        fps                     Delay between frame updates
+        debug                   Debug output level {0-7}
+        xohms                   Touchpanel sensitivity (X-plate resistance)
+        swapxy                  Swap x and y axis
+        backlight               Change backlight GPIO pin {e.g. 12, 18}
+
+
+Name:   rpi-ft5406
+Info:   Official Raspberry Pi display touchscreen
+Load:   dtoverlay=rpi-ft5406,<param>=<val>
+Params: touchscreen-size-x      Touchscreen X resolution (default 800)
+        touchscreen-size-y      Touchscreen Y resolution (default 600);
+        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);
+
+
+Name:   rpi-poe
+Info:   Raspberry Pi PoE HAT fan
+Load:   dtoverlay=rpi-poe,<param>[=<val>]
+Params: poe_fan_temp0           Temperature (in millicelcius) at which the fan
+                                turns on (default 40000)
+        poe_fan_temp0_hyst      Temperature delta (in millicelcius) at which
+                                the fan turns off (default 2000)
+        poe_fan_temp1           Temperature (in millicelcius) at which the fan
+                                speeds up (default 45000)
+        poe_fan_temp1_hyst      Temperature delta (in millicelcius) at which
+                                the fan slows down (default 2000)
+        poe_fan_temp2           Temperature (in millicelcius) at which the fan
+                                speeds up (default 50000)
+        poe_fan_temp2_hyst      Temperature delta (in millicelcius) at which
+                                the fan slows down (default 2000)
+        poe_fan_temp3           Temperature (in millicelcius) at which the fan
+                                speeds up (default 55000)
+        poe_fan_temp3_hyst      Temperature delta (in millicelcius) at which
+                                the fan slows down (default 5000)
+
+
+Name:   rpi-poe-plus
+Info:   Raspberry Pi PoE+ HAT fan
+Load:   dtoverlay=rpi-poe-plus,<param>[=<val>]
+Params: poe_fan_temp0           Temperature (in millicelcius) at which the fan
+                                turns on (default 40000)
+        poe_fan_temp0_hyst      Temperature delta (in millicelcius) at which
+                                the fan turns off (default 2000)
+        poe_fan_temp1           Temperature (in millicelcius) at which the fan
+                                speeds up (default 45000)
+        poe_fan_temp1_hyst      Temperature delta (in millicelcius) at which
+                                the fan slows down (default 2000)
+        poe_fan_temp2           Temperature (in millicelcius) at which the fan
+                                speeds up (default 50000)
+        poe_fan_temp2_hyst      Temperature delta (in millicelcius) at which
+                                the fan slows down (default 2000)
+        poe_fan_temp3           Temperature (in millicelcius) at which the fan
+                                speeds up (default 55000)
+        poe_fan_temp3_hyst      Temperature delta (in millicelcius) at which
+                                the fan slows down (default 5000)
+
+
+Name:   rpi-proto
+Info:   Configures the RPi Proto audio card
+Load:   dtoverlay=rpi-proto
+Params: <None>
+
+
+Name:   rpi-sense
+Info:   Raspberry Pi Sense HAT
+Load:   dtoverlay=rpi-sense
+Params: <None>
+
+
+Name:   rpi-tv
+Info:   Raspberry Pi TV HAT
+Load:   dtoverlay=rpi-tv
+Params: <None>
+
+
+Name:   rpivid-v4l2
+Info:   Load the V4L2 stateless video decoder driver for the HEVC block,
+        disabling the memory mapped devices in the process.
+Load:   dtoverlay=rpivid-v4l2
+Params: <None>
+
+
+Name:   rra-digidac1-wm8741-audio
+Info:   Configures the Red Rocks Audio DigiDAC1 soundcard
+Load:   dtoverlay=rra-digidac1-wm8741-audio
+Params: <None>
+
+
+Name:   sainsmart18
+Info:   Overlay for the SPI-connected Sainsmart 1.8" display (based on the
+        ST7735R chip).
+Load:   dtoverlay=sainsmart18,<param>=<val>
+Params: rotate                  Display rotation {0,90,180,270}
+        speed                   SPI bus speed in Hz (default 4000000)
+        fps                     Display frame rate in Hz
+        bgr                     Enable BGR mode (default off)
+        debug                   Debug output level {0-7}
+        dc_pin                  GPIO pin for D/C (default 24)
+        reset_pin               GPIO pin for RESET (default 25)
+
+
+Name:   sc16is750-i2c
+Info:   Overlay for the NXP SC16IS750 UART with I2C Interface
+        Enables the chip on I2C1 at 0x48 (or the "addr" parameter value). To
+        select another address, please refer to table 10 in reference manual.
+Load:   dtoverlay=sc16is750-i2c,<param>=<val>
+Params: int_pin                 GPIO used for IRQ (default 24)
+        addr                    Address (default 0x48)
+        xtal                    On-board crystal frequency (default 14745600)
+
+
+Name:   sc16is752-i2c
+Info:   Overlay for the NXP SC16IS752 dual UART with I2C Interface
+        Enables the chip on I2C1 at 0x48 (or the "addr" parameter value). To
+        select another address, please refer to table 10 in reference manual.
+Load:   dtoverlay=sc16is752-i2c,<param>=<val>
+Params: int_pin                 GPIO used for IRQ (default 24)
+        addr                    Address (default 0x48)
+        xtal                    On-board crystal frequency (default 14745600)
+
+
+Name:   sc16is752-spi0
+Info:   Overlay for the NXP SC16IS752 Dual UART with SPI Interface
+        Enables the chip on SPI0.
+Load:   dtoverlay=sc16is752-spi0,<param>=<val>
+Params: int_pin                 GPIO used for IRQ (default 24)
+        xtal                    On-board crystal frequency (default 14745600)
+
+
+Name:   sc16is752-spi1
+Info:   Overlay for the NXP SC16IS752 Dual UART with SPI Interface
+        Enables the chip on SPI1.
+        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.
+
+Load:   dtoverlay=sc16is752-spi1,<param>=<val>
+Params: int_pin                 GPIO used for IRQ (default 24)
+        xtal                    On-board crystal frequency (default 14745600)
+
+
+Name:   sdhost
+Info:   Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock.
+        N.B. This overlay is designed for situations where the mmc driver is
+        the default, so it disables the other (mmc) interface - this will kill
+        WiFi on a Pi3. If this isn't what you want, either use the sdtweak
+        overlay or the new sd_* dtparams of the base DTBs.
+Load:   dtoverlay=sdhost,<param>=<val>
+Params: overclock_50            Clock (in MHz) to use when the MMC framework
+                                requests 50MHz
+
+        force_pio               Disable DMA support (default off)
+
+        pio_limit               Number of blocks above which to use DMA
+                                (default 1)
+
+        debug                   Enable debug output (default off)
+
+
+Name:   sdio
+Info:   Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
+        and enables SDIO via GPIOs 22-27. An example of use in 1-bit mode is
+        "dtoverlay=sdio,bus_width=1,gpios_22_25"
+Load:   dtoverlay=sdio,<param>=<val>
+Params: sdio_overclock          SDIO Clock (in MHz) to use when the MMC
+                                framework requests 50MHz
+
+        poll_once               Disable SDIO-device polling every second
+                                (default on: polling once at boot-time)
+
+        bus_width               Set the SDIO host bus width (default 4 bits)
+
+        gpios_22_25             Select GPIOs 22-25 for 1-bit mode. Must be used
+                                with bus_width=1. This replaces the sdio-1bit
+                                overlay, which is now deprecated.
+
+        gpios_34_37             Select GPIOs 34-37 for 1-bit mode. Must be used
+                                with bus_width=1.
+
+        gpios_34_39             Select GPIOs 34-39 for 4-bit mode. Must be used
+                                with bus_width=4 (the default).
+
+
+Name:   sdio-1bit
+Info:   This overlay is now deprecated. Use
+        "dtoverlay=sdio,bus_width=1,gpios_22_25" instead.
+Load:   <Deprecated>
+
+
+Name:   sdtweak
+Info:   This overlay is now deprecated. Use the sd_* dtparams in the
+        base DTB, e.g. "dtoverlay=sdtweak,poll_once" becomes
+        "dtparam=sd_poll_once".
+Load:   <Deprecated>
+
+
+Name:   seeed-can-fd-hat-v1
+Info:   Overlay for Seeed Studio CAN BUS FD HAT with two CAN FD
+        channels without RTC. Use this overlay if your HAT has no
+        battery holder.
+        https://www.seeedstudio.com/2-Channel-CAN-BUS-FD-Shield-for-Raspberry-Pi-p-4072.html
+Load:   dtoverlay=seeed-can-fd-hat-v1
+Params: <None>
+
+
+Name:   seeed-can-fd-hat-v2
+Info:   Overlay for Seeed Studio CAN BUS FD HAT with two CAN FD
+        channels and an RTC. Use this overlay if your HAT has a
+        battery holder.
+        https://www.seeedstudio.com/CAN-BUS-FD-HAT-for-Raspberry-Pi-p-4742.html
+Load:   dtoverlay=seeed-can-fd-hat-v2
+Params: <None>
+
+
+Name:   sh1106-spi
+Info:   Overlay for SH1106 OLED via SPI using fbtft staging driver.
+Load:   dtoverlay=sh1106-spi,<param>=<val>
+Params: speed                   SPI bus speed (default 4000000)
+        rotate                  Display rotation (0, 90, 180 or 270; default 0)
+        fps                     Delay between frame updates (default 25)
+        debug                   Debug output level (0-7; default 0)
+        dc_pin                  GPIO pin for D/C (default 24)
+        reset_pin               GPIO pin for RESET (default 25)
+        height                  Display height (32 or 64; default 64)
+
+
+Name:   si446x-spi0
+Info:   Overlay for Si446x UHF Transceiver via SPI using si446x driver.
+        The driver is currently out-of-tree at
+        https://github.com/sunipkmukherjee/silabs.git
+Load:   dtoverlay=si446x-spi0,<param>=<val>
+Params: speed                   SPI bus speed (default 4000000)
+        int_pin                 GPIO pin for interrupts (default 17)
+        reset_pin               GPIO pin for RESET (default 27)
+
+
+Name:   smi
+Info:   Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25!
+Load:   dtoverlay=smi
+Params: <None>
+
+
+Name:   smi-dev
+Info:   Enables the userspace interface for the SMI driver
+Load:   dtoverlay=smi-dev
+Params: <None>
+
+
+Name:   smi-nand
+Info:   Enables access to NAND flash via the SMI interface
+Load:   dtoverlay=smi-nand
+Params: <None>
+
+
+Name:   spi-gpio35-39
+Info:   Move SPI function block to GPIO 35 to 39
+Load:   dtoverlay=spi-gpio35-39
+Params: <None>
+
+
+Name:   spi-gpio40-45
+Info:   Move SPI function block to GPIOs 40 to 45
+Load:   dtoverlay=spi-gpio40-45
+Params: <None>
+
+
+Name:   spi-rtc
+Info:   Adds support for a number of SPI Real Time Clock devices
+Load:   dtoverlay=spi-rtc,<param>=<val>
+Params: ds3232                  Select the DS3232 device
+        ds3234                  Select the DS3234 device
+        pcf2123                 Select the PCF2123 device
+
+        spi0_0                  Use spi0.0 (default)
+        spi0_1                  Use spi0.1
+        spi1_0                  Use spi1.0
+        spi1_1                  Use spi1.1
+        spi2_0                  Use spi2.0
+        spi2_1                  Use spi2.1
+        cs_high                 This device requires an active-high CS
+
+
+Name:   spi0-1cs
+Info:   Only use one CS pin for SPI0
+Load:   dtoverlay=spi0-1cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 8)
+        no_miso                 Don't claim and use the MISO pin (9), freeing
+                                it for other uses.
+
+
+Name:   spi0-2cs
+Info:   Change the CS pins for SPI0
+Load:   dtoverlay=spi0-2cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 8)
+        cs1_pin                 GPIO pin for CS1 (default 7)
+        no_miso                 Don't claim and use the MISO pin (9), freeing
+                                it for other uses.
+
+
+Name:   spi0-cs
+Info:   This overlay has been renamed spi0-2cs, keeping spi0-cs as an
+        alias for backwards compatibility.
+Load:   <Deprecated>
+
+
+Name:   spi0-hw-cs
+Info:   This overlay has been deprecated and removed because it is no longer
+        necessary and has been seen to prevent spi0 from working.
+Load:   <Deprecated>
+
+
+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.
+Load:   dtoverlay=spi1-1cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 18 - BCM SPI1_CE0).
+        cs0_spidev              Set to 'disabled' to stop the creation of a
+                                userspace device node /dev/spidev1.0 (default
+                                is 'okay' 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.
+Load:   dtoverlay=spi1-2cs,<param>=<val>
+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
+                                userspace device node /dev/spidev1.0 (default
+                                is 'okay' or enabled).
+        cs1_spidev              Set to 'disabled' to stop the creation of a
+                                userspace device node /dev/spidev1.1 (default
+                                is 'okay' 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.
+Load:   dtoverlay=spi1-3cs,<param>=<val>
+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
+                                userspace device node /dev/spidev1.0 (default
+                                is 'okay' or enabled).
+        cs1_spidev              Set to 'disabled' 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
+                                userspace device node /dev/spidev1.2 (default
+                                is 'okay' 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.
+Load:   dtoverlay=spi2-1cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 43 - BCM SPI2_CE0).
+        cs0_spidev              Set to 'disabled' to stop the creation of a
+                                userspace device node /dev/spidev2.0 (default
+                                is 'okay' 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.
+Load:   dtoverlay=spi2-2cs,<param>=<val>
+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
+                                userspace device node /dev/spidev2.0 (default
+                                is 'okay' or enabled).
+        cs1_spidev              Set to 'disabled' to stop the creation of a
+                                userspace device node /dev/spidev2.1 (default
+                                is 'okay' 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.
+Load:   dtoverlay=spi2-3cs,<param>=<val>
+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
+                                userspace device node /dev/spidev2.0 (default
+                                is 'okay' or enabled).
+        cs1_spidev              Set to 'disabled' 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
+                                userspace device node /dev/spidev2.2 (default
+                                is 'okay' 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.
+Load:   dtoverlay=spi3-1cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 0 - BCM SPI3_CE0).
+        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.
+Load:   dtoverlay=spi3-2cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 0 - BCM SPI3_CE0).
+        cs1_pin                 GPIO pin for CS1 (default 24 - BCM SPI3_CE1).
+        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.
+Load:   dtoverlay=spi4-1cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 4 - BCM SPI4_CE0).
+        cs0_spidev              Set to 'off' to prevent the creation of a
+                                userspace device node /dev/spidev4.0 (default
+                                is 'on' or enabled).
+
+
+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.
+Load:   dtoverlay=spi4-2cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 4 - BCM SPI4_CE0).
+        cs1_pin                 GPIO pin for CS1 (default 25 - BCM SPI4_CE1).
+        cs0_spidev              Set to 'off' to prevent the creation of a
+                                userspace device node /dev/spidev4.0 (default
+                                is 'on' or enabled).
+        cs1_spidev              Set to 'off' to prevent the creation of a
+                                userspace device node /dev/spidev4.1 (default
+                                is 'on' or enabled).
+
+
+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.
+Load:   dtoverlay=spi5-1cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 12 - BCM SPI5_CE0).
+        cs0_spidev              Set to 'off' to prevent the creation of a
+                                userspace device node /dev/spidev5.0 (default
+                                is 'on' or enabled).
+
+
+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.
+Load:   dtoverlay=spi5-2cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 12 - BCM SPI5_CE0).
+        cs1_pin                 GPIO pin for CS1 (default 26 - BCM SPI5_CE1).
+        cs0_spidev              Set to 'off' to prevent the creation of a
+                                userspace device node /dev/spidev5.0 (default
+                                is 'on' or enabled).
+        cs1_spidev              Set to 'off' to prevent the creation of a
+                                userspace device node /dev/spidev5.1 (default
+                                is 'on' or enabled).
+
+
+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
+        creation are configurable. BCM2711 only.
+Load:   dtoverlay=spi6-1cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 18 - BCM SPI6_CE0).
+        cs0_spidev              Set to 'off' to prevent the creation of a
+                                userspace device node /dev/spidev6.0 (default
+                                is 'on' or enabled).
+
+
+Name:   spi6-2cs
+Info:   Enables spi6 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=spi6-2cs,<param>=<val>
+Params: cs0_pin                 GPIO pin for CS0 (default 18 - BCM SPI6_CE0).
+        cs1_pin                 GPIO pin for CS1 (default 27 - BCM SPI6_CE1).
+        cs0_spidev              Set to 'off' to prevent the creation of a
+                                userspace device node /dev/spidev6.0 (default
+                                is 'on' or enabled).
+        cs1_spidev              Set to 'off' to prevent the creation of a
+                                userspace device node /dev/spidev6.1 (default
+                                is 'on' or enabled).
+
+
+Name:   ssd1306
+Info:   Overlay for activation of SSD1306 over I2C OLED display framebuffer.
+Load:   dtoverlay=ssd1306,<param>=<val>
+Params: address                 Location in display memory of first character.
+                                (default=0)
+        width                   Width of display. (default=128)
+        height                  Height of display. (default=64)
+        offset                  virtual channel a. (default=0)
+        normal                  Has no effect on displays tested. (default=not
+                                set)
+        sequential              Set this if every other scan line is missing.
+                                (default=not set)
+        remapped                Set this if display is garbled. (default=not
+                                set)
+        inverted                Set this if display is inverted and mirrored.
+                                (default=not set)
+
+        Examples:
+        Typical usage for 128x64 display: dtoverlay=ssd1306,inverted
+
+        Typical usage for 128x32 display: dtoverlay=ssd1306,inverted,sequential
+
+        i2c_baudrate=400000 will speed up the display.
+
+        i2c_baudrate=1000000 seems to work even though it's not officially
+        supported by the hardware, and is faster still.
+
+        For more information refer to the device datasheet at:
+        https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
+
+
+Name:   ssd1306-spi
+Info:   Overlay for SSD1306 OLED via SPI using fbtft staging driver.
+Load:   dtoverlay=ssd1306-spi,<param>=<val>
+Params: speed                   SPI bus speed (default 10000000)
+        rotate                  Display rotation (0, 90, 180 or 270; default 0)
+        fps                     Delay between frame updates (default 25)
+        debug                   Debug output level (0-7; default 0)
+        dc_pin                  GPIO pin for D/C (default 24)
+        reset_pin               GPIO pin for RESET (default 25)
+        height                  Display height (32 or 64; default 64)
+
+
+Name:   ssd1331-spi
+Info:   Overlay for SSD1331 OLED via SPI using fbtft staging driver.
+Load:   dtoverlay=ssd1331-spi,<param>=<val>
+Params: speed                   SPI bus speed (default 4500000)
+        rotate                  Display rotation (0, 90, 180 or 270; default 0)
+        fps                     Delay between frame updates (default 25)
+        debug                   Debug output level (0-7; default 0)
+        dc_pin                  GPIO pin for D/C (default 24)
+        reset_pin               GPIO pin for RESET (default 25)
+
+
+Name:   ssd1351-spi
+Info:   Overlay for SSD1351 OLED via SPI using fbtft staging driver.
+Load:   dtoverlay=ssd1351-spi,<param>=<val>
+Params: speed                   SPI bus speed (default 4500000)
+        rotate                  Display rotation (0, 90, 180 or 270; default 0)
+        fps                     Delay between frame updates (default 25)
+        debug                   Debug output level (0-7; default 0)
+        dc_pin                  GPIO pin for D/C (default 24)
+        reset_pin               GPIO pin for RESET (default 25)
+
+
+Name:   superaudioboard
+Info:   Configures the SuperAudioBoard sound card
+Load:   dtoverlay=superaudioboard,<param>=<val>
+Params: gpiopin                 GPIO pin for codec reset
+
+
+Name:   sx150x
+Info:   Configures the Semtech SX150X I2C GPIO expanders.
+Load:   dtoverlay=sx150x,<param>=<val>
+Params: sx150<x>-<n>-<m>        Enables SX150X device on I2C#<n> with slave
+                                address <m>. <x> may be 1-9. <n> may be 0 or 1.
+                                Permissible values of <m> (which is denoted in
+                                hex) depend on the device variant. For SX1501,
+                                SX1502, SX1504 and SX1505, <m> may be 20 or 21.
+                                For SX1503 and SX1506, <m> may be 20. For
+                                SX1507 and SX1509, <m> may be 3E, 3F, 70 or 71.
+                                For SX1508, <m> may be 20, 21, 22 or 23.
+
+        sx150<x>-<n>-<m>-int-gpio
+                                Integer, enables interrupts on SX150X device on
+                                I2C#<n> with slave address <m>, specifies
+                                the GPIO pin to which NINT output of SX150X is
+                                connected.
+
+
+Name:   tc358743
+Info:   Toshiba TC358743 HDMI to CSI-2 bridge chip.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=tc358743,<param>=<val>
+Params: 4lane                   Use 4 lanes (only applicable to Compute Modules
+                                CAM1 connector).
+
+        link-frequency          Set the link frequency. Only values of 297000000
+                                (574Mbit/s) and 486000000 (972Mbit/s - default)
+                                are supported by the driver.
+
+
+Name:   tc358743-audio
+Info:   Used in combination with the tc358743-fast overlay to route the audio
+        from the TC358743 over I2S to the Pi.
+        Wiring is LRCK/WFS to GPIO 19, BCK/SCK to GPIO 18, and DATA/SD to GPIO
+        20.
+Load:   dtoverlay=tc358743-audio,<param>=<val>
+Params: card-name               Override the default, "tc358743", card name.
+
+
+Name:   tinylcd35
+Info:   3.5" Color TFT Display by www.tinylcd.com
+        Options: Touch, RTC, keypad
+Load:   dtoverlay=tinylcd35,<param>=<val>
+Params: speed                   Display SPI bus speed
+
+        rotate                  Display rotation {0,90,180,270}
+
+        fps                     Delay between frame updates
+
+        debug                   Debug output level {0-7}
+
+        touch                   Enable touch panel
+
+        touchgpio               Touch controller IRQ GPIO
+
+        xohms                   Touchpanel: Resistance of X-plate in ohms
+
+        rtc-pcf                 PCF8563 Real Time Clock
+
+        rtc-ds                  DS1307 Real Time Clock
+
+        keypad                  Enable keypad
+
+        Examples:
+            Display with touchpanel, PCF8563 RTC and keypad:
+                dtoverlay=tinylcd35,touch,rtc-pcf,keypad
+            Old touch display:
+                dtoverlay=tinylcd35,touch,touchgpio=3
+
+
+Name:   tpm-slb9670
+Info:   Enables support for Infineon SLB9670 Trusted Platform Module add-on
+        boards, which can be used as a secure key storage and hwrng,
+        available as "Iridium SLB9670" by Infineon and "LetsTrust TPM" by pi3g.
+Load:   dtoverlay=tpm-slb9670
+Params: <None>
+
+
+Name:   uart0
+Info:   Change the pin usage of uart0
+Load:   dtoverlay=uart0,<param>=<val>
+Params: txd0_pin                GPIO pin for TXD0 (14, 32 or 36 - default 14)
+
+        rxd0_pin                GPIO pin for RXD0 (15, 33 or 37 - default 15)
+
+        pin_func                Alternative pin function - 4(Alt0) for 14&15,
+                                7(Alt3) for 32&33, 6(Alt2) for 36&37
+
+
+Name:   uart1
+Info:   Change the pin usage of uart1
+Load:   dtoverlay=uart1,<param>=<val>
+Params: txd1_pin                GPIO pin for TXD1 (14, 32 or 40 - default 14)
+
+        rxd1_pin                GPIO pin for RXD1 (15, 33 or 41 - default 15)
+
+
+Name:   uart2
+Info:   Enable uart 2 on GPIOs 0-3. BCM2711 only.
+Load:   dtoverlay=uart2,<param>
+Params: ctsrts                  Enable CTS/RTS on GPIOs 2-3 (default off)
+
+
+Name:   uart3
+Info:   Enable uart 3 on GPIOs 4-7. BCM2711 only.
+Load:   dtoverlay=uart3,<param>
+Params: ctsrts                  Enable CTS/RTS on GPIOs 6-7 (default off)
+
+
+Name:   uart4
+Info:   Enable uart 4 on GPIOs 8-11. BCM2711 only.
+Load:   dtoverlay=uart4,<param>
+Params: ctsrts                  Enable CTS/RTS on GPIOs 10-11 (default off)
+
+
+Name:   uart5
+Info:   Enable uart 5 on GPIOs 12-15. BCM2711 only.
+Load:   dtoverlay=uart5,<param>
+Params: ctsrts                  Enable CTS/RTS on GPIOs 14-15 (default off)
+
+
+Name:   udrc
+Info:   Configures the NW Digital Radio UDRC Hat
+Load:   dtoverlay=udrc,<param>=<val>
+Params: alsaname                Name of the ALSA audio device (default "udrc")
+
+
+Name:   ugreen-dabboard
+Info:   Configures the ugreen-dabboard I2S overlay
+        This is a simple overlay based on the simple-audio-card and the dmic
+        codec. It has the speciality that it is configured to use the codec
+        as a master I2S device. It works for example with the Si468x DAB
+        receiver on the uGreen DABBoard.
+Load:   dtoverlay=ugreen-dabboard,<param>=<val>
+Params: card-name               Override the default, "dabboard", card name.
+
+
+Name:   upstream
+Info:   Allow usage of downstream .dtb with upstream kernel. Comprises the
+        vc4-kms-v3d and dwc2 overlays.
+Load:   dtoverlay=upstream
+Params: <None>
+
+
+Name:   upstream-aux-interrupt
+Info:   This overlay has been deprecated and removed because it is no longer
+        necessary.
+Load:   <Deprecated>
+
+
+Name:   upstream-pi4
+Info:   Allow usage of downstream .dtb with upstream kernel on Pi 4. Comprises
+        the vc4-kms-v3d-pi4 and dwc2 overlays.
+Load:   dtoverlay=upstream-pi4
+Params: <None>
+
+
+Name:   vc4-fkms-v3d
+Info:   Enable Eric Anholt's DRM VC4 V3D driver on top of the dispmanx
+        display stack.
+Load:   dtoverlay=vc4-fkms-v3d,<param>
+Params: cma-512                 CMA is 512MB (needs 1GB)
+        cma-448                 CMA is 448MB (needs 1GB)
+        cma-384                 CMA is 384MB (needs 1GB)
+        cma-320                 CMA is 320MB (needs 1GB)
+        cma-256                 CMA is 256MB (needs 1GB)
+        cma-192                 CMA is 192MB (needs 1GB)
+        cma-128                 CMA is 128MB
+        cma-96                  CMA is 96MB
+        cma-64                  CMA is 64MB
+        cma-size                CMA size in bytes, 4MB aligned
+        cma-default             Use upstream's default value
+
+
+Name:   vc4-kms-dpi-at056tn53v1
+Info:   Enable an Innolux 5.6in VGA TFT connected to DPI interface under KMS.
+        Requires vc4-kms-v3d to be loaded.
+Load:   dtoverlay=vc4-kms-dpi-at056tn53v1
+Params: <None>
+
+
+Name:   vc4-kms-dsi-7inch
+Info:   Enable the Raspberry Pi DSI 7" screen.
+        Use edt-ft5406 for the touchscreen element.
+        Requires vc4-kms-v3d to be loaded.
+Load:   dtoverlay=vc4-kms-dsi-7inch
+Params: <None>
+
+
+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
+        Module.
+        Requires vc4-kms-v3d to be loaded.
+Load:   dtoverlay=vc4-kms-dsi-lt070me05000,<param>
+Params: reset                   GPIO for the reset signal (default 17)
+        enable                  GPIO for the enable signal (default 4)
+        dcdc-en                 GPIO for the DC-DC converter enable (default 5)
+
+
+Name:   vc4-kms-dsi-lt070me05000-v2
+Info:   Enable a JDI LT070ME05000 DSI display on DSI1 using Harlab's V2
+        interface board.
+        Note that this is a 4 lane DSI device, so it will only work on a Compute
+        Module.
+        Requires vc4-kms-v3d to be loaded.
+Load:   dtoverlay=vc4-kms-dsi-lt070me05000-v2
+Params: <None>
+
+
+Name:   vc4-kms-kippah-7inch
+Info:   Enable the Adafruit DPI Kippah with the 7" Ontat panel attached.
+        Requires vc4-kms-v3d to be loaded.
+Load:   dtoverlay=vc4-kms-kippah-7inch
+Params: <None>
+
+
+Name:   vc4-kms-v3d
+Info:   Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver.
+Load:   dtoverlay=vc4-kms-v3d,<param>
+Params: cma-512                 CMA is 512MB (needs 1GB)
+        cma-448                 CMA is 448MB (needs 1GB)
+        cma-384                 CMA is 384MB (needs 1GB)
+        cma-320                 CMA is 320MB (needs 1GB)
+        cma-256                 CMA is 256MB (needs 1GB)
+        cma-192                 CMA is 192MB (needs 1GB)
+        cma-128                 CMA is 128MB
+        cma-96                  CMA is 96MB
+        cma-64                  CMA is 64MB
+        cma-size                CMA size in bytes, 4MB aligned
+        cma-default             Use upstream's default value
+        audio                   Enable or disable audio over HDMI (default "on")
+        noaudio                 Disable all HDMI audio (default "off")
+        nocomposite             Disable the composite video output (default
+                                "off")
+
+
+Name:   vc4-kms-v3d-pi4
+Info:   Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver for Pi4.
+Load:   dtoverlay=vc4-kms-v3d-pi4,<param>
+Params: cma-512                 CMA is 512MB
+        cma-448                 CMA is 448MB
+        cma-384                 CMA is 384MB
+        cma-320                 CMA is 320MB
+        cma-256                 CMA is 256MB
+        cma-192                 CMA is 192MB
+        cma-128                 CMA is 128MB
+        cma-96                  CMA is 96MB
+        cma-64                  CMA is 64MB
+        cma-size                CMA size in bytes, 4MB aligned
+        cma-default             Use upstream's default value
+        audio                   Enable or disable audio over HDMI0 (default
+                                "on")
+        audio1                  Enable or disable audio over HDMI1 (default
+                                "on")
+        noaudio                 Disable all HDMI audio (default "off")
+        composite               Enable the composite output (disables all other
+                                outputs)
+
+
+Name:   vc4-kms-vga666
+Info:   Enable the VGA666 (resistor ladder ADC) for the vc4-kms-v3d driver.
+        Requires vc4-kms-v3d to be loaded.
+Load:   dtoverlay=vc4-kms-vga666,<param>
+Params: ddc                     Enables GPIOs 0&1 as the I2C to read the EDID
+                                from the display. NB These are NOT 5V tolerant
+                                GPIOs, therefore level shifters are required.
+
+
+Name:   vga666
+Info:   Overlay for the Fen Logic VGA666 board
+        This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds
+        after the kernel has started.
+        NOT for use with vc4-kms-v3d.
+Load:   dtoverlay=vga666
+Params: <None>
+
+
+Name:   w1-gpio
+Info:   Configures the w1-gpio Onewire interface module.
+        Use this overlay if you *don't* need a GPIO to drive an external pullup.
+Load:   dtoverlay=w1-gpio,<param>=<val>
+Params: gpiopin                 GPIO for I/O (default "4")
+        pullup                  Now enabled by default (ignored)
+
+
+Name:   w1-gpio-pullup
+Info:   Configures the w1-gpio Onewire interface module.
+        Use this overlay if you *do* need a GPIO to drive an external pullup.
+Load:   dtoverlay=w1-gpio-pullup,<param>=<val>
+Params: gpiopin                 GPIO for I/O (default "4")
+        extpullup               GPIO for external pullup (default "5")
+        pullup                  Now enabled by default (ignored)
+
+
+Name:   w5500
+Info:   Overlay for the Wiznet W5500 Ethernet Controller on SPI0
+Load:   dtoverlay=w5500,<param>=<val>
+Params: int_pin                 GPIO used for INT (default 25)
+
+        speed                   SPI bus speed (default 30000000)
+
+        cs                      SPI bus Chip Select (default 0)
+
+
+Name:   wittypi
+Info:   Configures the wittypi RTC module.
+Load:   dtoverlay=wittypi,<param>=<val>
+Params: led_gpio                GPIO for LED (default "17")
+        led_trigger             Choose which activity the LED tracks (default
+                                "default-on")
+
+
+Name:   wm8960-soundcard
+Info:   Overlay for the Waveshare wm8960 soundcard
+Load:   dtoverlay=wm8960-soundcard,<param>=<val>
+Params: alsaname                Changes the card name in ALSA
+        compatible              Changes the codec compatibility
+
+
+Troubleshooting
+===============
+
+If you are experiencing problems that you think are DT-related, enable DT
+diagnostic output by adding this to /boot/config.txt:
+
+    dtdebug=on
+
+and rebooting. Then run:
+
+    sudo vcdbg log msg
+
+and look for relevant messages.
+
+Further reading
+===============
+
+This is only meant to be a quick introduction to the subject of Device Tree on
+Raspberry Pi. There is a more complete explanation here:
+
+http://www.raspberrypi.org/documentation/configuration/device-tree.md
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Device tree overlay for GPIO connected rotary encoder.
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			rotary_pins: rotary_pins@4 {
+				brcm,pins = <4 17>; /* gpio 4 17 */
+				brcm,function = <0 0>; /* input */
+				brcm,pull = <2 2>; /* pull-up */
+			};
+
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			rotary: rotary@4 {
+				compatible = "rotary-encoder";
+				status = "okay";
+				pinctrl-names = "default";
+				pinctrl-0 = <&rotary_pins>;
+				gpios = <&gpio 4 0>, <&gpio 17 0>;
+				linux,axis = <0>; /* REL_X */
+				rotary-encoder,encoding = "gray";
+				rotary-encoder,steps = <24>; /* 24 default */
+				rotary-encoder,steps-per-period = <1>; /* corresponds to full period mode. See README */
+			};
+		};
+
+	};  
+
+	__overrides__ {
+		pin_a =		    <&rotary>,"gpios:4",
+				    <&rotary_pins>,"brcm,pins:0",
+				    /* modify reg values to allow multiple instantiation */
+				    <&rotary>,"reg:0",
+				    <&rotary_pins>,"reg:0";
+		pin_b =		    <&rotary>,"gpios:16",
+				    <&rotary_pins>,"brcm,pins:4";
+		relative_axis =     <&rotary>,"rotary-encoder,relative-axis?";
+		linux_axis =        <&rotary>,"linux,axis:0";
+		rollover =          <&rotary>,"rotary-encoder,rollover?";
+		steps-per-period =  <&rotary>,"rotary-encoder,steps-per-period:0";
+		steps =             <&rotary>,"rotary-encoder,steps:0";
+		wakeup =            <&rotary>,"wakeup-source?";
+		encoding =          <&rotary>,"rotary-encoder,encoding";
+                /* legacy parameters*/
+		rotary0_pin_a =     <&rotary>,"gpios:4",
+		                    <&rotary_pins>,"brcm,pins:0";
+		rotary0_pin_b =     <&rotary>,"gpios:16",
+		                    <&rotary_pins>,"brcm,pins:4";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Devicetree overlay for mailbox-driven Raspberry Pi DSI Display
+ * backlight controller
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			rpi_backlight: rpi_backlight {
+				compatible = "raspberrypi,rpi-backlight";
+				firmware = <&firmware>;
+				status = "okay";
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for the Cirrus Logic Audio Card
+/dts-v1/;
+/plugin/;
+#include <dt-bindings/pinctrl/bcm2835.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/mfd/arizona.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			wlf_5102_pins: wlf_5102_pins {
+				brcm,pins = <17 22 27>;
+				brcm,function = <
+					BCM2835_FSEL_GPIO_OUT
+					BCM2835_FSEL_GPIO_OUT
+					BCM2835_FSEL_GPIO_IN
+				>;
+			};
+			wlf_8804_pins: wlf_8804_pins {
+				brcm,pins = <8>;
+				brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0_cs_pins>;
+		__overlay__ {
+			brcm,pins = <7>;
+			brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+		};
+	};
+
+
+	fragment@3 {
+		target-path = "/";
+		__overlay__ {
+			rpi_cirrus_reg_1v8: rpi_cirrus_reg_1v8 {
+				compatible = "regulator-fixed";
+				regulator-name = "RPi-Cirrus 1v8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@5 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@6 {
+		target = <&spi0>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+			cs-gpios = <&gpio 7 GPIO_ACTIVE_LOW>;
+
+			wm5102@0{
+				compatible = "wlf,wm5102";
+				reg = <0>;
+
+				pinctrl-names = "default";
+				pinctrl-0 = <&wlf_5102_pins>;
+
+				spi-max-frequency = <500000>;
+
+				interrupt-parent = <&gpio>;
+				interrupts = <27 8>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				LDOVDD-supply = <&rpi_cirrus_reg_1v8>;
+				AVDD-supply = <&rpi_cirrus_reg_1v8>;
+				DBVDD1-supply = <&rpi_cirrus_reg_1v8>;
+				DBVDD2-supply = <&vdd_3v3_reg>;
+				DBVDD3-supply = <&vdd_3v3_reg>;
+				CPVDD-supply = <&rpi_cirrus_reg_1v8>;
+				SPKVDDL-supply = <&vdd_5v0_reg>;
+				SPKVDDR-supply = <&vdd_5v0_reg>;
+				DCVDD-supply = <&arizona_ldo1>;
+
+				reset-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
+				wlf,ldoena = <&gpio 22 GPIO_ACTIVE_HIGH>;
+				wlf,gpio-defaults = <
+					ARIZONA_GP_DEFAULT
+					ARIZONA_GP_DEFAULT
+					ARIZONA_GP_DEFAULT
+					ARIZONA_GP_DEFAULT
+					ARIZONA_GP_DEFAULT
+				>;
+				wlf,micd-configs = <0 1 0>;
+				wlf,dmic-ref = <
+					ARIZONA_DMIC_MICVDD
+					ARIZONA_DMIC_MICBIAS2
+					ARIZONA_DMIC_MICVDD
+					ARIZONA_DMIC_MICVDD
+				>;
+				wlf,inmode = <
+					ARIZONA_INMODE_DIFF
+					ARIZONA_INMODE_DMIC
+					ARIZONA_INMODE_SE
+					ARIZONA_INMODE_DIFF
+				>;
+				status = "okay";
+
+				arizona_ldo1: ldo1 {
+					regulator-name = "LDO1";
+					// default constraints as in
+					// arizona-ldo1.c
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1800000>;
+				};
+			};
+		};
+	};
+
+	fragment@7 {
+		target = <&i2c1>;
+		__overlay__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			wm8804@3b {
+				compatible = "wlf,wm8804";
+				reg = <0x3b>;
+				status = "okay";
+
+				pinctrl-names = "default";
+				pinctrl-0 = <&wlf_8804_pins>;
+
+				PVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+				wlf,reset-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>;
+			};
+		};
+	};
+
+	fragment@8 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "wlf,rpi-cirrus";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for RPi DAC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			pcm1794a-codec {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm1794a";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "rpi,rpi-dac";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-display-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-display-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-display-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for rpi-display by Watterott
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			rpi_display_pins: rpi_display_pins {
+				brcm,pins = <18 23 24 25>;
+				brcm,function = <1 1 1 0>; /* out out out in */
+				brcm,pull = <0 0 0 2>; /* - - - up */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			rpidisplay: rpi-display@0{
+				compatible = "ilitek,ili9341";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&rpi_display_pins>;
+
+				spi-max-frequency = <32000000>;
+				rotate = <270>;
+				bgr;
+				fps = <30>;
+				buswidth = <8>;
+				reset-gpios = <&gpio 23 1>;
+				dc-gpios = <&gpio 24 0>;
+				led-gpios = <&gpio 18 0>;
+				debug = <0>;
+			};
+
+			rpidisplay_ts: rpi-display-ts@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+
+				spi-max-frequency = <2000000>;
+				interrupts = <25 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 25 1>;
+				ti,x-plate-ohms = /bits/ 16 <60>;
+				ti,pressure-max = /bits/ 16 <255>;
+			};
+		};
+	};
+	__overrides__ {
+		speed =     <&rpidisplay>,"spi-max-frequency:0";
+		rotate =    <&rpidisplay>,"rotate:0";
+		fps =       <&rpidisplay>,"fps:0";
+		debug =     <&rpidisplay>,"debug:0";
+		xohms =     <&rpidisplay_ts>,"ti,x-plate-ohms;0";
+		swapxy =    <&rpidisplay_ts>,"ti,swap-xy?";
+		backlight = <&rpidisplay>,"led-gpios:4",
+		            <&rpi_display_pins>,"brcm,pins:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/soc/firmware";
+		__overlay__ {
+			ts: touchscreen {
+				compatible = "raspberrypi,firmware-ts";
+				touchscreen-size-x = <800>;
+				touchscreen-size-y = <480>;
+			};
+		};
+	};
+
+	__overrides__ {
+		touchscreen-size-x = <&ts>,"touchscreen-size-x:0";
+		touchscreen-size-y = <&ts>,"touchscreen-size-y:0";
+		touchscreen-inverted-x = <&ts>,"touchscreen-inverted-x?";
+		touchscreen-inverted-y = <&ts>,"touchscreen-inverted-y?";
+		touchscreen-swapped-x-y = <&ts>,"touchscreen-swapped-x-y?";
+        };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Overlay for the Raspberry Pi POE HAT.
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			fan0: rpi-poe-fan@0 {
+				compatible = "raspberrypi,rpi-poe-fan";
+				firmware = <&firmware>;
+				cooling-min-state = <0>;
+				cooling-max-state = <4>;
+				#cooling-cells = <2>;
+				cooling-levels = <0 1 10 100 255>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&cpu_thermal>;
+		__overlay__ {
+			trips {
+				trip0: trip0 {
+					temperature = <40000>;
+					hysteresis = <2000>;
+					type = "active";
+				};
+				trip1: trip1 {
+					temperature = <45000>;
+					hysteresis = <2000>;
+					type = "active";
+				};
+				trip2: trip2 {
+					temperature = <50000>;
+					hysteresis = <2000>;
+					type = "active";
+				};
+				trip3: trip3 {
+					temperature = <55000>;
+					hysteresis = <5000>;
+					type = "active";
+				};
+			};
+			cooling-maps {
+				map0 {
+					trip = <&trip0>;
+					cooling-device = <&fan0 0 1>;
+				};
+				map1 {
+					trip = <&trip1>;
+					cooling-device = <&fan0 1 2>;
+				};
+				map2 {
+					trip = <&trip2>;
+					cooling-device = <&fan0 2 3>;
+				};
+				map3 {
+					trip = <&trip3>;
+					cooling-device = <&fan0 3 4>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target-path = "/__overrides__";
+		__overlay__ {
+			poe_fan_temp0 =		<&trip0>,"temperature:0";
+			poe_fan_temp0_hyst =	<&trip0>,"hysteresis:0";
+			poe_fan_temp1 =		<&trip1>,"temperature:0";
+			poe_fan_temp1_hyst =	<&trip1>,"hysteresis:0";
+			poe_fan_temp2 =		<&trip2>,"temperature:0";
+			poe_fan_temp2_hyst =	<&trip2>,"hysteresis:0";
+			poe_fan_temp3 =		<&trip3>,"temperature:0";
+			poe_fan_temp3_hyst =	<&trip3>,"hysteresis:0";
+		};
+	};
+
+	__overrides__ {
+		poe_fan_temp0 =		<&trip0>,"temperature:0";
+		poe_fan_temp0_hyst =	<&trip0>,"hysteresis:0";
+		poe_fan_temp1 =		<&trip1>,"temperature:0";
+		poe_fan_temp1_hyst =	<&trip1>,"hysteresis:0";
+		poe_fan_temp2 =		<&trip2>,"temperature:0";
+		poe_fan_temp2_hyst =	<&trip2>,"hysteresis:0";
+		poe_fan_temp3 =		<&trip3>,"temperature:0";
+		poe_fan_temp3_hyst =	<&trip3>,"hysteresis:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+// Overlay for the Raspberry Pi PoE+ HAT.
+
+#include "rpi-poe-overlay.dts"
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@3 {
+		target-path = "/";
+		__overlay__ {
+			rpi_poe_power_supply: rpi-poe-power-supply@0 {
+				compatible = "raspberrypi,rpi-poe-power-supply";
+				firmware = <&firmware>;
+				status = "okay";
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for Rpi-Proto
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8731@1a {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8731";
+				reg = <0x1a>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "rpi,rpi-proto";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// rpi-sense HAT
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			rpi-sense@46 {
+				compatible = "rpi,rpi-sense";
+				reg = <0x46>;
+				keys-int-gpios = <&gpio 23 1>;
+				status = "okay";
+			};
+
+			lsm9ds1-magn@1c {
+				compatible = "st,lsm9ds1-magn";
+				reg = <0x1c>;
+				status = "okay";
+			};
+
+			lsm9ds1-accel6a {
+				compatible = "st,lsm9ds1-accel";
+				reg = <0x6a>;
+				status = "okay";
+			};
+
+			lps25h-press@5c {
+				compatible = "st,lps25h-press";
+				reg = <0x5c>;
+				status = "okay";
+			};
+
+			hts221-humid@5f {
+				compatible = "st,hts221-humid", "st,hts221";
+				reg = <0x5f>;
+				status = "okay";
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// rpi-tv HAT
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			cxd2880@0 {
+				compatible = "sony,cxd2880";
+				reg = <0>; /* CE0 */
+				spi-max-frequency = <50000000>;
+				status = "okay";
+			};
+		};
+	};
+
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpivid-v4l2-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpivid-v4l2-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rpivid-v4l2-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rpivid-v4l2-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for Raspberry Pi video decode engine
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/{
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&scb>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			codec@7eb10000 {
+				compatible = "raspberrypi,rpivid-vid-decoder";
+				reg = <0x0 0x7eb10000  0x0 0x1000>,  /* INTC */
+				      <0x0 0x7eb00000  0x0 0x10000>; /* HEVC */
+				reg-names = "intc",
+					    "hevc";
+
+				interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+
+				clocks = <&firmware_clocks 11>;
+				clock-names = "hevc";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&scb>;
+		__overlay__ {
+			hevc-decoder@7eb00000 {
+				status = "disabled";
+			};
+			rpivid-local-intc@7eb10000 {
+				status = "disabled";
+			};
+			h264-decoder@7eb20000 {
+				status = "disabled";
+			};
+			vp9-decoder@7eb30000 {
+				status = "disabled";
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for RRA DigiDAC1 Audio card
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8804@3b {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8804";
+				reg = <0x3b>;
+				status = "okay";
+				PVDD-supply = <&vdd_3v3_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+			};
+
+			wm8742: wm8741@1a {
+				compatible = "wlf,wm8741";
+				reg = <0x1a>;
+				status = "okay";
+				AVDD-supply = <&vdd_5v0_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "rra,digidac1-soundcard";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/sainsmart18-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sainsmart18-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/sainsmart18-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sainsmart18-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for the Sainsmart 1.8" TFT LCD with ST7735R chip 160x128
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			ss18: sainsmart18@0 {
+				compatible = "fbtft,sainsmart18";
+				reg = <0>;
+				pinctrl-names = "default";
+				spi-max-frequency = <40000000>;
+				rotate = <90>;
+				buswidth = <8>;
+				fps = <50>;
+				height = <160>;
+				width = <128>;
+				reset-gpios = <&gpio 25 1>;
+				dc-gpios = <&gpio 24 0>;
+				debug = <0>;
+			};
+		};
+	};
+
+	__overrides__ {
+		speed     = <&ss18>,"spi-max-frequency:0";
+		rotate    = <&ss18>,"rotate:0";
+		fps       = <&ss18>,"fps:0";
+		bgr       = <&ss18>,"bgr?";
+		debug     = <&ss18>,"debug:0";
+		dc_pin    = <&ss18>,"dc-gpios:4";
+		reset_pin = <&ss18>,"reset-gpios:4";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			sc16is750: sc16is750@48 {
+				compatible = "nxp,sc16is750";
+				reg = <0x48>; /* i2c address */
+				clocks = <&sc16is750_clk>;
+				interrupt-parent = <&gpio>;
+				interrupts = <24 2>; /* IRQ_TYPE_EDGE_FALLING */
+				gpio-controller;
+				#gpio-cells = <2>;
+				i2c-max-frequency = <400000>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			sc16is750_clk: sc16is750_i2c_clk@48 {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <14745600>;
+			};
+		};
+	};
+
+	__overrides__ {
+		int_pin = <&sc16is750>,"interrupts:0";
+		addr = <&sc16is750>,"reg:0", <&sc16is750_clk>,"name";
+		xtal = <&sc16is750_clk>,"clock-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_arm>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			sc16is752: sc16is752@48 {
+				compatible = "nxp,sc16is752";
+				reg = <0x48>; /* i2c address */
+				clocks = <&sc16is752_clk>;
+				interrupt-parent = <&gpio>;
+				interrupts = <24 2>; /* IRQ_TYPE_EDGE_FALLING */
+				gpio-controller;
+				#gpio-cells = <2>;
+				i2c-max-frequency = <400000>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			sc16is752_clk: sc16is752_i2c_clk@48 {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <14745600>;
+			};
+		};
+	};
+
+	__overrides__ {
+		int_pin = <&sc16is752>,"interrupts:0";
+		addr = <&sc16is752>,"reg:0",<&sc16is752_clk>,"name";
+		xtal = <&sc16is752_clk>,"clock-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/sc16is752-spi0-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sc16is752-spi0-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/sc16is752-spi0-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sc16is752-spi0-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			sc16is752: sc16is752@0 {
+				compatible = "nxp,sc16is752";
+				reg = <0>; /* CE0 */
+				clocks = <&sc16is752_clk>;
+				interrupt-parent = <&gpio>;
+				interrupts = <24 2>; /* IRQ_TYPE_EDGE_FALLING */
+				gpio-controller;
+				#gpio-cells = <2>;
+				spi-max-frequency = <4000000>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target-path = "/";
+		__overlay__ {
+			sc16is752_clk: sc16is752_spi0_0_clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <14745600>;
+			};
+		};
+	};
+
+	__overrides__ {
+		int_pin = <&sc16is752>,"interrupts:0";
+		xtal = <&sc16is752_clk>,"clock-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			spi1_pins: spi1_pins {
+				brcm,pins = <19 20 21>;
+				brcm,function = <3>; /* alt4 */
+			};
+
+			spi1_cs_pins: spi1_cs_pins {
+				brcm,pins = <18>;
+				brcm,function = <1>; /* output */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spi1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
+			cs-gpios = <&gpio 18 1>;
+			status = "okay";
+
+			sc16is752: sc16is752@0 {
+				compatible = "nxp,sc16is752";
+				reg = <0>; /* CE0 */
+				clocks = <&sc16is752_clk>;
+				interrupt-parent = <&gpio>;
+				interrupts = <24 2>; /* IRQ_TYPE_EDGE_FALLING */
+				gpio-controller;
+				#gpio-cells = <2>;
+				spi-max-frequency = <4000000>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&aux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target-path = "/";
+		__overlay__ {
+			sc16is752_clk: sc16is752_spi1_0_clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <14745600>;
+			};
+		};
+	};
+
+	__overrides__ {
+		int_pin = <&sc16is752>,"interrupts:0";
+		xtal = <&sc16is752_clk>,"clock-frequency:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/sdhost-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sdhost-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/sdhost-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sdhost-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/* Provide backwards compatible aliases for the old sdhost dtparams. */
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&sdhost>;
+		frag0: __overlay__ {
+			brcm,overclock-50 = <0>;
+			brcm,pio-limit = <1>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&mmc>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&mmcnr>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	__overrides__ {
+		overclock_50     = <&frag0>,"brcm,overclock-50:0";
+		force_pio        = <&frag0>,"brcm,force-pio?";
+		pio_limit        = <&frag0>,"brcm,pio-limit:0";
+		debug            = <&frag0>,"brcm,debug?";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/sdio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sdio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/sdio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sdio-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/* Enable SDIO from MMC interface via various GPIO groups */
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&mmcnr>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&mmc>;
+		sdio_ovl: __overlay__ {
+			pinctrl-0 = <&sdio_ovl_pins>;
+			pinctrl-names = "default";
+			non-removable;
+			bus-width = <4>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&gpio>;
+		__overlay__ {
+			sdio_ovl_pins: sdio_ovl_pins {
+				brcm,pins = <22 23 24 25 26 27>;
+				brcm,function = <7>; /* ALT3 = SD1 */
+				brcm,pull = <0 2 2 2 2 2>;
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&sdio_ovl_pins>;
+		__dormant__ {
+			brcm,pins = <22 23 24 25>;
+			brcm,pull = <0 2 2 2>;
+		};
+	};
+
+	fragment@4 {
+		target = <&sdio_ovl_pins>;
+		__dormant__ {
+			brcm,pins = <34 35 36 37>;
+			brcm,pull = <0 2 2 2>;
+		};
+	};
+
+	fragment@5 {
+		target = <&sdio_ovl_pins>;
+		__dormant__ {
+			brcm,pins = <34 35 36 37 38 39>;
+			brcm,pull = <0 2 2 2 2 2>;
+		};
+	};
+
+	fragment@6 {
+		target-path = "/aliases";
+		__overlay__ {
+			mmc1 = "/soc/mmc@7e300000";
+		};
+	};
+
+	__overrides__ {
+		poll_once = <&sdio_ovl>,"non-removable?";
+		bus_width = <&sdio_ovl>,"bus-width:0";
+		sdio_overclock = <&sdio_ovl>,"brcm,overclock-50:0";
+		gpios_22_25 = <0>,"=3";
+		gpios_34_37 = <0>,"=4";
+		gpios_34_39 = <0>,"=5";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v1-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v1-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v1-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v1-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// redo: ovmerge -c spi1-1cs-overlay.dts,cs0_pin=18,cs0_spidev=false mcp251xfd-overlay.dts,spi0-0,interrupt=25 mcp251xfd-overlay.dts,spi1-0,interrupt=24
+
+// Device tree overlay for https://www.seeedstudio.com/2-Channel-CAN-BUS-FD-Shield-for-Raspberry-Pi-p-4072.html
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/bcm2835.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			spi1_pins: spi1_pins {
+				brcm,pins = <19 20 21>;
+				brcm,function = <3>;
+			};
+			spi1_cs_pins: spi1_cs_pins {
+				brcm,pins = <18>;
+				brcm,function = <1>;
+			};
+		};
+	};
+	fragment@1 {
+		target = <&spi1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
+			cs-gpios = <&gpio 18 1>;
+			status = "okay";
+			spidev@0 {
+				compatible = "spidev";
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "disabled";
+			};
+		};
+	};
+	fragment@2 {
+		target = <&aux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@3 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+	fragment@4 {
+		target = <&gpio>;
+		__overlay__ {
+			mcp251xfd_pins: mcp251xfd_spi0_0_pins {
+				brcm,pins = <25>;
+				brcm,function = <BCM2835_FSEL_GPIO_IN>;
+			};
+		};
+	};
+	fragment@5 {
+		target-path = "/clocks";
+		__overlay__ {
+			clk_mcp251xfd_osc: mcp251xfd-spi0-0-osc {
+				#clock-cells = <0>;
+				compatible = "fixed-clock";
+				clock-frequency = <40000000>;
+			};
+		};
+	};
+	fragment@6 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			mcp251xfd@0 {
+				compatible = "microchip,mcp251xfd";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&mcp251xfd_pins>;
+				spi-max-frequency = <20000000>;
+				interrupt-parent = <&gpio>;
+				interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+				clocks = <&clk_mcp251xfd_osc>;
+			};
+		};
+	};
+	fragment@7 {
+		target-path = "spi1/spidev@0";
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+	fragment@8 {
+		target = <&gpio>;
+		__overlay__ {
+			mcp251xfd_pins_1: mcp251xfd_spi1_0_pins {
+				brcm,pins = <24>;
+				brcm,function = <BCM2835_FSEL_GPIO_IN>;
+			};
+		};
+	};
+	fragment@9 {
+		target-path = "/clocks";
+		__overlay__ {
+			clk_mcp251xfd_osc_1: mcp251xfd-spi1-0-osc {
+				#clock-cells = <0>;
+				compatible = "fixed-clock";
+				clock-frequency = <40000000>;
+			};
+		};
+	};
+	fragment@10 {
+		target = <&spi1>;
+		__overlay__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			mcp251xfd@0 {
+				compatible = "microchip,mcp251xfd";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&mcp251xfd_pins_1>;
+				spi-max-frequency = <20000000>;
+				interrupt-parent = <&gpio>;
+				interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+				clocks = <&clk_mcp251xfd_osc_1>;
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v2-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v2-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v2-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v2-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// redo: ovmerge -c mcp251xfd-overlay.dts,spi0-0,interrupt=25 mcp251xfd-overlay.dts,spi0-1,interrupt=24 i2c-rtc-overlay.dts,pcf85063
+
+// Device tree overlay for https://www.seeedstudio.com/CAN-BUS-FD-HAT-for-Raspberry-Pi-p-4742.html 
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/bcm2835.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+	fragment@0 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			mcp251xfd_pins: mcp251xfd_spi0_0_pins {
+				brcm,pins = <25>;
+				brcm,function = <BCM2835_FSEL_GPIO_IN>;
+			};
+		};
+	};
+	fragment@2 {
+		target-path = "/clocks";
+		__overlay__ {
+			clk_mcp251xfd_osc: mcp251xfd-spi0-0-osc {
+				#clock-cells = <0>;
+				compatible = "fixed-clock";
+				clock-frequency = <40000000>;
+			};
+		};
+	};
+	fragment@3 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			mcp251xfd@0 {
+				compatible = "microchip,mcp251xfd";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&mcp251xfd_pins>;
+				spi-max-frequency = <20000000>;
+				interrupt-parent = <&gpio>;
+				interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+				clocks = <&clk_mcp251xfd_osc>;
+			};
+		};
+	};
+	fragment@4 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+	fragment@5 {
+		target = <&gpio>;
+		__overlay__ {
+			mcp251xfd_pins_1: mcp251xfd_spi0_1_pins {
+				brcm,pins = <24>;
+				brcm,function = <BCM2835_FSEL_GPIO_IN>;
+			};
+		};
+	};
+	fragment@6 {
+		target-path = "/clocks";
+		__overlay__ {
+			clk_mcp251xfd_osc_1: mcp251xfd-spi0-1-osc {
+				#clock-cells = <0>;
+				compatible = "fixed-clock";
+				clock-frequency = <40000000>;
+			};
+		};
+	};
+	fragment@7 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			mcp251xfd@1 {
+				compatible = "microchip,mcp251xfd";
+				reg = <1>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&mcp251xfd_pins_1>;
+				spi-max-frequency = <20000000>;
+				interrupt-parent = <&gpio>;
+				interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+				clocks = <&clk_mcp251xfd_osc_1>;
+			};
+		};
+	};
+	fragment@8 {
+		target = <&i2cbus>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pcf85063@51 {
+				compatible = "nxp,pcf85063";
+				reg = <0x51>;
+			};
+		};
+	};
+	fragment@9 {
+		target = <&i2c_arm>;
+		i2cbus: __overlay__ {
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for SH1106 based SPI OLED display
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			sh1106_pins: sh1106_pins {
+                                brcm,pins = <25 24>;
+                                brcm,function = <1 1>; /* out out */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sh1106: sh1106@0{
+				compatible = "sinowealth,sh1106";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&sh1106_pins>;
+
+				spi-max-frequency = <4000000>;
+				bgr = <0>;
+				bpp = <1>;
+				rotate = <0>;
+				fps = <25>;
+				buswidth = <8>;
+				reset-gpios = <&gpio 25 1>;
+				dc-gpios = <&gpio 24 0>;
+				debug = <0>;
+
+				sinowealth,height = <64>;
+				sinowealth,width = <128>;
+				sinowealth,page-offset = <0>;
+			};
+		};
+	};
+
+	__overrides__ {
+		speed     = <&sh1106>,"spi-max-frequency:0";
+		rotate    = <&sh1106>,"rotate:0";
+		fps       = <&sh1106>,"fps:0";
+		debug     = <&sh1106>,"debug:0";
+		dc_pin    = <&sh1106>,"dc-gpios:4",
+		            <&sh1106_pins>,"brcm,pins:4";
+		reset_pin = <&sh1106>,"reset-gpios:4",
+		            <&sh1106_pins>,"brcm,pins:0";
+		height    = <&sh1106>,"sinowealth,height:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/si446x-spi0-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/si446x-spi0-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/si446x-spi0-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/si446x-spi0-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for the SiLabs Si446X Controller - SPI0
+// Default Interrupt Pin: 17
+// Default SDN Pin: 27
+/dts-v1/;
+/plugin/;
+
+   / {
+    compatible = "brcm,bcm2835";
+
+    fragment@0 {
+        target = <&spi0>;
+        __overlay__ {
+            // needed to avoid dtc warning
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            status = "okay";
+
+            uhf0: si446x@0{
+                compatible = "silabs,si446x";
+                reg = <0>; // CE0
+                pinctrl-names = "default";
+                pinctrl-0 = <&uhf0_pins>;
+                interrupt-parent = <&gpio>;
+                interrupts = <17 0x2>; // falling edge
+                spi-max-frequency = <4000000>;
+                sdn_pin = <27>;
+                irq_pin = <17>;
+                status = "okay";
+            };
+        };
+    };
+
+    fragment@1 {
+        target = <&gpio>;
+        __overlay__ {
+            uhf0_pins: uhf0_pins {
+                brcm,pins = <17 27>;
+                brcm,function = <0 1>; // in, out
+                brcm,pull = <2 0>; // high, none
+            };
+        };
+    };
+
+    __overrides__ {
+        int_pin = <&uhf0>, "interrupts:0",
+                  <&uhf0>, "irq_pin:0",
+                  <&uhf0_pins>, "brcm,pins:0";
+        reset_pin = <&uhf0>, "sdn_pin:0",
+                    <&uhf0_pins>, "brcm,pins:4";
+        speed   = <&uhf0>, "spi-max-frequency:0";
+    };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/smi-dev-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/smi-dev-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/smi-dev-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Description: Overlay to enable character device interface for SMI.
+// Author:	Luke Wren <luke@raspberrypi.org>
+
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&soc>;
+		__overlay__ {
+			smi_dev {
+				compatible = "brcm,bcm2835-smi-dev";
+				smi_handle = <&smi>;
+				status = "okay";
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/smi-nand-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/smi-nand-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/smi-nand-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Description: Overlay to enable NAND flash through
+// the secondary memory interface
+// Author:	Luke Wren
+
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&smi>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&smi_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&soc>;
+		__overlay__ {
+			nand: flash@0 {
+				compatible = "brcm,bcm2835-smi-nand";
+				smi_handle = <&smi>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				status = "okay";
+
+				partition@0 {
+					label = "stage2";
+					// 128k
+					reg = <0 0x20000>;
+					read-only;
+				};
+				partition@1 {
+					label = "firmware";
+					// 16M
+					reg = <0x20000 0x1000000>;
+					read-only;
+				};
+				partition@2 {
+					label = "root";
+					// 2G (will need to use 64 bit for >=4G)
+					reg = <0x1020000 0x80000000>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&gpio>;
+		__overlay__ {
+			smi_pins: smi_pins {
+				brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
+					12 13 14 15>;
+				/* Alt 1: SMI */
+				brcm,function = <5 5 5 5 5 5 5 5 5 5 5
+					5 5 5 5 5>;
+				/* /CS, /WE and /OE are pulled high, as they are
+				   generally active low signals */
+				brcm,pull = <2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0>;
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/smi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/smi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/smi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/smi-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Description:	Overlay to enable the secondary memory interface peripheral
+// Author:	Luke Wren
+
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&smi>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&smi_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			smi_pins: smi_pins {
+				/* Don't configure the top two address bits, as
+				   these are already used as ID_SD and ID_SC */
+				brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15
+					     16 17 18 19 20 21 22 23 24 25>;
+				/* Alt 1: SMI */
+				brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
+						 5 5 5 5 5 5 5 5 5>;
+				/* /CS, /WE and /OE are pulled high, as they are
+				   generally active low signals */
+				brcm,pull = <2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0
+					     0 0 0 0 0 0 0>;
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi0-1cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi0-1cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi0-1cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi0-1cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <8>;
+		};
+	};
+
+	fragment@1 {
+		target = <&spi0>;
+		frag1: __overlay__ {
+			cs-gpios = <&gpio 8 1>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&spi0_pins>;
+		__dormant__ {
+			brcm,pins = <10 11>;
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		no_miso = <0>,"=3";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi0-2cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi0-2cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi0-2cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi0-2cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <8 7>;
+		};
+	};
+
+	fragment@1 {
+		target = <&spi0>;
+		frag1: __overlay__ {
+			cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0_pins>;
+		__dormant__ {
+			brcm,pins = <10 11>;
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs1_pin  = <&frag0>,"brcm,pins:4",
+			   <&frag1>,"cs-gpios:16";
+		no_miso = <0>,"=2";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			spi1_pins: spi1_pins {
+				brcm,pins = <19 20 21>;
+				brcm,function = <3>; /* alt4 */
+			};
+
+			spi1_cs_pins: spi1_cs_pins {
+				brcm,pins = <18>;
+				brcm,function = <1>; /* output */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spi1>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
+			cs-gpios = <&gpio 18 1>;
+			status = "okay";
+
+			spidev1_0: spidev@0 {
+				compatible = "spidev";
+				reg = <0>;      /* CE0 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&aux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&spi1_cs_pins>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs0_spidev = <&spidev1_0>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			spi1_pins: spi1_pins {
+				brcm,pins = <19 20 21>;
+				brcm,function = <3>; /* alt4 */
+			};
+
+			spi1_cs_pins: spi1_cs_pins {
+				brcm,pins = <18 17>;
+				brcm,function = <1>; /* output */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spi1>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
+			cs-gpios = <&gpio 18 1>, <&gpio 17 1>;
+			status = "okay";
+
+			spidev1_0: spidev@0 {
+				compatible = "spidev";
+				reg = <0>;      /* CE0 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+
+			spidev1_1: spidev@1 {
+				compatible = "spidev";
+				reg = <1>;      /* CE1 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&aux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&spi1_cs_pins>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs1_pin  = <&spi1_cs_pins>,"brcm,pins:4",
+			   <&frag1>,"cs-gpios:16";
+		cs0_spidev = <&spidev1_0>,"status";
+		cs1_spidev = <&spidev1_1>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			spi1_pins: spi1_pins {
+				brcm,pins = <19 20 21>;
+				brcm,function = <3>; /* alt4 */
+			};
+
+			spi1_cs_pins: spi1_cs_pins {
+				brcm,pins = <18 17 16>;
+				brcm,function = <1>; /* output */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spi1>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
+			cs-gpios = <&gpio 18 1>, <&gpio 17 1>, <&gpio 16 1>;
+			status = "okay";
+
+			spidev1_0: spidev@0 {
+				compatible = "spidev";
+				reg = <0>;      /* CE0 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+
+			spidev1_1: spidev@1 {
+				compatible = "spidev";
+				reg = <1>;      /* CE1 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+
+			spidev1_2: spidev@2 {
+				compatible = "spidev";
+				reg = <2>;      /* CE2 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&aux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&spi1_cs_pins>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs1_pin  = <&spi1_cs_pins>,"brcm,pins:4",
+			   <&frag1>,"cs-gpios:16";
+		cs2_pin  = <&spi1_cs_pins>,"brcm,pins:8",
+			   <&frag1>,"cs-gpios:28";
+		cs0_spidev = <&spidev1_0>,"status";
+		cs1_spidev = <&spidev1_1>,"status";
+		cs2_spidev = <&spidev1_2>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			spi2_pins: spi2_pins {
+				brcm,pins = <40 41 42>;
+				brcm,function = <3>; /* alt4 */
+			};
+
+			spi2_cs_pins: spi2_cs_pins {
+				brcm,pins = <43>;
+				brcm,function = <1>; /* output */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spi2>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi2_pins &spi2_cs_pins>;
+			cs-gpios = <&gpio 43 1>;
+			status = "okay";
+
+			spidev2_0: spidev@0 {
+				compatible = "spidev";
+				reg = <0>;      /* CE0 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&aux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&spi2_cs_pins>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs0_spidev = <&spidev2_0>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			spi2_pins: spi2_pins {
+				brcm,pins = <40 41 42>;
+				brcm,function = <3>; /* alt4 */
+			};
+
+			spi2_cs_pins: spi2_cs_pins {
+				brcm,pins = <43 44>;
+				brcm,function = <1>; /* output */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spi2>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi2_pins &spi2_cs_pins>;
+			cs-gpios = <&gpio 43 1>, <&gpio 44 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";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&aux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&spi2_cs_pins>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs1_pin  = <&spi2_cs_pins>,"brcm,pins:4",
+			   <&frag1>,"cs-gpios:16";
+		cs0_spidev = <&spidev2_0>,"status";
+		cs1_spidev = <&spidev2_1>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&gpio>;
+		__overlay__ {
+			spi2_pins: spi2_pins {
+				brcm,pins = <40 41 42>;
+				brcm,function = <3>; /* alt4 */
+			};
+
+			spi2_cs_pins: spi2_cs_pins {
+				brcm,pins = <43 44 45>;
+				brcm,function = <1>; /* output */
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&spi2>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi2_pins &spi2_cs_pins>;
+			cs-gpios = <&gpio 43 1>, <&gpio 44 1>, <&gpio 45 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";
+			};
+
+			spidev2_2: spidev@2 {
+				compatible = "spidev";
+				reg = <2>;      /* CE2 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&aux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&spi2_cs_pins>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs1_pin  = <&spi2_cs_pins>,"brcm,pins:4",
+			   <&frag1>,"cs-gpios:16";
+		cs2_pin  = <&spi2_cs_pins>,"brcm,pins:8",
+			   <&frag1>,"cs-gpios:28";
+		cs0_spidev = <&spidev2_0>,"status";
+		cs1_spidev = <&spidev2_1>,"status";
+		cs2_spidev = <&spidev2_2>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&spi3_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <0>;
+			brcm,function = <1>; /* output */
+		};
+	};
+
+	fragment@1 {
+		target = <&spi3>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pinctrl-names = "default";
+		        pinctrl-0 = <&spi3_pins &spi3_cs_pins>;
+			cs-gpios = <&gpio 0 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  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs0_spidev = <&spidev3_0>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&spi3_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <0 24>;
+			brcm,function = <1>; /* output */
+		};
+	};
+
+	fragment@1 {
+		target = <&spi3>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pinctrl-names = "default";
+		        pinctrl-0 = <&spi3_pins &spi3_cs_pins>;
+			cs-gpios = <&gpio 0 1>, <&gpio 24 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  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs1_pin  = <&frag0>,"brcm,pins:4",
+			   <&frag1>,"cs-gpios:16";
+		cs0_spidev = <&spidev3_0>,"status";
+		cs1_spidev = <&spidev3_1>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&spi4_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <4>;
+			brcm,function = <1>; /* output */
+		};
+	};
+
+	fragment@1 {
+		target = <&spi4>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pinctrl-names = "default";
+		        pinctrl-0 = <&spi4_pins &spi4_cs_pins>;
+			cs-gpios = <&gpio 4 1>;
+			status = "okay";
+
+			spidev4_0: spidev@0 {
+				compatible = "spidev";
+				reg = <0>;      /* CE0 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs0_spidev = <&spidev4_0>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&spi4_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <4 25>;
+			brcm,function = <1>; /* output */
+		};
+	};
+
+	fragment@1 {
+		target = <&spi4>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pinctrl-names = "default";
+		        pinctrl-0 = <&spi4_pins &spi4_cs_pins>;
+			cs-gpios = <&gpio 4 1>, <&gpio 25 1>;
+			status = "okay";
+
+			spidev4_0: spidev@0 {
+				compatible = "spidev";
+				reg = <0>;      /* CE0 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+
+			spidev4_1: spidev@1 {
+				compatible = "spidev";
+				reg = <1>;      /* CE1 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs1_pin  = <&frag0>,"brcm,pins:4",
+			   <&frag1>,"cs-gpios:16";
+		cs0_spidev = <&spidev4_0>,"status";
+		cs1_spidev = <&spidev4_1>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&spi5_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <12>;
+			brcm,function = <1>; /* output */
+		};
+	};
+
+	fragment@1 {
+		target = <&spi5>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pinctrl-names = "default";
+		        pinctrl-0 = <&spi5_pins &spi5_cs_pins>;
+			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  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs0_spidev = <&spidev5_0>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&spi5_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <12 26>;
+			brcm,function = <1>; /* output */
+		};
+	};
+
+	fragment@1 {
+		target = <&spi5>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pinctrl-names = "default";
+		        pinctrl-0 = <&spi5_pins &spi5_cs_pins>;
+			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  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs1_pin  = <&frag0>,"brcm,pins:4",
+			   <&frag1>,"cs-gpios:16";
+		cs0_spidev = <&spidev5_0>,"status";
+		cs1_spidev = <&spidev5_1>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&spi6_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <18>;
+			brcm,function = <1>; /* output */
+		};
+	};
+
+	fragment@1 {
+		target = <&spi6>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pinctrl-names = "default";
+		        pinctrl-0 = <&spi6_pins &spi6_cs_pins>;
+			cs-gpios = <&gpio 18 1>;
+			status = "okay";
+
+			spidev6_0: spidev@0 {
+				compatible = "spidev";
+				reg = <0>;      /* CE0 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs0_spidev = <&spidev6_0>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+
+/ {
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&spi6_cs_pins>;
+		frag0: __overlay__ {
+			brcm,pins = <18 27>;
+			brcm,function = <1>; /* output */
+		};
+	};
+
+	fragment@1 {
+		target = <&spi6>;
+		frag1: __overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pinctrl-names = "default";
+		        pinctrl-0 = <&spi6_pins &spi6_cs_pins>;
+			cs-gpios = <&gpio 18 1>, <&gpio 27 1>;
+			status = "okay";
+
+			spidev6_0: spidev@0 {
+				compatible = "spidev";
+				reg = <0>;      /* CE0 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+
+			spidev6_1: spidev@1 {
+				compatible = "spidev";
+				reg = <1>;      /* CE1 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <125000000>;
+				status = "okay";
+			};
+		};
+	};
+
+	__overrides__ {
+		cs0_pin  = <&frag0>,"brcm,pins:0",
+			   <&frag1>,"cs-gpios:4";
+		cs1_pin  = <&frag0>,"brcm,pins:4",
+			   <&frag1>,"cs-gpios:16";
+		cs0_spidev = <&spidev6_0>,"status";
+		cs1_spidev = <&spidev6_1>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device tree overlay to move spi0 to gpio 35 to 39 on CM
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			cs-gpios = <&gpio 36 1>, <&gpio 35 1>;
+		};
+	};
+
+	fragment@1 {
+		target = <&spi0_cs_pins>;
+		__overlay__ {
+			brcm,pins = <36 35>;
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0_pins>;
+		__overlay__ {
+			brcm,pins = <37 38 39>;
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi-gpio40-45-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi-gpio40-45-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi-gpio40-45-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi-gpio40-45-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Boot EEPROM overlay
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			cs-gpios = <&gpio 43 1>, <&gpio 44 1>, <&gpio 45 1>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spi0_cs_pins>;
+		__overlay__ {
+			brcm,pins = <45 44 43>;
+			brcm,function = <1>; /* output */
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0_pins>;
+		__overlay__ {
+			brcm,pins = <40 41 42>;
+			brcm,function = <3>; /* alt4 */
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for several SPI-based Real Time Clocks
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&rtc>;
+		__dormant__ {
+			compatible = "maxim,ds3232";
+		};
+	};
+
+	fragment@1 {
+		target = <&rtc>;
+		__dormant__ {
+			compatible = "maxim,ds3234";
+		};
+	};
+
+	fragment@2 {
+		target = <&rtc>;
+		__dormant__ {
+			compatible = "nxp,rtc-pcf2123";
+		};
+	};
+
+	spidev: fragment@100 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	frag101: fragment@101 {
+		target = <&spi0>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			rtc: rtc@0 {
+				reg = <0>;
+				spi-max-frequency = <5000000>;
+			};
+		};
+	};
+
+	__overrides__ {
+		spi0_0 = <&spidev>, "target:0=",<&spidev0>,
+		         <&frag101>, "target:0=",<&spi0>,
+		         <&rtc>, "reg:0=0";
+		spi0_1 = <&spidev>, "target:0=",<&spidev1>,
+		         <&frag101>, "target:0=",<&spi0>,
+		         <&rtc>, "reg:0=1";
+		spi1_0 = <0>,"-100",
+		         <&frag101>, "target:0=",<&spi1>,
+		         <&rtc>, "reg:0=0";
+		spi1_1 = <0>,"-100",
+		         <&frag101>, "target:0=",<&spi1>,
+		         <&rtc>, "reg:0=1";
+		spi2_0 = <0>,"-100",
+		         <&frag101>, "target:0=",<&spi2>,
+		         <&rtc>, "reg:0=0";
+		spi2_1 = <0>,"-100",
+		         <&frag101>, "target:0=",<&spi2>,
+		         <&rtc>, "reg:0=1";
+		cs_high = <&rtc>, "spi-cs-high?";
+
+		ds3232 = <0>,"+0";
+		ds3234 = <0>,"+1";
+		pcf2123 = <0>,"+2";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ssd1306-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ssd1306-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ssd1306-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ssd1306-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for SSD1306 128x64 and 128x32 OLED displays
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+
+    fragment@0 {
+	target = <&i2c1>;
+	__overlay__ {
+	    status = "okay";
+
+	    #address-cells = <1>;
+	    #size-cells = <0>;
+
+	    ssd1306: oled@3c{
+		compatible = "solomon,ssd1306fb-i2c";
+		reg = <0x3c>;
+		solomon,width = <128>;
+		solomon,height = <64>;
+		solomon,page-offset = <0>;
+	    };
+	};
+    };
+
+    __overrides__ {
+	address = <&ssd1306>,"reg:0";
+	width = <&ssd1306>,"solomon,width:0";
+	height = <&ssd1306>,"solomon,height:0";
+	offset = <&ssd1306>,"solomon,page-offset:0";
+	normal = <&ssd1306>,"solomon,segment-no-remap?";
+	sequential = <&ssd1306>,"solomon,com-seq?";
+	remapped = <&ssd1306>,"solomon,com-lrremap?";
+	inverted = <&ssd1306>,"solomon,com-invdir?";
+    };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for SSD1306 based SPI OLED display
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			ssd1306_pins: ssd1306_pins {
+                                brcm,pins = <25 24>;
+                                brcm,function = <1 1>; /* out out */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ssd1306: ssd1306@0{
+				compatible = "solomon,ssd1306";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&ssd1306_pins>;
+
+				spi-max-frequency = <10000000>;
+				bgr = <0>;
+				bpp = <1>;
+				rotate = <0>;
+				fps = <25>;
+				buswidth = <8>;
+				reset-gpios = <&gpio 25 1>;
+				dc-gpios = <&gpio 24 0>;
+				debug = <0>;
+
+				solomon,height = <64>;
+				solomon,width = <128>;
+				solomon,page-offset = <0>;
+			};
+		};
+	};
+
+	__overrides__ {
+		speed     = <&ssd1306>,"spi-max-frequency:0";
+		rotate    = <&ssd1306>,"rotate:0";
+		fps       = <&ssd1306>,"fps:0";
+		debug     = <&ssd1306>,"debug:0";
+		dc_pin    = <&ssd1306>,"dc-gpios:4",
+		            <&ssd1306_pins>,"brcm,pins:4";
+		reset_pin = <&ssd1306>,"reset-gpios:4",
+		            <&ssd1306_pins>,"brcm,pins:0";
+		height    = <&ssd1306>,"solomon,height:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ssd1331-spi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ssd1331-spi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ssd1331-spi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ssd1331-spi-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for SSD1331 based SPI OLED display
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+        compatible = "brcm,bcm2835";
+
+        fragment@0 {
+                target = <&spi0>;
+                __overlay__ {
+                        status = "okay";
+                };
+        };
+
+        fragment@1 {
+                target = <&spidev0>;
+                __overlay__ {
+                        status = "disabled";
+                };
+        };
+
+        fragment@2 {
+                target = <&spidev1>;
+                __overlay__ {
+                        status = "disabled";
+                };
+        };
+
+        fragment@3 {
+                target = <&gpio>;
+                __overlay__ {
+                        ssd1331_pins: ssd1331_pins {
+                                brcm,pins = <25 24>;
+                                brcm,function = <1 1>; /* out out */
+                        };
+                };
+        };
+
+        fragment@4 {
+                target = <&spi0>;
+                __overlay__ {
+                        /* needed to avoid dtc warning */
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+
+                        ssd1331: ssd1331@0{
+                                compatible = "solomon,ssd1331";
+                                reg = <0>;
+                                pinctrl-names = "default";
+                                pinctrl-0 = <&ssd1331_pins>;
+
+                                spi-max-frequency = <4500000>;
+                                bgr = <0>;
+                                bpp = <16>;
+                                rotate = <0>;
+                                fps = <25>;
+                                buswidth = <8>;
+                                reset-gpios = <&gpio 25 1>;
+                                dc-gpios = <&gpio 24 0>;
+                                debug = <0>;
+
+                                solomon,height = <64>;
+                                solomon,width = <96>;
+                                solomon,page-offset = <0>;
+                        };
+                };
+        };
+
+        __overrides__ {
+                speed     = <&ssd1331>,"spi-max-frequency:0";
+                rotate    = <&ssd1331>,"rotate:0";
+                fps       = <&ssd1331>,"fps:0";
+                debug     = <&ssd1331>,"debug:0";
+                dc_pin    = <&ssd1331>,"dc-gpios:4",
+                            <&ssd1331_pins>,"brcm,pins:4";
+                reset_pin = <&ssd1331>,"reset-gpios:4",
+                            <&ssd1331_pins>,"brcm,pins:0";
+        };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for SSD1351 based SPI OLED display
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			ssd1351_pins: ssd1351_pins {
+                                brcm,pins = <25 24>;
+                                brcm,function = <1 1>; /* out out */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ssd1351: ssd1351@0{
+				compatible = "solomon,ssd1351";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&ssd1351_pins>;
+
+				spi-max-frequency = <4500000>;
+				bgr = <0>;
+				bpp = <16>;
+				rotate = <0>;
+				fps = <25>;
+				buswidth = <8>;
+				reset-gpios = <&gpio 25 1>;
+				dc-gpios = <&gpio 24 0>;
+				debug = <0>;
+
+				solomon,height = <128>;
+				solomon,width = <128>;
+				solomon,page-offset = <0>;
+			};
+		};
+	};
+
+	__overrides__ {
+		speed     = <&ssd1351>,"spi-max-frequency:0";
+		rotate    = <&ssd1351>,"rotate:0";
+		fps       = <&ssd1351>,"fps:0";
+		debug     = <&ssd1351>,"debug:0";
+		dc_pin    = <&ssd1351>,"dc-gpios:4",
+		            <&ssd1351_pins>,"brcm,pins:4";
+		reset_pin = <&ssd1351>,"reset-gpios:4",
+		            <&ssd1351_pins>,"brcm,pins:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for SuperAudioBoard
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "simple-audio-card";
+			i2s-controller = <&i2s>;
+			status = "okay";
+
+			simple-audio-card,name = "SuperAudioBoard";
+
+			simple-audio-card,widgets =
+				"Line", "Line In",
+				"Line", "Line Out";
+
+			simple-audio-card,routing =
+				"Line Out","AOUTA+",
+				"Line Out","AOUTA-",
+				"Line Out","AOUTB+",
+				"Line Out","AOUTB-",
+				"AINA","Line In",
+				"AINB","Line In";
+
+			simple-audio-card,format = "i2s";
+
+			simple-audio-card,bitclock-master = <&sound_master>;
+			simple-audio-card,frame-master = <&sound_master>;
+
+			simple-audio-card,cpu {
+				sound-dai = <&i2s>;
+				dai-tdm-slot-num = <2>;
+				dai-tdm-slot-width = <32>;
+			};
+
+			sound_master: simple-audio-card,codec {
+				sound-dai = <&cs4271>;
+				system-clock-frequency = <24576000>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+    
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			cs4271: cs4271@10 {
+				#sound-dai-cells = <0>;
+				compatible = "cirrus,cs4271";
+				reg = <0x10>;
+				status = "okay";
+				reset-gpio = <&gpio 26 0>; /* Pin 26, active high */
+			};
+		};
+	};
+	__overrides__ {
+		gpiopin = <&cs4271>,"reset-gpio:4";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/sx150x-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sx150x-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/sx150x-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/sx150x-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for SX150x I2C GPIO Expanders from Semtech
+
+// dtparams:
+//     sx150<x>-<n>-<m>          - Enables SX150X device on I2C#<n> with slave address <m>. <x> may be 1-9.
+//                                 <n> may be 0 or 1.  Permissible values of <m> (which is denoted in hex)
+//                                 depend on the device variant.
+//                                 For SX1501, SX1502, SX1504 and SX1505, <m> may be 20 or 21.
+//                                 For SX1503 and SX1506, <m> may be 20.
+//                                 For SX1507 and SX1509, <m> may be 3E, 3F, 70 or 71.
+//                                 For SX1508, <m> may be 20, 21, 22 or 23.
+//     sx150<x>-<n>-<m>-int-gpio - Integer, enables interrupts on SX150X device on I2C#<n> with slave address <m>,
+//                                 specifies the GPIO pin to which NINT output of SX150X is connected.
+//
+//
+// Example 1: A single SX1505 device on I2C#1 with its slave address set to 0x20 and NINT output connected to GPIO25:
+// dtoverlay=sx150x:sx1505-1-20,sx1505-1-20-int-gpio=25
+//
+// Example 2: Two SX1507 devices on I2C#0 with their slave addresses set to 0x3E and 0x70 (interrupts not used):
+// dtoverlay=sx150x:sx1507-0-3E,sx1507-0-70
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	// Enable I2C#0 interface
+	fragment@0 {
+		target = <&i2c0>;
+		__dormant__ {
+			status = "okay";
+		};
+	};
+
+	// Enable I2C#1 interface
+	fragment@1 {
+		target = <&i2c1>;
+		__dormant__ {
+			status = "okay";
+		};
+	};
+
+	// Enable a SX1501 on I2C#0 at slave addr 0x20
+	fragment@2 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1501_0_20: sx150x@20 {
+				compatible = "semtech,sx1501q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1501-0-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1501 on I2C#1 at slave addr 0x20
+	fragment@3 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1501_1_20: sx150x@20 {
+				compatible = "semtech,sx1501q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1501-1-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1501 on I2C#0 at slave addr 0x21
+	fragment@4 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1501_0_21: sx150x@21 {
+				compatible = "semtech,sx1501q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1501-0-21-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1501 on I2C#1 at slave addr 0x21
+	fragment@5 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1501_1_21: sx150x@21 {
+				compatible = "semtech,sx1501q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1501-1-21-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1502 on I2C#0 at slave addr 0x20
+	fragment@6 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1502_0_20: sx150x@20 {
+				compatible = "semtech,sx1502q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1502-0-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1502 on I2C#1 at slave addr 0x20
+	fragment@7 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1502_1_20: sx150x@20 {
+				compatible = "semtech,sx1502q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1502-1-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1502 on I2C#0 at slave addr 0x21
+	fragment@8 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1502_0_21: sx150x@21 {
+				compatible = "semtech,sx1502q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1502-0-21-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1502 on I2C#1 at slave addr 0x21
+	fragment@9 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1502_1_21: sx150x@21 {
+				compatible = "semtech,sx1502q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1501-1-21-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1503 on I2C#0 at slave addr 0x20
+	fragment@10 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1503_0_20: sx150x@20 {
+				compatible = "semtech,sx1503q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1503-0-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1503 on I2C#1 at slave addr 0x20
+	fragment@11 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1503_1_20: sx150x@20 {
+				compatible = "semtech,sx1503q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1503-1-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1504 on I2C#0 at slave addr 0x20
+	fragment@12 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1504_0_20: sx150x@20 {
+				compatible = "semtech,sx1504q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1504-0-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1504 on I2C#1 at slave addr 0x20
+	fragment@13 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1504_1_20: sx150x@20 {
+				compatible = "semtech,sx1504q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1504-1-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1504 on I2C#0 at slave addr 0x21
+	fragment@14 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1504_0_21: sx150x@21 {
+				compatible = "semtech,sx1504q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1504-0-21-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1504 on I2C#1 at slave addr 0x21
+	fragment@15 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1504_1_21: sx150x@21 {
+				compatible = "semtech,sx1504q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1504-1-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1505 on I2C#0 at slave addr 0x20
+	fragment@16 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1505_0_20: sx150x@20 {
+				compatible = "semtech,sx1505q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1505-0-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1505 on I2C#1 at slave addr 0x20
+	fragment@17 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1505_1_20: sx150x@20 {
+				compatible = "semtech,sx1505q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1505-1-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1505 on I2C#0 at slave addr 0x21
+	fragment@18 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1505_0_21: sx150x@21 {
+				compatible = "semtech,sx1505q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1505-0-21-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1505 on I2C#1 at slave addr 0x21
+	fragment@19 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1505_1_21: sx150x@21 {
+				compatible = "semtech,sx1505q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1505-1-21-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1506 on I2C#0 at slave addr 0x20
+	fragment@20 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1506_0_20: sx150x@20 {
+				compatible = "semtech,sx1506q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1506-0-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1506 on I2C#1 at slave addr 0x20
+	fragment@21 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1506_1_20: sx150x@20 {
+				compatible = "semtech,sx1506q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1506-1-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1507 on I2C#0 at slave addr 0x3E
+	fragment@22 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1507_0_3E: sx150x@3E {
+				compatible = "semtech,sx1507q";
+				reg = <0x3E>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1507_0_3E-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1507 on I2C#1 at slave addr 0x3E
+	fragment@23 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1507_1_3E: sx150x@3E {
+				compatible = "semtech,sx1507q";
+				reg = <0x3E>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1507_1_3E-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1507 on I2C#0 at slave addr 0x3F
+	fragment@24 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1507_0_3F: sx150x@3F {
+				compatible = "semtech,sx1507q";
+				reg = <0x3F>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1507_0_3F-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1507 on I2C#1 at slave addr 0x3F
+	fragment@25 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1507_1_3F: sx150x@3F {
+				compatible = "semtech,sx1507q";
+				reg = <0x3F>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1507_1_3F-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1507 on I2C#0 at slave addr 0x70
+	fragment@26 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1507_0_70: sx150x@70 {
+				compatible = "semtech,sx1507q";
+				reg = <0x70>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1507-0-70-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1507 on I2C#1 at slave addr 0x70
+	fragment@27 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1507_1_70: sx150x@70 {
+				compatible = "semtech,sx1507q";
+				reg = <0x70>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1507-1-70-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1507 on I2C#0 at slave addr 0x71
+	fragment@28 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1507_0_71: sx150x@71 {
+				compatible = "semtech,sx1507q";
+				reg = <0x71>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1507-0-71-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1507 on I2C#1 at slave addr 0x71
+	fragment@29 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1507_1_71: sx150x@71 {
+				compatible = "semtech,sx1507q";
+				reg = <0x71>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1507-1-71-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1508 on I2C#0 at slave addr 0x20
+	fragment@30 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1508_0_20: sx150x@20 {
+				compatible = "semtech,sx1508q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1508-0-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1508 on I2C#1 at slave addr 0x20
+	fragment@31 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1508_1_20: sx150x@20 {
+				compatible = "semtech,sx1508q";
+				reg = <0x20>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1508-1-20-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1508 on I2C#0 at slave addr 0x21
+	fragment@32 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1508_0_21: sx150x@21 {
+				compatible = "semtech,sx1508q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1508-0-21-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1508 on I2C#1 at slave addr 0x21
+	fragment@33 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1508_1_21: sx150x@21 {
+				compatible = "semtech,sx1508q";
+				reg = <0x21>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1508-1-21-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1508 on I2C#0 at slave addr 0x22
+	fragment@34 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1508_0_22: sx150x@22 {
+				compatible = "semtech,sx1508q";
+				reg = <0x22>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1508-0-22-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1508 on I2C#1 at slave addr 0x22
+	fragment@35 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1508_1_22: sx150x@22 {
+				compatible = "semtech,sx1508q";
+				reg = <0x22>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1508-1-22-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1508 on I2C#0 at slave addr 0x23
+	fragment@36 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1508_0_23: sx150x@23 {
+				compatible = "semtech,sx1508q";
+				reg = <0x23>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1508-0-23-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1508 on I2C#1 at slave addr 0x23
+	fragment@37 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1508_1_23: sx150x@23 {
+				compatible = "semtech,sx1508q";
+				reg = <0x23>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1508-1-23-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1509 on I2C#0 at slave addr 0x3E
+	fragment@38 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1509_0_3E: sx150x@3E {
+				compatible = "semtech,sx1509q";
+				reg = <0x3E>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1509_0_3E-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1509 on I2C#1 at slave addr 0x3E
+	fragment@39 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1509_1_3E: sx150x@3E {
+				compatible = "semtech,sx1509q";
+				reg = <0x3E>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1509_1_3E-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1509 on I2C#0 at slave addr 0x3F
+	fragment@40 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1509_0_3F: sx150x@3F {
+				compatible = "semtech,sx1509q";
+				reg = <0x3F>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1509_0_3F-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1509 on I2C#1 at slave addr 0x3F
+	fragment@41 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1509_1_3F: sx150x@3F {
+				compatible = "semtech,sx1509q";
+				reg = <0x3F>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1509_1_3F-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1509 on I2C#0 at slave addr 0x70
+	fragment@42 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1509_0_70: sx150x@70 {
+				compatible = "semtech,sx1509q";
+				reg = <0x70>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1509-0-70-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1509 on I2C#1 at slave addr 0x70
+	fragment@43 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1509_1_70: sx150x@70 {
+				compatible = "semtech,sx1509q";
+				reg = <0x70>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1509-1-70-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1509 on I2C#0 at slave addr 0x71
+	fragment@44 {
+		target = <&i2c0>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1509_0_71: sx150x@71 {
+				compatible = "semtech,sx1509q";
+				reg = <0x71>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1509-0-71-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable a SX1509 on I2C#1 at slave addr 0x71
+	fragment@45 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sx1509_1_71: sx150x@71 {
+				compatible = "semtech,sx1509q";
+				reg = <0x71>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				interrupts = <25 2>; /* 1st word overwritten by sx1509-1-71-int-gpio parameter
+				                        2nd word is 2 for falling-edge triggered */
+				status = "okay";
+			};
+		};
+	};
+
+	// Enable interrupts for a SX1501 on I2C#0 at slave addr 0x20
+	fragment@46 {
+		target = <&sx1501_0_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1501 on I2C#1 at slave addr 0x20
+	fragment@47 {
+		target = <&sx1501_1_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1501 on I2C#0 at slave addr 0x21
+	fragment@48 {
+		target = <&sx1501_0_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1501 on I2C#1 at slave addr 0x21
+	fragment@49 {
+		target = <&sx1501_1_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1502 on I2C#0 at slave addr 0x20
+	fragment@50 {
+		target = <&sx1502_0_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1502 on I2C#1 at slave addr 0x20
+	fragment@51 {
+		target = <&sx1502_1_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1502 on I2C#0 at slave addr 0x21
+	fragment@52 {
+		target = <&sx1502_0_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1502 on I2C#1 at slave addr 0x21
+	fragment@53 {
+		target = <&sx1502_1_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1503 on I2C#0 at slave addr 0x20
+	fragment@54 {
+		target = <&sx1503_0_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1503 on I2C#1 at slave addr 0x20
+	fragment@55 {
+		target = <&sx1503_1_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1504 on I2C#0 at slave addr 0x20
+	fragment@56 {
+		target = <&sx1504_0_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1504 on I2C#1 at slave addr 0x20
+	fragment@57 {
+		target = <&sx1504_1_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1504 on I2C#0 at slave addr 0x21
+	fragment@58 {
+		target = <&sx1504_0_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1504 on I2C#1 at slave addr 0x21
+	fragment@59 {
+		target = <&sx1504_1_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1505 on I2C#0 at slave addr 0x20
+	fragment@60 {
+		target = <&sx1505_0_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1505 on I2C#1 at slave addr 0x20
+	fragment@61 {
+		target = <&sx1505_1_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1505 on I2C#0 at slave addr 0x21
+	fragment@62 {
+		target = <&sx1505_0_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1505 on I2C#1 at slave addr 0x21
+	fragment@63 {
+		target = <&sx1505_1_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1506 on I2C#0 at slave addr 0x20
+	fragment@64 {
+		target = <&sx1506_0_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1506 on I2C#1 at slave addr 0x20
+	fragment@65 {
+		target = <&sx1506_1_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1507 on I2C#0 at slave addr 0x3E
+	fragment@66 {
+		target = <&sx1507_0_3E>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_3E_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1507 on I2C#1 at slave addr 0x3E
+	fragment@67 {
+		target = <&sx1507_1_3E>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_3E_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1507 on I2C#0 at slave addr 0x3F
+	fragment@68 {
+		target = <&sx1507_0_3F>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_3F_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1507 on I2C#1 at slave addr 0x3F
+	fragment@69 {
+		target = <&sx1507_1_3F>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_3F_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1507 on I2C#0 at slave addr 0x70
+	fragment@70 {
+		target = <&sx1507_0_70>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_70_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1507 on I2C#1 at slave addr 0x70
+	fragment@71 {
+		target = <&sx1507_1_70>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_70_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1507 on I2C#0 at slave addr 0x71
+	fragment@72 {
+		target = <&sx1507_0_71>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_71_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1507 on I2C#1 at slave addr 0x71
+	fragment@73 {
+		target = <&sx1507_1_71>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_71_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1508 on I2C#0 at slave addr 0x20
+	fragment@74 {
+		target = <&sx1508_0_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1508 on I2C#1 at slave addr 0x20
+	fragment@75 {
+		target = <&sx1508_1_20>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_20_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1508 on I2C#0 at slave addr 0x21
+	fragment@76 {
+		target = <&sx1508_0_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1508 on I2C#1 at slave addr 0x21
+	fragment@77 {
+		target = <&sx1508_1_21>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_21_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1508 on I2C#0 at slave addr 0x22
+	fragment@78 {
+		target = <&sx1508_0_22>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_22_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1508 on I2C#1 at slave addr 0x22
+	fragment@79 {
+		target = <&sx1508_1_22>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_22_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1508 on I2C#0 at slave addr 0x23
+	fragment@80 {
+		target = <&sx1508_0_23>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_23_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1508 on I2C#1 at slave addr 0x23
+	fragment@81 {
+		target = <&sx1508_1_23>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_23_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1509 on I2C#0 at slave addr 0x3E
+	fragment@82 {
+		target = <&sx1509_0_3E>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_3E_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1509 on I2C#1 at slave addr 0x3E
+	fragment@83 {
+		target = <&sx1509_1_3E>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_3E_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1509 on I2C#0 at slave addr 0x3F
+	fragment@84 {
+		target = <&sx1509_0_3F>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_3F_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1509 on I2C#1 at slave addr 0x3F
+	fragment@85 {
+		target = <&sx1509_1_3F>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_3F_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1509 on I2C#0 at slave addr 0x70
+	fragment@86 {
+		target = <&sx1509_0_70>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_70_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1509 on I2C#1 at slave addr 0x70
+	fragment@87 {
+		target = <&sx1509_1_70>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_70_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1509 on I2C#0 at slave addr 0x71
+	fragment@88 {
+		target = <&sx1509_0_71>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_0_71_pins>;
+		};
+	};
+
+	// Enable interrupts for a SX1509 on I2C#1 at slave addr 0x71
+	fragment@89 {
+		target = <&sx1509_1_71>;
+		__dormant__ {
+			interrupt-parent = <&gpio>;
+			interrupt-controller;
+			pinctrl-names = "default";
+			pinctrl-0 = <&sx150x_1_71_pins>;
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#0 interface at slave addr 0x20
+        // Configure as a input with no pull-up/down
+	fragment@90 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_0_20_pins: sx150x_0_20_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-0-20-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#1 interface at slave addr 0x20
+        // Configure as a input with no pull-up/down
+	fragment@91 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_1_20_pins: sx150x_1_20_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-1-20-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#0 interface at slave addr 0x21
+        // Configure as a input with no pull-up/down
+	fragment@92 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_0_21_pins: sx150x_0_21_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-0-21-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#1 interface at slave addr 0x21
+        // Configure as a input with no pull-up/down
+	fragment@93 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_1_21_pins: sx150x_1_21_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-1-21-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#0 interface at slave addr 0x22
+        // Configure as a input with no pull-up/down
+	fragment@94 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_0_22_pins: sx150x_0_22_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-0-22-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#1 interface at slave addr 0x22
+        // Configure as a input with no pull-up/down
+	fragment@95 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_1_22_pins: sx150x_1_22_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-1-22-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#0 interface at slave addr 0x23
+        // Configure as a input with no pull-up/down
+	fragment@96 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_0_23_pins: sx150x_0_23_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-0-23-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#1 interface at slave addr 0x23
+        // Configure as a input with no pull-up/down
+	fragment@97 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_1_23_pins: sx150x_1_23_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-1-23-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#0 interface at slave addr 0x3E
+        // Configure as a input with no pull-up/down
+	fragment@98 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_0_3E_pins: sx150x_0_3E_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-0-3E-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#1 interface at slave addr 0x3E
+        // Configure as a input with no pull-up/down
+	fragment@99 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_1_3E_pins: sx150x_1_3E_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-1-3E-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#0 interface at slave addr 0x3F
+        // Configure as a input with no pull-up/down
+	fragment@100 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_0_3F_pins: sx150x_0_3F_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-0-3F-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#1 interface at slave addr 0x3F
+        // Configure as a input with no pull-up/down
+	fragment@101 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_1_3F_pins: sx150x_1_3F_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-1-3F-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#0 interface at slave addr 0x70
+        // Configure as a input with no pull-up/down
+	fragment@102 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_0_70_pins: sx150x_0_70_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-0-70-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#1 interface at slave addr 0x70
+        // Configure as a input with no pull-up/down
+	fragment@103 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_1_70_pins: sx150x_1_70_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-1-70-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#0 interface at slave addr 0x71
+        // Configure as a input with no pull-up/down
+	fragment@104 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_0_71_pins: sx150x_0_71_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-0-71-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	// Configure GPIO pin connected to NINT output of a SX150x on I2C#1 interface at slave addr 0x71
+        // Configure as a input with no pull-up/down
+	fragment@105 {
+		target = <&gpio>;
+		__dormant__ {
+			sx150x_1_71_pins: sx150x_1_71_pins {
+				brcm,pins = <0>;  /* overwritten by sx150x-1-71-int-gpio parameter */
+				brcm,function = <0>;
+				brcm,pull = <0>;
+			};
+		};
+	};
+
+	__overrides__ {
+		sx1501-0-20          = <0>,"+0+2";
+		sx1501-1-20          = <0>,"+1+3";
+		sx1501-0-21          = <0>,"+0+4";
+		sx1501-1-21          = <0>,"+1+5";
+		sx1502-0-20          = <0>,"+0+6";
+		sx1502-1-20          = <0>,"+1+7";
+		sx1502-0-21          = <0>,"+0+8";
+		sx1502-1-21          = <0>,"+1+9";
+		sx1503-0-20          = <0>,"+0+10";
+		sx1503-1-20          = <0>,"+1+11";
+		sx1504-0-20          = <0>,"+0+12";
+		sx1504-1-20          = <0>,"+1+13";
+		sx1504-0-21          = <0>,"+0+14";
+		sx1504-1-21          = <0>,"+1+15";
+		sx1505-0-20          = <0>,"+0+16";
+		sx1505-1-20          = <0>,"+1+17";
+		sx1505-0-21          = <0>,"+0+18";
+		sx1505-1-21          = <0>,"+1+19";
+		sx1506-0-20          = <0>,"+0+20";
+		sx1506-1-20          = <0>,"+1+21";
+		sx1507-0-3E          = <0>,"+0+22";
+		sx1507-1-3E          = <0>,"+1+23";
+		sx1507-0-3F          = <0>,"+0+24";
+		sx1507-1-3F          = <0>,"+1+25";
+		sx1507-0-70          = <0>,"+0+26";
+		sx1507-1-70          = <0>,"+1+27";
+		sx1507-0-71          = <0>,"+0+28";
+		sx1507-1-71          = <0>,"+1+29";
+		sx1508-0-20          = <0>,"+0+30";
+		sx1508-1-20          = <0>,"+1+31";
+		sx1508-0-21          = <0>,"+0+32";
+		sx1508-1-21          = <0>,"+1+33";
+		sx1508-0-22          = <0>,"+0+34";
+		sx1508-1-22          = <0>,"+1+35";
+		sx1508-0-23          = <0>,"+0+36";
+		sx1508-1-23          = <0>,"+1+37";
+		sx1509-0-3E          = <0>,"+0+38";
+		sx1509-1-3E          = <0>,"+1+39";
+		sx1509-0-3F          = <0>,"+0+40";
+		sx1509-1-3F          = <0>,"+1+41";
+		sx1509-0-70          = <0>,"+0+42";
+		sx1509-1-70          = <0>,"+1+43";
+		sx1509-0-71          = <0>,"+0+44";
+		sx1509-1-71          = <0>,"+1+45";
+		sx1501-0-20-int-gpio = <0>,"+46+90",  <&sx150x_0_20_pins>,"brcm,pins:0", <&sx1501_0_20>,"interrupts:0";
+		sx1501-1-20-int-gpio = <0>,"+47+91",  <&sx150x_1_20_pins>,"brcm,pins:0", <&sx1501_1_20>,"interrupts:0";
+		sx1501-0-21-int-gpio = <0>,"+48+92",  <&sx150x_0_21_pins>,"brcm,pins:0", <&sx1501_0_21>,"interrupts:0";
+		sx1501-1-21-int-gpio = <0>,"+49+93",  <&sx150x_1_21_pins>,"brcm,pins:0", <&sx1501_1_21>,"interrupts:0";
+		sx1502-0-20-int-gpio = <0>,"+50+90",  <&sx150x_0_20_pins>,"brcm,pins:0", <&sx1502_0_20>,"interrupts:0";
+		sx1502-1-20-int-gpio = <0>,"+51+91",  <&sx150x_1_20_pins>,"brcm,pins:0", <&sx1502_1_20>,"interrupts:0";
+		sx1502-0-21-int-gpio = <0>,"+52+92",  <&sx150x_0_21_pins>,"brcm,pins:0", <&sx1502_0_21>,"interrupts:0";
+		sx1502-1-21-int-gpio = <0>,"+53+93",  <&sx150x_1_21_pins>,"brcm,pins:0", <&sx1502_1_21>,"interrupts:0";
+		sx1503-0-20-int-gpio = <0>,"+54+90",  <&sx150x_0_20_pins>,"brcm,pins:0", <&sx1503_0_20>,"interrupts:0";
+		sx1503-1-20-int-gpio = <0>,"+55+91",  <&sx150x_1_20_pins>,"brcm,pins:0", <&sx1503_1_20>,"interrupts:0";
+		sx1504-0-20-int-gpio = <0>,"+56+90",  <&sx150x_0_20_pins>,"brcm,pins:0", <&sx1504_0_20>,"interrupts:0";
+		sx1504-1-20-int-gpio = <0>,"+57+91",  <&sx150x_1_20_pins>,"brcm,pins:0", <&sx1504_1_20>,"interrupts:0";
+		sx1504-0-21-int-gpio = <0>,"+58+92",  <&sx150x_0_21_pins>,"brcm,pins:0", <&sx1504_0_21>,"interrupts:0";
+		sx1504-1-21-int-gpio = <0>,"+59+93",  <&sx150x_1_21_pins>,"brcm,pins:0", <&sx1504_1_21>,"interrupts:0";
+		sx1505-0-20-int-gpio = <0>,"+60+90",  <&sx150x_0_20_pins>,"brcm,pins:0", <&sx1505_0_20>,"interrupts:0";
+		sx1505-1-20-int-gpio = <0>,"+61+91",  <&sx150x_1_20_pins>,"brcm,pins:0", <&sx1505_1_20>,"interrupts:0";
+		sx1505-0-21-int-gpio = <0>,"+62+92",  <&sx150x_0_21_pins>,"brcm,pins:0", <&sx1505_0_21>,"interrupts:0";
+		sx1505-1-21-int-gpio = <0>,"+63+93",  <&sx150x_1_21_pins>,"brcm,pins:0", <&sx1505_1_21>,"interrupts:0";
+		sx1506-0-20-int-gpio = <0>,"+64+90",  <&sx150x_0_20_pins>,"brcm,pins:0", <&sx1506_0_20>,"interrupts:0";
+		sx1506-1-20-int-gpio = <0>,"+65+91",  <&sx150x_1_20_pins>,"brcm,pins:0", <&sx1506_1_20>,"interrupts:0";
+		sx1507-0-3E-int-gpio = <0>,"+66+98",  <&sx150x_0_3E_pins>,"brcm,pins:0", <&sx1507_0_3E>,"interrupts:0";
+		sx1507-1-3E-int-gpio = <0>,"+67+99",  <&sx150x_1_3E_pins>,"brcm,pins:0", <&sx1507_1_3E>,"interrupts:0";
+		sx1507-0-3F-int-gpio = <0>,"+68+100", <&sx150x_0_3F_pins>,"brcm,pins:0", <&sx1507_0_3F>,"interrupts:0";
+		sx1507-1-3F-int-gpio = <0>,"+69+101", <&sx150x_1_3F_pins>,"brcm,pins:0", <&sx1507_1_3F>,"interrupts:0";
+		sx1507-0-70-int-gpio = <0>,"+60+102", <&sx150x_0_70_pins>,"brcm,pins:0", <&sx1507_0_70>,"interrupts:0";
+		sx1507-1-70-int-gpio = <0>,"+71+103", <&sx150x_1_70_pins>,"brcm,pins:0", <&sx1507_1_70>,"interrupts:0";
+		sx1507-0-71-int-gpio = <0>,"+72+104", <&sx150x_0_71_pins>,"brcm,pins:0", <&sx1507_0_71>,"interrupts:0";
+		sx1507-1-71-int-gpio = <0>,"+73+105", <&sx150x_1_71_pins>,"brcm,pins:0", <&sx1507_1_71>,"interrupts:0";
+		sx1508-0-20-int-gpio = <0>,"+74+90",  <&sx150x_0_20_pins>,"brcm,pins:0", <&sx1508_0_20>,"interrupts:0";
+		sx1508-1-20-int-gpio = <0>,"+75+91",  <&sx150x_1_20_pins>,"brcm,pins:0", <&sx1508_1_20>,"interrupts:0";
+		sx1508-0-21-int-gpio = <0>,"+76+92",  <&sx150x_0_21_pins>,"brcm,pins:0", <&sx1508_0_21>,"interrupts:0";
+		sx1508-1-21-int-gpio = <0>,"+77+93",  <&sx150x_1_21_pins>,"brcm,pins:0", <&sx1508_1_21>,"interrupts:0";
+		sx1508-0-22-int-gpio = <0>,"+78+94",  <&sx150x_0_22_pins>,"brcm,pins:0", <&sx1508_0_22>,"interrupts:0";
+		sx1508-1-22-int-gpio = <0>,"+79+95",  <&sx150x_1_22_pins>,"brcm,pins:0", <&sx1508_1_22>,"interrupts:0";
+		sx1508-0-23-int-gpio = <0>,"+80+96",  <&sx150x_0_23_pins>,"brcm,pins:0", <&sx1508_0_23>,"interrupts:0";
+		sx1508-1-23-int-gpio = <0>,"+81+97",  <&sx150x_1_23_pins>,"brcm,pins:0", <&sx1508_1_23>,"interrupts:0";
+		sx1509-0-3E-int-gpio = <0>,"+82+98",  <&sx150x_0_3E_pins>,"brcm,pins:0", <&sx1509_0_3E>,"interrupts:0";
+		sx1509-1-3E-int-gpio = <0>,"+83+99",  <&sx150x_1_3E_pins>,"brcm,pins:0", <&sx1509_1_3E>,"interrupts:0";
+		sx1509-0-3F-int-gpio = <0>,"+84+100", <&sx150x_0_3F_pins>,"brcm,pins:0", <&sx1509_0_3F>,"interrupts:0";
+		sx1509-1-3F-int-gpio = <0>,"+85+101", <&sx150x_1_3F_pins>,"brcm,pins:0", <&sx1509_1_3F>,"interrupts:0";
+		sx1509-0-70-int-gpio = <0>,"+86+102", <&sx150x_0_70_pins>,"brcm,pins:0", <&sx1509_0_70>,"interrupts:0";
+		sx1509-1-70-int-gpio = <0>,"+87+103", <&sx150x_1_70_pins>,"brcm,pins:0", <&sx1509_1_70>,"interrupts:0";
+		sx1509-0-71-int-gpio = <0>,"+88+104", <&sx150x_0_71_pins>,"brcm,pins:0", <&sx1509_0_71>,"interrupts:0";
+		sx1509-1-71-int-gpio = <0>,"+89+105", <&sx150x_1_71_pins>,"brcm,pins:0", <&sx1509_1_71>,"interrupts:0";
+	};
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions to add I2S audio from the Toshiba TC358743 HDMI to CSI2 bridge.
+// Requires tc358743 overlay to have been loaded to actually function.
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			tc358743_codec: tc358743-codec {
+				#sound-dai-cells = <0>;
+				compatible = "linux,spdif-dir";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		sound_overlay: __overlay__ {
+			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>;
+			status = "okay";
+
+			simple-audio-card,cpu {
+				sound-dai = <&i2s>;
+				dai-tdm-slot-num = <2>;
+				dai-tdm-slot-width = <32>;
+			};
+			dailink0_slave: simple-audio-card,codec {
+				sound-dai = <&tc358743_codec>;
+			};
+		};
+	};
+
+	__overrides__ {
+		card-name = <&sound_overlay>,"simple-audio-card,name";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/tc358743-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/tc358743-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/tc358743-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/tc358743-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for Toshiba TC358743 HDMI to CSI2 bridge on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			tc358743@0f {
+				compatible = "toshiba,tc358743";
+				reg = <0x0f>;
+				status = "okay";
+
+				clocks = <&tc358743_clk>;
+				clock-names = "refclk";
+
+				port {
+					tc358743: endpoint {
+						remote-endpoint = <&csi1_ep>;
+						clock-lanes = <0>;
+						clock-noncontinuous;
+						link-frequencies =
+							/bits/ 64 <486000000>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&csi1>;
+		__overlay__ {
+			status = "okay";
+
+			port {
+				csi1_ep: endpoint {
+					remote-endpoint = <&tc358743>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&tc358743>;
+		__overlay__ {
+			data-lanes = <1 2>;
+		};
+	};
+
+	fragment@3 {
+		target = <&tc358743>;
+		__dormant__ {
+			data-lanes = <1 2 3 4>;
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@6 {
+		target-path = "/";
+		__overlay__ {
+			tc358743_clk: bridge-clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <27000000>;
+			};
+		};
+	};
+
+	fragment@7 {
+		target = <&csi1_ep>;
+		__overlay__ {
+			data-lanes = <1 2>;
+		};
+	};
+
+	fragment@8 {
+		target = <&csi1_ep>;
+		__dormant__ {
+			data-lanes = <1 2 3 4>;
+		};
+	};
+
+	__overrides__ {
+		4lane = <0>, "-2+3-7+8";
+		link-frequency = <&tc358743>,"link-frequencies#0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * tinylcd35-overlay.dts
+ *
+ * -------------------------------------------------
+ * www.tinlylcd.com
+ * -------------------------------------------------
+ * Device---Driver-----BUS       GPIO's
+ * display  tinylcd35  spi0.0    25 24 18
+ * touch    ads7846    spi0.1    5
+ * rtc      ds1307     i2c1-0068
+ * rtc      pcf8563    i2c1-0051
+ * keypad   gpio-keys  --------- 17 22 27 23 28
+ *
+ *
+ * TinyLCD.com 3.5 inch TFT
+ *
+ *  Version 001
+ *  5/3/2015  -- Noralf Trønnes     Initial Device tree framework
+ *  10/3/2015 -- tinylcd@gmail.com  added ds1307 support.
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			tinylcd35_pins: tinylcd35_pins {
+				brcm,pins = <25 24 18>;
+				brcm,function = <1>; /* out */
+			};
+			tinylcd35_ts_pins: tinylcd35_ts_pins {
+				brcm,pins = <5>;
+				brcm,function = <0>; /* in */
+			};
+			keypad_pins: keypad_pins {
+				brcm,pins = <4 17 22 23 27>;
+				brcm,function = <0>; /* in */
+				brcm,pull = <1>; /* down */
+			};
+		};
+	};
+
+	fragment@4 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			tinylcd35: tinylcd35@0{
+				compatible = "neosec,tinylcd";
+				reg = <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&tinylcd35_pins>,
+					    <&tinylcd35_ts_pins>;
+
+				spi-max-frequency = <48000000>;
+				rotate = <270>;
+				fps = <20>;
+				bgr;
+				buswidth = <8>;
+				reset-gpios = <&gpio 25 1>;
+				dc-gpios = <&gpio 24 0>;
+				led-gpios = <&gpio 18 0>;
+				debug = <0>;
+
+				init = <0x10000B0 0x80
+					0x10000C0 0x0A 0x0A
+					0x10000C1 0x01 0x01
+					0x10000C2 0x33
+					0x10000C5 0x00 0x42 0x80
+					0x10000B1 0xD0 0x11
+					0x10000B4 0x02
+					0x10000B6 0x00 0x22 0x3B
+					0x10000B7 0x07
+					0x1000036 0x58
+					0x10000F0 0x36 0xA5 0xD3
+					0x10000E5 0x80
+					0x10000E5 0x01
+					0x10000B3 0x00
+					0x10000E5 0x00
+					0x10000F0 0x36 0xA5 0x53
+					0x10000E0 0x00 0x35 0x33 0x00 0x00 0x00 0x00 0x35 0x33 0x00 0x00 0x00
+					0x100003A 0x55
+					0x1000011
+					0x2000001
+					0x1000029>;
+			};
+
+			tinylcd35_ts: tinylcd35_ts@1 {
+				compatible = "ti,ads7846";
+				reg = <1>;
+				status = "disabled";
+
+				spi-max-frequency = <2000000>;
+				interrupts = <5 2>; /* high-to-low edge triggered */
+				interrupt-parent = <&gpio>;
+				pendown-gpio = <&gpio 5 0>;
+				ti,x-plate-ohms = /bits/ 16 <100>;
+				ti,pressure-max = /bits/ 16 <255>;
+			};
+		};
+	};
+
+	/*  RTC    */
+
+	fragment@5 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			pcf8563: pcf8563@51 {
+				compatible = "nxp,pcf8563";
+				reg = <0x51>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@6 {
+		target = <&i2c1>;
+		__dormant__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			ds1307: ds1307@68 {
+				compatible = "dallas,ds1307";
+				reg = <0x68>;
+				status = "okay";
+			};
+		};
+	};
+
+	/*
+	 * Values for input event code is found under the
+	 * 'Keys and buttons' heading in include/uapi/linux/input.h
+	 */
+	fragment@7 {
+		target-path = "/soc";
+		__overlay__ {
+			keypad: keypad {
+				compatible = "gpio-keys";
+				pinctrl-names = "default";
+				pinctrl-0 = <&keypad_pins>;
+				status = "disabled";
+				autorepeat;
+
+				button@17 {
+					label = "GPIO KEY_UP";
+					linux,code = <103>;
+					gpios = <&gpio 17 0>;
+				};
+				button@22 {
+					label = "GPIO KEY_DOWN";
+					linux,code = <108>;
+					gpios = <&gpio 22 0>;
+				};
+				button@27 {
+					label = "GPIO KEY_LEFT";
+					linux,code = <105>;
+					gpios = <&gpio 27 0>;
+				};
+				button@23 {
+					label = "GPIO KEY_RIGHT";
+					linux,code = <106>;
+					gpios = <&gpio 23 0>;
+				};
+				button@4 {
+					label = "GPIO KEY_ENTER";
+					linux,code = <28>;
+					gpios = <&gpio 4 0>;
+				};
+			};
+		};
+	};
+
+	__overrides__ {
+		speed =      <&tinylcd35>,"spi-max-frequency:0";
+		rotate =     <&tinylcd35>,"rotate:0";
+		fps =        <&tinylcd35>,"fps:0";
+		debug =      <&tinylcd35>,"debug:0";
+		touch =      <&tinylcd35_ts>,"status";
+		touchgpio =  <&tinylcd35_ts_pins>,"brcm,pins:0",
+			     <&tinylcd35_ts>,"interrupts:0",
+			     <&tinylcd35_ts>,"pendown-gpio:4";
+		xohms =      <&tinylcd35_ts>,"ti,x-plate-ohms;0";
+		rtc-pcf =    <0>,"=5";
+		rtc-ds =     <0>,"=6";
+		keypad =     <&keypad>,"status";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for the Infineon SLB9670 Trusted Platform Module add-on
+ * boards, which can be used as a secure key storage and hwrng.
+ * available as "Iridium SLB9670" by Infineon and "LetsTrust TPM" by pi3g.
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev1>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			slb9670: slb9670@1 {
+				compatible = "infineon,slb9670";
+				reg = <1>;	/* CE1 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				spi-max-frequency = <32000000>;
+				status = "okay";
+			};
+
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart0-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart0-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart0-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart0-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&uart0>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart0_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			uart0_pins: uart0_pins {
+				brcm,pins = <14 15>;
+				brcm,function = <4>; /* alt0 */
+				brcm,pull = <0 2>;
+			};
+		};
+	};
+
+	__overrides__ {
+		txd0_pin = <&uart0_pins>,"brcm,pins:0";
+		rxd0_pin = <&uart0_pins>,"brcm,pins:4";
+		pin_func = <&uart0_pins>,"brcm,function:0";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart1-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart1-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart1-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart1-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&uart1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart1_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			uart1_pins: uart1_pins {
+				brcm,pins = <14 15>;
+				brcm,function = <2>; /* alt5 */
+				brcm,pull = <0 2>;
+			};
+		};
+	};
+
+	fragment@2 {
+		target-path = "/chosen";
+		__overlay__ {
+			bootargs = "8250.nr_uarts=1";
+		};
+	};
+
+	__overrides__ {
+		txd1_pin = <&uart1_pins>,"brcm,pins:0";
+		rxd1_pin = <&uart1_pins>,"brcm,pins:4";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart2-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart2-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart2-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart2-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&uart2>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart2_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&uart2_pins>;
+		__dormant__ {
+			brcm,pins = <0 1 2 3>;
+			brcm,pull = <0 2 2 0>;
+		};
+	};
+
+	__overrides__ {
+		ctsrts = <0>,"=1";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart3-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart3-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart3-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart3-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&uart3>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart3_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&uart3_pins>;
+		__dormant__ {
+			brcm,pins = <4 5 6 7>;
+			brcm,pull = <0 2 2 0>;
+		};
+	};
+
+	__overrides__ {
+		ctsrts = <0>,"=1";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart4-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart4-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart4-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart4-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&uart4>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart4_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&uart4_pins>;
+		__dormant__ {
+			brcm,pins = <8 9 10 11>;
+			brcm,pull = <0 2 2 0>;
+		};
+	};
+
+	__overrides__ {
+		ctsrts = <0>,"=1";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart5-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart5-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/uart5-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/uart5-overlay.dts	2021-07-25 16:45:35.158807390 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2711";
+
+	fragment@0 {
+		target = <&uart5>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart5_pins>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&uart5_pins>;
+		__dormant__ {
+			brcm,pins = <12 13 14 15>;
+			brcm,pull = <0 2 2 0>;
+		};
+	};
+
+	__overrides__ {
+		ctsrts = <0>,"=1";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/udrc-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/udrc-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/udrc-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/udrc-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+#include <dt-bindings/clock/bcm2835.h>
+/*
+ * Device tree overlay for the Universal Digital Radio Controller
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+    fragment@0 {
+        target = <&i2s>;
+        __overlay__ {
+            clocks = <&clocks BCM2835_CLOCK_PCM>;
+            clock-names = "pcm";
+            status = "okay";
+        };
+    };
+
+    fragment@1 {
+        target-path = "/";
+        __overlay__ {
+            regulators {
+                compatible = "simple-bus";
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                udrc0_ldoin: udrc0_ldoin {
+                    compatible = "regulator-fixed";
+                    regulator-name = "ldoin";
+                    regulator-min-microvolt = <3300000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                };
+            };
+        };
+    };
+
+    fragment@2 {
+        target = <&i2c1>;
+        __overlay__ {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            status = "okay";
+            clocks = <&clocks BCM2835_CLOCK_VPU>;
+            clock-frequency = <400000>;
+
+            tlv320aic32x4: tlv320aic32x4@18 {
+                compatible = "ti,tlv320aic32x4";
+                #sound-dai-cells = <0>;
+                reg = <0x18>;
+                status = "okay";
+
+                clocks = <&clocks BCM2835_CLOCK_GP0>;
+                clock-names = "mclk";
+                assigned-clocks = <&clocks BCM2835_CLOCK_GP0>;
+                assigned-clock-rates = <25000000>;
+
+                pinctrl-names = "default";
+                pinctrl-0 = <&gpclk0_pin &aic3204_reset>;
+
+                reset-gpios = <&gpio 13 0>;
+
+                iov-supply = <&udrc0_ldoin>;
+                ldoin-supply = <&udrc0_ldoin>;
+            };
+        };
+    };
+
+    fragment@3 {
+        target = <&sound>;
+        snd: __overlay__ {
+            compatible = "simple-audio-card";
+            i2s-controller = <&i2s>;
+            status = "okay";
+
+            simple-audio-card,name = "udrc";
+            simple-audio-card,format = "i2s";
+
+            simple-audio-card,bitclock-master = <&dailink0_master>;
+            simple-audio-card,frame-master = <&dailink0_master>;
+
+            simple-audio-card,widgets =
+                "Line", "Line In",
+                "Line", "Line Out";
+
+            simple-audio-card,routing =
+                "IN1_R", "Line In",
+                "IN1_L", "Line In",
+                "CM_L", "Line In",
+                "CM_R", "Line In",
+                "Line Out", "LOR",
+                "Line Out", "LOL";
+
+            dailink0_master: simple-audio-card,cpu {
+                sound-dai = <&i2s>;
+            };
+
+            simple-audio-card,codec {
+                sound-dai = <&tlv320aic32x4>;
+            };
+        };
+    };
+
+    fragment@4 {
+        target = <&gpio>;
+        __overlay__ {
+            gpclk0_pin: gpclk0_pin {
+                brcm,pins = <4>;
+                brcm,function = <4>;
+            };
+
+            aic3204_reset: aic3204_reset {
+                brcm,pins = <13>;
+                brcm,function = <1>;
+                brcm,pull = <1>;
+            };
+
+            aic3204_gpio: aic3204_gpio {
+                brcm,pins = <26>;
+            };
+        };
+    };
+
+    __overrides__ {
+        alsaname = <&snd>, "simple-audio-card,name";
+    };
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/ugreen-dabboard-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for the ugreen dabboard I2S
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path = "/";
+		__overlay__ {
+			dmic_codec: dmic-codec {
+				#sound-dai-cells = <0>;
+				compatible = "dmic-codec";
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&sound>;
+		sound_overlay: __overlay__ {
+			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,widgets = "Microphone", "Microphone Jack";
+			status = "okay";
+			simple-audio-card,cpu {
+				sound-dai = <&i2s>;
+			};
+			dailink0_slave: simple-audio-card,codec {
+				#sound-dai-cells = <0>;
+				sound-dai = <&dmic_codec>;
+			};
+		};
+	};
+
+	__overrides__ {
+		card-name = <&sound_overlay>,"simple-audio-card,name";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/upstream-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/upstream-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/upstream-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/upstream-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-default dwc2-overlay.dts,dr_mode=otg
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/bcm2835.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+	fragment@0 {
+		target = <&i2c2>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@1 {
+		target = <&fb>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+	fragment@2 {
+		target = <&pixelvalve0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@3 {
+		target = <&pixelvalve1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@4 {
+		target = <&pixelvalve2>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@5 {
+		target = <&hvs>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@6 {
+		target = <&hdmi>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@7 {
+		target = <&v3d>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@8 {
+		target = <&vc4>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@9 {
+		target = <&clocks>;
+		__overlay__ {
+			claim-clocks = <BCM2835_PLLD_DSI0 BCM2835_PLLD_DSI1 BCM2835_PLLH_AUX BCM2835_PLLH_PIX>;
+		};
+	};
+	fragment@10 {
+		target = <&vec>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@11 {
+		target = <&txp>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@12 {
+		target = <&audio>;
+		__overlay__ {
+			brcm,disable-hdmi;
+		};
+	};
+	fragment@13 {
+		target = <&usb>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		__overlay__ {
+			compatible = "brcm,bcm2835-usb";
+			dr_mode = "otg";
+			g-np-tx-fifo-size = <32>;
+			g-rx-fifo-size = <558>;
+			g-tx-fifo-size = <512 512 512 512 512 256 256>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// redo: ovmerge -c vc4-kms-v3d-pi4-overlay.dts,cma-default dwc2-overlay.dts,dr_mode=otg
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/bcm2835.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+	fragment@0 {
+		target = <&ddc0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@1 {
+		target = <&ddc1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@2 {
+		target = <&hdmi0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@3 {
+		target = <&hdmi1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@4 {
+		target = <&hvs>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@5 {
+		target = <&pixelvalve0>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@6 {
+		target = <&pixelvalve1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@7 {
+		target = <&pixelvalve2>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@8 {
+		target = <&pixelvalve3>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@9 {
+		target = <&pixelvalve4>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@10 {
+		target = <&v3d>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@11 {
+		target = <&vc4>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@12 {
+		target = <&txp>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@13 {
+		target = <&fb>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+	fragment@14 {
+		target = <&firmwarekms>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+	fragment@15 {
+		target = <&vec>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+	fragment@16 {
+		target = <&audio>;
+		__overlay__ {
+			brcm,disable-hdmi;
+		};
+	};
+	fragment@17 {
+		target = <&dvp>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@18 {
+		target = <&aon_intr>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+	fragment@19 {
+		target = <&usb>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		__overlay__ {
+			compatible = "brcm,bcm2835-usb";
+			dr_mode = "otg";
+			g-np-tx-fifo-size = <32>;
+			g-rx-fifo-size = <558>;
+			g-tx-fifo-size = <512 512 512 512 512 256 256>;
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * vc4-fkms-v3d-overlay.dts
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "cma-overlay.dts"
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@1 {
+		target = <&fb>;
+		__overlay__  {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&firmwarekms>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&v3d>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target = <&vc4>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-dpi-at056tn53v1-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-dpi-at056tn53v1-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-dpi-at056tn53v1-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-dpi-at056tn53v1-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * vc4-kms-dpi-at056tn53v1-overlay.dts
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/bcm2835.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			panel: panel {
+				compatible = "innolux,at056tn53v1", "simple-panel";
+
+				port {
+					panel_in: endpoint {
+						remote-endpoint = <&dpi_out>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&dpi>;
+		__overlay__  {
+			status = "okay";
+
+			pinctrl-names = "default";
+			pinctrl-0 = <&dpi_18bit_cpadhi_gpio0>;
+
+			port {
+				dpi_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for RaspberryPi 7" Touchscreen panel
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&dsi1>;
+		__overlay__ {
+			#address-cells = <1>; size-cells = <0>;
+			status = "okay";
+			port {
+				dsi_out_port: endpoint {
+					remote-endpoint = <&panel_dsi_port>;
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+			lcd@45 {
+				compatible = "raspberrypi,7inch-touchscreen-panel";
+				reg = <0x45>;
+				port {
+					panel_dsi_port: endpoint {
+						remote-endpoint = <&dsi_out_port>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay to connect a JDI LT070ME05000 DSI panel to DSI1.
+ * This uses 4 DSI data lanes, so can only be used with a Compute Module.
+ *
+ * Credit to forum user gizmomouse on
+ * https://www.raspberrypi.org/forums/viewtopic.php?f=98&t=253912 and
+ * Andrey Vostrukhin of Harlab for the overlay.
+ *
+ * Refer to https://github.com/harlab/CM4_LCD_LT070ME05000 for schematics and
+ * other documentation.
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&dsi1>;
+		__overlay__{
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port {
+				dsi_out_port:endpoint {
+					remote-endpoint = <&panel_dsi_port>;
+				};
+			};
+
+			lt070me05000:lt070me05000@0 {
+				compatible    = "jdi,lt070me05000";
+				status        = "okay";
+				reg           = <0>;
+				reset-gpios   = <&gpio 17 1>;   // LCD RST
+				enable-gpios  = <&gpio 4 0>;    // LCD Enable
+				dcdc-en-gpios = <&gpio 5 0>;    // LCD DC-DC Enable
+				port {
+					panel_dsi_port: endpoint {
+						remote-endpoint = <&dsi_out_port>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			lt070me05000_pins: lt070me05000_pins {
+				brcm,pins = <4 5 17>;
+				brcm,function = <1 1 1>; // out
+				brcm,pull = <0 0 0>; // off
+			};
+		};
+
+	};
+
+	__overrides__ {
+		reset = <&lt070me05000_pins>,"brcm,pins:8",
+			<&lt070me05000>,"reset-gpios:4";
+
+		enable = <&lt070me05000_pins>,"brcm,pins:0",
+			<&lt070me05000>,"enable-gpios:4";
+
+		dcdc-en = <&lt070me05000_pins>,"brcm,pins:4",
+			<&lt070me05000>,"dcdc-en-gpios:4";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-v2-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-v2-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-v2-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-v2-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay to connect a JDI LT070ME05000 DSI panel to DSI1.
+ * This uses 4 DSI data lanes, so can only be used with a Compute Module.
+ *
+ * The overlay is for V2 of Harlab's interface board that uses a PCA9536 to
+ * handle the panel's control GPIOs instead of wiring it back to Pi GPIOs.
+ *
+ * Credit to Andrey Vostrukhin of Harlab for the overlay.
+ *
+ * Refer to https://github.com/harlab/CM4_LCD_LT070ME05000 for schematics and
+ * other documentation.
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pca: pca@41 {
+				compatible = "nxp,pca9536";
+				reg = <0x41>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&dsi1>;
+		__overlay__{
+			status = "okay";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port {
+				dsi_out_port:endpoint {
+					remote-endpoint = <&panel_dsi_port>;
+				};
+			};
+
+			lt070me05000:lt070me05000@0 {
+				compatible    = "jdi,lt070me05000";
+				status        = "okay";
+				reg           = <0>;
+				reset-gpios   = <&pca 0 1>;
+				enable-gpios  = <&pca 2 0>;
+				dcdc-en-gpios = <&pca 1 0>;
+				port {
+					panel_dsi_port: endpoint {
+						remote-endpoint = <&dsi_out_port>;
+					};
+				};
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * vc4-kms-v3d-overlay.dts
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/pinctrl/bcm2835.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			panel: panel {
+				compatible = "ontat,yx700wv03", "simple-panel";
+
+				port {
+					panel_in: endpoint {
+						remote-endpoint = <&dpi_out>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&dpi>;
+		__overlay__  {
+			status = "okay";
+
+			pinctrl-names = "default";
+			pinctrl-0 = <&dpi_18bit_gpio0>;
+
+			port {
+				dpi_out: endpoint@0 {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * vc4-kms-v3d-overlay.dts
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/bcm2835.h>
+
+#include "cma-overlay.dts"
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@1 {
+		target = <&i2c2>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&fb>;
+		__overlay__  {
+			status = "disabled";
+		};
+	};
+
+	fragment@3 {
+		target = <&pixelvalve0>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target = <&pixelvalve1>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&pixelvalve2>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@6 {
+		target = <&hvs>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@7 {
+		target = <&hdmi>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@8 {
+		target = <&v3d>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@9 {
+		target = <&vc4>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@10 {
+		target = <&clocks>;
+		__overlay__  {
+			claim-clocks = <
+				BCM2835_PLLD_DSI0
+				BCM2835_PLLD_DSI1
+				BCM2835_PLLH_AUX
+				BCM2835_PLLH_PIX
+			>;
+		};
+	};
+
+	fragment@11 {
+		target = <&vec>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@12 {
+		target = <&txp>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@13 {
+		target = <&hdmi>;
+		__dormant__  {
+			dmas;
+		};
+	};
+
+	fragment@14 {
+		target = <&audio>;
+		__overlay__  {
+		    brcm,disable-hdmi;
+		};
+	};
+
+	__overrides__ {
+		audio   = <0>,"!13", <0>,"=14";
+		noaudio = <0>,"=13", <0>,"!14";
+		nocomposite = <0>, "!11";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * vc4-kms-v3d-pi4-overlay.dts
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/bcm2835.h>
+
+#include "cma-overlay.dts"
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@1 {
+		target = <&ddc0>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&ddc1>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&hdmi0>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target = <&hdmi1>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&hvs>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@6 {
+		target = <&pixelvalve0>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@7 {
+		target = <&pixelvalve1>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@8 {
+		target = <&pixelvalve2>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@9 {
+		target = <&pixelvalve3>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@10 {
+		target = <&pixelvalve4>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@11 {
+		target = <&v3d>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@12 {
+		target = <&vc4>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@13 {
+		target = <&txp>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@14 {
+		target = <&fb>;
+		__overlay__  {
+			status = "disabled";
+		};
+	};
+
+	fragment@15 {
+		target = <&firmwarekms>;
+		__overlay__  {
+			status = "disabled";
+		};
+	};
+
+	fragment@16 {
+		target = <&vec>;
+		__overlay__  {
+			status = "disabled";
+		};
+	};
+
+	fragment@17 {
+		target = <&hdmi0>;
+		__dormant__  {
+			dmas;
+		};
+	};
+
+	fragment@18 {
+		target = <&hdmi1>;
+		__dormant__  {
+			dmas;
+		};
+	};
+
+	fragment@19 {
+		target = <&audio>;
+		__overlay__  {
+		    brcm,disable-hdmi;
+		};
+	};
+
+	fragment@20 {
+		target = <&dvp>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	fragment@21 {
+		target = <&pixelvalve3>;
+		__dormant__  {
+			status = "okay";
+		};
+	};
+
+	fragment@22 {
+		target = <&vec>;
+		__dormant__  {
+			status = "okay";
+		};
+	};
+
+	fragment@23 {
+		target = <&aon_intr>;
+		__overlay__  {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		audio   = <0>,"!17";
+		audio1   = <0>,"!18";
+		noaudio = <0>,"=17", <0>,"=18", <0>,"!19";
+		composite = <0>, "!1",
+			    <0>, "!2",
+			    <0>, "!3",
+			    <0>, "!4",
+			    <0>, "!6",
+			    <0>, "!7",
+			    <0>, "!8",
+			    <0>, "!9",
+			    <0>, "!10",
+			    <0>, "!16",
+			    <0>, "=21",
+			    <0>, "=22";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vc4-kms-vga666-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * vc4-kms-vga666-overlay.dts
+ * Configures a FenLogic or similar VGA666 DPI adapter when using the
+ * vc4-kms-v3d driver.
+ * If a suitable I2C level shifter is connected to GPIOs 0&1 and the VGA
+ * ID1/SDA (pin 12) and ID3/SCL (pin 15) lines, then there is the option to
+ * enable reading the EDID from the display.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/pinctrl/bcm2835.h>
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			vga_connector: vga_connector {
+				compatible = "vga-connector";
+				label = "vga";
+
+				port {
+					vga_con_in: endpoint {
+						remote-endpoint = <&vga666_out>;
+					};
+				};
+			};
+
+			vga_dac {
+				compatible = "dumb-vga-dac";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+
+						vga666_in: endpoint {
+							remote-endpoint = <&dpi_out>;
+						};
+					};
+
+					port@1 {
+						reg = <1>;
+
+						vga666_out: endpoint {
+							remote-endpoint = <&vga_con_in>;
+						};
+					};
+				};
+			};
+
+		};
+	};
+
+	fragment@1 {
+		target = <&dpi>;
+		__overlay__  {
+			status = "okay";
+
+			pinctrl-names = "default";
+			pinctrl-0 = <&dpi_18bit_gpio2>;
+
+			port {
+				dpi_out: endpoint@0 {
+					remote-endpoint = <&vga666_in>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&vga_connector>;
+		__dormant__  {
+			ddc-i2c-bus = <&i2c_vc>;
+		};
+	};
+
+	fragment@3 {
+		target = <&i2c0if>;
+		__dormant__ {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c0mux>;
+		__dormant__ {
+			status = "okay";
+		};
+	};
+
+	__overrides__ {
+		ddc = <0>,"=2", <0>,"=3", <0>,"=4";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/vga666-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vga666-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/vga666-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/vga666-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	// There is no VGA driver module, but we need a platform device
+	// node (that doesn't already use pinctrl) to hang the pinctrl
+	// reference on - leds will do
+
+	fragment@0 {
+		target = <&leds>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&vga666_pins>;
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			vga666_pins: vga666_pins {
+				brcm,pins = <2 3 4 5 6 7 8 9 10 11 12
+					     13 14 15 16 17 18 19 20 21>;
+				brcm,function = <6>; /* alt2 */
+				brcm,pull = <0>; /* no pull */
+			};
+		};
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for w1-gpio module (without external pullup)
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+
+			w1: onewire@0 {
+				compatible = "w1-gpio";
+				pinctrl-names = "default";
+				pinctrl-0 = <&w1_pins>;
+				gpios = <&gpio 4 0>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			w1_pins: w1_pins@0 {
+				brcm,pins = <4>;
+				brcm,function = <0>; // in (initially)
+				brcm,pull = <0>; // off
+			};
+		};
+	};
+
+	__overrides__ {
+		gpiopin =       <&w1>,"gpios:4",
+				<&w1>,"reg:0",
+				<&w1_pins>,"brcm,pins:0",
+				<&w1_pins>,"reg:0";
+		pullup;		// Silently ignore unneeded parameter
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for w1-gpio module (with external pullup)
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+
+			w1: onewire@0 {
+				compatible = "w1-gpio";
+				pinctrl-names = "default";
+				pinctrl-0 = <&w1_pins>;
+				gpios = <&gpio 4 0>, <&gpio 5 1>;
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&gpio>;
+		__overlay__ {
+			w1_pins: w1_pins@0 {
+				brcm,pins = <4 5>;
+				brcm,function = <0 1>; // in out
+				brcm,pull = <0 0>; // off off
+			};
+		};
+	};
+
+	__overrides__ {
+		gpiopin =       <&w1>,"gpios:4",
+				<&w1>,"reg:0",
+				<&w1_pins>,"brcm,pins:0",
+				<&w1_pins>,"reg:0";
+		extpullup =     <&w1>,"gpios:16",
+				<&w1_pins>,"brcm,pins:4";
+		pullup;		// Silently ignore unneeded parameter
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/w5500-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/w5500-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/w5500-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/w5500-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Overlay for the Wiznet w5500 Ethernet Controller
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&spidev0>;
+		__overlay__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@1 {
+		target = <&spidev1>;
+		__dormant__ {
+			status = "disabled";
+		};
+	};
+
+	fragment@2 {
+		target = <&spi0>;
+		__overlay__ {
+			/* needed to avoid dtc warning */
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			status = "okay";
+
+			eth1: w5500@0{
+				compatible = "wiznet,w5500";
+				reg = <0>; /* CE0 */
+				pinctrl-names = "default";
+				pinctrl-0 = <&eth1_pins>;
+				interrupt-parent = <&gpio>;
+				interrupts = <25 0x8>;
+				spi-max-frequency = <30000000>;
+//				local-mac-address = [aa bb cc dd ee ff];
+				status = "okay";
+			};
+		};
+	};
+
+	fragment@3 {
+		target = <&gpio>;
+		__overlay__ {
+			eth1_pins: eth1_pins {
+				brcm,pins = <25>;
+				brcm,function = <0>; /* in */
+				brcm,pull = <0>; /* none */
+			};
+		};
+	};
+
+	__overrides__ {
+		int_pin = <&eth1>, "interrupts:0",
+		          <&eth1_pins>, "brcm,pins:0";
+		speed   = <&eth1>, "spi-max-frequency:0";
+		cs      = <&eth1>, "reg:0",
+			  <0>, "!0=1";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/wittypi-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/wittypi-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/wittypi-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/wittypi-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Device Tree overlay for Witty Pi extension board by UUGear
+ *
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&leds>;
+		__overlay__ {
+			compatible = "gpio-leds";
+			wittypi_led: wittypi_led {
+				label = "wittypi_led";
+				linux,default-trigger = "default-on";
+				gpios = <&gpio 17 0>;
+			};
+		};
+	};
+
+	fragment@1 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			rtc: ds1337@68 {
+				compatible = "dallas,ds1337";
+				reg = <0x68>;
+				wakeup-source;
+			};
+		};
+	};
+
+	__overrides__ {
+		led_gpio =	<&wittypi_led>,"gpios:4";
+		led_trigger =	<&wittypi_led>,"linux,default-trigger";
+	};
+
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts
--- linux-5.10.52-orig/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts	2021-07-25 16:45:35.168807223 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// Definitions for Waveshare WM8960 https://github.com/waveshare/WM8960-Audio-HAT
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2835";
+
+	fragment@0 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target-path="/";
+		__overlay__ {
+			wm8960_mclk: wm8960_mclk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <12288000>;
+			};
+		};
+	};
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8960: wm8960 {
+				compatible = "wlf,wm8960";
+				reg = <0x1a>;
+				#sound-dai-cells = <0>;
+				AVDD-supply = <&vdd_5v0_reg>;
+				DVDD-supply = <&vdd_3v3_reg>;
+			};
+		};
+	};
+
+
+	fragment@3 {
+		target = <&sound>;
+		slave_overlay: __overlay__ {
+			compatible = "simple-audio-card";
+			simple-audio-card,format = "i2s";
+			simple-audio-card,name = "wm8960-soundcard"; 
+			status = "okay";
+
+			simple-audio-card,widgets =
+				"Microphone", "Mic Jack",
+				"Line", "Line In",
+				"Line", "Line Out",
+				"Speaker", "Speaker",
+				"Headphone", "Headphone Jack";
+			simple-audio-card,routing =
+				"Headphone Jack", "HP_L",
+				"Headphone Jack", "HP_R",
+				"Speaker", "SPK_LP",
+				"Speaker", "SPK_LN",
+				"LINPUT1", "Mic Jack",
+				"LINPUT3", "Mic Jack",
+				"RINPUT1", "Mic Jack",
+				"RINPUT2", "Mic Jack";
+
+			simple-audio-card,cpu {
+				sound-dai = <&i2s>;
+			};
+			dailink0_slave: simple-audio-card,codec {
+				sound-dai = <&wm8960>;
+				clocks = <&wm8960_mclk>;
+				clock-names = "mclk";
+			};
+		};
+	};
+
+	__overrides__ {
+		alsaname = <&slave_overlay>,"simple-audio-card,name";
+		compatible = <&wm8960>,"compatible";
+	};
+};
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/configs/bcm2709_defconfig linux-5.10.52-v7l+/arch/arm/configs/bcm2709_defconfig
--- linux-5.10.52-orig/arch/arm/configs/bcm2709_defconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/configs/bcm2709_defconfig	2021-07-25 16:45:35.368803870 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+CONFIG_LOCALVERSION="-v7"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_GENERIC_IRQ_DEBUGFS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=m
+CONFIG_IKCONFIG_PROC=y
+CONFIG_MEMCG=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_ARCH_BCM=y
+CONFIG_ARCH_BCM2835=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_SMP=y
+CONFIG_VMSPLIT_2G=y
+# CONFIG_CPU_SW_DOMAIN_PAN is not set
+CONFIG_UACCESS_WITH_MEMCPY=y
+# CONFIG_ATAGS is not set
+CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_PM=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=m
+CONFIG_CRYPTO_AES_ARM=m
+CONFIG_CRYPTO_AES_ARM_BS=m
+CONFIG_OPROFILE=m
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BINFMT_MISC=m
+CONFIG_CLEANCACHE=y
+CONFIG_FRONTSWAP=y
+CONFIG_CMA=y
+CONFIG_ZSWAP=y
+CONFIG_Z3FOLD=m
+CONFIG_ZSMALLOC=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_NET_IPVTI=m
+CONFIG_NET_FOU=m
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BBR=m
+CONFIG_IPV6=m
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_ILA=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETFILTER=y
+CONFIG_BRIDGE_NETFILTER=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_LOG_NETDEV=m
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_NETDEV=y
+CONFIG_NFT_NUMGEN=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_CONNLIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_OBJREF=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_OSF=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
+CONFIG_NF_FLOW_TABLE_INET=m
+CONFIG_NF_FLOW_TABLE=m
+CONFIG_NETFILTER_XT_SET=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_PE_SIP=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_FLOW_TABLE_IPV4=m
+CONFIG_NF_LOG_ARP=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_NF_FLOW_TABLE_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NF_LOG_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
+CONFIG_ATM=m
+CONFIG_L2TP=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_ATALK=m
+CONFIG_6LOWPAN=m
+CONFIG_IEEE802154=m
+CONFIG_IEEE802154_6LOWPAN=m
+CONFIG_MAC802154=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_HHF=m
+CONFIG_NET_SCH_PIE=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_PLUG=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_IPSET=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_BATMAN_ADV=m
+CONFIG_OPENVSWITCH=m
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_NET_PKTGEN=m
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_MKISS=m
+CONFIG_6PACK=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_YAM=m
+CONFIG_CAN=m
+CONFIG_CAN_J1939=m
+CONFIG_CAN_ISOTP=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_SLCAN=m
+CONFIG_CAN_MCP251X=m
+CONFIG_CAN_MCP251XFD=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_CAN_GS_USB=m
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_6LOWPAN=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_HCIUART_BCM=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_ATH3K=m
+CONFIG_CFG80211=m
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_MESH=y
+CONFIG_WIMAX=m
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_NET_9P=m
+CONFIG_NFC=m
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_MTD=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_SPI_NOR=m
+CONFIG_MTD_UBI=m
+CONFIG_OF_CONFIGFS=y
+CONFIG_ZRAM=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_ATA_OVER_ETH=m
+CONFIG_EEPROM_AT24=m
+CONFIG_TI_ST=m
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=m
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_THIN_PROVISIONING=m
+CONFIG_DM_CACHE=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_DELAY=m
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+CONFIG_IFB=m
+CONFIG_MACVLAN=m
+CONFIG_IPVLAN=m
+CONFIG_VXLAN=m
+CONFIG_NETCONSOLE=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_NET_VRF=m
+CONFIG_ENC28J60=m
+CONFIG_QCA7000_SPI=m
+CONFIG_QCA7000_UART=m
+CONFIG_WIZNET_W5100=m
+CONFIG_WIZNET_W5100_SPI=m
+CONFIG_MDIO_BITBANG=m
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_LAN78XX=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_AX88179_178A=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SR9700=m
+CONFIG_USB_NET_SR9800=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_NET_KALMIA=m
+CONFIG_USB_NET_QMI_WWAN=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+CONFIG_USB_NET_AQC111=m
+CONFIG_ATH9K=m
+CONFIG_ATH9K_HTC=m
+CONFIG_CARL9170=m
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_USB=m
+CONFIG_AR5523=m
+CONFIG_AT76C50X_USB=m
+CONFIG_B43=m
+# CONFIG_B43_PHY_N is not set
+CONFIG_B43LEGACY=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_USB=y
+CONFIG_BRCMDBG=y
+CONFIG_HOSTAP=m
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MT7601U=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x2U=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RTL8187=m
+CONFIG_RTL8192CU=m
+CONFIG_RTL8XXXU=m
+CONFIG_USB_ZD1201=m
+CONFIG_ZD1211RW=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_WIMAX_I2400M_USB=m
+CONFIG_IEEE802154_AT86RF230=m
+CONFIG_IEEE802154_MRF24J40=m
+CONFIG_IEEE802154_CC2520=m
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_MATRIX=m
+CONFIG_KEYBOARD_CAP11XX=m
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=m
+CONFIG_JOYSTICK_XPAD=m
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_JOYSTICK_PSXPAD_SPI=m
+CONFIG_JOYSTICK_PSXPAD_SPI_FF=y
+CONFIG_JOYSTICK_RPISENSE=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_EXC3000=m
+CONFIG_TOUCHSCREEN_GOODIX=m
+CONFIG_TOUCHSCREEN_ILI210X=m
+CONFIG_TOUCHSCREEN_EDT_FT5X06=m
+CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_STMPE=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_POWERMATE=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_SERIO=m
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_BRCM_CHAR_DRIVERS=y
+CONFIG_BCM_VCIO=y
+CONFIG_BCM2835_DEVGPIOMEM=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_BCM2835AUX=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_SC16IS7XX=m
+CONFIG_SERIAL_SC16IS7XX_SPI=y
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_TTY_PRINTK=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=y
+CONFIG_TCG_TPM=m
+CONFIG_TCG_TIS_SPI=m
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX_GPMUX=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_MUX_PINCTRL=m
+CONFIG_I2C_BCM2708=m
+CONFIG_I2C_BCM2835=m
+# CONFIG_I2C_BRCMSTB is not set
+CONFIG_I2C_GPIO=m
+CONFIG_I2C_ROBOTFUZZ_OSIF=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_SPI=y
+CONFIG_SPI_BCM2835=m
+CONFIG_SPI_BCM2835AUX=m
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPI_SLAVE=y
+CONFIG_PPS=m
+CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PINCTRL_MCP23S08=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_BCM_VIRT=y
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_ARIZONA=m
+CONFIG_GPIO_FSM=m
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_MOCKUP=m
+CONFIG_W1=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_W1_MASTER_DS1WM=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2408=m
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2438=m
+CONFIG_W1_SLAVE_DS2780=m
+CONFIG_W1_SLAVE_DS2781=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_W1_SLAVE_DS28E17=m
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_RPI_POE_POWER=m
+CONFIG_BATTERY_DS2760=m
+CONFIG_BATTERY_MAX17040=m
+CONFIG_BATTERY_GAUGE_LTC2941=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_GPIO_FAN=m
+CONFIG_SENSORS_IIO_HWMON=m
+CONFIG_SENSORS_JC42=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_RASPBERRYPI_HWMON=m
+CONFIG_SENSORS_RPI_POE_FAN=m
+CONFIG_SENSORS_SHT21=m
+CONFIG_SENSORS_SHT3x=m
+CONFIG_SENSORS_SHTC1=m
+CONFIG_SENSORS_INA2XX=m
+CONFIG_SENSORS_TMP102=m
+CONFIG_THERMAL=y
+CONFIG_BCM2835_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_GPIO_WATCHDOG=m
+CONFIG_BCM2835_WDT=y
+CONFIG_MFD_STMPE=y
+CONFIG_STMPE_SPI=y
+CONFIG_MFD_ARIZONA_I2C=m
+CONFIG_MFD_ARIZONA_SPI=m
+CONFIG_MFD_WM5102=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_ARIZONA_LDO1=m
+CONFIG_REGULATOR_ARIZONA_MICSUPP=m
+CONFIG_RC_CORE=y
+CONFIG_LIRC=y
+CONFIG_BPF_LIRC_MODE2=y
+CONFIG_RC_DECODERS=y
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_IR_IMON_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_IR_IMON=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_RC_LOOPBACK=m
+CONFIG_IR_GPIO_CIR=m
+CONFIG_IR_GPIO_TX=m
+CONFIG_IR_PWM_TX=m
+CONFIG_IR_TOY=m
+CONFIG_MEDIA_CEC_RC=y
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_USB_PWC=m
+CONFIG_VIDEO_CPIA2=m
+CONFIG_USB_ZR364XX=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_S2255=m
+CONFIG_VIDEO_USBTV=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_STK1160_COMMON=m
+CONFIG_VIDEO_GO7007=m
+CONFIG_VIDEO_GO7007_USB=m
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
+CONFIG_VIDEO_AU0828=m
+CONFIG_VIDEO_AU0828_RC=y
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_ALSA=m
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_VIDEO_TM6000=m
+CONFIG_VIDEO_TM6000_ALSA=m
+CONFIG_VIDEO_TM6000_DVB=m
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_PCTV452E=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_TECHNISAT_USB2=m
+CONFIG_DVB_USB_V2=m
+CONFIG_DVB_USB_AF9015=m
+CONFIG_DVB_USB_AF9035=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_AZ6007=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_LME2510=m
+CONFIG_DVB_USB_MXL111SF=m
+CONFIG_DVB_USB_RTL28XXU=m
+CONFIG_DVB_USB_DVBSKY=m
+CONFIG_SMS_USB_DRV=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+CONFIG_DVB_AS102=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_V4L2=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_RADIO_SI470X=m
+CONFIG_USB_SI470X=m
+CONFIG_I2C_SI470X=m
+CONFIG_RADIO_SI4713=m
+CONFIG_I2C_SI4713=m
+CONFIG_USB_MR800=m
+CONFIG_USB_DSBR=m
+CONFIG_RADIO_SHARK=m
+CONFIG_RADIO_SHARK2=m
+CONFIG_USB_KEENE=m
+CONFIG_USB_MA901=m
+CONFIG_RADIO_TEA5764=m
+CONFIG_RADIO_SAA7706H=m
+CONFIG_RADIO_TEF6862=m
+CONFIG_RADIO_WL1273=m
+CONFIG_RADIO_WL128X=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_BCM2835_UNICAM=m
+CONFIG_VIDEO_UDA1342=m
+CONFIG_VIDEO_SONY_BTF_MPX=m
+CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_TC358743=m
+CONFIG_VIDEO_TVP5150=m
+CONFIG_VIDEO_TW2804=m
+CONFIG_VIDEO_TW9903=m
+CONFIG_VIDEO_TW9906=m
+CONFIG_VIDEO_IMX219=m
+CONFIG_VIDEO_IMX290=m
+CONFIG_VIDEO_IMX477=m
+CONFIG_VIDEO_OV5647=m
+CONFIG_VIDEO_OV7251=m
+CONFIG_VIDEO_OV7640=m
+CONFIG_VIDEO_OV9281=m
+CONFIG_VIDEO_IRS1125=m
+CONFIG_VIDEO_MT9V011=m
+CONFIG_DRM=m
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_UDL=m
+CONFIG_DRM_PANEL_SIMPLE=m
+CONFIG_DRM_PANEL_JDI_LT070ME05000=m
+CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m
+CONFIG_DRM_DISPLAY_CONNECTOR=m
+CONFIG_DRM_SIMPLE_BRIDGE=m
+CONFIG_DRM_VC4=m
+CONFIG_DRM_VC4_HDMI_CEC=y
+CONFIG_TINYDRM_ILI9225=m
+CONFIG_TINYDRM_ILI9341=m
+CONFIG_TINYDRM_MI0283QT=m
+CONFIG_TINYDRM_REPAPER=m
+CONFIG_TINYDRM_ST7586=m
+CONFIG_TINYDRM_ST7735R=m
+CONFIG_DRM_GUD=m
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FB_UDL=m
+CONFIG_FB_SIMPLE=y
+CONFIG_FB_SSD1307=m
+CONFIG_FB_RPISENSE=m
+CONFIG_BACKLIGHT_RPI=m
+CONFIG_BACKLIGHT_GPIO=m
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_ALOOP=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_USB_HIFACE=m
+CONFIG_SND_SOC=m
+CONFIG_SND_BCM2835_SOC_I2S=m
+CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+CONFIG_SND_BCM2708_SOC_PIFI_40=m
+CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=m
+CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m
+CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M=m
+CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
+CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD=m
+CONFIG_SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD=m
+CONFIG_SND_AUDIOSENSE_PI=m
+CONFIG_SND_DIGIDAC1_SOUNDCARD=m
+CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO=m
+CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2=m
+CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS=m
+CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_BOSS2_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_DIGIONE=m
+CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC=m
+CONFIG_SND_BCM2708_SOC_FE_PI_AUDIO=m
+CONFIG_SND_PISOUND=m
+CONFIG_SND_SOC_AD193X_SPI=m
+CONFIG_SND_SOC_AD193X_I2C=m
+CONFIG_SND_SOC_ADAU1701=m
+CONFIG_SND_SOC_ADAU7002=m
+CONFIG_SND_SOC_AK4554=m
+CONFIG_SND_SOC_CS4265=m
+CONFIG_SND_SOC_ICS43432=m
+CONFIG_SND_SOC_MA120X0P=m
+CONFIG_SND_SOC_MAX98357A=m
+CONFIG_SND_SOC_SPDIF=m
+CONFIG_SND_SOC_WM8804_I2C=m
+CONFIG_SND_SOC_WM8960=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_ACRUX=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_ASUS=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_BETOP_FF=m
+CONFIG_HID_BIGBEN_FF=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_EMS_FF=m
+CONFIG_HID_ELECOM=m
+CONFIG_HID_ELO=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_GEMBIRD=m
+CONFIG_HID_HOLTEK=m
+CONFIG_HID_KEYTOUCH=m
+CONFIG_HID_KYE=m
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SONY=m
+CONFIG_SONY_FF=y
+CONFIG_HID_SPEEDLINK=m
+CONFIG_HID_STEAM=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THINGM=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_WACOM=m
+CONFIG_HID_WIIMOTE=m
+CONFIG_HID_XINMO=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_HID_ZYDACRON=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_I2C_HID=m
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=m
+CONFIG_USB_DWCOTG=y
+CONFIG_USB_PRINTER=m
+CONFIG_USB_TMC=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USBIP_CORE=m
+CONFIG_USBIP_VHCI_HCD=m
+CONFIG_USBIP_HOST=m
+CONFIG_USBIP_VUDC=m
+CONFIG_USB_DWC2=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_DEBUG=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_YUREX=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_USB_GADGET=m
+CONFIG_USB_ZERO=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_MIDI_GADGET=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_ACM_MS=m
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_HID=m
+CONFIG_USB_G_WEBCAM=m
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BCM2835_MMC=y
+CONFIG_MMC_BCM2835_DMA=y
+CONFIG_MMC_BCM2835_SDHOST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SPI=m
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PCA955X=m
+CONFIG_LEDS_PCA963X=m
+CONFIG_LEDS_IS31FL32XX=m
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_INPUT=y
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_LEDS_TRIGGER_NETDEV=m
+CONFIG_LEDS_TRIGGER_ACTPWR=y
+CONFIG_ACCESSIBILITY=y
+CONFIG_SPEAKUP=m
+CONFIG_SPEAKUP_SYNTH_SOFT=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_ABX80X=m
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_DS1374=m
+CONFIG_RTC_DRV_DS1672=m
+CONFIG_RTC_DRV_MAX6900=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_ISL1208=m
+CONFIG_RTC_DRV_ISL12022=m
+CONFIG_RTC_DRV_X1205=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_PCF85063=m
+CONFIG_RTC_DRV_PCF85363=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_M41T80=m
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_FM3130=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_RX8025=m
+CONFIG_RTC_DRV_EM3027=m
+CONFIG_RTC_DRV_RV3028=m
+CONFIG_RTC_DRV_SD3078=m
+CONFIG_RTC_DRV_M41T93=m
+CONFIG_RTC_DRV_M41T94=m
+CONFIG_RTC_DRV_DS1302=m
+CONFIG_RTC_DRV_DS1305=m
+CONFIG_RTC_DRV_DS1390=m
+CONFIG_RTC_DRV_R9701=m
+CONFIG_RTC_DRV_RX4581=m
+CONFIG_RTC_DRV_RS5C348=m
+CONFIG_RTC_DRV_MAX6902=m
+CONFIG_RTC_DRV_PCF2123=m
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_PCF2127=m
+CONFIG_RTC_DRV_RV3029C2=m
+CONFIG_DMADEVICES=y
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_BCM2708=y
+CONFIG_DMABUF_HEAPS=y
+CONFIG_DMABUF_HEAPS_SYSTEM=y
+CONFIG_DMABUF_HEAPS_CMA=y
+CONFIG_AUXDISPLAY=y
+CONFIG_HD44780=m
+CONFIG_UIO=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_STAGING=y
+CONFIG_PRISM2_USB=m
+CONFIG_R8712U=m
+CONFIG_R8188EU=m
+CONFIG_VT6656=m
+CONFIG_STAGING_MEDIA=y
+CONFIG_FB_TFT=m
+CONFIG_FB_TFT_AGM1264K_FL=m
+CONFIG_FB_TFT_BD663474=m
+CONFIG_FB_TFT_HX8340BN=m
+CONFIG_FB_TFT_HX8347D=m
+CONFIG_FB_TFT_HX8353D=m
+CONFIG_FB_TFT_HX8357D=m
+CONFIG_FB_TFT_ILI9163=m
+CONFIG_FB_TFT_ILI9320=m
+CONFIG_FB_TFT_ILI9325=m
+CONFIG_FB_TFT_ILI9340=m
+CONFIG_FB_TFT_ILI9341=m
+CONFIG_FB_TFT_ILI9481=m
+CONFIG_FB_TFT_ILI9486=m
+CONFIG_FB_TFT_PCD8544=m
+CONFIG_FB_TFT_RA8875=m
+CONFIG_FB_TFT_S6D02A1=m
+CONFIG_FB_TFT_S6D1121=m
+CONFIG_FB_TFT_SH1106=m
+CONFIG_FB_TFT_SSD1289=m
+CONFIG_FB_TFT_SSD1306=m
+CONFIG_FB_TFT_SSD1331=m
+CONFIG_FB_TFT_SSD1351=m
+CONFIG_FB_TFT_ST7735R=m
+CONFIG_FB_TFT_ST7789V=m
+CONFIG_FB_TFT_TINYLCD=m
+CONFIG_FB_TFT_TLS8204=m
+CONFIG_FB_TFT_UC1701=m
+CONFIG_FB_TFT_UPD161704=m
+CONFIG_FB_TFT_WATTEROTT=m
+CONFIG_BCM2835_VCHIQ=y
+CONFIG_SND_BCM2835=m
+CONFIG_VIDEO_BCM2835=m
+CONFIG_VIDEO_CODEC_BCM2835=m
+CONFIG_VIDEO_ISP_BCM2835=m
+CONFIG_CLK_RASPBERRYPI=y
+CONFIG_MAILBOX=y
+CONFIG_BCM2835_MBOX=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_RASPBERRYPI_POWER=y
+CONFIG_EXTCON=m
+CONFIG_EXTCON_ARIZONA=m
+CONFIG_IIO=m
+CONFIG_IIO_BUFFER_CB=m
+CONFIG_MCP320X=m
+CONFIG_MCP3422=m
+CONFIG_TI_ADS1015=m
+CONFIG_BME680=m
+CONFIG_CCS811=m
+CONFIG_SENSIRION_SGP30=m
+CONFIG_SPS30=m
+CONFIG_DHT11=m
+CONFIG_HDC100X=m
+CONFIG_HTU21=m
+CONFIG_INV_MPU6050_I2C=m
+CONFIG_APDS9960=m
+CONFIG_BH1750=m
+CONFIG_TSL4531=m
+CONFIG_VEML6070=m
+CONFIG_BMP280=m
+CONFIG_MAXIM_THERMOCOUPLE=m
+CONFIG_MAX31856=m
+CONFIG_PWM_BCM2835=m
+CONFIG_PWM_PCA9685=m
+CONFIG_RPI_AXIPERF=m
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+CONFIG_JFS_STATISTICS=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_GFS2_FS=m
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_F2FS_FS=y
+CONFIG_FS_ENCRYPTION=y
+CONFIG_FANOTIFY=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_OVERLAY_FS=m
+CONFIG_FSCACHE=y
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_HISTOGRAM=y
+CONFIG_CACHEFILES=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_EXFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_UBIFS_FS=m
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+CONFIG_9P_FS=m
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_DLM=m
+CONFIG_SECURITY=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_LSM=""
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_LIBCRC32C=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=5
+CONFIG_PRINTK_TIME=y
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+CONFIG_KDB_KEYBOARD=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_RCU_TRACE is not set
+CONFIG_LATENCYTOP=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_STACK_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_SCHED_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_UPROBE_EVENTS is not set
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/configs/bcm2711_defconfig linux-5.10.52-v7l+/arch/arm/configs/bcm2711_defconfig
--- linux-5.10.52-orig/arch/arm/configs/bcm2711_defconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/configs/bcm2711_defconfig	2021-07-25 16:45:35.368803870 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+CONFIG_LOCALVERSION="-v7l"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_GENERIC_IRQ_DEBUGFS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=m
+CONFIG_IKCONFIG_PROC=y
+CONFIG_MEMCG=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_ARCH_BCM=y
+CONFIG_ARCH_BCM2835=y
+CONFIG_ARM_LPAE=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_SMP=y
+CONFIG_HIGHMEM=y
+CONFIG_UACCESS_WITH_MEMCPY=y
+# CONFIG_ATAGS is not set
+CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_PM=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=m
+CONFIG_CRYPTO_AES_ARM=m
+CONFIG_CRYPTO_AES_ARM_BS=m
+CONFIG_OPROFILE=m
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLK_DEV_THROTTLING=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BINFMT_MISC=m
+CONFIG_CLEANCACHE=y
+CONFIG_FRONTSWAP=y
+CONFIG_CMA=y
+CONFIG_ZSWAP=y
+CONFIG_Z3FOLD=m
+CONFIG_ZSMALLOC=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_NET_IPVTI=m
+CONFIG_NET_FOU=m
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BBR=m
+CONFIG_IPV6=m
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_ILA=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETFILTER=y
+CONFIG_BRIDGE_NETFILTER=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_LOG_NETDEV=m
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_NETDEV=y
+CONFIG_NFT_NUMGEN=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_CONNLIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_OBJREF=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_OSF=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
+CONFIG_NF_FLOW_TABLE_INET=m
+CONFIG_NF_FLOW_TABLE=m
+CONFIG_NETFILTER_XT_SET=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_PE_SIP=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_FLOW_TABLE_IPV4=m
+CONFIG_NF_LOG_ARP=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_NF_FLOW_TABLE_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NF_LOG_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
+CONFIG_ATM=m
+CONFIG_L2TP=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_ATALK=m
+CONFIG_6LOWPAN=m
+CONFIG_IEEE802154=m
+CONFIG_IEEE802154_6LOWPAN=m
+CONFIG_MAC802154=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_HHF=m
+CONFIG_NET_SCH_PIE=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_PLUG=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_IPSET=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_BATMAN_ADV=m
+CONFIG_OPENVSWITCH=m
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_NET_PKTGEN=m
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_MKISS=m
+CONFIG_6PACK=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_YAM=m
+CONFIG_CAN=m
+CONFIG_CAN_J1939=m
+CONFIG_CAN_ISOTP=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_SLCAN=m
+CONFIG_CAN_MCP251X=m
+CONFIG_CAN_MCP251XFD=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_CAN_GS_USB=m
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_6LOWPAN=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_HCIUART_BCM=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_ATH3K=m
+CONFIG_CFG80211=m
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_MESH=y
+CONFIG_WIMAX=m
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_NET_9P=m
+CONFIG_NFC=m
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+# CONFIG_PCIEASPM is not set
+CONFIG_PCI_MSI=y
+CONFIG_PCIE_BRCMSTB=y
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_MTD=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_SPI_NOR=m
+CONFIG_MTD_UBI=m
+CONFIG_OF_CONFIGFS=y
+CONFIG_ZRAM=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_ATA_OVER_ETH=m
+CONFIG_BLK_DEV_NVME=y
+CONFIG_EEPROM_AT24=m
+CONFIG_TI_ST=m
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=m
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_ATA=m
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_MV=m
+CONFIG_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_THIN_PROVISIONING=m
+CONFIG_DM_CACHE=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_DELAY=m
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+CONFIG_IFB=m
+CONFIG_MACVLAN=m
+CONFIG_IPVLAN=m
+CONFIG_VXLAN=m
+CONFIG_NETCONSOLE=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_NET_VRF=m
+CONFIG_BCMGENET=y
+CONFIG_ENC28J60=m
+CONFIG_QCA7000_SPI=m
+CONFIG_QCA7000_UART=m
+CONFIG_WIZNET_W5100=m
+CONFIG_WIZNET_W5100_SPI=m
+CONFIG_MICREL_PHY=y
+CONFIG_MDIO_BITBANG=m
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=y
+CONFIG_USB_LAN78XX=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_AX88179_178A=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SR9700=m
+CONFIG_USB_NET_SR9800=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_NET_KALMIA=m
+CONFIG_USB_NET_QMI_WWAN=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+CONFIG_USB_NET_AQC111=m
+CONFIG_ATH9K=m
+CONFIG_ATH9K_HTC=m
+CONFIG_CARL9170=m
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_USB=m
+CONFIG_AR5523=m
+CONFIG_AT76C50X_USB=m
+CONFIG_B43=m
+# CONFIG_B43_PHY_N is not set
+CONFIG_B43LEGACY=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_USB=y
+CONFIG_BRCMDBG=y
+CONFIG_HOSTAP=m
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MT7601U=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x2U=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RTL8187=m
+CONFIG_RTL8192CU=m
+CONFIG_RTL8XXXU=m
+CONFIG_USB_ZD1201=m
+CONFIG_ZD1211RW=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_WIMAX_I2400M_USB=m
+CONFIG_IEEE802154_AT86RF230=m
+CONFIG_IEEE802154_MRF24J40=m
+CONFIG_IEEE802154_CC2520=m
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_MATRIX=m
+CONFIG_KEYBOARD_CAP11XX=m
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=m
+CONFIG_JOYSTICK_XPAD=m
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_JOYSTICK_PSXPAD_SPI=m
+CONFIG_JOYSTICK_PSXPAD_SPI_FF=y
+CONFIG_JOYSTICK_RPISENSE=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_EXC3000=m
+CONFIG_TOUCHSCREEN_GOODIX=m
+CONFIG_TOUCHSCREEN_ILI210X=m
+CONFIG_TOUCHSCREEN_EDT_FT5X06=m
+CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_STMPE=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_POWERMATE=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_SERIO=m
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_BRCM_CHAR_DRIVERS=y
+CONFIG_BCM_VCIO=y
+CONFIG_BCM2835_DEVGPIOMEM=y
+CONFIG_RPIVID_MEM=m
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_BCM2835AUX=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_SC16IS7XX=m
+CONFIG_SERIAL_SC16IS7XX_SPI=y
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_TTY_PRINTK=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=y
+CONFIG_TCG_TPM=m
+CONFIG_TCG_TIS_SPI=m
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX_GPMUX=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_MUX_PINCTRL=m
+CONFIG_I2C_BCM2708=m
+CONFIG_I2C_BCM2835=m
+CONFIG_I2C_BRCMSTB=m
+CONFIG_I2C_GPIO=m
+CONFIG_I2C_ROBOTFUZZ_OSIF=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_SPI=y
+CONFIG_SPI_BCM2835=m
+CONFIG_SPI_BCM2835AUX=m
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPI_SLAVE=y
+CONFIG_PPS=m
+CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PINCTRL_MCP23S08=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_BCM_VIRT=y
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_ARIZONA=m
+CONFIG_GPIO_FSM=m
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_MOCKUP=m
+CONFIG_W1=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_W1_MASTER_DS1WM=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2408=m
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2438=m
+CONFIG_W1_SLAVE_DS2780=m
+CONFIG_W1_SLAVE_DS2781=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_W1_SLAVE_DS28E17=m
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_RPI_POE_POWER=m
+CONFIG_BATTERY_DS2760=m
+CONFIG_BATTERY_MAX17040=m
+CONFIG_BATTERY_GAUGE_LTC2941=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_GPIO_FAN=m
+CONFIG_SENSORS_IIO_HWMON=m
+CONFIG_SENSORS_JC42=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_RASPBERRYPI_HWMON=m
+CONFIG_SENSORS_RPI_POE_FAN=m
+CONFIG_SENSORS_SHT21=m
+CONFIG_SENSORS_SHT3x=m
+CONFIG_SENSORS_SHTC1=m
+CONFIG_SENSORS_INA2XX=m
+CONFIG_SENSORS_TMP102=m
+CONFIG_THERMAL=y
+CONFIG_BCM2711_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_GPIO_WATCHDOG=m
+CONFIG_BCM2835_WDT=y
+CONFIG_MFD_STMPE=y
+CONFIG_STMPE_SPI=y
+CONFIG_MFD_ARIZONA_I2C=m
+CONFIG_MFD_ARIZONA_SPI=m
+CONFIG_MFD_WM5102=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_ARIZONA_LDO1=m
+CONFIG_REGULATOR_ARIZONA_MICSUPP=m
+CONFIG_REGULATOR_GPIO=y
+CONFIG_RC_CORE=y
+CONFIG_LIRC=y
+CONFIG_BPF_LIRC_MODE2=y
+CONFIG_RC_DECODERS=y
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_IR_IMON_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_IR_IMON=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_RC_LOOPBACK=m
+CONFIG_IR_GPIO_CIR=m
+CONFIG_IR_GPIO_TX=m
+CONFIG_IR_PWM_TX=m
+CONFIG_IR_TOY=m
+CONFIG_MEDIA_CEC_RC=y
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_USB_PWC=m
+CONFIG_VIDEO_CPIA2=m
+CONFIG_USB_ZR364XX=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_S2255=m
+CONFIG_VIDEO_USBTV=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_STK1160_COMMON=m
+CONFIG_VIDEO_GO7007=m
+CONFIG_VIDEO_GO7007_USB=m
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
+CONFIG_VIDEO_AU0828=m
+CONFIG_VIDEO_AU0828_RC=y
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_ALSA=m
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_VIDEO_TM6000=m
+CONFIG_VIDEO_TM6000_ALSA=m
+CONFIG_VIDEO_TM6000_DVB=m
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_PCTV452E=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_TECHNISAT_USB2=m
+CONFIG_DVB_USB_V2=m
+CONFIG_DVB_USB_AF9015=m
+CONFIG_DVB_USB_AF9035=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_AZ6007=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_LME2510=m
+CONFIG_DVB_USB_MXL111SF=m
+CONFIG_DVB_USB_RTL28XXU=m
+CONFIG_DVB_USB_DVBSKY=m
+CONFIG_SMS_USB_DRV=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+CONFIG_DVB_AS102=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_V4L2=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_RADIO_SI470X=m
+CONFIG_USB_SI470X=m
+CONFIG_I2C_SI470X=m
+CONFIG_RADIO_SI4713=m
+CONFIG_I2C_SI4713=m
+CONFIG_USB_MR800=m
+CONFIG_USB_DSBR=m
+CONFIG_RADIO_SHARK=m
+CONFIG_RADIO_SHARK2=m
+CONFIG_USB_KEENE=m
+CONFIG_USB_MA901=m
+CONFIG_RADIO_TEA5764=m
+CONFIG_RADIO_SAA7706H=m
+CONFIG_RADIO_TEF6862=m
+CONFIG_RADIO_WL1273=m
+CONFIG_RADIO_WL128X=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_BCM2835_UNICAM=m
+CONFIG_VIDEO_UDA1342=m
+CONFIG_VIDEO_SONY_BTF_MPX=m
+CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_TC358743=m
+CONFIG_VIDEO_TVP5150=m
+CONFIG_VIDEO_TW2804=m
+CONFIG_VIDEO_TW9903=m
+CONFIG_VIDEO_TW9906=m
+CONFIG_VIDEO_IMX219=m
+CONFIG_VIDEO_IMX290=m
+CONFIG_VIDEO_IMX477=m
+CONFIG_VIDEO_OV5647=m
+CONFIG_VIDEO_OV7251=m
+CONFIG_VIDEO_OV7640=m
+CONFIG_VIDEO_OV9281=m
+CONFIG_VIDEO_IRS1125=m
+CONFIG_VIDEO_MT9V011=m
+CONFIG_DRM=m
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_UDL=m
+CONFIG_DRM_PANEL_SIMPLE=m
+CONFIG_DRM_PANEL_JDI_LT070ME05000=m
+CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m
+CONFIG_DRM_DISPLAY_CONNECTOR=m
+CONFIG_DRM_SIMPLE_BRIDGE=m
+CONFIG_DRM_V3D=m
+CONFIG_DRM_VC4=m
+CONFIG_DRM_VC4_HDMI_CEC=y
+CONFIG_TINYDRM_ILI9225=m
+CONFIG_TINYDRM_ILI9341=m
+CONFIG_TINYDRM_MI0283QT=m
+CONFIG_TINYDRM_REPAPER=m
+CONFIG_TINYDRM_ST7586=m
+CONFIG_TINYDRM_ST7735R=m
+CONFIG_DRM_GUD=m
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FB_UDL=m
+CONFIG_FB_SIMPLE=y
+CONFIG_FB_SSD1307=m
+CONFIG_FB_RPISENSE=m
+CONFIG_BACKLIGHT_RPI=m
+CONFIG_BACKLIGHT_GPIO=m
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_ALOOP=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_USB_HIFACE=m
+CONFIG_SND_SOC=m
+CONFIG_SND_BCM2835_SOC_I2S=m
+CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+CONFIG_SND_BCM2708_SOC_PIFI_40=m
+CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=m
+CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m
+CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M=m
+CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
+CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD=m
+CONFIG_SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD=m
+CONFIG_SND_AUDIOSENSE_PI=m
+CONFIG_SND_DIGIDAC1_SOUNDCARD=m
+CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO=m
+CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2=m
+CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS=m
+CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_BOSS2_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_DIGIONE=m
+CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC=m
+CONFIG_SND_BCM2708_SOC_FE_PI_AUDIO=m
+CONFIG_SND_PISOUND=m
+CONFIG_SND_SOC_AD193X_SPI=m
+CONFIG_SND_SOC_AD193X_I2C=m
+CONFIG_SND_SOC_ADAU1701=m
+CONFIG_SND_SOC_ADAU7002=m
+CONFIG_SND_SOC_AK4554=m
+CONFIG_SND_SOC_CS4265=m
+CONFIG_SND_SOC_ICS43432=m
+CONFIG_SND_SOC_MA120X0P=m
+CONFIG_SND_SOC_MAX98357A=m
+CONFIG_SND_SOC_SPDIF=m
+CONFIG_SND_SOC_WM8804_I2C=m
+CONFIG_SND_SOC_WM8960=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_ACRUX=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_ASUS=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_BETOP_FF=m
+CONFIG_HID_BIGBEN_FF=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_EMS_FF=m
+CONFIG_HID_ELECOM=m
+CONFIG_HID_ELO=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_GEMBIRD=m
+CONFIG_HID_HOLTEK=m
+CONFIG_HID_KEYTOUCH=m
+CONFIG_HID_KYE=m
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SONY=m
+CONFIG_SONY_FF=y
+CONFIG_HID_SPEEDLINK=m
+CONFIG_HID_STEAM=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THINGM=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_WACOM=m
+CONFIG_HID_WIIMOTE=m
+CONFIG_HID_XINMO=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_HID_ZYDACRON=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_I2C_HID=m
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=m
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PLATFORM=y
+CONFIG_USB_DWCOTG=y
+CONFIG_USB_PRINTER=m
+CONFIG_USB_TMC=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=y
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USBIP_CORE=m
+CONFIG_USBIP_VHCI_HCD=m
+CONFIG_USBIP_HOST=m
+CONFIG_USBIP_VUDC=m
+CONFIG_USB_DWC2=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_DEBUG=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_YUREX=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_UAC1=y
+CONFIG_USB_CONFIGFS_F_UAC2=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_UVC=y
+CONFIG_USB_CONFIGFS_F_PRINTER=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_MIDI_GADGET=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_ACM_MS=m
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_HID=m
+CONFIG_USB_G_WEBCAM=m
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BCM2835_MMC=y
+CONFIG_MMC_BCM2835_DMA=y
+CONFIG_MMC_BCM2835_SDHOST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_IPROC=y
+CONFIG_MMC_SPI=m
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PCA955X=m
+CONFIG_LEDS_PCA963X=m
+CONFIG_LEDS_IS31FL32XX=m
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_INPUT=y
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_LEDS_TRIGGER_NETDEV=m
+CONFIG_LEDS_TRIGGER_ACTPWR=y
+CONFIG_ACCESSIBILITY=y
+CONFIG_SPEAKUP=m
+CONFIG_SPEAKUP_SYNTH_SOFT=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_ABX80X=m
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_DS1374=m
+CONFIG_RTC_DRV_DS1672=m
+CONFIG_RTC_DRV_MAX6900=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_ISL1208=m
+CONFIG_RTC_DRV_ISL12022=m
+CONFIG_RTC_DRV_X1205=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_PCF85063=m
+CONFIG_RTC_DRV_PCF85363=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_M41T80=m
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_FM3130=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_RX8025=m
+CONFIG_RTC_DRV_EM3027=m
+CONFIG_RTC_DRV_RV3028=m
+CONFIG_RTC_DRV_SD3078=m
+CONFIG_RTC_DRV_M41T93=m
+CONFIG_RTC_DRV_M41T94=m
+CONFIG_RTC_DRV_DS1302=m
+CONFIG_RTC_DRV_DS1305=m
+CONFIG_RTC_DRV_DS1390=m
+CONFIG_RTC_DRV_R9701=m
+CONFIG_RTC_DRV_RX4581=m
+CONFIG_RTC_DRV_RS5C348=m
+CONFIG_RTC_DRV_MAX6902=m
+CONFIG_RTC_DRV_PCF2123=m
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_PCF2127=m
+CONFIG_RTC_DRV_RV3029C2=m
+CONFIG_DMADEVICES=y
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_BCM2708=y
+CONFIG_DMABUF_HEAPS=y
+CONFIG_DMABUF_HEAPS_SYSTEM=y
+CONFIG_DMABUF_HEAPS_CMA=y
+CONFIG_AUXDISPLAY=y
+CONFIG_HD44780=m
+CONFIG_UIO=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_STAGING=y
+CONFIG_PRISM2_USB=m
+CONFIG_R8712U=m
+CONFIG_R8188EU=m
+CONFIG_VT6656=m
+CONFIG_STAGING_MEDIA=y
+CONFIG_VIDEO_RPIVID=m
+CONFIG_FB_TFT=m
+CONFIG_FB_TFT_AGM1264K_FL=m
+CONFIG_FB_TFT_BD663474=m
+CONFIG_FB_TFT_HX8340BN=m
+CONFIG_FB_TFT_HX8347D=m
+CONFIG_FB_TFT_HX8353D=m
+CONFIG_FB_TFT_HX8357D=m
+CONFIG_FB_TFT_ILI9163=m
+CONFIG_FB_TFT_ILI9320=m
+CONFIG_FB_TFT_ILI9325=m
+CONFIG_FB_TFT_ILI9340=m
+CONFIG_FB_TFT_ILI9341=m
+CONFIG_FB_TFT_ILI9481=m
+CONFIG_FB_TFT_ILI9486=m
+CONFIG_FB_TFT_PCD8544=m
+CONFIG_FB_TFT_RA8875=m
+CONFIG_FB_TFT_S6D02A1=m
+CONFIG_FB_TFT_S6D1121=m
+CONFIG_FB_TFT_SH1106=m
+CONFIG_FB_TFT_SSD1289=m
+CONFIG_FB_TFT_SSD1306=m
+CONFIG_FB_TFT_SSD1331=m
+CONFIG_FB_TFT_SSD1351=m
+CONFIG_FB_TFT_ST7735R=m
+CONFIG_FB_TFT_ST7789V=m
+CONFIG_FB_TFT_TINYLCD=m
+CONFIG_FB_TFT_TLS8204=m
+CONFIG_FB_TFT_UC1701=m
+CONFIG_FB_TFT_UPD161704=m
+CONFIG_FB_TFT_WATTEROTT=m
+CONFIG_BCM2835_VCHIQ=y
+CONFIG_SND_BCM2835=m
+CONFIG_VIDEO_BCM2835=m
+CONFIG_VIDEO_CODEC_BCM2835=m
+CONFIG_VIDEO_ISP_BCM2835=m
+CONFIG_CLK_RASPBERRYPI=y
+CONFIG_MAILBOX=y
+CONFIG_BCM2835_MBOX=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_RASPBERRYPI_POWER=y
+CONFIG_EXTCON_ARIZONA=m
+CONFIG_IIO=m
+CONFIG_IIO_BUFFER_CB=m
+CONFIG_MCP320X=m
+CONFIG_MCP3422=m
+CONFIG_TI_ADS1015=m
+CONFIG_BME680=m
+CONFIG_CCS811=m
+CONFIG_SENSIRION_SGP30=m
+CONFIG_SPS30=m
+CONFIG_DHT11=m
+CONFIG_HDC100X=m
+CONFIG_HTU21=m
+CONFIG_INV_MPU6050_I2C=m
+CONFIG_APDS9960=m
+CONFIG_BH1750=m
+CONFIG_TSL4531=m
+CONFIG_VEML6070=m
+CONFIG_BMP280=m
+CONFIG_MAXIM_THERMOCOUPLE=m
+CONFIG_MAX31856=m
+CONFIG_PWM_BCM2835=m
+CONFIG_PWM_PCA9685=m
+CONFIG_RPI_AXIPERF=m
+CONFIG_NVMEM_RMEM=m
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+CONFIG_JFS_STATISTICS=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_GFS2_FS=m
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_F2FS_FS=y
+CONFIG_FS_ENCRYPTION=y
+CONFIG_FANOTIFY=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_OVERLAY_FS=m
+CONFIG_FSCACHE=y
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_HISTOGRAM=y
+CONFIG_CACHEFILES=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_EXFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_UBIFS_FS=m
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+CONFIG_9P_FS=m
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_DLM=m
+CONFIG_SECURITY=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_LSM=""
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_LIBCRC32C=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=5
+CONFIG_PRINTK_TIME=y
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+CONFIG_KDB_KEYBOARD=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_RCU_TRACE is not set
+CONFIG_LATENCYTOP=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_STACK_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_SCHED_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_UPROBE_EVENTS is not set
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/configs/bcmrpi_defconfig linux-5.10.52-v7l+/arch/arm/configs/bcmrpi_defconfig
--- linux-5.10.52-orig/arch/arm/configs/bcmrpi_defconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/configs/bcmrpi_defconfig	2021-07-25 16:45:35.368803870 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_GENERIC_IRQ_DEBUGFS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=m
+CONFIG_IKCONFIG_PROC=y
+CONFIG_MEMCG=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_ARCH_MULTI_V6=y
+# CONFIG_ARCH_MULTI_V7 is not set
+CONFIG_ARCH_BCM=y
+CONFIG_ARCH_BCM2835=y
+# CONFIG_CACHE_L2X0 is not set
+# CONFIG_CPU_SW_DOMAIN_PAN is not set
+CONFIG_UACCESS_WITH_MEMCPY=y
+# CONFIG_ATAGS is not set
+CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
+CONFIG_VFP=y
+# CONFIG_SUSPEND is not set
+CONFIG_PM=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_CRYPTO_SHA1_ARM=m
+CONFIG_CRYPTO_AES_ARM=m
+CONFIG_OPROFILE=m
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BINFMT_MISC=m
+CONFIG_CLEANCACHE=y
+CONFIG_FRONTSWAP=y
+CONFIG_CMA=y
+CONFIG_ZSWAP=y
+CONFIG_Z3FOLD=m
+CONFIG_ZSMALLOC=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_NET_IPVTI=m
+CONFIG_NET_FOU=m
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BBR=m
+CONFIG_IPV6=m
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_ILA=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETFILTER=y
+CONFIG_BRIDGE_NETFILTER=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_LOG_NETDEV=m
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_NETDEV=y
+CONFIG_NFT_NUMGEN=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_CONNLIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_OBJREF=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_OSF=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
+CONFIG_NF_FLOW_TABLE_INET=m
+CONFIG_NF_FLOW_TABLE=m
+CONFIG_NETFILTER_XT_SET=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_PE_SIP=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_FLOW_TABLE_IPV4=m
+CONFIG_NF_LOG_ARP=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_NF_FLOW_TABLE_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NF_LOG_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
+CONFIG_ATM=m
+CONFIG_L2TP=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_ATALK=m
+CONFIG_6LOWPAN=m
+CONFIG_IEEE802154=m
+CONFIG_IEEE802154_6LOWPAN=m
+CONFIG_MAC802154=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_HHF=m
+CONFIG_NET_SCH_PIE=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_PLUG=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_IPSET=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_BATMAN_ADV=m
+CONFIG_OPENVSWITCH=m
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_NET_PKTGEN=m
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_MKISS=m
+CONFIG_6PACK=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_YAM=m
+CONFIG_CAN=m
+CONFIG_CAN_J1939=m
+CONFIG_CAN_ISOTP=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_SLCAN=m
+CONFIG_CAN_MCP251X=m
+CONFIG_CAN_MCP251XFD=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_CAN_GS_USB=m
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_6LOWPAN=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_HCIUART_BCM=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_ATH3K=m
+CONFIG_CFG80211=m
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_MESH=y
+CONFIG_WIMAX=m
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_NET_9P=m
+CONFIG_NFC=m
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_MTD=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_SPI_NOR=m
+CONFIG_MTD_UBI=m
+CONFIG_OF_CONFIGFS=y
+CONFIG_ZRAM=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_ATA_OVER_ETH=m
+CONFIG_EEPROM_AT24=m
+CONFIG_TI_ST=m
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=m
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_THIN_PROVISIONING=m
+CONFIG_DM_CACHE=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_DELAY=m
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+CONFIG_IFB=m
+CONFIG_MACVLAN=m
+CONFIG_IPVLAN=m
+CONFIG_VXLAN=m
+CONFIG_NETCONSOLE=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_NET_VRF=m
+CONFIG_ENC28J60=m
+CONFIG_QCA7000_SPI=m
+CONFIG_QCA7000_UART=m
+CONFIG_WIZNET_W5100=m
+CONFIG_WIZNET_W5100_SPI=m
+CONFIG_MDIO_BITBANG=m
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_LAN78XX=m
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_AX88179_178A=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SR9700=m
+CONFIG_USB_NET_SR9800=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_NET_KALMIA=m
+CONFIG_USB_NET_QMI_WWAN=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+CONFIG_USB_NET_AQC111=m
+CONFIG_ATH9K=m
+CONFIG_ATH9K_HTC=m
+CONFIG_CARL9170=m
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_USB=m
+CONFIG_AR5523=m
+CONFIG_AT76C50X_USB=m
+CONFIG_B43=m
+# CONFIG_B43_PHY_N is not set
+CONFIG_B43LEGACY=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_USB=y
+CONFIG_BRCMDBG=y
+CONFIG_HOSTAP=m
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MT7601U=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x2U=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RTL8187=m
+CONFIG_RTL8192CU=m
+CONFIG_RTL8XXXU=m
+CONFIG_USB_ZD1201=m
+CONFIG_ZD1211RW=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_WIMAX_I2400M_USB=m
+CONFIG_IEEE802154_AT86RF230=m
+CONFIG_IEEE802154_MRF24J40=m
+CONFIG_IEEE802154_CC2520=m
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_MATRIX=m
+CONFIG_KEYBOARD_CAP11XX=m
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=m
+CONFIG_JOYSTICK_XPAD=m
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_JOYSTICK_PSXPAD_SPI=m
+CONFIG_JOYSTICK_PSXPAD_SPI_FF=y
+CONFIG_JOYSTICK_RPISENSE=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_EXC3000=m
+CONFIG_TOUCHSCREEN_GOODIX=m
+CONFIG_TOUCHSCREEN_ILI210X=m
+CONFIG_TOUCHSCREEN_EDT_FT5X06=m
+CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_STMPE=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_POWERMATE=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_SERIO=m
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_BRCM_CHAR_DRIVERS=y
+CONFIG_BCM_VCIO=y
+CONFIG_BCM2835_DEVGPIOMEM=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_BCM2835AUX=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_SC16IS7XX=m
+CONFIG_SERIAL_SC16IS7XX_SPI=y
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_TTY_PRINTK=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=y
+CONFIG_TCG_TPM=m
+CONFIG_TCG_TIS_SPI=m
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX_GPMUX=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_MUX_PINCTRL=m
+CONFIG_I2C_BCM2708=m
+CONFIG_I2C_BCM2835=m
+# CONFIG_I2C_BRCMSTB is not set
+CONFIG_I2C_GPIO=m
+CONFIG_I2C_ROBOTFUZZ_OSIF=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_SPI=y
+CONFIG_SPI_BCM2835=m
+CONFIG_SPI_BCM2835AUX=m
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPI_SLAVE=y
+CONFIG_PPS=m
+CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PINCTRL_MCP23S08=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_ARIZONA=m
+CONFIG_GPIO_FSM=m
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_MOCKUP=m
+CONFIG_W1=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_W1_MASTER_DS1WM=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2408=m
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2438=m
+CONFIG_W1_SLAVE_DS2780=m
+CONFIG_W1_SLAVE_DS2781=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_W1_SLAVE_DS28E17=m
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_RPI_POE_POWER=m
+CONFIG_BATTERY_DS2760=m
+CONFIG_BATTERY_MAX17040=m
+CONFIG_BATTERY_GAUGE_LTC2941=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_GPIO_FAN=m
+CONFIG_SENSORS_IIO_HWMON=m
+CONFIG_SENSORS_JC42=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_RASPBERRYPI_HWMON=m
+CONFIG_SENSORS_RPI_POE_FAN=m
+CONFIG_SENSORS_SHT21=m
+CONFIG_SENSORS_SHT3x=m
+CONFIG_SENSORS_SHTC1=m
+CONFIG_SENSORS_INA2XX=m
+CONFIG_SENSORS_TMP102=m
+CONFIG_THERMAL=y
+CONFIG_BCM2835_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_GPIO_WATCHDOG=m
+CONFIG_BCM2835_WDT=y
+CONFIG_MFD_STMPE=y
+CONFIG_STMPE_SPI=y
+CONFIG_MFD_ARIZONA_I2C=m
+CONFIG_MFD_ARIZONA_SPI=m
+CONFIG_MFD_WM5102=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_ARIZONA_LDO1=m
+CONFIG_REGULATOR_ARIZONA_MICSUPP=m
+CONFIG_RC_CORE=y
+CONFIG_LIRC=y
+CONFIG_BPF_LIRC_MODE2=y
+CONFIG_RC_DECODERS=y
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_IR_IMON_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_IR_IMON=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_RC_LOOPBACK=m
+CONFIG_IR_GPIO_CIR=m
+CONFIG_IR_GPIO_TX=m
+CONFIG_IR_PWM_TX=m
+CONFIG_IR_TOY=m
+CONFIG_MEDIA_CEC_RC=y
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_USB_PWC=m
+CONFIG_VIDEO_CPIA2=m
+CONFIG_USB_ZR364XX=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_S2255=m
+CONFIG_VIDEO_USBTV=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_STK1160_COMMON=m
+CONFIG_VIDEO_GO7007=m
+CONFIG_VIDEO_GO7007_USB=m
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
+CONFIG_VIDEO_AU0828=m
+CONFIG_VIDEO_AU0828_RC=y
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_ALSA=m
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_VIDEO_TM6000=m
+CONFIG_VIDEO_TM6000_ALSA=m
+CONFIG_VIDEO_TM6000_DVB=m
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_PCTV452E=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_TECHNISAT_USB2=m
+CONFIG_DVB_USB_V2=m
+CONFIG_DVB_USB_AF9015=m
+CONFIG_DVB_USB_AF9035=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_AZ6007=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_LME2510=m
+CONFIG_DVB_USB_MXL111SF=m
+CONFIG_DVB_USB_RTL28XXU=m
+CONFIG_DVB_USB_DVBSKY=m
+CONFIG_SMS_USB_DRV=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+CONFIG_DVB_AS102=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_V4L2=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_RADIO_SI470X=m
+CONFIG_USB_SI470X=m
+CONFIG_I2C_SI470X=m
+CONFIG_RADIO_SI4713=m
+CONFIG_I2C_SI4713=m
+CONFIG_USB_MR800=m
+CONFIG_USB_DSBR=m
+CONFIG_RADIO_SHARK=m
+CONFIG_RADIO_SHARK2=m
+CONFIG_USB_KEENE=m
+CONFIG_USB_MA901=m
+CONFIG_RADIO_TEA5764=m
+CONFIG_RADIO_SAA7706H=m
+CONFIG_RADIO_TEF6862=m
+CONFIG_RADIO_WL1273=m
+CONFIG_RADIO_WL128X=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_BCM2835_UNICAM=m
+CONFIG_VIDEO_UDA1342=m
+CONFIG_VIDEO_SONY_BTF_MPX=m
+CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_TC358743=m
+CONFIG_VIDEO_TVP5150=m
+CONFIG_VIDEO_TW2804=m
+CONFIG_VIDEO_TW9903=m
+CONFIG_VIDEO_TW9906=m
+CONFIG_VIDEO_IMX219=m
+CONFIG_VIDEO_IMX290=m
+CONFIG_VIDEO_IMX477=m
+CONFIG_VIDEO_OV5647=m
+CONFIG_VIDEO_OV7251=m
+CONFIG_VIDEO_OV7640=m
+CONFIG_VIDEO_OV9281=m
+CONFIG_VIDEO_IRS1125=m
+CONFIG_VIDEO_MT9V011=m
+CONFIG_DRM=m
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_UDL=m
+CONFIG_DRM_PANEL_SIMPLE=m
+CONFIG_DRM_PANEL_JDI_LT070ME05000=m
+CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m
+CONFIG_DRM_DISPLAY_CONNECTOR=m
+CONFIG_DRM_SIMPLE_BRIDGE=m
+CONFIG_DRM_VC4=m
+CONFIG_DRM_VC4_HDMI_CEC=y
+CONFIG_TINYDRM_ILI9225=m
+CONFIG_TINYDRM_ILI9341=m
+CONFIG_TINYDRM_MI0283QT=m
+CONFIG_TINYDRM_REPAPER=m
+CONFIG_TINYDRM_ST7586=m
+CONFIG_TINYDRM_ST7735R=m
+CONFIG_DRM_GUD=m
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FB_UDL=m
+CONFIG_FB_SIMPLE=y
+CONFIG_FB_SSD1307=m
+CONFIG_FB_RPISENSE=m
+CONFIG_BACKLIGHT_RPI=m
+CONFIG_BACKLIGHT_GPIO=m
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_ALOOP=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_USB_HIFACE=m
+CONFIG_SND_SOC=m
+CONFIG_SND_BCM2835_SOC_I2S=m
+CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+CONFIG_SND_BCM2708_SOC_PIFI_40=m
+CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=m
+CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m
+CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M=m
+CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
+CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD=m
+CONFIG_SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD=m
+CONFIG_SND_AUDIOSENSE_PI=m
+CONFIG_SND_DIGIDAC1_SOUNDCARD=m
+CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO=m
+CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2=m
+CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS=m
+CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_BOSS2_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_DIGIONE=m
+CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC=m
+CONFIG_SND_BCM2708_SOC_FE_PI_AUDIO=m
+CONFIG_SND_PISOUND=m
+CONFIG_SND_SOC_AD193X_SPI=m
+CONFIG_SND_SOC_AD193X_I2C=m
+CONFIG_SND_SOC_ADAU1701=m
+CONFIG_SND_SOC_ADAU7002=m
+CONFIG_SND_SOC_AK4554=m
+CONFIG_SND_SOC_CS4265=m
+CONFIG_SND_SOC_ICS43432=m
+CONFIG_SND_SOC_MA120X0P=m
+CONFIG_SND_SOC_MAX98357A=m
+CONFIG_SND_SOC_SPDIF=m
+CONFIG_SND_SOC_WM8804_I2C=m
+CONFIG_SND_SOC_WM8960=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_ACRUX=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_ASUS=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_BETOP_FF=m
+CONFIG_HID_BIGBEN_FF=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_EMS_FF=m
+CONFIG_HID_ELECOM=m
+CONFIG_HID_ELO=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_GEMBIRD=m
+CONFIG_HID_HOLTEK=m
+CONFIG_HID_KEYTOUCH=m
+CONFIG_HID_KYE=m
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SONY=m
+CONFIG_SONY_FF=y
+CONFIG_HID_SPEEDLINK=m
+CONFIG_HID_STEAM=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THINGM=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_WACOM=m
+CONFIG_HID_WIIMOTE=m
+CONFIG_HID_XINMO=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_HID_ZYDACRON=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_I2C_HID=m
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=m
+CONFIG_USB_DWCOTG=y
+CONFIG_USB_PRINTER=m
+CONFIG_USB_TMC=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USBIP_CORE=m
+CONFIG_USBIP_VHCI_HCD=m
+CONFIG_USBIP_HOST=m
+CONFIG_USBIP_VUDC=m
+CONFIG_USB_DWC2=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_DEBUG=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_YUREX=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_USB_GADGET=m
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_UAC1=y
+CONFIG_USB_CONFIGFS_F_UAC2=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_UVC=y
+CONFIG_USB_CONFIGFS_F_PRINTER=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_MIDI_GADGET=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_ACM_MS=m
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_HID=m
+CONFIG_USB_G_WEBCAM=m
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BCM2835_MMC=y
+CONFIG_MMC_BCM2835_DMA=y
+CONFIG_MMC_BCM2835_SDHOST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SPI=m
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PCA955X=m
+CONFIG_LEDS_PCA963X=m
+CONFIG_LEDS_IS31FL32XX=m
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_INPUT=y
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_LEDS_TRIGGER_NETDEV=m
+CONFIG_LEDS_TRIGGER_ACTPWR=y
+CONFIG_ACCESSIBILITY=y
+CONFIG_SPEAKUP=m
+CONFIG_SPEAKUP_SYNTH_SOFT=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_ABX80X=m
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_DS1374=m
+CONFIG_RTC_DRV_DS1672=m
+CONFIG_RTC_DRV_MAX6900=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_ISL1208=m
+CONFIG_RTC_DRV_ISL12022=m
+CONFIG_RTC_DRV_X1205=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_PCF85063=m
+CONFIG_RTC_DRV_PCF85363=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_M41T80=m
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_FM3130=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_RX8025=m
+CONFIG_RTC_DRV_EM3027=m
+CONFIG_RTC_DRV_RV3028=m
+CONFIG_RTC_DRV_SD3078=m
+CONFIG_RTC_DRV_M41T93=m
+CONFIG_RTC_DRV_M41T94=m
+CONFIG_RTC_DRV_DS1302=m
+CONFIG_RTC_DRV_DS1305=m
+CONFIG_RTC_DRV_DS1390=m
+CONFIG_RTC_DRV_R9701=m
+CONFIG_RTC_DRV_RX4581=m
+CONFIG_RTC_DRV_RS5C348=m
+CONFIG_RTC_DRV_MAX6902=m
+CONFIG_RTC_DRV_PCF2123=m
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_PCF2127=m
+CONFIG_RTC_DRV_RV3029C2=m
+CONFIG_DMADEVICES=y
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_BCM2708=y
+CONFIG_DMABUF_HEAPS=y
+CONFIG_DMABUF_HEAPS_SYSTEM=y
+CONFIG_DMABUF_HEAPS_CMA=y
+CONFIG_AUXDISPLAY=y
+CONFIG_HD44780=m
+CONFIG_UIO=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_STAGING=y
+CONFIG_PRISM2_USB=m
+CONFIG_R8712U=m
+CONFIG_R8188EU=m
+CONFIG_VT6656=m
+CONFIG_STAGING_MEDIA=y
+CONFIG_FB_TFT=m
+CONFIG_FB_TFT_AGM1264K_FL=m
+CONFIG_FB_TFT_BD663474=m
+CONFIG_FB_TFT_HX8340BN=m
+CONFIG_FB_TFT_HX8347D=m
+CONFIG_FB_TFT_HX8353D=m
+CONFIG_FB_TFT_HX8357D=m
+CONFIG_FB_TFT_ILI9163=m
+CONFIG_FB_TFT_ILI9320=m
+CONFIG_FB_TFT_ILI9325=m
+CONFIG_FB_TFT_ILI9340=m
+CONFIG_FB_TFT_ILI9341=m
+CONFIG_FB_TFT_ILI9481=m
+CONFIG_FB_TFT_ILI9486=m
+CONFIG_FB_TFT_PCD8544=m
+CONFIG_FB_TFT_RA8875=m
+CONFIG_FB_TFT_S6D02A1=m
+CONFIG_FB_TFT_S6D1121=m
+CONFIG_FB_TFT_SH1106=m
+CONFIG_FB_TFT_SSD1289=m
+CONFIG_FB_TFT_SSD1306=m
+CONFIG_FB_TFT_SSD1331=m
+CONFIG_FB_TFT_SSD1351=m
+CONFIG_FB_TFT_ST7735R=m
+CONFIG_FB_TFT_ST7789V=m
+CONFIG_FB_TFT_TINYLCD=m
+CONFIG_FB_TFT_TLS8204=m
+CONFIG_FB_TFT_UC1701=m
+CONFIG_FB_TFT_UPD161704=m
+CONFIG_FB_TFT_WATTEROTT=m
+CONFIG_BCM2835_VCHIQ=y
+CONFIG_SND_BCM2835=m
+CONFIG_VIDEO_BCM2835=m
+CONFIG_VIDEO_CODEC_BCM2835=m
+CONFIG_VIDEO_ISP_BCM2835=m
+CONFIG_CLK_RASPBERRYPI=y
+CONFIG_MAILBOX=y
+CONFIG_BCM2835_MBOX=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_RASPBERRYPI_POWER=y
+CONFIG_EXTCON=m
+CONFIG_EXTCON_ARIZONA=m
+CONFIG_IIO=m
+CONFIG_IIO_BUFFER_CB=m
+CONFIG_MCP320X=m
+CONFIG_MCP3422=m
+CONFIG_TI_ADS1015=m
+CONFIG_BME680=m
+CONFIG_CCS811=m
+CONFIG_SENSIRION_SGP30=m
+CONFIG_SPS30=m
+CONFIG_DHT11=m
+CONFIG_HDC100X=m
+CONFIG_HTU21=m
+CONFIG_INV_MPU6050_I2C=m
+CONFIG_APDS9960=m
+CONFIG_BH1750=m
+CONFIG_TSL4531=m
+CONFIG_VEML6070=m
+CONFIG_BMP280=m
+CONFIG_MAXIM_THERMOCOUPLE=m
+CONFIG_MAX31856=m
+CONFIG_PWM_BCM2835=m
+CONFIG_PWM_PCA9685=m
+CONFIG_RPI_AXIPERF=m
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+CONFIG_JFS_STATISTICS=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_GFS2_FS=m
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_F2FS_FS=y
+CONFIG_FANOTIFY=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_OVERLAY_FS=m
+CONFIG_FSCACHE=y
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_HISTOGRAM=y
+CONFIG_CACHEFILES=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_EXFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_UBIFS_FS=m
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+CONFIG_9P_FS=m
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_DLM=m
+CONFIG_SECURITY=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_LSM=""
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_LIBCRC32C=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=5
+CONFIG_PRINTK_TIME=y
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+CONFIG_KDB_KEYBOARD=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_LATENCYTOP=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_STACK_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_SCHED_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_UPROBE_EVENTS is not set
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/configs/multi_v7_defconfig linux-5.10.52-v7l+/arch/arm/configs/multi_v7_defconfig
--- linux-5.10.52-orig/arch/arm/configs/multi_v7_defconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/configs/multi_v7_defconfig	2021-07-25 16:45:35.378803702 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1092 @
 CONFIG_NVMEM_SUNXI_SID=y
 CONFIG_NVMEM_VF610_OCOTP=y
 CONFIG_MESON_MX_EFUSE=m
+CONFIG_NVMEM_RMEM=m
 CONFIG_FSI=m
 CONFIG_FSI_MASTER_GPIO=m
 CONFIG_FSI_MASTER_HUB=m
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/include/asm/cacheflush.h linux-5.10.52-v7l+/arch/arm/include/asm/cacheflush.h
--- linux-5.10.52-orig/arch/arm/include/asm/cacheflush.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/include/asm/cacheflush.h	2021-07-25 16:45:35.408803199 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:94 @
  *	DMA Cache Coherency
  *	===================
  *
+ *	dma_inv_range(start, end)
+ *
+ *		Invalidate (discard) the specified virtual address range.
+ *		May not write back any entries.  If 'start' or 'end'
+ *		are not cache line aligned, those lines must be written
+ *		back.
+ *		- start  - virtual start address
+ *		- end    - virtual end address
+ *
+ *	dma_clean_range(start, end)
+ *
+ *		Clean (write back) the specified virtual address range.
+ *		- start  - virtual start address
+ *		- end    - virtual end address
+ *
  *	dma_flush_range(start, end)
  *
  *		Clean and invalidate the specified virtual address range.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:130 @
 	void (*dma_map_area)(const void *, size_t, int);
 	void (*dma_unmap_area)(const void *, size_t, int);
 
+	void (*dma_inv_range)(const void *, const void *);
+	void (*dma_clean_range)(const void *, const void *);
 	void (*dma_flush_range)(const void *, const void *);
 } __no_randomize_layout;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:157 @
  * is visible to DMA, or data written by DMA to system memory is
  * visible to the CPU.
  */
+#define dmac_inv_range			cpu_cache.dma_inv_range
+#define dmac_clean_range		cpu_cache.dma_clean_range
 #define dmac_flush_range		cpu_cache.dma_flush_range
 
 #else
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:178 @
  * is visible to DMA, or data written by DMA to system memory is
  * visible to the CPU.
  */
+extern void dmac_inv_range(const void *, const void *);
+extern void dmac_clean_range(const void *, const void *);
 extern void dmac_flush_range(const void *, const void *);
 
 #endif
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/include/asm/glue-cache.h linux-5.10.52-v7l+/arch/arm/include/asm/glue-cache.h
--- linux-5.10.52-orig/arch/arm/include/asm/glue-cache.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/include/asm/glue-cache.h	2021-07-25 16:45:35.418803031 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:158 @
 #define __cpuc_coherent_user_range	__glue(_CACHE,_coherent_user_range)
 #define __cpuc_flush_dcache_area	__glue(_CACHE,_flush_kern_dcache_area)
 
+#define dmac_inv_range			__glue(_CACHE,_dma_inv_range)
+#define dmac_clean_range		__glue(_CACHE,_dma_clean_range)
 #define dmac_flush_range		__glue(_CACHE,_dma_flush_range)
 #endif
 
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/include/asm/irqflags.h linux-5.10.52-v7l+/arch/arm/include/asm/irqflags.h
--- linux-5.10.52-orig/arch/arm/include/asm/irqflags.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/include/asm/irqflags.h	2021-07-25 16:45:35.418803031 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:166 @
 }
 
 /*
- * restore saved IRQ & FIQ state
+ * restore saved IRQ state
  */
 #define arch_local_irq_restore arch_local_irq_restore
 static inline void arch_local_irq_restore(unsigned long flags)
 {
-	asm volatile(
-		"	msr	" IRQMASK_REG_NAME_W ", %0	@ local_irq_restore"
+	unsigned long temp = 0;
+	flags &= ~(1 << 6);
+	asm volatile (
+		" mrs %0, cpsr"
+		: "=r" (temp)
+		:
+		: "memory", "cc");
+		/* Preserve FIQ bit */
+		temp &= (1 << 6);
+		flags = flags | temp;
+	asm volatile (
+		"    msr    cpsr_c, %0    @ local_irq_restore"
 		:
 		: "r" (flags)
 		: "memory", "cc");
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/include/asm/string.h linux-5.10.52-v7l+/arch/arm/include/asm/string.h
--- linux-5.10.52-orig/arch/arm/include/asm/string.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/include/asm/string.h	2021-07-25 16:45:35.438802696 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:42 @
 	return __memset64(p, v, n * 8, v >> 32);
 }
 
+#ifdef CONFIG_BCM2835_FAST_MEMCPY
+#define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *, const void *, size_t);
+#endif
+
 #endif
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/include/asm/uaccess.h linux-5.10.52-v7l+/arch/arm/include/asm/uaccess.h
--- linux-5.10.52-orig/arch/arm/include/asm/uaccess.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/include/asm/uaccess.h	2021-07-25 16:45:35.438802696 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:519 @
 extern unsigned long __must_check
 arm_copy_from_user(void *to, const void __user *from, unsigned long n);
 
+extern unsigned long __must_check
+__copy_from_user_std(void *to, const void __user *from, unsigned long n);
+
 static inline unsigned long __must_check
 raw_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/kernel/fiqasm.S linux-5.10.52-v7l+/arch/arm/kernel/fiqasm.S
--- linux-5.10.52-orig/arch/arm/kernel/fiqasm.S	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/kernel/fiqasm.S	2021-07-25 16:45:35.458802361 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:50 @
 	mov	r0, r0		@ avoid hazard prior to ARMv4
 	ret	lr
 ENDPROC(__get_fiq_regs)
+
+ENTRY(__FIQ_Branch)
+	mov pc, r8
+ENDPROC(__FIQ_Branch)
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/kernel/fiq.c linux-5.10.52-v7l+/arch/arm/kernel/fiq.c
--- linux-5.10.52-orig/arch/arm/kernel/fiq.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/kernel/fiq.c	2021-07-25 16:45:35.458802361 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:59 @
 static unsigned long dfl_fiq_insn;
 static struct pt_regs dfl_fiq_regs;
 
+extern int irq_activate(struct irq_desc *desc);
+
 /* Default reacquire function
  * - we always relinquish FIQ control
  * - we always reacquire FIQ control
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:145 @
 
 void enable_fiq(int fiq)
 {
+	struct irq_desc *desc = irq_to_desc(fiq + fiq_start);
+	irq_activate(desc);
 	enable_irq(fiq + fiq_start);
 }
 
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/kernel/reboot.c linux-5.10.52-v7l+/arch/arm/kernel/reboot.c
--- linux-5.10.52-orig/arch/arm/kernel/reboot.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/kernel/reboot.c	2021-07-25 16:45:35.468802193 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:105 @
  */
 void machine_halt(void)
 {
-	local_irq_disable();
-	smp_send_stop();
-	while (1);
+	machine_power_off();
 }
 
 /*
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/kernel/setup.c linux-5.10.52-v7l+/arch/arm/kernel/setup.c
--- linux-5.10.52-orig/arch/arm/kernel/setup.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/kernel/setup.c	2021-07-25 16:45:35.468802193 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1258 @
 {
 	int i, j;
 	u32 cpuid;
+	struct device_node *np;
+	const char *model;
 
 	for_each_online_cpu(i) {
 		/*
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1319 @
 	seq_printf(m, "Revision\t: %04x\n", system_rev);
 	seq_printf(m, "Serial\t\t: %s\n", system_serial);
 
+	np = of_find_node_by_path("/");
+	if (np) {
+		if (!of_property_read_string(np, "model",
+					     &model))
+			seq_printf(m, "Model\t\t: %s\n", model);
+		of_node_put(np);
+	}
+
 	return 0;
 }
 
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/arm-mem.h linux-5.10.52-v7l+/arch/arm/lib/arm-mem.h
--- linux-5.10.52-orig/arch/arm/lib/arm-mem.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/lib/arm-mem.h	2021-07-25 16:45:35.478802025 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+Copyright (c) 2013, Raspberry Pi Foundation
+Copyright (c) 2013, RISC OS Open Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * 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.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+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 HOLDER 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.
+*/
+
+.macro myfunc fname
+ .func fname
+ .global fname
+fname:
+.endm
+
+.macro preload_leading_step1  backwards, ptr, base
+/* If the destination is already 16-byte aligned, then we need to preload
+ * between 0 and prefetch_distance (inclusive) cache lines ahead so there
+ * are no gaps when the inner loop starts.
+ */
+ .if backwards
+        sub     ptr, base, #1
+        bic     ptr, ptr, #31
+ .else
+        bic     ptr, base, #31
+ .endif
+ .set OFFSET, 0
+ .rept prefetch_distance+1
+        pld     [ptr, #OFFSET]
+  .if backwards
+   .set OFFSET, OFFSET-32
+  .else
+   .set OFFSET, OFFSET+32
+  .endif
+ .endr
+.endm
+
+.macro preload_leading_step2  backwards, ptr, base, leading_bytes, tmp
+/* However, if the destination is not 16-byte aligned, we may need to
+ * preload one more cache line than that. The question we need to ask is:
+ * are the leading bytes more than the amount by which the source
+ * pointer will be rounded down for preloading, and if so, by how many
+ * cache lines?
+ */
+ .if backwards
+/* Here we compare against how many bytes we are into the
+ * cache line, counting down from the highest such address.
+ * Effectively, we want to calculate
+ *     leading_bytes = dst&15
+ *     cacheline_offset = 31-((src-leading_bytes-1)&31)
+ *     extra_needed = leading_bytes - cacheline_offset
+ * and test if extra_needed is <= 0, or rearranging:
+ *     leading_bytes + (src-leading_bytes-1)&31 <= 31
+ */
+        mov     tmp, base, lsl #32-5
+        sbc     tmp, tmp, leading_bytes, lsl #32-5
+        adds    tmp, tmp, leading_bytes, lsl #32-5
+        bcc     61f
+        pld     [ptr, #-32*(prefetch_distance+1)]
+ .else
+/* Effectively, we want to calculate
+ *     leading_bytes = (-dst)&15
+ *     cacheline_offset = (src+leading_bytes)&31
+ *     extra_needed = leading_bytes - cacheline_offset
+ * and test if extra_needed is <= 0.
+ */
+        mov     tmp, base, lsl #32-5
+        add     tmp, tmp, leading_bytes, lsl #32-5
+        rsbs    tmp, tmp, leading_bytes, lsl #32-5
+        bls     61f
+        pld     [ptr, #32*(prefetch_distance+1)]
+ .endif
+61:
+.endm
+
+.macro preload_trailing  backwards, base, remain, tmp
+        /* We need either 0, 1 or 2 extra preloads */
+ .if backwards
+        rsb     tmp, base, #0
+        mov     tmp, tmp, lsl #32-5
+ .else
+        mov     tmp, base, lsl #32-5
+ .endif
+        adds    tmp, tmp, remain, lsl #32-5
+        adceqs  tmp, tmp, #0
+        /* The instruction above has two effects: ensures Z is only
+         * set if C was clear (so Z indicates that both shifted quantities
+         * were 0), and clears C if Z was set (so C indicates that the sum
+         * of the shifted quantities was greater and not equal to 32) */
+        beq     82f
+ .if backwards
+        sub     tmp, base, #1
+        bic     tmp, tmp, #31
+ .else
+        bic     tmp, base, #31
+ .endif
+        bcc     81f
+ .if backwards
+        pld     [tmp, #-32*(prefetch_distance+1)]
+81:
+        pld     [tmp, #-32*prefetch_distance]
+ .else
+        pld     [tmp, #32*(prefetch_distance+2)]
+81:
+        pld     [tmp, #32*(prefetch_distance+1)]
+ .endif
+82:
+.endm
+
+.macro preload_all    backwards, narrow_case, shift, base, remain, tmp0, tmp1
+ .if backwards
+        sub     tmp0, base, #1
+        bic     tmp0, tmp0, #31
+        pld     [tmp0]
+        sub     tmp1, base, remain, lsl #shift
+ .else
+        bic     tmp0, base, #31
+        pld     [tmp0]
+        add     tmp1, base, remain, lsl #shift
+        sub     tmp1, tmp1, #1
+ .endif
+        bic     tmp1, tmp1, #31
+        cmp     tmp1, tmp0
+        beq     92f
+ .if narrow_case
+        /* In this case, all the data fits in either 1 or 2 cache lines */
+        pld     [tmp1]
+ .else
+91:
+  .if backwards
+        sub     tmp0, tmp0, #32
+  .else
+        add     tmp0, tmp0, #32
+  .endif
+        cmp     tmp0, tmp1
+        pld     [tmp0]
+        bne     91b
+ .endif
+92:
+.endm
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/copy_from_user.S linux-5.10.52-v7l+/arch/arm/lib/copy_from_user.S
--- linux-5.10.52-orig/arch/arm/lib/copy_from_user.S	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/lib/copy_from_user.S	2021-07-25 16:45:35.478802025 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:110 @
 
 	.text
 
-ENTRY(arm_copy_from_user)
+ENTRY(__copy_from_user_std)
+WEAK(arm_copy_from_user)
 #ifdef CONFIG_CPU_SPECTRE
 	get_thread_info r3
 	ldr	r3, [r3, #TI_ADDR_LIMIT]
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:121 @
 #include "copy_template.S"
 
 ENDPROC(arm_copy_from_user)
+ENDPROC(__copy_from_user_std)
 
 	.pushsection .text.fixup,"ax"
 	.align 0
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/exports_rpi.c linux-5.10.52-v7l+/arch/arm/lib/exports_rpi.c
--- linux-5.10.52-orig/arch/arm/lib/exports_rpi.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/lib/exports_rpi.c	2021-07-25 16:45:35.478802025 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/**
+ * Copyright (c) 2014, 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 <linux/kernel.h>
+#include <linux/module.h>
+
+EXPORT_SYMBOL(memcmp);
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/Makefile linux-5.10.52-v7l+/arch/arm/lib/Makefile
--- linux-5.10.52-orig/arch/arm/lib/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/lib/Makefile	2021-07-25 16:45:35.478802025 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:10 @
 
 lib-y		:= changebit.o csumipv6.o csumpartial.o               \
 		   csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
-		   delay.o delay-loop.o findbit.o memchr.o memcpy.o   \
-		   memmove.o memset.o setbit.o                        \
+		   delay.o delay-loop.o findbit.o memchr.o            \
+		   setbit.o                                           \
 		   strchr.o strrchr.o                                 \
 		   testchangebit.o testclearbit.o testsetbit.o        \
 		   ashldi3.o ashrdi3.o lshrdi3.o muldi3.o             \
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:28 @
   lib-y	+= backtrace.o
 endif
 
+# Choose optimised implementations for Raspberry Pi
+ifeq ($(CONFIG_BCM2835_FAST_MEMCPY),y)
+  CFLAGS_uaccess_with_memcpy.o += -DCOPY_FROM_USER_THRESHOLD=1600
+  CFLAGS_uaccess_with_memcpy.o += -DCOPY_TO_USER_THRESHOLD=672
+  obj-$(CONFIG_MODULES) += exports_rpi.o
+  lib-y        += memcpy_rpi.o memmove_rpi.o memset_rpi.o memcmp_rpi.o
+else
+  lib-y        += memcpy.o memmove.o memset.o
+endif
+
 # using lib_ here won't override already available weak symbols
 obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
 
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/memcmp_rpi.S linux-5.10.52-v7l+/arch/arm/lib/memcmp_rpi.S
--- linux-5.10.52-orig/arch/arm/lib/memcmp_rpi.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/lib/memcmp_rpi.S	2021-07-25 16:45:35.488801858 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+Copyright (c) 2013, Raspberry Pi Foundation
+Copyright (c) 2013, RISC OS Open Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * 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.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+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 HOLDER 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 <linux/linkage.h>
+#include "arm-mem.h"
+
+/* Prevent the stack from becoming executable */
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
+
+    .text
+    .arch armv6
+    .object_arch armv4
+    .arm
+    .altmacro
+    .p2align 2
+
+.macro memcmp_process_head  unaligned
+ .if unaligned
+        ldr     DAT0, [S_1], #4
+        ldr     DAT1, [S_1], #4
+        ldr     DAT2, [S_1], #4
+        ldr     DAT3, [S_1], #4
+ .else
+        ldmia   S_1!, {DAT0, DAT1, DAT2, DAT3}
+ .endif
+        ldmia   S_2!, {DAT4, DAT5, DAT6, DAT7}
+.endm
+
+.macro memcmp_process_tail
+        cmp     DAT0, DAT4
+        cmpeq   DAT1, DAT5
+        cmpeq   DAT2, DAT6
+        cmpeq   DAT3, DAT7
+        bne     200f
+.endm
+
+.macro memcmp_leading_31bytes
+        movs    DAT0, OFF, lsl #31
+        ldrmib  DAT0, [S_1], #1
+        ldrcsh  DAT1, [S_1], #2
+        ldrmib  DAT4, [S_2], #1
+        ldrcsh  DAT5, [S_2], #2
+        movpl   DAT0, #0
+        movcc   DAT1, #0
+        movpl   DAT4, #0
+        movcc   DAT5, #0
+        submi   N, N, #1
+        subcs   N, N, #2
+        cmp     DAT0, DAT4
+        cmpeq   DAT1, DAT5
+        bne     200f
+        movs    DAT0, OFF, lsl #29
+        ldrmi   DAT0, [S_1], #4
+        ldrcs   DAT1, [S_1], #4
+        ldrcs   DAT2, [S_1], #4
+        ldrmi   DAT4, [S_2], #4
+        ldmcsia S_2!, {DAT5, DAT6}
+        movpl   DAT0, #0
+        movcc   DAT1, #0
+        movcc   DAT2, #0
+        movpl   DAT4, #0
+        movcc   DAT5, #0
+        movcc   DAT6, #0
+        submi   N, N, #4
+        subcs   N, N, #8
+        cmp     DAT0, DAT4
+        cmpeq   DAT1, DAT5
+        cmpeq   DAT2, DAT6
+        bne     200f
+        tst     OFF, #16
+        beq     105f
+        memcmp_process_head  1
+        sub     N, N, #16
+        memcmp_process_tail
+105:
+.endm
+
+.macro memcmp_trailing_15bytes  unaligned
+        movs    N, N, lsl #29
+ .if unaligned
+        ldrcs   DAT0, [S_1], #4
+        ldrcs   DAT1, [S_1], #4
+ .else
+        ldmcsia S_1!, {DAT0, DAT1}
+ .endif
+        ldrmi   DAT2, [S_1], #4
+        ldmcsia S_2!, {DAT4, DAT5}
+        ldrmi   DAT6, [S_2], #4
+        movcc   DAT0, #0
+        movcc   DAT1, #0
+        movpl   DAT2, #0
+        movcc   DAT4, #0
+        movcc   DAT5, #0
+        movpl   DAT6, #0
+        cmp     DAT0, DAT4
+        cmpeq   DAT1, DAT5
+        cmpeq   DAT2, DAT6
+        bne     200f
+        movs    N, N, lsl #2
+        ldrcsh  DAT0, [S_1], #2
+        ldrmib  DAT1, [S_1]
+        ldrcsh  DAT4, [S_2], #2
+        ldrmib  DAT5, [S_2]
+        movcc   DAT0, #0
+        movpl   DAT1, #0
+        movcc   DAT4, #0
+        movpl   DAT5, #0
+        cmp     DAT0, DAT4
+        cmpeq   DAT1, DAT5
+        bne     200f
+.endm
+
+.macro memcmp_long_inner_loop  unaligned
+110:
+        memcmp_process_head  unaligned
+        pld     [S_2, #prefetch_distance*32 + 16]
+        memcmp_process_tail
+        memcmp_process_head  unaligned
+        pld     [S_1, OFF]
+        memcmp_process_tail
+        subs    N, N, #32
+        bhs     110b
+        /* Just before the final (prefetch_distance+1) 32-byte blocks,
+         * deal with final preloads */
+        preload_trailing  0, S_1, N, DAT0
+        preload_trailing  0, S_2, N, DAT0
+        add     N, N, #(prefetch_distance+2)*32 - 16
+120:
+        memcmp_process_head  unaligned
+        memcmp_process_tail
+        subs    N, N, #16
+        bhs     120b
+        /* Trailing words and bytes */
+        tst     N, #15
+        beq     199f
+        memcmp_trailing_15bytes  unaligned
+199:    /* Reached end without detecting a difference */
+        mov     a1, #0
+        setend  le
+        pop     {DAT1-DAT6, pc}
+.endm
+
+.macro memcmp_short_inner_loop  unaligned
+        subs    N, N, #16     /* simplifies inner loop termination */
+        blo     122f
+120:
+        memcmp_process_head  unaligned
+        memcmp_process_tail
+        subs    N, N, #16
+        bhs     120b
+122:    /* Trailing words and bytes */
+        tst     N, #15
+        beq     199f
+        memcmp_trailing_15bytes  unaligned
+199:    /* Reached end without detecting a difference */
+        mov     a1, #0
+        setend  le
+        pop     {DAT1-DAT6, pc}
+.endm
+
+/*
+ * int memcmp(const void *s1, const void *s2, size_t n);
+ * On entry:
+ * a1 = pointer to buffer 1
+ * a2 = pointer to buffer 2
+ * a3 = number of bytes to compare (as unsigned chars)
+ * On exit:
+ * a1 = >0/=0/<0 if s1 >/=/< s2
+ */
+
+.set prefetch_distance, 2
+
+ENTRY(memcmp)
+        S_1     .req    a1
+        S_2     .req    a2
+        N       .req    a3
+        DAT0    .req    a4
+        DAT1    .req    v1
+        DAT2    .req    v2
+        DAT3    .req    v3
+        DAT4    .req    v4
+        DAT5    .req    v5
+        DAT6    .req    v6
+        DAT7    .req    ip
+        OFF     .req    lr
+
+        push    {DAT1-DAT6, lr}
+        setend  be /* lowest-addressed bytes are most significant */
+
+        /* To preload ahead as we go, we need at least (prefetch_distance+2) 32-byte blocks */
+        cmp     N, #(prefetch_distance+3)*32 - 1
+        blo     170f
+
+        /* Long case */
+        /* Adjust N so that the decrement instruction can also test for
+         * inner loop termination. We want it to stop when there are
+         * (prefetch_distance+1) complete blocks to go. */
+        sub     N, N, #(prefetch_distance+2)*32
+        preload_leading_step1  0, DAT0, S_1
+        preload_leading_step1  0, DAT1, S_2
+        tst     S_2, #31
+        beq     154f
+        rsb     OFF, S_2, #0 /* no need to AND with 15 here */
+        preload_leading_step2  0, DAT0, S_1, OFF, DAT2
+        preload_leading_step2  0, DAT1, S_2, OFF, DAT2
+        memcmp_leading_31bytes
+154:    /* Second source now cacheline (32-byte) aligned; we have at
+         * least one prefetch to go. */
+        /* Prefetch offset is best selected such that it lies in the
+         * first 8 of each 32 bytes - but it's just as easy to aim for
+         * the first one */
+        and     OFF, S_1, #31
+        rsb     OFF, OFF, #32*prefetch_distance
+        tst     S_1, #3
+        bne     140f
+        memcmp_long_inner_loop  0
+140:    memcmp_long_inner_loop  1
+
+170:    /* Short case */
+        teq     N, #0
+        beq     199f
+        preload_all 0, 0, 0, S_1, N, DAT0, DAT1
+        preload_all 0, 0, 0, S_2, N, DAT0, DAT1
+        tst     S_2, #3
+        beq     174f
+172:    subs    N, N, #1
+        blo     199f
+        ldrb    DAT0, [S_1], #1
+        ldrb    DAT4, [S_2], #1
+        cmp     DAT0, DAT4
+        bne     200f
+        tst     S_2, #3
+        bne     172b
+174:    /* Second source now 4-byte aligned; we have 0 or more bytes to go */
+        tst     S_1, #3
+        bne     140f
+        memcmp_short_inner_loop  0
+140:    memcmp_short_inner_loop  1
+
+200:    /* Difference found: determine sign. */
+        movhi   a1, #1
+        movlo   a1, #-1
+        setend  le
+        pop     {DAT1-DAT6, pc}
+
+        .unreq  S_1
+        .unreq  S_2
+        .unreq  N
+        .unreq  DAT0
+        .unreq  DAT1
+        .unreq  DAT2
+        .unreq  DAT3
+        .unreq  DAT4
+        .unreq  DAT5
+        .unreq  DAT6
+        .unreq  DAT7
+        .unreq  OFF
+ENDPROC(memcmp)
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/memcpymove.h linux-5.10.52-v7l+/arch/arm/lib/memcpymove.h
--- linux-5.10.52-orig/arch/arm/lib/memcpymove.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/lib/memcpymove.h	2021-07-25 16:45:35.488801858 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+Copyright (c) 2013, Raspberry Pi Foundation
+Copyright (c) 2013, RISC OS Open Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * 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.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+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 HOLDER 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.
+*/
+
+.macro unaligned_words  backwards, align, use_pld, words, r0, r1, r2, r3, r4, r5, r6, r7, r8
+ .if words == 1
+  .if backwards
+        mov     r1, r0, lsl #32-align*8
+        ldr     r0, [S, #-4]!
+        orr     r1, r1, r0, lsr #align*8
+        str     r1, [D, #-4]!
+  .else
+        mov     r0, r1, lsr #align*8
+        ldr     r1, [S, #4]!
+        orr     r0, r0, r1, lsl #32-align*8
+        str     r0, [D], #4
+  .endif
+ .elseif words == 2
+  .if backwards
+        ldr     r1, [S, #-4]!
+        mov     r2, r0, lsl #32-align*8
+        ldr     r0, [S, #-4]!
+        orr     r2, r2, r1, lsr #align*8
+        mov     r1, r1, lsl #32-align*8
+        orr     r1, r1, r0, lsr #align*8
+        stmdb   D!, {r1, r2}
+  .else
+        ldr     r1, [S, #4]!
+        mov     r0, r2, lsr #align*8
+        ldr     r2, [S, #4]!
+        orr     r0, r0, r1, lsl #32-align*8
+        mov     r1, r1, lsr #align*8
+        orr     r1, r1, r2, lsl #32-align*8
+        stmia   D!, {r0, r1}
+  .endif
+ .elseif words == 4
+  .if backwards
+        ldmdb   S!, {r2, r3}
+        mov     r4, r0, lsl #32-align*8
+        ldmdb   S!, {r0, r1}
+        orr     r4, r4, r3, lsr #align*8
+        mov     r3, r3, lsl #32-align*8
+        orr     r3, r3, r2, lsr #align*8
+        mov     r2, r2, lsl #32-align*8
+        orr     r2, r2, r1, lsr #align*8
+        mov     r1, r1, lsl #32-align*8
+        orr     r1, r1, r0, lsr #align*8
+        stmdb   D!, {r1, r2, r3, r4}
+  .else
+        ldmib   S!, {r1, r2}
+        mov     r0, r4, lsr #align*8
+        ldmib   S!, {r3, r4}
+        orr     r0, r0, r1, lsl #32-align*8
+        mov     r1, r1, lsr #align*8
+        orr     r1, r1, r2, lsl #32-align*8
+        mov     r2, r2, lsr #align*8
+        orr     r2, r2, r3, lsl #32-align*8
+        mov     r3, r3, lsr #align*8
+        orr     r3, r3, r4, lsl #32-align*8
+        stmia   D!, {r0, r1, r2, r3}
+  .endif
+ .elseif words == 8
+  .if backwards
+        ldmdb   S!, {r4, r5, r6, r7}
+        mov     r8, r0, lsl #32-align*8
+        ldmdb   S!, {r0, r1, r2, r3}
+   .if use_pld
+        pld     [S, OFF]
+   .endif
+        orr     r8, r8, r7, lsr #align*8
+        mov     r7, r7, lsl #32-align*8
+        orr     r7, r7, r6, lsr #align*8
+        mov     r6, r6, lsl #32-align*8
+        orr     r6, r6, r5, lsr #align*8
+        mov     r5, r5, lsl #32-align*8
+        orr     r5, r5, r4, lsr #align*8
+        mov     r4, r4, lsl #32-align*8
+        orr     r4, r4, r3, lsr #align*8
+        mov     r3, r3, lsl #32-align*8
+        orr     r3, r3, r2, lsr #align*8
+        mov     r2, r2, lsl #32-align*8
+        orr     r2, r2, r1, lsr #align*8
+        mov     r1, r1, lsl #32-align*8
+        orr     r1, r1, r0, lsr #align*8
+        stmdb   D!, {r5, r6, r7, r8}
+        stmdb   D!, {r1, r2, r3, r4}
+  .else
+        ldmib   S!, {r1, r2, r3, r4}
+        mov     r0, r8, lsr #align*8
+        ldmib   S!, {r5, r6, r7, r8}
+   .if use_pld
+        pld     [S, OFF]
+   .endif
+        orr     r0, r0, r1, lsl #32-align*8
+        mov     r1, r1, lsr #align*8
+        orr     r1, r1, r2, lsl #32-align*8
+        mov     r2, r2, lsr #align*8
+        orr     r2, r2, r3, lsl #32-align*8
+        mov     r3, r3, lsr #align*8
+        orr     r3, r3, r4, lsl #32-align*8
+        mov     r4, r4, lsr #align*8
+        orr     r4, r4, r5, lsl #32-align*8
+        mov     r5, r5, lsr #align*8
+        orr     r5, r5, r6, lsl #32-align*8
+        mov     r6, r6, lsr #align*8
+        orr     r6, r6, r7, lsl #32-align*8
+        mov     r7, r7, lsr #align*8
+        orr     r7, r7, r8, lsl #32-align*8
+        stmia   D!, {r0, r1, r2, r3}
+        stmia   D!, {r4, r5, r6, r7}
+  .endif
+ .endif
+.endm
+
+.macro memcpy_leading_15bytes  backwards, align
+        movs    DAT1, DAT2, lsl #31
+        sub     N, N, DAT2
+ .if backwards
+        ldrmib  DAT0, [S, #-1]!
+        ldrcsh  DAT1, [S, #-2]!
+        strmib  DAT0, [D, #-1]!
+        strcsh  DAT1, [D, #-2]!
+ .else
+        ldrmib  DAT0, [S], #1
+        ldrcsh  DAT1, [S], #2
+        strmib  DAT0, [D], #1
+        strcsh  DAT1, [D], #2
+ .endif
+        movs    DAT1, DAT2, lsl #29
+ .if backwards
+        ldrmi   DAT0, [S, #-4]!
+  .if align == 0
+        ldmcsdb S!, {DAT1, DAT2}
+  .else
+        ldrcs   DAT2, [S, #-4]!
+        ldrcs   DAT1, [S, #-4]!
+  .endif
+        strmi   DAT0, [D, #-4]!
+        stmcsdb D!, {DAT1, DAT2}
+ .else
+        ldrmi   DAT0, [S], #4
+  .if align == 0
+        ldmcsia S!, {DAT1, DAT2}
+  .else
+        ldrcs   DAT1, [S], #4
+        ldrcs   DAT2, [S], #4
+  .endif
+        strmi   DAT0, [D], #4
+        stmcsia D!, {DAT1, DAT2}
+ .endif
+.endm
+
+.macro memcpy_trailing_15bytes  backwards, align
+        movs    N, N, lsl #29
+ .if backwards
+  .if align == 0
+        ldmcsdb S!, {DAT0, DAT1}
+  .else
+        ldrcs   DAT1, [S, #-4]!
+        ldrcs   DAT0, [S, #-4]!
+  .endif
+        ldrmi   DAT2, [S, #-4]!
+        stmcsdb D!, {DAT0, DAT1}
+        strmi   DAT2, [D, #-4]!
+ .else
+  .if align == 0
+        ldmcsia S!, {DAT0, DAT1}
+  .else
+        ldrcs   DAT0, [S], #4
+        ldrcs   DAT1, [S], #4
+  .endif
+        ldrmi   DAT2, [S], #4
+        stmcsia D!, {DAT0, DAT1}
+        strmi   DAT2, [D], #4
+ .endif
+        movs    N, N, lsl #2
+ .if backwards
+        ldrcsh  DAT0, [S, #-2]!
+        ldrmib  DAT1, [S, #-1]
+        strcsh  DAT0, [D, #-2]!
+        strmib  DAT1, [D, #-1]
+ .else
+        ldrcsh  DAT0, [S], #2
+        ldrmib  DAT1, [S]
+        strcsh  DAT0, [D], #2
+        strmib  DAT1, [D]
+ .endif
+.endm
+
+.macro memcpy_long_inner_loop  backwards, align
+ .if align != 0
+  .if backwards
+        ldr     DAT0, [S, #-align]!
+  .else
+        ldr     LAST, [S, #-align]!
+  .endif
+ .endif
+110:
+ .if align == 0
+  .if backwards
+        ldmdb   S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
+        pld     [S, OFF]
+        stmdb   D!, {DAT4, DAT5, DAT6, LAST}
+        stmdb   D!, {DAT0, DAT1, DAT2, DAT3}
+  .else
+        ldmia   S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
+        pld     [S, OFF]
+        stmia   D!, {DAT0, DAT1, DAT2, DAT3}
+        stmia   D!, {DAT4, DAT5, DAT6, LAST}
+  .endif
+ .else
+        unaligned_words  backwards, align, 1, 8, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7, LAST
+ .endif
+        subs    N, N, #32
+        bhs     110b
+        /* Just before the final (prefetch_distance+1) 32-byte blocks, deal with final preloads */
+        preload_trailing  backwards, S, N, OFF
+        add     N, N, #(prefetch_distance+2)*32 - 32
+120:
+ .if align == 0
+  .if backwards
+        ldmdb   S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
+        stmdb   D!, {DAT4, DAT5, DAT6, LAST}
+        stmdb   D!, {DAT0, DAT1, DAT2, DAT3}
+  .else
+        ldmia   S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
+        stmia   D!, {DAT0, DAT1, DAT2, DAT3}
+        stmia   D!, {DAT4, DAT5, DAT6, LAST}
+  .endif
+ .else
+        unaligned_words  backwards, align, 0, 8, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7, LAST
+ .endif
+        subs    N, N, #32
+        bhs     120b
+        tst     N, #16
+ .if align == 0
+  .if backwards
+        ldmnedb S!, {DAT0, DAT1, DAT2, LAST}
+        stmnedb D!, {DAT0, DAT1, DAT2, LAST}
+  .else
+        ldmneia S!, {DAT0, DAT1, DAT2, LAST}
+        stmneia D!, {DAT0, DAT1, DAT2, LAST}
+  .endif
+ .else
+        beq     130f
+        unaligned_words  backwards, align, 0, 4, DAT0, DAT1, DAT2, DAT3, LAST
+130:
+ .endif
+        /* Trailing words and bytes */
+        tst      N, #15
+        beq      199f
+ .if align != 0
+        add     S, S, #align
+ .endif
+        memcpy_trailing_15bytes  backwards, align
+199:
+        pop     {DAT3, DAT4, DAT5, DAT6, DAT7}
+        pop     {D, DAT1, DAT2, pc}
+.endm
+
+.macro memcpy_medium_inner_loop  backwards, align
+120:
+ .if backwards
+  .if align == 0
+        ldmdb   S!, {DAT0, DAT1, DAT2, LAST}
+  .else
+        ldr     LAST, [S, #-4]!
+        ldr     DAT2, [S, #-4]!
+        ldr     DAT1, [S, #-4]!
+        ldr     DAT0, [S, #-4]!
+  .endif
+        stmdb   D!, {DAT0, DAT1, DAT2, LAST}
+ .else
+  .if align == 0
+        ldmia   S!, {DAT0, DAT1, DAT2, LAST}
+  .else
+        ldr     DAT0, [S], #4
+        ldr     DAT1, [S], #4
+        ldr     DAT2, [S], #4
+        ldr     LAST, [S], #4
+  .endif
+        stmia   D!, {DAT0, DAT1, DAT2, LAST}
+ .endif
+        subs     N, N, #16
+        bhs      120b
+        /* Trailing words and bytes */
+        tst      N, #15
+        beq      199f
+        memcpy_trailing_15bytes  backwards, align
+199:
+        pop     {D, DAT1, DAT2, pc}
+.endm
+
+.macro memcpy_short_inner_loop  backwards, align
+        tst     N, #16
+ .if backwards
+  .if align == 0
+        ldmnedb S!, {DAT0, DAT1, DAT2, LAST}
+  .else
+        ldrne   LAST, [S, #-4]!
+        ldrne   DAT2, [S, #-4]!
+        ldrne   DAT1, [S, #-4]!
+        ldrne   DAT0, [S, #-4]!
+  .endif
+        stmnedb D!, {DAT0, DAT1, DAT2, LAST}
+ .else
+  .if align == 0
+        ldmneia S!, {DAT0, DAT1, DAT2, LAST}
+  .else
+        ldrne   DAT0, [S], #4
+        ldrne   DAT1, [S], #4
+        ldrne   DAT2, [S], #4
+        ldrne   LAST, [S], #4
+  .endif
+        stmneia D!, {DAT0, DAT1, DAT2, LAST}
+ .endif
+        memcpy_trailing_15bytes  backwards, align
+199:
+        pop     {D, DAT1, DAT2, pc}
+.endm
+
+.macro memcpy backwards
+        D       .req    a1
+        S       .req    a2
+        N       .req    a3
+        DAT0    .req    a4
+        DAT1    .req    v1
+        DAT2    .req    v2
+        DAT3    .req    v3
+        DAT4    .req    v4
+        DAT5    .req    v5
+        DAT6    .req    v6
+        DAT7    .req    sl
+        LAST    .req    ip
+        OFF     .req    lr
+
+        .cfi_startproc
+
+        push    {D, DAT1, DAT2, lr}
+
+        .cfi_def_cfa_offset 16
+        .cfi_rel_offset D, 0
+        .cfi_undefined  S
+        .cfi_undefined  N
+        .cfi_undefined  DAT0
+        .cfi_rel_offset DAT1, 4
+        .cfi_rel_offset DAT2, 8
+        .cfi_undefined  LAST
+        .cfi_rel_offset lr, 12
+
+ .if backwards
+        add     D, D, N
+        add     S, S, N
+ .endif
+
+        /* See if we're guaranteed to have at least one 16-byte aligned 16-byte write */
+        cmp     N, #31
+        blo     170f
+        /* To preload ahead as we go, we need at least (prefetch_distance+2) 32-byte blocks */
+        cmp     N, #(prefetch_distance+3)*32 - 1
+        blo     160f
+
+        /* Long case */
+        push    {DAT3, DAT4, DAT5, DAT6, DAT7}
+
+        .cfi_def_cfa_offset 36
+        .cfi_rel_offset D, 20
+        .cfi_rel_offset DAT1, 24
+        .cfi_rel_offset DAT2, 28
+        .cfi_rel_offset DAT3, 0
+        .cfi_rel_offset DAT4, 4
+        .cfi_rel_offset DAT5, 8
+        .cfi_rel_offset DAT6, 12
+        .cfi_rel_offset DAT7, 16
+        .cfi_rel_offset lr, 32
+
+        /* Adjust N so that the decrement instruction can also test for
+         * inner loop termination. We want it to stop when there are
+         * (prefetch_distance+1) complete blocks to go. */
+        sub     N, N, #(prefetch_distance+2)*32
+        preload_leading_step1  backwards, DAT0, S
+ .if backwards
+        /* Bug in GAS: it accepts, but mis-assembles the instruction
+         * ands    DAT2, D, #60, 2
+         * which sets DAT2 to the number of leading bytes until destination is aligned and also clears C (sets borrow)
+         */
+        .word   0xE210513C
+        beq     154f
+ .else
+        ands    DAT2, D, #15
+        beq     154f
+        rsb     DAT2, DAT2, #16 /* number of leading bytes until destination aligned */
+ .endif
+        preload_leading_step2  backwards, DAT0, S, DAT2, OFF
+        memcpy_leading_15bytes backwards, 1
+154:    /* Destination now 16-byte aligned; we have at least one prefetch as well as at least one 16-byte output block */
+        /* Prefetch offset is best selected such that it lies in the first 8 of each 32 bytes - but it's just as easy to aim for the first one */
+ .if backwards
+        rsb     OFF, S, #3
+        and     OFF, OFF, #28
+        sub     OFF, OFF, #32*(prefetch_distance+1)
+ .else
+        and     OFF, S, #28
+        rsb     OFF, OFF, #32*prefetch_distance
+ .endif
+        movs    DAT0, S, lsl #31
+        bhi     157f
+        bcs     156f
+        bmi     155f
+        memcpy_long_inner_loop  backwards, 0
+155:    memcpy_long_inner_loop  backwards, 1
+156:    memcpy_long_inner_loop  backwards, 2
+157:    memcpy_long_inner_loop  backwards, 3
+
+        .cfi_def_cfa_offset 16
+        .cfi_rel_offset D, 0
+        .cfi_rel_offset DAT1, 4
+        .cfi_rel_offset DAT2, 8
+        .cfi_same_value DAT3
+        .cfi_same_value DAT4
+        .cfi_same_value DAT5
+        .cfi_same_value DAT6
+        .cfi_same_value DAT7
+        .cfi_rel_offset lr, 12
+
+160:    /* Medium case */
+        preload_all  backwards, 0, 0, S, N, DAT2, OFF
+        sub     N, N, #16     /* simplifies inner loop termination */
+ .if backwards
+        ands    DAT2, D, #15
+        beq     164f
+ .else
+        ands    DAT2, D, #15
+        beq     164f
+        rsb     DAT2, DAT2, #16
+ .endif
+        memcpy_leading_15bytes backwards, align
+164:    /* Destination now 16-byte aligned; we have at least one 16-byte output block */
+        tst     S, #3
+        bne     140f
+        memcpy_medium_inner_loop  backwards, 0
+140:    memcpy_medium_inner_loop  backwards, 1
+
+170:    /* Short case, less than 31 bytes, so no guarantee of at least one 16-byte block */
+        teq     N, #0
+        beq     199f
+        preload_all  backwards, 1, 0, S, N, DAT2, LAST
+        tst     D, #3
+        beq     174f
+172:    subs    N, N, #1
+        blo     199f
+ .if backwards
+        ldrb    DAT0, [S, #-1]!
+        strb    DAT0, [D, #-1]!
+ .else
+        ldrb    DAT0, [S], #1
+        strb    DAT0, [D], #1
+ .endif
+        tst     D, #3
+        bne     172b
+174:    /* Destination now 4-byte aligned; we have 0 or more output bytes to go */
+        tst     S, #3
+        bne     140f
+        memcpy_short_inner_loop  backwards, 0
+140:    memcpy_short_inner_loop  backwards, 1
+
+        .cfi_endproc
+
+        .unreq  D
+        .unreq  S
+        .unreq  N
+        .unreq  DAT0
+        .unreq  DAT1
+        .unreq  DAT2
+        .unreq  DAT3
+        .unreq  DAT4
+        .unreq  DAT5
+        .unreq  DAT6
+        .unreq  DAT7
+        .unreq  LAST
+        .unreq  OFF
+.endm
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/memcpy_rpi.S linux-5.10.52-v7l+/arch/arm/lib/memcpy_rpi.S
--- linux-5.10.52-orig/arch/arm/lib/memcpy_rpi.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/lib/memcpy_rpi.S	2021-07-25 16:45:35.488801858 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+Copyright (c) 2013, Raspberry Pi Foundation
+Copyright (c) 2013, RISC OS Open Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * 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.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+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 HOLDER 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 <linux/linkage.h>
+#include "arm-mem.h"
+#include "memcpymove.h"
+
+/* Prevent the stack from becoming executable */
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
+
+    .text
+    .arch armv6
+    .object_arch armv4
+    .arm
+    .altmacro
+    .p2align 2
+
+/*
+ * void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
+ * On entry:
+ * a1 = pointer to destination
+ * a2 = pointer to source
+ * a3 = number of bytes to copy
+ * On exit:
+ * a1 preserved
+ */
+
+.set prefetch_distance, 3
+
+ENTRY(mmiocpy)
+ENTRY(memcpy)
+        memcpy  0
+ENDPROC(memcpy)
+ENDPROC(mmiocpy)
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/memmove_rpi.S linux-5.10.52-v7l+/arch/arm/lib/memmove_rpi.S
--- linux-5.10.52-orig/arch/arm/lib/memmove_rpi.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/lib/memmove_rpi.S	2021-07-25 16:45:35.488801858 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+Copyright (c) 2013, Raspberry Pi Foundation
+Copyright (c) 2013, RISC OS Open Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * 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.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+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 HOLDER 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 <linux/linkage.h>
+#include "arm-mem.h"
+#include "memcpymove.h"
+
+/* Prevent the stack from becoming executable */
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
+
+    .text
+    .arch armv6
+    .object_arch armv4
+    .arm
+    .altmacro
+    .p2align 2
+
+/*
+ * void *memmove(void *s1, const void *s2, size_t n);
+ * On entry:
+ * a1 = pointer to destination
+ * a2 = pointer to source
+ * a3 = number of bytes to copy
+ * On exit:
+ * a1 preserved
+ */
+
+.set prefetch_distance, 3
+
+ENTRY(memmove)
+        cmp     a2, a1
+        bpl     memcpy  /* pl works even over -1 - 0 and 0x7fffffff - 0x80000000 boundaries */
+        memcpy  1
+ENDPROC(memmove)
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/memset_rpi.S linux-5.10.52-v7l+/arch/arm/lib/memset_rpi.S
--- linux-5.10.52-orig/arch/arm/lib/memset_rpi.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm/lib/memset_rpi.S	2021-07-25 16:45:35.488801858 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+Copyright (c) 2013, Raspberry Pi Foundation
+Copyright (c) 2013, RISC OS Open Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * 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.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+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 HOLDER 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 <linux/linkage.h>
+#include "arm-mem.h"
+
+/* Prevent the stack from becoming executable */
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
+
+    .text
+    .arch armv6
+    .object_arch armv4
+    .arm
+    .altmacro
+    .p2align 2
+
+/*
+ *  void *memset(void *s, int c, size_t n);
+ *  On entry:
+ *  a1 = pointer to buffer to fill
+ *  a2 = byte pattern to fill with (caller-narrowed)
+ *  a3 = number of bytes to fill
+ *  On exit:
+ *  a1 preserved
+ */
+ENTRY(mmioset)
+ENTRY(memset)
+ENTRY(__memset32)
+ENTRY(__memset64)
+
+        S       .req    a1
+        DAT0    .req    a2
+        N       .req    a3
+        DAT1    .req    a4
+        DAT2    .req    ip
+        DAT3    .req    lr
+
+        orr     DAT0, DAT0, DAT0, lsl #8
+        push    {S, lr}
+        orr     DAT0, DAT0, DAT0, lsl #16
+        mov     DAT1, DAT0
+
+        /* See if we're guaranteed to have at least one 16-byte aligned 16-byte write */
+        cmp     N, #31
+        blo     170f
+
+161:    sub     N, N, #16     /* simplifies inner loop termination */
+        /* Leading words and bytes */
+        tst     S, #15
+        beq     164f
+        rsb     DAT3, S, #0   /* bits 0-3 = number of leading bytes until aligned */
+        movs    DAT2, DAT3, lsl #31
+        submi   N, N, #1
+        strmib  DAT0, [S], #1
+        subcs   N, N, #2
+        strcsh  DAT0, [S], #2
+        movs    DAT2, DAT3, lsl #29
+        submi   N, N, #4
+        strmi   DAT0, [S], #4
+        subcs   N, N, #8
+        stmcsia S!, {DAT0, DAT1}
+164:    /* Delayed set up of DAT2 and DAT3 so we could use them as scratch registers above */
+        mov     DAT2, DAT0
+        mov     DAT3, DAT0
+        /* Now the inner loop of 16-byte stores */
+165:    stmia   S!, {DAT0, DAT1, DAT2, DAT3}
+        subs    N, N, #16
+        bhs     165b
+166:    /* Trailing words and bytes */
+        movs    N, N, lsl #29
+        stmcsia S!, {DAT0, DAT1}
+        strmi   DAT0, [S], #4
+        movs    N, N, lsl #2
+        strcsh  DAT0, [S], #2
+        strmib  DAT0, [S]
+199:    pop     {S, pc}
+
+170:    /* Short case */
+        mov     DAT2, DAT0
+        mov     DAT3, DAT0
+        tst     S, #3
+        beq     174f
+172:    subs    N, N, #1
+        blo     199b
+        strb    DAT0, [S], #1
+        tst     S, #3
+        bne     172b
+174:    tst     N, #16
+        stmneia S!, {DAT0, DAT1, DAT2, DAT3}
+        b       166b
+
+        .unreq  S
+        .unreq  DAT0
+        .unreq  N
+        .unreq  DAT1
+        .unreq  DAT2
+        .unreq  DAT3
+ENDPROC(__memset64)
+ENDPROC(__memset32)
+ENDPROC(memset)
+ENDPROC(mmioset)
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/lib/uaccess_with_memcpy.c linux-5.10.52-v7l+/arch/arm/lib/uaccess_with_memcpy.c
--- linux-5.10.52-orig/arch/arm/lib/uaccess_with_memcpy.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/lib/uaccess_with_memcpy.c	2021-07-25 16:45:35.488801858 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:22 @
 #include <asm/current.h>
 #include <asm/page.h>
 
+#ifndef COPY_FROM_USER_THRESHOLD
+#define COPY_FROM_USER_THRESHOLD 64
+#endif
+
+#ifndef COPY_TO_USER_THRESHOLD
+#define COPY_TO_USER_THRESHOLD 64
+#endif
+
 static int
 pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:54 @
 		return 0;
 
 	pmd = pmd_offset(pud, addr);
-	if (unlikely(pmd_none(*pmd)))
+	if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
 		return 0;
 
 	/*
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:97 @
 	return 1;
 }
 
-static unsigned long noinline
+static int
+pin_page_for_read(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
+{
+	unsigned long addr = (unsigned long)_addr;
+	pgd_t *pgd;
+	p4d_t *p4d;
+	pmd_t *pmd;
+	pte_t *pte;
+	pud_t *pud;
+	spinlock_t *ptl;
+
+	pgd = pgd_offset(current->mm, addr);
+	if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
+		return 0;
+
+	p4d = p4d_offset(pgd, addr);
+	if (unlikely(p4d_none(*p4d) || p4d_bad(*p4d)))
+		return 0;
+
+	pud = pud_offset(p4d, addr);
+	if (unlikely(pud_none(*pud) || pud_bad(*pud)))
+		return 0;
+
+	pmd = pmd_offset(pud, addr);
+	if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
+		return 0;
+
+	pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
+	if (unlikely(!pte_present(*pte) || !pte_young(*pte))) {
+		pte_unmap_unlock(pte, ptl);
+		return 0;
+	}
+
+	*ptep = pte;
+	*ptlp = ptl;
+
+	return 1;
+}
+
+unsigned long noinline
 __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
 {
 	unsigned long ua_flags;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:189 @
 	return n;
 }
 
+unsigned long noinline
+__copy_from_user_memcpy(void *to, const void __user *from, unsigned long n)
+{
+	unsigned long ua_flags;
+	int atomic;
+
+	if (unlikely(uaccess_kernel())) {
+		memcpy(to, (const void *)from, n);
+		return 0;
+	}
+
+	/* the mmap semaphore is taken only if not in an atomic context */
+	atomic = in_atomic();
+
+	if (!atomic)
+		mmap_read_lock(current->mm);
+	while (n) {
+		pte_t *pte;
+		spinlock_t *ptl;
+		int tocopy;
+
+		while (!pin_page_for_read(from, &pte, &ptl)) {
+			char temp;
+			if (!atomic)
+				mmap_read_unlock(current->mm);
+			if (__get_user(temp, (char __user *)from))
+				goto out;
+			if (!atomic)
+				mmap_read_lock(current->mm);
+		}
+
+		tocopy = (~(unsigned long)from & ~PAGE_MASK) + 1;
+		if (tocopy > n)
+			tocopy = n;
+
+		ua_flags = uaccess_save_and_enable();
+		memcpy(to, (const void *)from, tocopy);
+		uaccess_restore(ua_flags);
+		to += tocopy;
+		from += tocopy;
+		n -= tocopy;
+
+		pte_unmap_unlock(pte, ptl);
+	}
+	if (!atomic)
+		mmap_read_unlock(current->mm);
+
+out:
+	return n;
+}
+
 unsigned long
 arm_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:250 @
 	 * With frame pointer disabled, tail call optimization kicks in
 	 * as well making this test almost invisible.
 	 */
-	if (n < 64) {
+	if (n < COPY_TO_USER_THRESHOLD) {
 		unsigned long ua_flags = uaccess_save_and_enable();
 		n = __copy_to_user_std(to, from, n);
 		uaccess_restore(ua_flags);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:260 @
 	}
 	return n;
 }
+
+unsigned long __must_check
+arm_copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+#ifdef CONFIG_BCM2835_FAST_MEMCPY
+	/*
+	 * This test is stubbed out of the main function above to keep
+	 * the overhead for small copies low by avoiding a large
+	 * register dump on the stack just to reload them right away.
+	 * With frame pointer disabled, tail call optimization kicks in
+	 * as well making this test almost invisible.
+	 */
+	if (n < COPY_TO_USER_THRESHOLD) {
+		unsigned long ua_flags = uaccess_save_and_enable();
+		n = __copy_from_user_std(to, from, n);
+		uaccess_restore(ua_flags);
+	} else {
+		n = __copy_from_user_memcpy(to, from, n);
+	}
+#else
+	unsigned long ua_flags = uaccess_save_and_enable();
+	n = __copy_from_user_std(to, from, n);
+	uaccess_restore(ua_flags);
+#endif
+	return n;
+}
 	
 static unsigned long noinline
 __clear_user_memset(void __user *addr, unsigned long n)
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/mach-bcm/board_bcm2835.c linux-5.10.52-v7l+/arch/arm/mach-bcm/board_bcm2835.c
--- linux-5.10.52-orig/arch/arm/mach-bcm/board_bcm2835.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/mach-bcm/board_bcm2835.c	2021-07-25 16:45:35.498801690 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:8 @
 
 #include <linux/init.h>
 #include <linux/irqchip.h>
+#include <linux/mm.h>
 #include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <asm/system_info.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/memory.h>
+#include <asm/pgtable.h>
 
 #include "platsmp.h"
 
+#define BCM2835_USB_VIRT_BASE   (VMALLOC_START)
+#define BCM2835_USB_VIRT_MPHI   (VMALLOC_START + 0x10000)
+
+static void __init bcm2835_init(void)
+{
+	struct device_node *np = of_find_node_by_path("/system");
+	u32 val;
+	u64 val64;
+
+	if (!of_property_read_u32(np, "linux,revision", &val))
+		system_rev = val;
+	if (!of_property_read_u64(np, "linux,serial", &val64))
+		system_serial_low = val64;
+}
+
+/*
+ * We need to map registers that are going to be accessed by the FIQ
+ * very early, before any kernel threads are spawned. Because if done
+ * later, the mapping tables are not updated instantly but lazily upon
+ * first access through a data abort handler. While that is fine
+ * when executing regular kernel code, if the first access in a specific
+ * thread happens while running FIQ code this will result in a panic.
+ *
+ * For more background see the following old mailing list thread:
+ * https://www.spinics.net/lists/arm-kernel/msg325250.html
+ */
+static int __init bcm2835_map_usb(unsigned long node, const char *uname,
+					int depth, void *data)
+{
+	struct map_desc map[2];
+	const __be32 *reg;
+	int len;
+	unsigned long p2b_offset = *((unsigned long *) data);
+
+	if (!of_flat_dt_is_compatible(node, "brcm,bcm2708-usb"))
+		return 0;
+	reg = of_get_flat_dt_prop(node, "reg", &len);
+	if (!reg || len != (sizeof(unsigned long) * 4))
+		return 0;
+
+	/* Use information about the physical addresses of the
+	 * registers from the device tree, but use legacy
+	 * iotable_init() static mapping function to map them,
+	 * as ioremap() is not functional at this stage in boot.
+	 */
+	map[0].virtual = (unsigned long) BCM2835_USB_VIRT_BASE;
+	map[0].pfn = __phys_to_pfn(be32_to_cpu(reg[0]) - p2b_offset);
+	map[0].length = be32_to_cpu(reg[1]);
+	map[0].type = MT_DEVICE;
+	map[1].virtual = (unsigned long) BCM2835_USB_VIRT_MPHI;
+	map[1].pfn = __phys_to_pfn(be32_to_cpu(reg[2]) - p2b_offset);
+	map[1].length = be32_to_cpu(reg[3]);
+	map[1].type = MT_DEVICE;
+		iotable_init(map, 2);
+
+	return 1;
+}
+
+static void __init bcm2835_map_io(void)
+{
+	const __be32 *ranges, *address_cells;
+	unsigned long root, addr_cells;
+	int soc, len;
+	unsigned long p2b_offset;
+
+	debug_ll_io_init();
+
+	root = of_get_flat_dt_root();
+	/* Find out how to map bus to physical address first from soc/ranges */
+	soc = of_get_flat_dt_subnode_by_name(root, "soc");
+	if (soc < 0)
+		return;
+	address_cells = of_get_flat_dt_prop(root, "#address-cells", &len);
+	if (!address_cells || len < (sizeof(unsigned long)))
+		return;
+	addr_cells = be32_to_cpu(address_cells[0]);
+	ranges = of_get_flat_dt_prop(soc, "ranges", &len);
+	if (!ranges || len < (sizeof(unsigned long) * (2 + addr_cells)))
+		return;
+	p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[addr_cells]);
+
+	/* Now search for bcm2708-usb node in device tree */
+	of_scan_flat_dt(bcm2835_map_usb, &p2b_offset);
+}
+
 static const char * const bcm2835_compat[] = {
 #ifdef CONFIG_ARCH_MULTI_V6
 	"brcm,bcm2835",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:117 @
 };
 
 DT_MACHINE_START(BCM2835, "BCM2835")
+	.map_io = bcm2835_map_io,
+	.init_machine = bcm2835_init,
 	.dt_compat = bcm2835_compat,
 	.smp = smp_ops(bcm2836_smp_ops),
 MACHINE_END
+
+static const char * const bcm2711_compat[] = {
+#ifdef CONFIG_ARCH_MULTI_V7
+	"brcm,bcm2711",
+#endif
+	NULL
+};
+
+DT_MACHINE_START(BCM2711, "BCM2711")
+#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
+	.dma_zone_size	= SZ_1G,
+#endif
+	.map_io = bcm2835_map_io,
+	.init_machine = bcm2835_init,
+	.dt_compat = bcm2711_compat,
+	.smp = smp_ops(bcm2836_smp_ops),
+MACHINE_END
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/mach-bcm/Kconfig linux-5.10.52-v7l+/arch/arm/mach-bcm/Kconfig
--- linux-5.10.52-orig/arch/arm/mach-bcm/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/mach-bcm/Kconfig	2021-07-25 16:45:35.498801690 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:164 @
 	select ARM_TIMER_SP804
 	select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
 	select BCM2835_TIMER
+	select BRCMSTB_L2_IRQ
+	select FIQ
 	select PINCTRL
 	select PINCTRL_BCM2835
 	select MFD_CORE
+	select MFD_SYSCON if ARCH_MULTI_V7
 	help
 	  This enables support for the Broadcom BCM2711 and BCM283x SoCs.
 	  This SoC is used in the Raspberry Pi and Roku 2 devices.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:188 @
 	  The base chip is BCM53573 and there are some packaging modifications
 	  like BCM47189 and BCM47452.
 
+config BCM2835_FAST_MEMCPY
+	bool "Enable optimized __copy_to_user and __copy_from_user"
+	depends on ARCH_BCM2835 && ARCH_MULTI_V6
+	default y
+	help
+	  Optimized versions of __copy_to_user and __copy_from_user for Pi1.
+
 config ARCH_BCM_63XX
 	bool "Broadcom BCM63xx DSL SoC"
 	depends on ARCH_MULTI_V7
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/mm/cache-v6.S linux-5.10.52-v7l+/arch/arm/mm/cache-v6.S
--- linux-5.10.52-orig/arch/arm/mm/cache-v6.S	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/mm/cache-v6.S	2021-07-25 16:45:35.848795822 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:201 @
  *	- start   - virtual start address of region
  *	- end     - virtual end address of region
  */
-v6_dma_inv_range:
+ENTRY(v6_dma_inv_range)
 #ifdef CONFIG_DMA_CACHE_RWFO
 	ldrb	r2, [r0]			@ read for ownership
 	strb	r2, [r0]			@ write for ownership
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:246 @
  *	- start   - virtual start address of region
  *	- end     - virtual end address of region
  */
-v6_dma_clean_range:
+ENTRY(v6_dma_clean_range)
 	bic	r0, r0, #D_CACHE_LINE_SIZE - 1
 1:
 #ifdef CONFIG_DMA_CACHE_RWFO
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/mm/cache-v7.S linux-5.10.52-v7l+/arch/arm/mm/cache-v7.S
--- linux-5.10.52-orig/arch/arm/mm/cache-v7.S	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/mm/cache-v7.S	2021-07-25 16:45:35.848795822 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:366 @
  *	- start   - virtual start address of region
  *	- end     - virtual end address of region
  */
-v7_dma_inv_range:
+ENTRY(b15_dma_inv_range)
+ENTRY(v7_dma_inv_range)
 	dcache_line_size r2, r3
 	sub	r3, r2, #1
 	tst	r0, r3
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:397 @
  *	- start   - virtual start address of region
  *	- end     - virtual end address of region
  */
-v7_dma_clean_range:
+ENTRY(b15_dma_clean_range)
+ENTRY(v7_dma_clean_range)
 	dcache_line_size r2, r3
 	sub	r3, r2, #1
 	bic	r0, r0, r3
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/mm/proc-macros.S linux-5.10.52-v7l+/arch/arm/mm/proc-macros.S
--- linux-5.10.52-orig/arch/arm/mm/proc-macros.S	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/mm/proc-macros.S	2021-07-25 16:45:35.868795487 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:337 @
 	.long	\name\()_flush_kern_dcache_area
 	.long	\name\()_dma_map_area
 	.long	\name\()_dma_unmap_area
+	.long	\name\()_dma_inv_range
+	.long	\name\()_dma_clean_range
 	.long	\name\()_dma_flush_range
 	.size	\name\()_cache_fns, . - \name\()_cache_fns
 .endm
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/mm/proc-syms.c linux-5.10.52-v7l+/arch/arm/mm/proc-syms.c
--- linux-5.10.52-orig/arch/arm/mm/proc-syms.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/mm/proc-syms.c	2021-07-25 16:45:35.868795487 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:30 @
 EXPORT_SYMBOL(__cpuc_flush_user_range);
 EXPORT_SYMBOL(__cpuc_coherent_kern_range);
 EXPORT_SYMBOL(__cpuc_flush_dcache_area);
+EXPORT_SYMBOL(dmac_inv_range);
+EXPORT_SYMBOL(dmac_clean_range);
+EXPORT_SYMBOL(dmac_flush_range);
 #else
 EXPORT_SYMBOL(cpu_cache);
 #endif
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/mm/proc-v6.S linux-5.10.52-v7l+/arch/arm/mm/proc-v6.S
--- linux-5.10.52-orig/arch/arm/mm/proc-v6.S	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/mm/proc-v6.S	2021-07-25 16:45:35.868795487 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:73 @
  *
  *	IRQs are already disabled.
  */
+
+/* See jira SW-5991 for details of this workaround */
 ENTRY(cpu_v6_do_idle)
-	mov	r1, #0
-	mcr	p15, 0, r1, c7, c10, 4		@ DWB - WFI may enter a low-power mode
-	mcr	p15, 0, r1, c7, c0, 4		@ wait for interrupt
+	.align 5
+	mov     r1, #2
+1:	subs	r1, #1
+	nop
+	mcreq	p15, 0, r1, c7, c10, 4		@ DWB - WFI may enter a low-power mode
+	mcreq	p15, 0, r1, c7, c0, 4		@ wait for interrupt
+	nop
+	nop
+	nop
+	bne 1b
 	ret	lr
 
 ENTRY(cpu_v6_dcache_clean_area)
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/mm/proc-v7.S linux-5.10.52-v7l+/arch/arm/mm/proc-v7.S
--- linux-5.10.52-orig/arch/arm/mm/proc-v7.S	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/mm/proc-v7.S	2021-07-25 16:45:35.868795487 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:290 @
 	mov	r10, #0
 1:	adr	r0, __v7_setup_stack_ptr
 	ldr	r12, [r0]
+	tst	r12, #0x1f
+	addeq	r12, r12, #4
 	add	r12, r12, r0			@ the local stack
 	stmia	r12, {r1-r6, lr}		@ v7_invalidate_l1 touches r0-r6
 	bl      v7_invalidate_l1
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:479 @
 	adr	r0, __v7_setup_stack_ptr
 	ldr	r12, [r0]
 	add	r12, r12, r0			@ the local stack
+	tst	r12, #0x1f
+	addeq	r12, r12, #4
 	stmia	r12, {r1-r6, lr}		@ v7_invalidate_l1 touches r0-r6
 	bl      v7_invalidate_l1
 	ldmia	r12, {r1-r6, lr}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:564 @
 	.bss
 	.align	2
 __v7_setup_stack:
-	.space	4 * 7				@ 7 registers
+	.space	4 * 8				@ 7 registers + 1 spare
 
 	__INITDATA
 
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm/vfp/vfpmodule.c linux-5.10.52-v7l+/arch/arm/vfp/vfpmodule.c
--- linux-5.10.52-orig/arch/arm/vfp/vfpmodule.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm/vfp/vfpmodule.c	2021-07-25 16:45:35.898794984 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:179 @
 		 * case the thread migrates to a different CPU. The
 		 * restoring is done lazily.
 		 */
-		if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu])
+		if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
+			/* vfp_save_state oopses on VFP11 if EX bit set */
+			fmxr(FPEXC, fpexc & ~FPEXC_EX);
 			vfp_save_state(vfp_current_hw_state[cpu], fpexc);
+		}
 #endif
 
 		/*
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:460 @
 	/* if vfp is on, then save state for resumption */
 	if (fpexc & FPEXC_EN) {
 		pr_debug("%s: saving vfp state\n", __func__);
+		/* vfp_save_state oopses on VFP11 if EX bit set */
+		fmxr(FPEXC, fpexc & ~FPEXC_EX);
 		vfp_save_state(&ti->vfpstate, fpexc);
 
 		/* disable, just in case */
 		fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
 	} else if (vfp_current_hw_state[ti->cpu]) {
 #ifndef CONFIG_SMP
-		fmxr(FPEXC, fpexc | FPEXC_EN);
+		/* vfp_save_state oopses on VFP11 if EX bit set */
+		fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
 		vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
 		fmxr(FPEXC, fpexc);
 #endif
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:532 @
 		/*
 		 * Save the last VFP state on this CPU.
 		 */
-		fmxr(FPEXC, fpexc | FPEXC_EN);
+		/* vfp_save_state oopses on VFP11 if EX bit set */
+		fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
 		vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN);
 		fmxr(FPEXC, fpexc);
 	}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:599 @
 	struct thread_info *thread = current_thread_info();
 	struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
 	unsigned long fpexc;
+	u32 fpsid = fmrx(FPSID);
 
 	/* Disable VFP to avoid corrupting the new thread state. */
 	vfp_flush_hwstate(thread);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:622 @
 	/* Ensure the VFP is enabled. */
 	fpexc |= FPEXC_EN;
 
-	/* Ensure FPINST2 is invalid and the exception flag is cleared. */
-	fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
+	/* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */
+	if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) {
+		/* Ensure FPINST2 is invalid and the exception flag is cleared. */
+		fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
+	}
+
 	hwstate->fpexc = fpexc;
 
 	hwstate->fpinst = ufp_exc->fpinst;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:741 @
 	cpu = get_cpu();
 
 	fpexc = fmrx(FPEXC) | FPEXC_EN;
-	fmxr(FPEXC, fpexc);
+	/* vfp_save_state oopses on VFP11 if EX bit set */
+	fmxr(FPEXC, fpexc & ~FPEXC_EX);
 
 	/*
 	 * Save the userland NEON/VFP state. Under UP,
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
--- linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts	2021-07-25 16:45:35.938794313 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+#include "../../../../arm/boot/dts/bcm2710-rpi-2-b.dts"
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts
--- linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts	2021-07-25 16:45:35.938794313 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+#include "../../../../arm/boot/dts/bcm2710-rpi-3-b.dts"
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts
--- linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts	2021-07-25 16:45:35.938794313 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+#include "../../../../arm/boot/dts/bcm2710-rpi-3-b-plus.dts"
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts
--- linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts	2021-07-25 16:45:35.938794313 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+#include "../../../../arm/boot/dts/bcm2710-rpi-cm3.dts"
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts
--- linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts	2021-07-25 16:45:35.938794313 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+#include "../../../../arm/boot/dts/bcm2711-rpi-400.dts"
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts
--- linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts	2021-07-25 16:45:35.938794313 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
-// SPDX-License-Identifier: GPL-2.0
-#include "arm/bcm2711-rpi-4-b.dts"
+#include "../../../../arm/boot/dts/bcm2711-rpi-4-b.dts"
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4.dts linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4.dts
--- linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4.dts	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4.dts	2021-07-25 16:45:35.938794313 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+#include "../../../../arm/boot/dts/bcm2711-rpi-cm4.dts"
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/Makefile linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/Makefile
--- linux-5.10.52-orig/arch/arm64/boot/dts/broadcom/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/boot/dts/broadcom/Makefile	2021-07-25 16:45:35.938794313 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
 # SPDX-License-Identifier: GPL-2.0
-dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb \
-			      bcm2837-rpi-3-a-plus.dtb \
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rpi-3-a-plus.dtb \
 			      bcm2837-rpi-3-b.dtb \
 			      bcm2837-rpi-3-b-plus.dtb \
 			      bcm2837-rpi-cm3-io3.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-2-b.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-cm3.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-cm4.dtb
 
 subdir-y	+= northstar2
 subdir-y	+= stingray
+
+# Enable fixups to support overlays on BCM2835 platforms
+ifeq ($(CONFIG_ARCH_BCM2835),y)
+	DTC_FLAGS ?= -@
+endif
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/boot/dts/Makefile linux-5.10.52-v7l+/arch/arm64/boot/dts/Makefile
--- linux-5.10.52-orig/arch/arm64/boot/dts/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/boot/dts/Makefile	2021-07-25 16:45:35.898794984 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:33 @
 subdir-y += toshiba
 subdir-y += xilinx
 subdir-y += zte
+
+subdir-y += overlays
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/configs/bcm2711_defconfig linux-5.10.52-v7l+/arch/arm64/configs/bcm2711_defconfig
--- linux-5.10.52-orig/arch/arm64/configs/bcm2711_defconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm64/configs/bcm2711_defconfig	2021-07-25 16:45:36.088791798 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+CONFIG_LOCALVERSION="-v8"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_GENERIC_IRQ_DEBUGFS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=m
+CONFIG_IKCONFIG_PROC=y
+CONFIG_MEMCG=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_ARCH_BCM2835=y
+# CONFIG_CAVIUM_ERRATUM_22375 is not set
+# CONFIG_CAVIUM_ERRATUM_23154 is not set
+# CONFIG_CAVIUM_ERRATUM_27456 is not set
+CONFIG_COMPAT=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_SETEND_EMULATION=y
+CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+# CONFIG_SUSPEND is not set
+CONFIG_PM=y
+CONFIG_CPU_IDLE=y
+CONFIG_ARM_CPUIDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_KVM=y
+CONFIG_CRYPTO_AES_ARM64_BS=m
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLK_DEV_THROTTLING=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BINFMT_MISC=m
+CONFIG_CLEANCACHE=y
+CONFIG_FRONTSWAP=y
+CONFIG_CMA=y
+CONFIG_ZSWAP=y
+CONFIG_Z3FOLD=m
+CONFIG_ZSMALLOC=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_NET_IPVTI=m
+CONFIG_NET_FOU=m
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BBR=m
+CONFIG_IPV6=m
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_ILA=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETFILTER=y
+CONFIG_BRIDGE_NETFILTER=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_LOG_NETDEV=m
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_NETDEV=y
+CONFIG_NFT_NUMGEN=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_CONNLIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_OBJREF=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_OSF=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
+CONFIG_NF_FLOW_TABLE_INET=m
+CONFIG_NF_FLOW_TABLE=m
+CONFIG_NETFILTER_XT_SET=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_PE_SIP=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_FLOW_TABLE_IPV4=m
+CONFIG_NF_LOG_ARP=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_NF_FLOW_TABLE_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NF_LOG_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
+CONFIG_ATM=m
+CONFIG_L2TP=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_ATALK=m
+CONFIG_6LOWPAN=m
+CONFIG_IEEE802154=m
+CONFIG_IEEE802154_6LOWPAN=m
+CONFIG_MAC802154=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_HHF=m
+CONFIG_NET_SCH_PIE=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_PLUG=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_IPSET=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_BATMAN_ADV=m
+CONFIG_OPENVSWITCH=m
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_NET_PKTGEN=m
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_MKISS=m
+CONFIG_6PACK=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_YAM=m
+CONFIG_CAN=m
+CONFIG_CAN_J1939=m
+CONFIG_CAN_ISOTP=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_SLCAN=m
+CONFIG_CAN_MCP251X=m
+CONFIG_CAN_MCP251XFD=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_CAN_GS_USB=m
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_6LOWPAN=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_HCIUART_BCM=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_ATH3K=m
+CONFIG_CFG80211=m
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_MESH=y
+CONFIG_WIMAX=m
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_NET_9P=m
+CONFIG_NFC=m
+CONFIG_PCI=y
+CONFIG_PCIE_BRCMSTB=y
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_MTD=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_SPI_NOR=m
+CONFIG_MTD_UBI=m
+CONFIG_OF_CONFIGFS=y
+CONFIG_ZRAM=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_ATA_OVER_ETH=m
+CONFIG_BLK_DEV_NVME=y
+CONFIG_EEPROM_AT24=m
+CONFIG_TI_ST=m
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=m
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_ATA=m
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_MV=m
+CONFIG_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_THIN_PROVISIONING=m
+CONFIG_DM_CACHE=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_DELAY=m
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+CONFIG_IFB=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_IPVLAN=m
+CONFIG_VXLAN=m
+CONFIG_NETCONSOLE=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_NET_VRF=m
+CONFIG_BCMGENET=y
+CONFIG_ENC28J60=m
+CONFIG_QCA7000_SPI=m
+CONFIG_QCA7000_UART=m
+CONFIG_WIZNET_W5100=m
+CONFIG_WIZNET_W5100_SPI=m
+CONFIG_MICREL_PHY=y
+CONFIG_MDIO_BITBANG=m
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=y
+CONFIG_USB_LAN78XX=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_AX88179_178A=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SR9700=m
+CONFIG_USB_NET_SR9800=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_NET_KALMIA=m
+CONFIG_USB_NET_QMI_WWAN=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+CONFIG_USB_NET_AQC111=m
+CONFIG_ATH9K=m
+CONFIG_ATH9K_HTC=m
+CONFIG_CARL9170=m
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_USB=m
+CONFIG_AR5523=m
+CONFIG_AT76C50X_USB=m
+CONFIG_B43=m
+# CONFIG_B43_PHY_N is not set
+CONFIG_B43LEGACY=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_USB=y
+CONFIG_BRCMDBG=y
+CONFIG_HOSTAP=m
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MT7601U=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x2U=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RTL8187=m
+CONFIG_RTL8192CU=m
+CONFIG_RTL8XXXU=m
+CONFIG_USB_ZD1201=m
+CONFIG_ZD1211RW=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_WIMAX_I2400M_USB=m
+CONFIG_IEEE802154_AT86RF230=m
+CONFIG_IEEE802154_MRF24J40=m
+CONFIG_IEEE802154_CC2520=m
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_MATRIX=m
+CONFIG_KEYBOARD_CAP11XX=m
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=m
+CONFIG_JOYSTICK_XPAD=m
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_JOYSTICK_PSXPAD_SPI=m
+CONFIG_JOYSTICK_PSXPAD_SPI_FF=y
+CONFIG_JOYSTICK_RPISENSE=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_EXC3000=m
+CONFIG_TOUCHSCREEN_GOODIX=m
+CONFIG_TOUCHSCREEN_ILI210X=m
+CONFIG_TOUCHSCREEN_EDT_FT5X06=m
+CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_STMPE=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_POWERMATE=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_SERIO=m
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_BRCM_CHAR_DRIVERS=y
+CONFIG_BCM_VCIO=y
+CONFIG_BCM2835_DEVGPIOMEM=y
+CONFIG_RPIVID_MEM=m
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_BCM2835AUX=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_SC16IS7XX=m
+CONFIG_SERIAL_SC16IS7XX_SPI=y
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_TTY_PRINTK=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=y
+CONFIG_TCG_TPM=m
+CONFIG_TCG_TIS_SPI=m
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX_GPMUX=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_MUX_PINCTRL=m
+CONFIG_I2C_BCM2708=m
+CONFIG_I2C_BCM2835=m
+CONFIG_I2C_BRCMSTB=m
+CONFIG_I2C_GPIO=m
+CONFIG_I2C_ROBOTFUZZ_OSIF=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_SPI=y
+CONFIG_SPI_BCM2835=m
+CONFIG_SPI_BCM2835AUX=m
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPI_SLAVE=y
+CONFIG_PPS=m
+CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PINCTRL_MCP23S08=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_BCM_VIRT=y
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_ARIZONA=m
+CONFIG_GPIO_FSM=m
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_MOCKUP=m
+CONFIG_W1=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_W1_MASTER_DS1WM=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2408=m
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2438=m
+CONFIG_W1_SLAVE_DS2780=m
+CONFIG_W1_SLAVE_DS2781=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_W1_SLAVE_DS28E17=m
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_RPI_POE_POWER=m
+CONFIG_BATTERY_DS2760=m
+CONFIG_BATTERY_MAX17040=m
+CONFIG_BATTERY_GAUGE_LTC2941=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_GPIO_FAN=m
+CONFIG_SENSORS_IIO_HWMON=m
+CONFIG_SENSORS_JC42=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_RASPBERRYPI_HWMON=m
+CONFIG_SENSORS_RPI_POE_FAN=m
+CONFIG_SENSORS_SHT21=m
+CONFIG_SENSORS_SHT3x=m
+CONFIG_SENSORS_SHTC1=m
+CONFIG_SENSORS_INA2XX=m
+CONFIG_SENSORS_TMP102=m
+CONFIG_THERMAL=y
+CONFIG_BCM2711_THERMAL=y
+CONFIG_BCM2835_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_GPIO_WATCHDOG=m
+CONFIG_BCM2835_WDT=y
+CONFIG_MFD_STMPE=y
+CONFIG_STMPE_SPI=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MFD_ARIZONA_I2C=m
+CONFIG_MFD_ARIZONA_SPI=m
+CONFIG_MFD_WM5102=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_ARIZONA_LDO1=m
+CONFIG_REGULATOR_ARIZONA_MICSUPP=m
+CONFIG_REGULATOR_GPIO=y
+CONFIG_RC_CORE=y
+CONFIG_LIRC=y
+CONFIG_BPF_LIRC_MODE2=y
+CONFIG_RC_DECODERS=y
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_IR_IMON_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_IR_IMON=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_RC_LOOPBACK=m
+CONFIG_IR_GPIO_CIR=m
+CONFIG_IR_GPIO_TX=m
+CONFIG_IR_PWM_TX=m
+CONFIG_IR_TOY=m
+CONFIG_MEDIA_CEC_RC=y
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_USB_PWC=m
+CONFIG_VIDEO_CPIA2=m
+CONFIG_USB_ZR364XX=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_S2255=m
+CONFIG_VIDEO_USBTV=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_STK1160_COMMON=m
+CONFIG_VIDEO_GO7007=m
+CONFIG_VIDEO_GO7007_USB=m
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
+CONFIG_VIDEO_AU0828=m
+CONFIG_VIDEO_AU0828_RC=y
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_ALSA=m
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_VIDEO_TM6000=m
+CONFIG_VIDEO_TM6000_ALSA=m
+CONFIG_VIDEO_TM6000_DVB=m
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_PCTV452E=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_TECHNISAT_USB2=m
+CONFIG_DVB_USB_V2=m
+CONFIG_DVB_USB_AF9015=m
+CONFIG_DVB_USB_AF9035=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_AZ6007=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_LME2510=m
+CONFIG_DVB_USB_MXL111SF=m
+CONFIG_DVB_USB_RTL28XXU=m
+CONFIG_DVB_USB_DVBSKY=m
+CONFIG_SMS_USB_DRV=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+CONFIG_DVB_AS102=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_V4L2=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_RADIO_SI470X=m
+CONFIG_USB_SI470X=m
+CONFIG_I2C_SI470X=m
+CONFIG_RADIO_SI4713=m
+CONFIG_I2C_SI4713=m
+CONFIG_USB_MR800=m
+CONFIG_USB_DSBR=m
+CONFIG_RADIO_SHARK=m
+CONFIG_RADIO_SHARK2=m
+CONFIG_USB_KEENE=m
+CONFIG_USB_MA901=m
+CONFIG_RADIO_TEA5764=m
+CONFIG_RADIO_SAA7706H=m
+CONFIG_RADIO_TEF6862=m
+CONFIG_RADIO_WL1273=m
+CONFIG_RADIO_WL128X=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_BCM2835_UNICAM=m
+CONFIG_V4L_TEST_DRIVERS=y
+CONFIG_VIDEO_VIMC=m
+CONFIG_VIDEO_VIVID=m
+CONFIG_VIDEO_VIM2M=m
+CONFIG_VIDEO_VICODEC=m
+CONFIG_VIDEO_UDA1342=m
+CONFIG_VIDEO_SONY_BTF_MPX=m
+CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_TC358743=m
+CONFIG_VIDEO_TVP5150=m
+CONFIG_VIDEO_TW2804=m
+CONFIG_VIDEO_TW9903=m
+CONFIG_VIDEO_TW9906=m
+CONFIG_VIDEO_IMX219=m
+CONFIG_VIDEO_IMX290=m
+CONFIG_VIDEO_IMX477=m
+CONFIG_VIDEO_OV5647=m
+CONFIG_VIDEO_OV7251=m
+CONFIG_VIDEO_OV7640=m
+CONFIG_VIDEO_OV9281=m
+CONFIG_VIDEO_IRS1125=m
+CONFIG_VIDEO_MT9V011=m
+CONFIG_DRM=m
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_UDL=m
+CONFIG_DRM_PANEL_SIMPLE=m
+CONFIG_DRM_PANEL_JDI_LT070ME05000=m
+CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m
+CONFIG_DRM_DISPLAY_CONNECTOR=m
+CONFIG_DRM_SIMPLE_BRIDGE=m
+CONFIG_DRM_V3D=m
+CONFIG_DRM_VC4=m
+CONFIG_DRM_VC4_HDMI_CEC=y
+CONFIG_TINYDRM_ILI9225=m
+CONFIG_TINYDRM_ILI9341=m
+CONFIG_TINYDRM_MI0283QT=m
+CONFIG_TINYDRM_REPAPER=m
+CONFIG_TINYDRM_ST7586=m
+CONFIG_TINYDRM_ST7735R=m
+CONFIG_DRM_GUD=m
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FB_UDL=m
+CONFIG_FB_SIMPLE=y
+CONFIG_FB_SSD1307=m
+CONFIG_FB_RPISENSE=m
+CONFIG_BACKLIGHT_RPI=m
+CONFIG_BACKLIGHT_GPIO=m
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_ALOOP=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_USB_HIFACE=m
+CONFIG_SND_SOC=m
+CONFIG_SND_BCM2835_SOC_I2S=m
+CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+CONFIG_SND_BCM2708_SOC_PIFI_40=m
+CONFIG_SND_BCM2708_SOC_RPI_CIRRUS=m
+CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m
+CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M=m
+CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
+CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD=m
+CONFIG_SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD=m
+CONFIG_SND_AUDIOSENSE_PI=m
+CONFIG_SND_DIGIDAC1_SOUNDCARD=m
+CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO=m
+CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2=m
+CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS=m
+CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_BOSS2_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_DIGIONE=m
+CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC=m
+CONFIG_SND_BCM2708_SOC_FE_PI_AUDIO=m
+CONFIG_SND_PISOUND=m
+CONFIG_SND_SOC_AD193X_SPI=m
+CONFIG_SND_SOC_AD193X_I2C=m
+CONFIG_SND_SOC_ADAU1701=m
+CONFIG_SND_SOC_ADAU7002=m
+CONFIG_SND_SOC_AK4554=m
+CONFIG_SND_SOC_CS4265=m
+CONFIG_SND_SOC_ICS43432=m
+CONFIG_SND_SOC_MA120X0P=m
+CONFIG_SND_SOC_MAX98357A=m
+CONFIG_SND_SOC_SPDIF=m
+CONFIG_SND_SOC_WM8804_I2C=m
+CONFIG_SND_SOC_WM8960=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_ACRUX=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_ASUS=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_BETOP_FF=m
+CONFIG_HID_BIGBEN_FF=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_EMS_FF=m
+CONFIG_HID_ELECOM=m
+CONFIG_HID_ELO=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_GEMBIRD=m
+CONFIG_HID_HOLTEK=m
+CONFIG_HID_KEYTOUCH=m
+CONFIG_HID_KYE=m
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SONY=m
+CONFIG_SONY_FF=y
+CONFIG_HID_SPEEDLINK=m
+CONFIG_HID_STEAM=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THINGM=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_WACOM=m
+CONFIG_HID_WIIMOTE=m
+CONFIG_HID_XINMO=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_HID_ZYDACRON=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_I2C_HID=m
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=m
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PLATFORM=y
+CONFIG_USB_DWCOTG=y
+CONFIG_USB_PRINTER=m
+CONFIG_USB_TMC=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=y
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USBIP_CORE=m
+CONFIG_USBIP_VHCI_HCD=m
+CONFIG_USBIP_HOST=m
+CONFIG_USBIP_VUDC=m
+CONFIG_USB_DWC2=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_DEBUG=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_YUREX=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_UAC1=y
+CONFIG_USB_CONFIGFS_F_UAC2=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_UVC=y
+CONFIG_USB_CONFIGFS_F_PRINTER=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_MIDI_GADGET=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_ACM_MS=m
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_HID=m
+CONFIG_USB_G_WEBCAM=m
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BCM2835_MMC=y
+CONFIG_MMC_BCM2835_DMA=y
+CONFIG_MMC_BCM2835_SDHOST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_IPROC=y
+CONFIG_MMC_SPI=m
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PCA955X=m
+CONFIG_LEDS_PCA963X=m
+CONFIG_LEDS_IS31FL32XX=m
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_INPUT=y
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_LEDS_TRIGGER_NETDEV=m
+CONFIG_LEDS_TRIGGER_ACTPWR=y
+CONFIG_ACCESSIBILITY=y
+CONFIG_SPEAKUP=m
+CONFIG_SPEAKUP_SYNTH_SOFT=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_ABX80X=m
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_DS1374=m
+CONFIG_RTC_DRV_DS1672=m
+CONFIG_RTC_DRV_MAX6900=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_ISL1208=m
+CONFIG_RTC_DRV_ISL12022=m
+CONFIG_RTC_DRV_X1205=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_PCF85063=m
+CONFIG_RTC_DRV_PCF85363=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_M41T80=m
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_FM3130=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_RX8025=m
+CONFIG_RTC_DRV_EM3027=m
+CONFIG_RTC_DRV_RV3028=m
+CONFIG_RTC_DRV_SD3078=m
+CONFIG_RTC_DRV_M41T93=m
+CONFIG_RTC_DRV_M41T94=m
+CONFIG_RTC_DRV_DS1302=m
+CONFIG_RTC_DRV_DS1305=m
+CONFIG_RTC_DRV_DS1390=m
+CONFIG_RTC_DRV_R9701=m
+CONFIG_RTC_DRV_RX4581=m
+CONFIG_RTC_DRV_RS5C348=m
+CONFIG_RTC_DRV_MAX6902=m
+CONFIG_RTC_DRV_PCF2123=m
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_PCF2127=m
+CONFIG_RTC_DRV_RV3029C2=m
+CONFIG_DMADEVICES=y
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_BCM2708=y
+CONFIG_DMABUF_HEAPS=y
+CONFIG_DMABUF_HEAPS_SYSTEM=y
+CONFIG_DMABUF_HEAPS_CMA=y
+CONFIG_AUXDISPLAY=y
+CONFIG_HD44780=m
+CONFIG_UIO=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_VHOST_NET=m
+CONFIG_VHOST_CROSS_ENDIAN_LEGACY=y
+CONFIG_STAGING=y
+CONFIG_PRISM2_USB=m
+CONFIG_R8712U=m
+CONFIG_R8188EU=m
+CONFIG_VT6656=m
+CONFIG_STAGING_MEDIA=y
+CONFIG_VIDEO_RPIVID=m
+CONFIG_ASHMEM=y
+CONFIG_FB_TFT=m
+CONFIG_FB_TFT_AGM1264K_FL=m
+CONFIG_FB_TFT_BD663474=m
+CONFIG_FB_TFT_HX8340BN=m
+CONFIG_FB_TFT_HX8347D=m
+CONFIG_FB_TFT_HX8353D=m
+CONFIG_FB_TFT_HX8357D=m
+CONFIG_FB_TFT_ILI9163=m
+CONFIG_FB_TFT_ILI9320=m
+CONFIG_FB_TFT_ILI9325=m
+CONFIG_FB_TFT_ILI9340=m
+CONFIG_FB_TFT_ILI9341=m
+CONFIG_FB_TFT_ILI9481=m
+CONFIG_FB_TFT_ILI9486=m
+CONFIG_FB_TFT_PCD8544=m
+CONFIG_FB_TFT_RA8875=m
+CONFIG_FB_TFT_S6D02A1=m
+CONFIG_FB_TFT_S6D1121=m
+CONFIG_FB_TFT_SH1106=m
+CONFIG_FB_TFT_SSD1289=m
+CONFIG_FB_TFT_SSD1306=m
+CONFIG_FB_TFT_SSD1331=m
+CONFIG_FB_TFT_SSD1351=m
+CONFIG_FB_TFT_ST7735R=m
+CONFIG_FB_TFT_ST7789V=m
+CONFIG_FB_TFT_TINYLCD=m
+CONFIG_FB_TFT_TLS8204=m
+CONFIG_FB_TFT_UC1701=m
+CONFIG_FB_TFT_UPD161704=m
+CONFIG_FB_TFT_WATTEROTT=m
+CONFIG_BCM2835_VCHIQ=y
+CONFIG_SND_BCM2835=m
+CONFIG_VIDEO_BCM2835=m
+CONFIG_VIDEO_CODEC_BCM2835=m
+CONFIG_VIDEO_ISP_BCM2835=m
+CONFIG_CLK_RASPBERRYPI=y
+CONFIG_MAILBOX=y
+CONFIG_BCM2835_MBOX=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_RASPBERRYPI_POWER=y
+CONFIG_EXTCON_ARIZONA=m
+CONFIG_IIO=m
+CONFIG_IIO_BUFFER_CB=m
+CONFIG_MCP320X=m
+CONFIG_MCP3422=m
+CONFIG_TI_ADS1015=m
+CONFIG_BME680=m
+CONFIG_CCS811=m
+CONFIG_SENSIRION_SGP30=m
+CONFIG_SPS30=m
+CONFIG_DHT11=m
+CONFIG_HDC100X=m
+CONFIG_HTU21=m
+CONFIG_INV_MPU6050_I2C=m
+CONFIG_APDS9960=m
+CONFIG_BH1750=m
+CONFIG_TSL4531=m
+CONFIG_VEML6070=m
+CONFIG_BMP280=m
+CONFIG_MAXIM_THERMOCOUPLE=m
+CONFIG_MAX31856=m
+CONFIG_PWM_BCM2835=m
+CONFIG_PWM_PCA9685=m
+CONFIG_RPI_AXIPERF=m
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_BINDERFS=y
+CONFIG_NVMEM_RMEM=m
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+CONFIG_JFS_STATISTICS=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_GFS2_FS=m
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_F2FS_FS=y
+CONFIG_FS_ENCRYPTION=y
+CONFIG_FANOTIFY=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_OVERLAY_FS=m
+CONFIG_FSCACHE=y
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_HISTOGRAM=y
+CONFIG_CACHEFILES=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_EXFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_UBIFS_FS=m
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+CONFIG_9P_FS=m
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_DLM=m
+CONFIG_SECURITY=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_LSM=""
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_LIBCRC32C=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=5
+CONFIG_PRINTK_TIME=y
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+CONFIG_KDB_KEYBOARD=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_LATENCYTOP=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_STACK_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_SCHED_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_UPROBE_EVENTS is not set
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/configs/bcmrpi3_defconfig linux-5.10.52-v7l+/arch/arm64/configs/bcmrpi3_defconfig
--- linux-5.10.52-orig/arch/arm64/configs/bcmrpi3_defconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/arch/arm64/configs/bcmrpi3_defconfig	2021-07-25 16:45:36.088791798 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+CONFIG_LOCALVERSION="-v8"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=m
+CONFIG_IKCONFIG_PROC=y
+CONFIG_MEMCG=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_ARCH_BCM2835=y
+# CONFIG_CAVIUM_ERRATUM_22375 is not set
+# CONFIG_CAVIUM_ERRATUM_23154 is not set
+# CONFIG_CAVIUM_ERRATUM_27456 is not set
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=4
+CONFIG_HZ_1000=y
+CONFIG_COMPAT=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_SETEND_EMULATION=y
+CONFIG_RANDOMIZE_BASE=y
+CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+# CONFIG_SUSPEND is not set
+CONFIG_PM=y
+CONFIG_CPU_IDLE=y
+CONFIG_ARM_CPUIDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_CRYPTO_AES_ARM64_BS=m
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BINFMT_MISC=y
+CONFIG_CLEANCACHE=y
+CONFIG_FRONTSWAP=y
+CONFIG_CMA=y
+CONFIG_ZSWAP=y
+CONFIG_Z3FOLD=m
+CONFIG_ZSMALLOC=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_NET_FOU=m
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BBR=m
+CONFIG_IPV6=m
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_ILA=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETFILTER=y
+CONFIG_BRIDGE_NETFILTER=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_LOG_NETDEV=m
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_NETDEV=y
+CONFIG_NFT_NUMGEN=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_CONNLIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_OBJREF=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_OSF=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
+CONFIG_NF_FLOW_TABLE_INET=m
+CONFIG_NF_FLOW_TABLE=m
+CONFIG_NETFILTER_XT_SET=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_PE_SIP=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_FLOW_TABLE_IPV4=m
+CONFIG_NF_LOG_ARP=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_NF_FLOW_TABLE_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NF_LOG_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
+CONFIG_ATM=m
+CONFIG_L2TP=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_ATALK=m
+CONFIG_6LOWPAN=m
+CONFIG_IEEE802154=m
+CONFIG_IEEE802154_6LOWPAN=m
+CONFIG_MAC802154=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_PLUG=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_IPSET=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_BATMAN_ADV=m
+CONFIG_OPENVSWITCH=m
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_NET_PKTGEN=m
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_MKISS=m
+CONFIG_6PACK=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_YAM=m
+CONFIG_CAN=m
+CONFIG_CAN_J1939=m
+CONFIG_CAN_ISOTP=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_MCP251X=m
+CONFIG_CAN_MCP251XFD=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_6LOWPAN=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_HCIUART_BCM=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_ATH3K=m
+CONFIG_CFG80211=m
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_MESH=y
+CONFIG_WIMAX=m
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_NET_9P=m
+CONFIG_NFC=m
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_MTD=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_UBI=m
+CONFIG_OF_CONFIGFS=y
+CONFIG_ZRAM=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_ATA_OVER_ETH=m
+CONFIG_EEPROM_AT24=m
+CONFIG_TI_ST=m
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=m
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_THIN_PROVISIONING=m
+CONFIG_DM_CACHE=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_DELAY=m
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+CONFIG_IFB=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_IPVLAN=m
+CONFIG_VXLAN=m
+CONFIG_NETCONSOLE=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_NET_VRF=m
+CONFIG_ENC28J60=m
+CONFIG_QCA7000_SPI=m
+CONFIG_QCA7000_UART=m
+CONFIG_WIZNET_W5100=m
+CONFIG_WIZNET_W5100_SPI=m
+CONFIG_MDIO_BITBANG=m
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_LAN78XX=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_AX88179_178A=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SR9700=m
+CONFIG_USB_NET_SR9800=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_NET_KALMIA=m
+CONFIG_USB_NET_QMI_WWAN=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+CONFIG_USB_NET_AQC111=m
+CONFIG_ATH9K=m
+CONFIG_ATH9K_HTC=m
+CONFIG_CARL9170=m
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_USB=m
+CONFIG_AR5523=m
+CONFIG_AT76C50X_USB=m
+CONFIG_B43=m
+# CONFIG_B43_PHY_N is not set
+CONFIG_B43LEGACY=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_USB=y
+CONFIG_HOSTAP=m
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MT7601U=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x2U=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RTL8187=m
+CONFIG_RTL8192CU=m
+CONFIG_USB_ZD1201=m
+CONFIG_ZD1211RW=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_WIMAX_I2400M_USB=m
+CONFIG_IEEE802154_AT86RF230=m
+CONFIG_IEEE802154_MRF24J40=m
+CONFIG_IEEE802154_CC2520=m
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_MATRIX=m
+CONFIG_KEYBOARD_CAP11XX=m
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=m
+CONFIG_JOYSTICK_XPAD=m
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_JOYSTICK_RPISENSE=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_ILI210X=m
+CONFIG_TOUCHSCREEN_EKTF2127=m
+CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_STMPE=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_POWERMATE=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_SERIO=m
+CONFIG_SERIO_RAW=m
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_BRCM_CHAR_DRIVERS=y
+CONFIG_BCM_VCIO=y
+CONFIG_BCM2835_DEVGPIOMEM=y
+# CONFIG_BCM2835_SMI_DEV is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_BCM2835AUX=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_SC16IS7XX=m
+CONFIG_SERIAL_SC16IS7XX_SPI=y
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_TTY_PRINTK=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=y
+CONFIG_TCG_TPM=m
+CONFIG_TCG_TIS_SPI=m
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX=m
+CONFIG_I2C_MUX_GPMUX=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_MUX_PINCTRL=m
+CONFIG_I2C_BCM2708=m
+CONFIG_I2C_BCM2835=m
+# CONFIG_I2C_BRCMSTB is not set
+CONFIG_I2C_GPIO=m
+CONFIG_SPI=y
+CONFIG_SPI_BCM2835=m
+CONFIG_SPI_BCM2835AUX=m
+CONFIG_SPI_SPIDEV=y
+CONFIG_PPS=m
+CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_BCM_VIRT=y
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_ARIZONA=m
+CONFIG_GPIO_FSM=m
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_MOCKUP=m
+CONFIG_W1=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_W1_MASTER_DS1WM=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2408=m
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2780=m
+CONFIG_W1_SLAVE_DS2781=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_W1_SLAVE_DS28E17=m
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_RPI_POE_POWER=m
+CONFIG_BATTERY_DS2760=m
+CONFIG_BATTERY_MAX17040=m
+CONFIG_SENSORS_IIO_HWMON=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_RASPBERRYPI_HWMON=m
+CONFIG_SENSORS_RPI_POE_FAN=m
+CONFIG_SENSORS_SHT21=m
+CONFIG_SENSORS_SHTC1=m
+CONFIG_SENSORS_INA2XX=m
+CONFIG_THERMAL=y
+CONFIG_BCM2835_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_BCM2835_WDT=y
+CONFIG_MFD_STMPE=y
+CONFIG_STMPE_SPI=y
+CONFIG_MFD_ARIZONA_I2C=m
+CONFIG_MFD_ARIZONA_SPI=m
+CONFIG_MFD_WM5102=y
+CONFIG_RC_CORE=y
+CONFIG_LIRC=y
+CONFIG_BPF_LIRC_MODE2=y
+CONFIG_RC_DECODERS=y
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_IR_IMON_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_IR_IMON=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_RC_LOOPBACK=m
+CONFIG_IR_GPIO_CIR=m
+CONFIG_IR_GPIO_TX=m
+CONFIG_IR_PWM_TX=m
+CONFIG_IR_TOY=m
+CONFIG_MEDIA_CEC_RC=y
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_USB_PWC=m
+CONFIG_VIDEO_CPIA2=m
+CONFIG_USB_ZR364XX=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_S2255=m
+CONFIG_VIDEO_USBTV=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_STK1160_COMMON=m
+CONFIG_VIDEO_GO7007=m
+CONFIG_VIDEO_GO7007_USB=m
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
+CONFIG_VIDEO_AU0828=m
+CONFIG_DVB_USB_V2=m
+CONFIG_DVB_USB_AF9035=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_AZ6007=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_MXL111SF=m
+CONFIG_DVB_USB_DVBSKY=m
+CONFIG_SMS_USB_DRV=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+CONFIG_DVB_AS102=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_V4L2=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_RADIO_SI470X=m
+CONFIG_USB_SI470X=m
+CONFIG_I2C_SI470X=m
+CONFIG_RADIO_SI4713=m
+CONFIG_I2C_SI4713=m
+CONFIG_USB_MR800=m
+CONFIG_USB_DSBR=m
+CONFIG_RADIO_SHARK=m
+CONFIG_RADIO_SHARK2=m
+CONFIG_USB_KEENE=m
+CONFIG_USB_MA901=m
+CONFIG_RADIO_TEA5764=m
+CONFIG_RADIO_SAA7706H=m
+CONFIG_RADIO_TEF6862=m
+CONFIG_RADIO_WL1273=m
+CONFIG_RADIO_WL128X=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_BCM2835_UNICAM=m
+CONFIG_V4L_TEST_DRIVERS=y
+CONFIG_VIDEO_VIMC=m
+CONFIG_VIDEO_VIVID=m
+CONFIG_VIDEO_VIM2M=m
+CONFIG_VIDEO_VICODEC=m
+CONFIG_VIDEO_UDA1342=m
+CONFIG_VIDEO_SONY_BTF_MPX=m
+CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_TC358743=m
+CONFIG_VIDEO_TVP5150=m
+CONFIG_VIDEO_TW2804=m
+CONFIG_VIDEO_TW9903=m
+CONFIG_VIDEO_TW9906=m
+CONFIG_VIDEO_IMX219=m
+CONFIG_VIDEO_IMX290=m
+CONFIG_VIDEO_IMX477=m
+CONFIG_VIDEO_OV5647=m
+CONFIG_VIDEO_OV7251=m
+CONFIG_VIDEO_OV7640=m
+CONFIG_VIDEO_OV9281=m
+CONFIG_VIDEO_IRS1125=m
+CONFIG_VIDEO_MT9V011=m
+CONFIG_DRM=m
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_UDL=m
+CONFIG_DRM_PANEL_SIMPLE=m
+CONFIG_DRM_PANEL_JDI_LT070ME05000=m
+CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m
+CONFIG_DRM_DISPLAY_CONNECTOR=m
+CONFIG_DRM_SIMPLE_BRIDGE=m
+CONFIG_DRM_VC4=m
+CONFIG_DRM_VC4_HDMI_CEC=y
+CONFIG_DRM_GUD=m
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FB_UDL=m
+CONFIG_FB_SSD1307=m
+CONFIG_FB_RPISENSE=m
+CONFIG_BACKLIGHT_RPI=m
+CONFIG_BACKLIGHT_GPIO=m
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_ALOOP=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_SOC=m
+CONFIG_SND_BCM2835_SOC_I2S=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP=m
+CONFIG_SND_BCM2708_SOC_PIFI_40=m
+CONFIG_SND_BCM2708_SOC_RPI_DAC=m
+CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m
+CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
+CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m
+CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M=m
+CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m
+CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m
+CONFIG_SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD=m
+CONFIG_SND_AUDIOSENSE_PI=m
+CONFIG_SND_DIGIDAC1_SOUNDCARD=m
+CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO=m
+CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC=m
+CONFIG_SND_BCM2708_SOC_ALLO_BOSS2_DAC=m
+CONFIG_SND_PISOUND=m
+CONFIG_SND_SOC_AD193X_SPI=m
+CONFIG_SND_SOC_AD193X_I2C=m
+CONFIG_SND_SOC_ADAU1701=m
+CONFIG_SND_SOC_AK4554=m
+CONFIG_SND_SOC_CS4265=m
+CONFIG_SND_SOC_ICS43432=m
+CONFIG_SND_SOC_MA120X0P=m
+CONFIG_SND_SOC_MAX98357A=m
+CONFIG_SND_SOC_WM8804_I2C=m
+CONFIG_SND_SOC_WM8960=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_HIDRAW=y
+CONFIG_UHID=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_ACRUX=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_BETOP_FF=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_EMS_FF=m
+CONFIG_HID_ELECOM=m
+CONFIG_HID_ELO=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_GEMBIRD=m
+CONFIG_HID_HOLTEK=m
+CONFIG_HID_KEYTOUCH=m
+CONFIG_HID_KYE=m
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SONY=m
+CONFIG_HID_SPEEDLINK=m
+CONFIG_HID_STEAM=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THINGM=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_WACOM=m
+CONFIG_HID_WIIMOTE=m
+CONFIG_HID_XINMO=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_HID_ZYDACRON=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_I2C_HID=m
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=m
+CONFIG_USB_DWCOTG=y
+CONFIG_USB_PRINTER=m
+CONFIG_USB_TMC=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USBIP_CORE=m
+CONFIG_USBIP_VHCI_HCD=m
+CONFIG_USBIP_HOST=m
+CONFIG_USB_DWC2=y
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_DEBUG=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_YUREX=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_USB_GADGET=m
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BCM2835_MMC=y
+CONFIG_MMC_BCM2835_DMA=y
+CONFIG_MMC_BCM2835_SDHOST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_IPROC=m
+CONFIG_MMC_SPI=m
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PCA955X=m
+CONFIG_LEDS_PCA963X=m
+CONFIG_LEDS_IS31FL32XX=m
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_INPUT=y
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_LEDS_TRIGGER_NETDEV=m
+CONFIG_LEDS_TRIGGER_ACTPWR=y
+CONFIG_ACCESSIBILITY=y
+CONFIG_SPEAKUP=m
+CONFIG_SPEAKUP_SYNTH_SOFT=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_ABX80X=m
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_DS1374=m
+CONFIG_RTC_DRV_DS1672=m
+CONFIG_RTC_DRV_MAX6900=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_ISL1208=m
+CONFIG_RTC_DRV_ISL12022=m
+CONFIG_RTC_DRV_X1205=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_PCF85063=m
+CONFIG_RTC_DRV_PCF85363=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_M41T80=m
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_FM3130=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_RX8025=m
+CONFIG_RTC_DRV_EM3027=m
+CONFIG_RTC_DRV_RV3028=m
+CONFIG_RTC_DRV_SD3078=m
+CONFIG_RTC_DRV_M41T93=m
+CONFIG_RTC_DRV_M41T94=m
+CONFIG_RTC_DRV_DS1302=m
+CONFIG_RTC_DRV_DS1305=m
+CONFIG_RTC_DRV_DS1390=m
+CONFIG_RTC_DRV_R9701=m
+CONFIG_RTC_DRV_RX4581=m
+CONFIG_RTC_DRV_RS5C348=m
+CONFIG_RTC_DRV_MAX6902=m
+CONFIG_RTC_DRV_PCF2123=m
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_PCF2127=m
+CONFIG_RTC_DRV_RV3029C2=m
+CONFIG_DMADEVICES=y
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_BCM2708=y
+CONFIG_DMABUF_HEAPS=y
+CONFIG_DMABUF_HEAPS_SYSTEM=y
+CONFIG_DMABUF_HEAPS_CMA=y
+CONFIG_UIO=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_STAGING=y
+CONFIG_PRISM2_USB=m
+CONFIG_R8712U=m
+CONFIG_R8188EU=m
+CONFIG_VT6656=m
+CONFIG_STAGING_MEDIA=y
+CONFIG_ASHMEM=y
+CONFIG_FB_TFT=m
+CONFIG_FB_TFT_AGM1264K_FL=m
+CONFIG_FB_TFT_BD663474=m
+CONFIG_FB_TFT_HX8340BN=m
+CONFIG_FB_TFT_HX8347D=m
+CONFIG_FB_TFT_HX8353D=m
+CONFIG_FB_TFT_HX8357D=m
+CONFIG_FB_TFT_ILI9163=m
+CONFIG_FB_TFT_ILI9320=m
+CONFIG_FB_TFT_ILI9325=m
+CONFIG_FB_TFT_ILI9340=m
+CONFIG_FB_TFT_ILI9341=m
+CONFIG_FB_TFT_ILI9481=m
+CONFIG_FB_TFT_ILI9486=m
+CONFIG_FB_TFT_PCD8544=m
+CONFIG_FB_TFT_RA8875=m
+CONFIG_FB_TFT_S6D02A1=m
+CONFIG_FB_TFT_S6D1121=m
+CONFIG_FB_TFT_SH1106=m
+CONFIG_FB_TFT_SSD1289=m
+CONFIG_FB_TFT_SSD1306=m
+CONFIG_FB_TFT_SSD1331=m
+CONFIG_FB_TFT_SSD1351=m
+CONFIG_FB_TFT_ST7735R=m
+CONFIG_FB_TFT_TINYLCD=m
+CONFIG_FB_TFT_TLS8204=m
+CONFIG_FB_TFT_UC1701=m
+CONFIG_FB_TFT_UPD161704=m
+CONFIG_FB_TFT_WATTEROTT=m
+CONFIG_BCM2835_VCHIQ=y
+CONFIG_SND_BCM2835=m
+CONFIG_VIDEO_BCM2835=m
+CONFIG_VIDEO_CODEC_BCM2835=m
+CONFIG_VIDEO_ISP_BCM2835=m
+CONFIG_CLK_RASPBERRYPI=y
+CONFIG_MAILBOX=y
+CONFIG_BCM2835_MBOX=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_RASPBERRYPI_POWER=y
+CONFIG_EXTCON=m
+CONFIG_EXTCON_ARIZONA=m
+CONFIG_IIO=m
+CONFIG_IIO_BUFFER_CB=m
+CONFIG_MCP320X=m
+CONFIG_MCP3422=m
+CONFIG_BME680=m
+CONFIG_CCS811=m
+CONFIG_SENSIRION_SGP30=m
+CONFIG_SPS30=m
+CONFIG_DHT11=m
+CONFIG_HTU21=m
+CONFIG_APDS9960=m
+CONFIG_BH1750=m
+CONFIG_MAXIM_THERMOCOUPLE=m
+CONFIG_MAX31856=m
+CONFIG_PWM_BCM2835=m
+CONFIG_PWM_PCA9685=m
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_BINDERFS=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+CONFIG_JFS_STATISTICS=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_GFS2_FS=m
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_F2FS_FS=y
+CONFIG_FS_ENCRYPTION=y
+CONFIG_FANOTIFY=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_OVERLAY_FS=m
+CONFIG_FSCACHE=y
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_HISTOGRAM=y
+CONFIG_CACHEFILES=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_EXFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_UBIFS_FS=m
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+CONFIG_9P_FS=m
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_DLM=m
+CONFIG_SECURITY=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_LSM=""
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
+CONFIG_CRC_ITU_T=y
+CONFIG_LIBCRC32C=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=5
+CONFIG_PRINTK_TIME=y
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+CONFIG_KDB_KEYBOARD=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_LATENCYTOP=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_STACK_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_SCHED_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/configs/defconfig linux-5.10.52-v7l+/arch/arm64/configs/defconfig
--- linux-5.10.52-orig/arch/arm64/configs/defconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/configs/defconfig	2021-07-25 16:45:36.088791798 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1030 @
 CONFIG_NVMEM_SUNXI_SID=y
 CONFIG_UNIPHIER_EFUSE=y
 CONFIG_MESON_EFUSE=m
+CONFIG_NVMEM_RMEM=m
 CONFIG_FPGA=y
 CONFIG_FPGA_MGR_STRATIX10_SOC=m
 CONFIG_FPGA_BRIDGE=m
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/crypto/aes-cipher-glue.c linux-5.10.52-v7l+/arch/arm64/crypto/aes-cipher-glue.c
--- linux-5.10.52-orig/arch/arm64/crypto/aes-cipher-glue.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/crypto/aes-cipher-glue.c	2021-07-25 16:45:36.098791631 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:12 @
 #include <linux/crypto.h>
 #include <linux/module.h>
 
+MODULE_ALIAS_CRYPTO("ecb(aes)");
+MODULE_ALIAS_CRYPTO("cbc(aes)");
+MODULE_ALIAS_CRYPTO("ctr(aes)");
+MODULE_ALIAS_CRYPTO("xts(aes)");
+MODULE_ALIAS_CRYPTO("cts(cbc(aes))");
+MODULE_ALIAS_CRYPTO("essiv(cbc(aes),sha256)");
+MODULE_ALIAS_CRYPTO("cmac(aes)");
+MODULE_ALIAS_CRYPTO("xcbc(aes)");
+MODULE_ALIAS_CRYPTO("cbcmac(aes)");
+
 asmlinkage void __aes_arm64_encrypt(u32 *rk, u8 *out, const u8 *in, int rounds);
 asmlinkage void __aes_arm64_decrypt(u32 *rk, u8 *out, const u8 *in, int rounds);
 
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/crypto/aes-glue.c linux-5.10.52-v7l+/arch/arm64/crypto/aes-glue.c
--- linux-5.10.52-orig/arch/arm64/crypto/aes-glue.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/crypto/aes-glue.c	2021-07-25 16:45:36.098791631 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:58 @
 #define aes_mac_update		neon_aes_mac_update
 MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 NEON");
 #endif
-#if defined(USE_V8_CRYPTO_EXTENSIONS) || !IS_ENABLED(CONFIG_CRYPTO_AES_ARM64_BS)
+#if defined(USE_V8_CRYPTO_EXTENSIONS)
 MODULE_ALIAS_CRYPTO("ecb(aes)");
 MODULE_ALIAS_CRYPTO("cbc(aes)");
 MODULE_ALIAS_CRYPTO("ctr(aes)");
 MODULE_ALIAS_CRYPTO("xts(aes)");
-#endif
 MODULE_ALIAS_CRYPTO("cts(cbc(aes))");
 MODULE_ALIAS_CRYPTO("essiv(cbc(aes),sha256)");
 MODULE_ALIAS_CRYPTO("cmac(aes)");
 MODULE_ALIAS_CRYPTO("xcbc(aes)");
 MODULE_ALIAS_CRYPTO("cbcmac(aes)");
+#endif
 
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_LICENSE("GPL v2");
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/crypto/aes-neonbs-glue.c linux-5.10.52-v7l+/arch/arm64/crypto/aes-neonbs-glue.c
--- linux-5.10.52-orig/arch/arm64/crypto/aes-neonbs-glue.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/crypto/aes-neonbs-glue.c	2021-07-25 16:45:36.098791631 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:21 @
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_LICENSE("GPL v2");
 
-MODULE_ALIAS_CRYPTO("ecb(aes)");
-MODULE_ALIAS_CRYPTO("cbc(aes)");
-MODULE_ALIAS_CRYPTO("ctr(aes)");
-MODULE_ALIAS_CRYPTO("xts(aes)");
-
 asmlinkage void aesbs_convert_key(u8 out[], u32 const rk[], int rounds);
 
 asmlinkage void aesbs_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[],
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/Kconfig.platforms linux-5.10.52-v7l+/arch/arm64/Kconfig.platforms
--- linux-5.10.52-orig/arch/arm64/Kconfig.platforms	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/Kconfig.platforms	2021-07-25 16:45:35.898794984 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:42 @
 	select ARM_AMBA
 	select ARM_GIC
 	select ARM_TIMER_SP804
+	select BRCMSTB_L2_IRQ
 	help
 	  This enables support for the Broadcom BCM2837 and BCM2711 SoC.
 	  These SoCs are used in the Raspberry Pi 3 and 4 devices.
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/kernel/armv8_deprecated.c linux-5.10.52-v7l+/arch/arm64/kernel/armv8_deprecated.c
--- linux-5.10.52-orig/arch/arm64/kernel/armv8_deprecated.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/kernel/armv8_deprecated.c	2021-07-25 16:45:36.138790960 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:185 @
 
 	switch (ops->status) {
 	case INSN_DEPRECATED:
+#if 0
 		insn->current_mode = INSN_EMULATE;
 		/* Disable the HW mode if it was turned on at early boot time */
 		run_all_cpu_set_hw_mode(insn, false);
+#else
+		insn->current_mode = INSN_HW;
+		run_all_cpu_set_hw_mode(insn, true);
 		insn->max = INSN_HW;
+#endif
 		break;
 	case INSN_OBSOLETE:
 		insn->current_mode = INSN_UNDEF;
diff -Nur --no-dereference linux-5.10.52-orig/arch/arm64/kernel/cpuinfo.c linux-5.10.52-v7l+/arch/arm64/kernel/cpuinfo.c
--- linux-5.10.52-orig/arch/arm64/kernel/cpuinfo.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/arch/arm64/kernel/cpuinfo.c	2021-07-25 16:45:36.148790792 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:20 @
 #include <linux/elf.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/of_platform.h>
 #include <linux/personality.h>
 #include <linux/preempt.h>
 #include <linux/printk.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:141 @
 {
 	int i, j;
 	bool compat = personality(current->personality) == PER_LINUX32;
+	struct device_node *np;
+	const char *model;
+	const char *serial;
+	u32 revision;
 
 	for_each_online_cpu(i) {
 		struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:205 @
 		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))
+			seq_printf(m, "Revision\t: %04x\n", revision);
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/");
+	if (np) {
+		if (!of_property_read_string(np, "serial-number",
+					     &serial))
+			seq_printf(m, "Serial\t\t: %s\n", serial);
+		if (!of_property_read_string(np, "model",
+					     &model))
+			seq_printf(m, "Model\t\t: %s\n", model);
+		of_node_put(np);
+	}
+
 	return 0;
 }
 
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/admin-guide/media/bcm2835-isp.rst linux-5.10.52-v7l+/Documentation/admin-guide/media/bcm2835-isp.rst
--- linux-5.10.52-orig/Documentation/admin-guide/media/bcm2835-isp.rst	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/admin-guide/media/bcm2835-isp.rst	2021-07-25 16:45:33.208840083 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+.. SPDX-License-Identifier: GPL-2.0
+
+BCM2835 ISP Driver
+==================
+
+Introduction
+------------
+
+The BCM2835 Image Sensor Pipeline (ISP) is a fixed function hardware pipeline
+for performing image processing operations.  Images are fed to the input
+of the ISP through memory frame buffers.  These images may be in various YUV,
+RGB, or Bayer formats.  A typical use case would have Bayer images obtained from
+an image sensor by the BCM2835 Unicam peripheral, written to a memory
+frame buffer, and finally fed into the input of the ISP.  Two concurrent output
+images may be generated in YUV or RGB format at different resolutions.
+Statistics output is also generated for Bayer input images.
+
+The bcm2835-isp driver exposes the following media pads as V4L2 device nodes:
+
+.. tabularcolumns:: |l|l|l|l|
+
+.. cssclass: longtable
+
+.. flat-table::
+
+    * - *Pad*
+      - *Direction*
+      - *Purpose*
+      - *Formats*
+
+    * - "bcm2835-isp0-output0"
+      - sink
+      - Accepts Bayer, RGB or YUV format frame buffers as input to the ISP HW
+        pipeline.
+      - :ref:`RAW8 <V4L2-PIX-FMT-SRGGB8>`,
+        :ref:`RAW10P <V4L2-PIX-FMT-SRGGB10P>`,
+        :ref:`RAW12P <V4L2-PIX-FMT-SRGGB12P>`,
+        :ref:`RAW14P <V4L2-PIX-FMT-SRGGB14P>`,
+        :ref:`RAW16 <V4L2-PIX-FMT-SRGGB16>`,
+        :ref:`RGB24/BGR24 <V4L2-PIX-FMT-RGB24>`,
+        :ref:`YUYV <V4L2-PIX-FMT-YUYV>`,
+        :ref:`YVYU <V4L2-PIX-FMT-YVYU>`,
+        :ref:`UYVY <V4L2-PIX-FMT-UYVY>`,
+        :ref:`VYUY <V4L2-PIX-FMT-VYUY>`,
+        :ref:`YUV420/YVU420 <V4L2-PIX-FMT-YUV420>`
+
+    * - "bcm2835-isp0-capture1"
+      - source
+      - High resolution YUV or RGB processed output from the ISP.
+      - :ref:`RGB565 <V4L2-PIX-FMT-RGB565>`,
+        :ref:`RGB24/BGR24 <V4L2-PIX-FMT-RGB24>`,
+        :ref:`ABGR32 <V4L2-PIX-FMT-ABGR32>`,
+        :ref:`YUYV <V4L2-PIX-FMT-YUYV>`,
+        :ref:`YVYU <V4L2-PIX-FMT-YVYU>`,
+        :ref:`UYVY <V4L2-PIX-FMT-UYVY>`,
+        :ref:`VYUY <V4L2-PIX-FMT-VYUY>`.
+        :ref:`YUV420/YVU420 <V4L2-PIX-FMT-YUV420>`,
+        :ref:`NV12/NV21 <V4L2-PIX-FMT-NV12>`,
+
+    * - "bcm2835-isp0-capture2"
+      - source
+      - Low resolution YUV processed output from the ISP. The output of
+        this pad cannot have a resolution larger than the "bcm2835-isp0-capture1" pad in any dimension.
+      - :ref:`YUYV <V4L2-PIX-FMT-YUYV>`,
+        :ref:`YVYU <V4L2-PIX-FMT-YVYU>`,
+        :ref:`UYVY <V4L2-PIX-FMT-UYVY>`,
+        :ref:`VYUY <V4L2-PIX-FMT-VYUY>`.
+        :ref:`YUV420/YVU420 <V4L2-PIX-FMT-YUV420>`,
+        :ref:`NV12/NV21 <V4L2-PIX-FMT-NV12>`,
+
+    * - "bcm2835-isp0-capture1"
+      - source
+      - Image statistics calculated from the input image provided on the
+        "bcm2835-isp0-output0" pad.  Statistics are only available for Bayer
+        format input images.
+      - :ref:`v4l2-meta-fmt-bcm2835-isp-stats`.
+
+Pipeline Configuration
+----------------------
+
+The ISP pipeline can be configure through user-space by calling
+:ref:`VIDIOC_S_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` on the “bcm2835-isp0-output0”
+node with the appropriate parameters as shown in the table below.
+
+.. tabularcolumns:: |p{2cm}|p{5.0cm}|
+
+.. cssclass: longtable
+
+.. flat-table::
+
+    * - *id*
+      - *Parameter*
+
+    * - ``V4L2_CID_USER_BCM2835_ISP_CC_MATRIX``
+      - struct :c:type:`bcm2835_isp_custom_ccm`
+
+    * - ``V4L2_CID_USER_BCM2835_ISP_LENS_SHADING``
+      - struct :c:type:`bcm2835_isp_lens_shading`
+
+    * - ``V4L2_CID_USER_BCM2835_ISP_BLACK_LEVEL``
+      - struct :c:type:`bcm2835_isp_black_level`
+
+    * - ``V4L2_CID_USER_BCM2835_ISP_GEQ``
+      - struct :c:type:`bcm2835_isp_geq`
+
+    * - ``V4L2_CID_USER_BCM2835_ISP_GAMMA``
+      - struct :c:type:`bcm2835_isp_gamma`
+
+    * - ``V4L2_CID_USER_BCM2835_ISP_DENOISE``
+      - struct :c:type:`bcm2835_isp_denoise`
+
+    * - ``V4L2_CID_USER_BCM2835_ISP_SHARPEN``
+      - struct :c:type:`bcm2835_isp_sharpen`
+
+    * - ``V4L2_CID_USER_BCM2835_ISP_DPC``
+      - struct :c:type:`bcm2835_isp_dpc`
+
+++++++++++++++++++++++++
+Configuration Parameters
+++++++++++++++++++++++++
+
+.. kernel-doc:: include/uapi/linux/bcm2835-isp.h
+   :functions: bcm2835_isp_rational bcm2835_isp_ccm bcm2835_isp_custom_ccm
+                bcm2835_isp_gain_format bcm2835_isp_lens_shading
+                bcm2835_isp_black_level bcm2835_isp_geq bcm2835_isp_gamma
+                bcm2835_isp_denoise bcm2835_isp_sharpen
+                bcm2835_isp_dpc_mode bcm2835_isp_dpc
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml	2021-07-25 16:45:33.378837233 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/raspberrypi,firmware-clocks.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RaspberryPi Firmware Clocks Device Tree Bindings
+
+maintainers:
+  - Maxime Ripard <mripard@kernel.org>
+
+properties:
+  "#clock-cells":
+    const: 1
+
+  compatible:
+    const: raspberrypi,firmware-clocks
+
+required:
+  - "#clock-cells"
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    firmware_clocks: firmware-clocks {
+        compatible = "raspberrypi,firmware-clocks";
+        #clock-cells = <1>;
+    };
+
+...
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml	2021-07-25 16:45:33.408836730 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:56 @
       - const: audio
       - const: cec
 
+  interrupts:
+    items:
+      - description: CEC TX interrupt
+      - description: CEC RX interrupt
+      - description: CEC stuck at low interrupt
+      - description: Wake-up interrupt
+      - description: Hotplug connected interrupt
+      - description: Hotplug removed interrupt
+
+  interrupt-names:
+    items:
+      - const: cec-tx
+      - const: cec-rx
+      - const: cec-low
+      - const: wakeup
+      - const: hpd-connected
+      - const: hpd-removed
+
   ddc:
     allOf:
       - $ref: /schemas/types.yaml#/definitions/phandle
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:111 @
   - resets
   - ddc
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml	2021-07-25 16:45:33.408836730 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:23 @
     enum:
       - brcm,bcm2835-dsi0
       - brcm,bcm2835-dsi1
+      - brcm,bcm2711-dsi1
 
   reg:
     maxItems: 1
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml	2021-07-25 16:45:33.408836730 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:14 @
 
 properties:
   compatible:
-    const: brcm,bcm2835-hdmi
+    enum:
+      - brcm,bcm2835-hdmi
+      - brcm,bcm2711-hdmi0
+      - brcm,bcm2711-hdmi1
 
   reg:
+    oneOf:
+      - items:
+        - description: HDMI register range
+        - description: HD register range
+
+      - items:
+        - description: HDMI controller register range
+        - description: DVP register range
+        - description: HDMI PHY register range
+        - description: Rate Manager register range
+        - description: Packet RAM register range
+        - description: Metadata RAM register range
+        - description: CSC register range
+        - description: CEC register range
+        - description: HD register range
+
+  reg-names:
     items:
-      - description: HDMI register range
-      - description: HD register range
+      - const: hdmi
+      - const: dvp
+      - const: phy
+      - const: rm
+      - const: packet
+      - const: metadata
+      - const: csc
+      - const: cec
+      - const: hd
 
   interrupts:
     minItems: 2
 
   clocks:
-    items:
-      - description: The pixel clock
-      - description: The HDMI state machine clock
+    oneOf:
+      - items:
+        - description: The pixel clock
+        - description: The HDMI state machine clock
+
+      - items:
+        - description: The HDMI state machine clock
 
   clock-names:
-    items:
-      - const: pixel
+    oneOf:
+      - items:
+        - const: pixel
+        - const: hdmi
+
       - const: hdmi
 
   ddc:
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:87 @
   dma-names:
     const: audio-rx
 
+  resets:
+    maxItems: 1
+
 required:
   - compatible
   - reg
-  - interrupts
   - clocks
   - ddc
 
 additionalProperties: false
 
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - brcm,bcm2711-hdmi0
+          - brcm,bcm2711-hdmi1
+
+then:
+  properties:
+    reg:
+      minItems: 9
+
+    clocks:
+      maxItems: 1
+
+    clock-names:
+      maxItems: 1
+
+  required:
+    - reg-names
+    - resets
+
+else:
+  properties:
+    reg:
+      maxItems: 2
+
+    clocks:
+      minItems: 2
+
+    clock-names:
+      minItems: 2
+
+  required:
+    - interrupts
+
 examples:
   - |
     #include <dt-bindings/clock/bcm2835.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:152 @
         clock-names = "pixel", "hdmi";
     };
 
+  - |
+    hdmi0: hdmi@7ef00700 {
+        compatible = "brcm,bcm2711-hdmi0";
+        reg = <0x7ef00700 0x300>,
+              <0x7ef00300 0x200>,
+              <0x7ef00f00 0x80>,
+              <0x7ef00f80 0x80>,
+              <0x7ef01b00 0x200>,
+              <0x7ef01f00 0x400>,
+              <0x7ef00200 0x80>,
+              <0x7ef04300 0x100>,
+              <0x7ef20000 0x100>;
+        reg-names = "hdmi",
+                    "dvp",
+                    "phy",
+                    "rm",
+                    "packet",
+                    "metadata",
+                    "csc",
+                    "cec",
+                    "hd";
+        clocks = <&firmware_clocks 13>;
+        clock-names = "hdmi";
+        resets = <&dvp 0>;
+        ddc = <&ddc0>;
+    };
+
 ...
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml	2021-07-25 16:45:33.408836730 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:24 @
       - brcm,bcm2835-vc4
       - brcm,cygnus-vc4
 
+  raspberrypi,firmware:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: >
+      Phandle to the mailbox node to communicate with the firmware.
+
 required:
   - compatible
 
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml	2021-07-25 16:45:33.408836730 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:14 @
 
 properties:
   compatible:
-    const: brcm,bcm2835-vec
+    enum:
+      - brcm,bcm2835-vec
+      - brcm,bcm2711-vec
 
   reg:
     maxItems: 1
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/display/panel/panel-simple.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/display/panel/panel-simple.yaml	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/display/panel/panel-simple.yaml	2021-07-25 16:45:33.428836395 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:150 @
       - ivo,m133nwf4-r0
         # Innolux AT043TN24 4.3" WQVGA TFT LCD panel
       - innolux,at043tn24
+        # Innolux AT056tN53V1 5.6" VGA (640x480) TFT LCD panel
+      - innolux,at056tn53v1
         # Innolux AT070TN92 7.0" WQVGA TFT LCD panel
       - innolux,at070tn92
         # Innolux G070Y2-L01 7" WVGA (800x480) TFT LCD panel
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt	2021-07-25 16:45:33.478835557 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+Bindings for the Raspberry Pi PoE HAT fan
+
+Required properties:
+- compatible	: "raspberrypi,rpi-poe-fan"
+- firmware	: Reference to the RPi firmware device node
+- pwms		: the PWM that is used to control the PWM fan
+- cooling-levels      : PWM duty cycle values in a range from 0 to 255
+			which correspond to thermal cooling states
+
+Example:
+	fan0: rpi-poe-fan@0 {
+		compatible = "raspberrypi,rpi-poe-fan";
+		firmware = <&firmware>;
+		cooling-min-state = <0>;
+		cooling-max-state = <3>;
+		#cooling-cells = <2>;
+		cooling-levels = <0 50 150 255>;
+		status = "okay";
+	};
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			trips {
+				threshold: trip-point@0 {
+					temperature = <45000>;
+					hysteresis = <5000>;
+					type = "active";
+				};
+				target: trip-point@1 {
+					temperature = <50000>;
+					hysteresis = <2000>;
+					type = "active";
+				};
+				cpu_hot: cpu_hot@0 {
+					temperature = <55000>;
+					hysteresis = <2000>;
+					type = "active";
+				};
+			};
+			cooling-maps {
+				map0 {
+					trip = <&threshold>;
+					cooling-device = <&fan0 0 1>;
+				};
+				map1 {
+					trip = <&target>;
+					cooling-device = <&fan0 1 2>;
+				};
+				map2 {
+					trip = <&cpu_hot>;
+					cooling-device = <&fan0 2 3>;
+				};
+			};
+		};
+	};
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/media/bcm2835-unicam.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/bcm2835-unicam.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/media/bcm2835-unicam.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/bcm2835-unicam.txt	2021-07-25 16:45:33.568834048 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+Broadcom BCM283x Camera Interface (Unicam)
+------------------------------------------
+
+The Unicam block on BCM283x SoCs is the receiver for either
+CSI-2 or CCP2 data from image sensors or similar devices.
+
+The main platform using this SoC is the Raspberry Pi family of boards.
+On the Pi the VideoCore firmware can also control this hardware block,
+and driving it from two different processors will cause issues.
+To avoid this, the firmware checks the device tree configuration
+during boot. If it finds device tree nodes called csi0 or csi1 then
+it will stop the firmware accessing the block, and it can then
+safely be used via the device tree binding.
+
+Required properties:
+===================
+- compatible	: must be "brcm,bcm2835-unicam".
+- reg		: physical base address and length of the register sets for the
+		  device.
+- interrupts	: should contain the IRQ line for this Unicam instance.
+- clocks	: list of clock specifiers, corresponding to entries in
+		  clock-names property.
+- clock-names	: must contain "lp" and "vpu" entries, matching entries in the
+		  clocks property.
+
+Unicam supports a single port node. It should contain one 'port' child node
+with child 'endpoint' node. Please refer to the bindings defined in
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Within the endpoint node the "remote-endpoint" and "data-lanes" properties
+are mandatory.
+Data lane reordering is not supported so the data lanes must be in order,
+starting at 1. The number of data lanes should represent the number of
+usable lanes for the hardware block. That may be limited by either the SoC or
+how the platform presents the interface, and the lower value must be used.
+
+Lane reordering is not supported on the clock lane either, so the optional
+property "clock-lane" will implicitly be <0>.
+Similarly lane inversion is not supported, therefore "lane-polarities" will
+implicitly be <0 0 0 0 0>.
+Neither of these values will be checked.
+
+Example:
+	csi1: csi1@7e801000 {
+		compatible = "brcm,bcm2835-unicam";
+		reg = <0x7e801000 0x800>,
+		      <0x7e802004 0x4>;
+		interrupts = <2 7>;
+		clocks = <&clocks BCM2835_CLOCK_CAM1>,
+			 <&firmware_clocks 4>;
+		clock-names = "lp", "vpu";
+		port {
+			csi1_ep: endpoint {
+				remote-endpoint = <&tc358743_0>;
+				data-lanes = <1 2>;
+			};
+		};
+	};
+
+	i2c0: i2c@7e205000 {
+		tc358743: csi-hdmi-bridge@0f {
+			compatible = "toshiba,tc358743";
+			reg = <0x0f>;
+
+			clocks = <&tc358743_clk>;
+			clock-names = "refclk";
+
+			tc358743_clk: bridge-clk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <27000000>;
+			};
+
+			port {
+				tc358743_0: endpoint {
+					remote-endpoint = <&csi1_ep>;
+					clock-lanes = <0>;
+					data-lanes = <1 2>;
+					clock-noncontinuous;
+					link-frequencies =
+						/bits/ 64 <297000000>;
+				};
+			};
+		};
+	};
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/imx219.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/imx219.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/imx219.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/imx219.txt	2021-07-25 16:45:33.568834048 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+* Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor
+
+The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor with
+an active array size of 3280H x 2464V. It is programmable through I2C
+interface. The I2C address is fixed to 0x10 as per sensor data sheet.
+Image data is sent through MIPI CSI-2, which is configured as either 2 or 4
+data lanes.
+
+Required Properties:
+- compatible: value should be "sony,imx219" for imx219 sensor
+- reg: I2C bus address of the device
+- clocks: reference to the xclk input clock.
+- clock-names: should be "xclk".
+- DOVDD-supply: Digital I/O voltage supply, 1.8 volts
+- AVDD-supply: Analog voltage supply, 2.8 volts
+- DVDD-supply: Digital core voltage supply, 1.2 volts
+
+Optional Properties:
+- xclr-gpios: reference to the GPIO connected to the xclr pin, if any. Must be
+	      released after all supplies are applied.
+	      This is an active high signal to the imx219.
+
+The imx219 device node should contain one 'port' child node with
+an 'endpoint' subnode. For further reading on port node refer to
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Endpoint node required properties for CSI-2 connection are:
+- remote-endpoint: a phandle to the bus receiver's endpoint node.
+- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
+- data-lanes: should be set to <1 2>, or  <1 2 3 4> (two or four lane CSI-2
+  supported)
+
+Example:
+	sensor@10 {
+		compatible = "sony,imx219";
+		reg = <0x10>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&imx219_clk>;
+		clock-names = "xclk";
+		xclr-gpios = <&gpio_sensor 0 0>;
+		DOVDD-supply = <&vgen4_reg>; /* 1.8v */
+		AVDD-supply = <&vgen3_reg>;  /* 2.8v */
+		DVDD-supply = <&vgen2_reg>;  /* 1.2v */
+
+		imx219_clk: camera-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <24000000>;
+		};
+
+		port {
+			sensor_out: endpoint {
+				remote-endpoint = <&csiss_in>;
+				clock-lanes = <0>;
+				data-lanes = <1 2>;
+			};
+		};
+	};
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/imx290.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/imx290.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/imx290.txt	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/imx290.txt	2021-07-25 16:45:33.568834048 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
 * Sony IMX290 1/2.8-Inch CMOS Image Sensor
 
 The Sony IMX290 is a 1/2.8-Inch CMOS Solid-state image sensor with
-Square Pixel for Color Cameras. It is programmable through I2C and 4-wire
-interfaces. The sensor output is available via CMOS logic parallel SDR output,
+Square Pixel for Color or Monochrome Cameras. It is programmable through I2C
+and 4-wire interfaces.
+The sensor output is available via CMOS logic parallel SDR output,
 Low voltage LVDS DDR output and CSI-2 serial data output. The CSI-2 bus is the
 default. No bindings have been defined for the other busses.
 
 Required Properties:
-- compatible: Should be "sony,imx290"
+- compatible: Should be "sony,imx290", or "sony,imx290-mono"
 - reg: I2C bus address of the device
 - clocks: Reference to the xclk clock.
 - clock-names: Should be "xclk".
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/imx378.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/imx378.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/imx378.yaml	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/imx378.yaml	2021-07-25 16:45:33.568834048 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/imx378.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony 1/2.3-Inch 12Mpixel CMOS Digital Image Sensor
+
+maintainers:
+  - Naushir Patuck <naush@raspberypi.com>
+
+description: |-
+  The Sony IMX378 is a 1/2.3-inch CMOS active pixel digital image sensor
+  with an active array size of 4056H x 3040V. It is programmable through
+  I2C interface. The I2C address is fixed to 0x1A as per sensor data sheet.
+  Image data is sent through MIPI CSI-2, which is configured as either 2 or
+  4 data lanes.
+
+properties:
+  compatible:
+    const: sony,imx378
+
+  reg:
+    description: I2C device address
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  VDIG-supply:
+    description:
+      Digital I/O voltage supply, 1.05 volts
+
+  VANA-supply:
+    description:
+      Analog voltage supply, 2.8 volts
+
+  VDDL-supply:
+    description:
+      Digital core voltage supply, 1.8 volts
+
+  reset-gpios:
+    description: |-
+      Reference to the GPIO connected to the xclr pin, if any.
+      Must be released (set high) after all supplies and INCK are applied.
+
+  # See ../video-interfaces.txt for more details
+  port:
+    type: object
+    properties:
+      endpoint:
+        type: object
+        properties:
+          data-lanes:
+            description: |-
+              The sensor supports either two-lane, or four-lane operation.
+              For two-lane operation the property must be set to <1 2>.
+            items:
+              - const: 1
+              - const: 2
+
+          clock-noncontinuous:
+            type: boolean
+            description: |-
+              MIPI CSI-2 clock is non-continuous if this property is present,
+              otherwise it's continuous.
+
+          link-frequencies:
+            allOf:
+              - $ref: /schemas/types.yaml#/definitions/uint64-array
+            description:
+              Allowed data bus frequencies.
+
+        required:
+          - link-frequencies
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - VANA-supply
+  - VDIG-supply
+  - VDDL-supply
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        imx378: sensor@10 {
+            compatible = "sony,imx378";
+            reg = <0x1a>;
+            clocks = <&imx378_clk>;
+            VANA-supply = <&imx378_vana>;   /* 2.8v */
+            VDIG-supply = <&imx378_vdig>;   /* 1.05v */
+            VDDL-supply = <&imx378_vddl>;   /* 1.8v */
+
+            port {
+                imx378_0: endpoint {
+                    remote-endpoint = <&csi1_ep>;
+                    data-lanes = <1 2>;
+                    clock-noncontinuous;
+                    link-frequencies = /bits/ 64 <450000000>;
+                };
+            };
+        };
+    };
+
+...
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/imx477.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/imx477.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/imx477.yaml	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/imx477.yaml	2021-07-25 16:45:33.568834048 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/imx477.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony 1/2.3-Inch 12Mpixel CMOS Digital Image Sensor
+
+maintainers:
+  - Naushir Patuck <naush@raspberypi.com>
+
+description: |-
+  The Sony IMX477 is a 1/2.3-inch CMOS active pixel digital image sensor
+  with an active array size of 4056H x 3040V. It is programmable through
+  I2C interface. The I2C address is fixed to 0x1A as per sensor data sheet.
+  Image data is sent through MIPI CSI-2, which is configured as either 2 or
+  4 data lanes.
+
+properties:
+  compatible:
+    const: sony,imx477
+
+  reg:
+    description: I2C device address
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  VDIG-supply:
+    description:
+      Digital I/O voltage supply, 1.05 volts
+
+  VANA-supply:
+    description:
+      Analog voltage supply, 2.8 volts
+
+  VDDL-supply:
+    description:
+      Digital core voltage supply, 1.8 volts
+
+  reset-gpios:
+    description: |-
+      Reference to the GPIO connected to the xclr pin, if any.
+      Must be released (set high) after all all supplies and INCK are applied.
+
+  # See ../video-interfaces.txt for more details
+  port:
+    type: object
+    properties:
+      endpoint:
+        type: object
+        properties:
+          data-lanes:
+            description: |-
+              The sensor supports either two-lane, or four-lane operation.
+              For two-lane operation the property must be set to <1 2>.
+            items:
+              - const: 1
+              - const: 2
+
+          clock-noncontinuous:
+            type: boolean
+            description: |-
+              MIPI CSI-2 clock is non-continuous if this property is present,
+              otherwise it's continuous.
+
+          link-frequencies:
+            allOf:
+              - $ref: /schemas/types.yaml#/definitions/uint64-array
+            description:
+              Allowed data bus frequencies.
+
+        required:
+          - link-frequencies
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - VANA-supply
+  - VDIG-supply
+  - VDDL-supply
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        imx477: sensor@10 {
+            compatible = "sony,imx477";
+            reg = <0x1a>;
+            clocks = <&imx477_clk>;
+            VANA-supply = <&imx477_vana>;   /* 2.8v */
+            VDIG-supply = <&imx477_vdig>;   /* 1.05v */
+            VDDL-supply = <&imx477_vddl>;   /* 1.8v */
+
+            port {
+                imx477_0: endpoint {
+                    remote-endpoint = <&csi1_ep>;
+                    data-lanes = <1 2>;
+                    clock-noncontinuous;
+                    link-frequencies = /bits/ 64 <450000000>;
+                };
+            };
+        };
+    };
+
+...
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/irs1125.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/irs1125.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/media/i2c/irs1125.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/i2c/irs1125.txt	2021-07-25 16:45:33.568834048 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+* Infineon irs1125 time of flight sensor
+
+The Infineon irs1125 is a time of flight digital image sensor with
+an active array size of 352H x 286V. It is programmable through I2C
+interface. The I2C address defaults to 0x3D, but can be reconfigured
+to address 0x3C or 0x41 via I2C commands. Image data is sent through
+MIPI CSI-2, which is configured as either 1 or 2 data lanes.
+
+Required Properties:
+- compatible: value should be "infineon,irs1125" for irs1125 sensor
+- reg: I2C bus address of the device
+- clocks: reference to the xclk input clock.
+- pwdn-gpios: reference to the GPIO connected to the reset pin.
+	      This is an active low signal to the iirs1125.
+
+The irs1125 device node should contain one 'port' child node with
+an 'endpoint' subnode. For further reading on port node refer to
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Endpoint node required properties for CSI-2 connection are:
+- remote-endpoint: a phandle to the bus receiver's endpoint node.
+- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
+- data-lanes: should be set to <1> or <1 2> (one or two lane CSI-2
+  supported)
+
+Example:
+	sensor@10 {
+		compatible = "infineon,irs1125";
+		reg = <0x3D>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&irs1125_clk>;
+		pwdn-gpios = <&gpio 5 0>;
+
+		irs1125_clk: camera-clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <26000000>;
+		};
+
+		port {
+			sensor_out: endpoint {
+				remote-endpoint = <&csiss_in>;
+				clock-lanes = <0>;
+				data-lanes = <1 2>;
+			};
+		};
+	};
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/media/rpivid_hevc.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/rpivid_hevc.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/media/rpivid_hevc.yaml	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/media/rpivid_hevc.yaml	2021-07-25 16:45:33.578833880 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/rpivid_hevc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Raspberry Pi HEVC Decoder
+
+maintainers:
+  - Raspberry Pi <kernel-list@raspberrypi.com>
+
+description: |-
+  The Camera Adaptation Layer (CAL) is a key component for image capture
+  applications. The capture module provides the system interface and the
+  processing capability to connect CSI2 image-sensor modules to the
+  DRA72x device.
+
+properties:
+  compatible:
+    enum:
+      - raspberrypi,rpivid-vid-decoder
+
+  reg:
+    minItems: 2
+    items:
+      - description: The HEVC main register region
+      - description: The Interrupt controller register region
+
+  reg-names:
+    minItems: 2
+    items:
+      - const: hevc
+      - const: intc
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: The HEVC block clock
+
+  clock-names:
+    items:
+      - const: hevc
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    video-codec@7eb10000 {
+        compatible = "raspberrypi,rpivid-vid-decoder";
+        reg = <0x0 0x7eb10000 0x1000>,	/* INTC */
+              <0x0 0x7eb00000 0x10000>; /* HEVC */
+        reg-names = "intc",
+                    "hevc";
+
+        interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+
+        clocks = <&clk 0>;
+        clock-names = "hevc";
+    };
+
+...
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt	2021-07-25 16:45:33.608833377 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+* Broadcom BCM2835 SMI character device driver.
+
+SMI or secondary memory interface is a peripheral specific to certain Broadcom
+SOCs, and is helpful for talking to things like parallel-interface displays
+and NAND flashes (in fact, most things with a parallel register interface).
+
+This driver adds a character device which provides a user-space interface to
+an instance of the SMI driver.
+
+Required properties:
+- compatible: "brcm,bcm2835-smi-dev"
+- smi_handle: a phandle to the smi node.
+
+Optional properties:
+- None.
+
+
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt	2021-07-25 16:45:33.608833377 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+* Broadcom BCM2835 SMI driver.
+
+SMI or secondary memory interface is a peripheral specific to certain Broadcom
+SOCs, and is helpful for talking to things like parallel-interface displays
+and NAND flashes (in fact, most things with a parallel register interface).
+
+Required properties:
+- compatible: "brcm,bcm2835-smi"
+- reg: Should contain location and length of SMI registers and SMI clkman regs
+- interrupts: *the* SMI interrupt.
+- pinctrl-names: should be "default".
+- pinctrl-0: the phandle of the gpio pin node.
+- brcm,smi-clock-source: the clock source for clkman
+- brcm,smi-clock-divisor: the integer clock divisor for clkman
+- dmas: the dma controller phandle and the DREQ number (4 on a 2835)
+- dma-names: the name used by the driver to request its channel.
+  Should be "rx-tx".
+
+Optional properties:
+- None.
+
+Examples:
+
+8 data pin configuration:
+
+smi: smi@7e600000 {
+	compatible = "brcm,bcm2835-smi";
+	reg = <0x7e600000 0x44>, <0x7e1010b0 0x8>;
+	interrupts = <2 16>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&smi_pins>;
+	brcm,smi-clock-source = <6>;
+	brcm,smi-clock-divisor = <4>;
+	dmas = <&dma 4>;
+	dma-names = "rx-tx";
+
+	status = "okay";
+};
+
+smi_pins: smi_pins {
+	brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
+	/* Alt 1: SMI */
+	brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5>;
+	/* /CS, /WE and /OE are pulled high, as they are
+	   generally active low signals */
+	brcm,pull = <2 2 2 2 2 2 0 0 0 0 0 0 0 0>;
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/net/microchip,lan78xx.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/net/microchip,lan78xx.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/net/microchip,lan78xx.txt	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/net/microchip,lan78xx.txt	2021-07-25 16:45:33.658832539 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:17 @
 - microchip,led-modes: a 0..4 element vector, with each element configuring
   the operating mode of an LED. Omitted LEDs are turned off. Allowed values
   are defined in "include/dt-bindings/net/microchip-lan78xx.h".
+- microchip,downshift-after: sets the number of failed auto-negotiation
+  attempts after which the link is downgraded from 1000BASE-T. Should be one of
+  2, 3, 4, 5 or 0, where 0 means never downshift.
 
 Example:
 
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/nvmem/rmem.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/nvmem/rmem.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/nvmem/rmem.yaml	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/nvmem/rmem.yaml	2021-07-25 16:45:33.668832371 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/rmem.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Reserved Memory Based nvmem Device
+
+maintainers:
+  - Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+
+allOf:
+  - $ref: "nvmem.yaml#"
+
+properties:
+  compatible:
+    items:
+      - enum:
+        - raspberrypi,bootloader-config
+      - const: nvmem-rmem
+
+  no-map:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Avoid creating a virtual mapping of the region as part of the OS'
+      standard mapping of system memory.
+
+required:
+  - compatible
+  - no-map
+
+unevaluatedProperties: false
+
+examples:
+  - |
+        reserved-memory {
+                #address-cells = <1>;
+                #size-cells = <1>;
+
+                blconfig: nvram@10000000 {
+                        compatible = "raspberrypi,bootloader-config", "nvmem-rmem";
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+                        reg = <0x10000000 0x1000>;
+                        no-map;
+                };
+        };
+
+...
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt	2021-07-25 16:45:33.678832204 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+Brcmstb PCIe Host Controller Device Tree Bindings
+
+Required Properties:
+- compatible
+  "brcm,bcm7425-pcie" -- for 7425 family MIPS-based SOCs.
+  "brcm,bcm7435-pcie" -- for 7435 family MIPS-based SOCs.
+  "brcm,bcm7445-pcie" -- for 7445 and later ARM based SOCs (not including
+      the 7278).
+  "brcm,bcm7278-pcie"  -- for 7278 family ARM-based SOCs.
+
+- reg -- the register start address and length for the PCIe reg block.
+- interrupts -- two interrupts are specified; the first interrupt is for
+     the PCI host controller and the second is for MSI if the built-in
+     MSI controller is to be used.
+- interrupt-names -- names of the interrupts (above): "pcie" and "msi".
+- #address-cells -- set to <3>.
+- #size-cells -- set to <2>.
+- #interrupt-cells: set to <1>.
+- interrupt-map-mask and interrupt-map, standard PCI properties to define the
+     mapping of the PCIe interface to interrupt numbers.
+- ranges: ranges for the PCI memory and I/O regions.
+- linux,pci-domain -- should be unique per host controller.
+
+Optional Properties:
+- clocks -- phandle of pcie clock.
+- clock-names -- set to "sw_pcie" if clocks is used.
+- dma-ranges -- Specifies the inbound memory mapping regions when
+     an "identity map" is not possible.
+- msi-controller -- this property is typically specified to have the
+     PCIe controller use its internal MSI controller.
+- msi-parent -- set to use an external MSI interrupt controller.
+- brcm,enable-ssc -- (boolean) indicates usage of spread-spectrum clocking.
+- max-link-speed --  (integer) indicates desired generation of link:
+     1 => 2.5 Gbps (gen1), 2 => 5.0 Gbps (gen2), 3 => 8.0 Gbps (gen3).
+
+Example Node:
+
+pcie0: pcie@f0460000 {
+		reg = <0x0 0xf0460000 0x0 0x9310>;
+		interrupts = <0x0 0x0 0x4>;
+		compatible = "brcm,bcm7445-pcie";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges = <0x02000000 0x00000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x08000000
+			  0x02000000 0x00000000 0x08000000 0x00000000 0xc8000000 0x00000000 0x08000000>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 7>;
+		interrupt-map = <0 0 0 1 &intc 0 47 3
+				 0 0 0 2 &intc 0 48 3
+				 0 0 0 3 &intc 0 49 3
+				 0 0 0 4 &intc 0 50 3>;
+		clocks = <&sw_pcie0>;
+		clock-names = "sw_pcie";
+		msi-parent = <&pcie0>;  /* use PCIe's internal MSI controller */
+		msi-controller;         /* use PCIe's internal MSI controller */
+		brcm,ssc;
+		max-link-speed = <1>;
+		linux,pci-domain = <0>;
+	};
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt	2021-07-25 16:45:33.728831365 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:34 @
 - inactive-delay-ms: Delay (default 100) to wait after driving gpio inactive
 - timeout-ms: Time to wait before asserting a WARN_ON(1). If nothing is
               specified, 3000 ms is used.
+- export : Export the GPIO line to the sysfs system
 
 Examples:
 
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/serial/pl011.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/serial/pl011.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/serial/pl011.yaml	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/serial/pl011.yaml	2021-07-25 16:45:33.798830192 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:101 @
     $ref: /schemas/types.yaml#/definitions/uint32
     default: 3000
 
+  cts-event-workaround:
+    description:
+      Enables the (otherwise vendor-specific) workaround for the
+      CTS-induced TX lockup.
+    type: boolean
+
 required:
   - compatible
   - reg
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/vendor-prefixes.txt linux-5.10.52-v7l+/Documentation/devicetree/bindings/vendor-prefixes.txt
--- linux-5.10.52-orig/Documentation/devicetree/bindings/vendor-prefixes.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/vendor-prefixes.txt	2021-07-25 16:45:33.898828515 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+Device tree binding vendor prefix registry.  Keep list in alphabetical order.
+
+This isn't an exhaustive list, but you should add new prefixes to it before
+using them to avoid name-space collisions.
+
+abilis	Abilis Systems
+abracon	Abracon Corporation
+actions	Actions Semiconductor Co., Ltd.
+active-semi	Active-Semi International Inc
+ad	Avionic Design GmbH
+adafruit	Adafruit Industries, LLC
+adapteva	Adapteva, Inc.
+adaptrum	Adaptrum, Inc.
+adh	AD Holdings Plc.
+adi	Analog Devices, Inc.
+advantech	Advantech Corporation
+aeroflexgaisler	Aeroflex Gaisler AB
+al	Annapurna Labs
+allo	Allo.com
+allwinner	Allwinner Technology Co., Ltd.
+alphascale	AlphaScale Integrated Circuits Systems, Inc.
+altr	Altera Corp.
+amarula	Amarula Solutions
+amazon	Amazon.com, Inc.
+amcc	Applied Micro Circuits Corporation (APM, formally AMCC)
+amd	Advanced Micro Devices (AMD), Inc.
+amediatech	Shenzhen Amediatech Technology Co., Ltd
+amlogic	Amlogic, Inc.
+ampire	Ampire Co., Ltd.
+ams	AMS AG
+amstaos	AMS-Taos Inc.
+analogix	Analogix Semiconductor, Inc.
+andestech	Andes Technology Corporation
+apm	Applied Micro Circuits Corporation (APM)
+aptina	Aptina Imaging
+arasan	Arasan Chip Systems
+archermind ArcherMind Technology (Nanjing) Co., Ltd.
+arctic	Arctic Sand
+aries	Aries Embedded GmbH
+arm	ARM Ltd.
+armadeus	ARMadeus Systems SARL
+arrow	Arrow Electronics
+artesyn	Artesyn Embedded Technologies Inc.
+asahi-kasei	Asahi Kasei Corp.
+aspeed	ASPEED Technology Inc.
+asus	AsusTek Computer Inc.
+atlas	Atlas Scientific LLC
+atmel	Atmel Corporation
+auo	AU Optronics Corporation
+auvidea Auvidea GmbH
+avago	Avago Technologies
+avia	avia semiconductor
+avic	Shanghai AVIC Optoelectronics Co., Ltd.
+avnet	Avnet, Inc.
+axentia	Axentia Technologies AB
+axis	Axis Communications AB
+bananapi BIPAI KEJI LIMITED
+bhf	Beckhoff Automation GmbH & Co. KG
+bitmain	Bitmain Technologies
+blokaslabs	Vilniaus Blokas UAB
+boe	BOE Technology Group Co., Ltd.
+bosch	Bosch Sensortec GmbH
+boundary	Boundary Devices Inc.
+brcm	Broadcom Corporation
+buffalo	Buffalo, Inc.
+bticino Bticino International
+calxeda	Calxeda
+capella	Capella Microsystems, Inc
+cascoda	Cascoda, Ltd.
+catalyst	Catalyst Semiconductor, Inc.
+cavium	Cavium, Inc.
+cdns	Cadence Design Systems Inc.
+cdtech	CDTech(H.K.) Electronics Limited
+ceva	Ceva, Inc.
+chipidea	Chipidea, Inc
+chipone		ChipOne
+chipspark	ChipSPARK
+chrp	Common Hardware Reference Platform
+chunghwa	Chunghwa Picture Tubes Ltd.
+ciaa	Computadora Industrial Abierta Argentina
+cirrus	Cirrus Logic, Inc.
+cloudengines	Cloud Engines, Inc.
+cnm	Chips&Media, Inc.
+cnxt	Conexant Systems, Inc.
+compulab	CompuLab Ltd.
+cortina	Cortina Systems, Inc.
+cosmic	Cosmic Circuits
+crane	Crane Connectivity Solutions
+creative	Creative Technology Ltd
+crystalfontz	Crystalfontz America, Inc.
+csky	Hangzhou C-SKY Microsystems Co., Ltd
+cubietech	Cubietech, Ltd.
+cypress	Cypress Semiconductor Corporation
+cznic	CZ.NIC, z.s.p.o.
+dallas	Maxim Integrated Products (formerly Dallas Semiconductor)
+dataimage	DataImage, Inc.
+davicom	DAVICOM Semiconductor, Inc.
+delta	Delta Electronics, Inc.
+denx	Denx Software Engineering
+devantech	Devantech, Ltd.
+dh	DH electronics GmbH
+digi	Digi International Inc.
+digilent	Diglent, Inc.
+dioo	Dioo Microcircuit Co., Ltd
+dlc	DLC Display Co., Ltd.
+dlg	Dialog Semiconductor
+dlink	D-Link Corporation
+dmo	Data Modul AG
+domintech	Domintech Co., Ltd.
+dongwoon	Dongwoon Anatech
+dptechnics	DPTechnics
+dragino	Dragino Technology Co., Limited
+ea	Embedded Artists AB
+ebs-systart EBS-SYSTART GmbH
+ebv	EBV Elektronik
+eckelmann	Eckelmann AG
+edt	Emerging Display Technologies
+eeti	eGalax_eMPIA Technology Inc
+elan	Elan Microelectronic Corp.
+elgin	Elgin S/A.
+embest	Shenzhen Embest Technology Co., Ltd.
+emlid	Emlid, Ltd.
+emmicro	EM Microelectronic
+emtrion	emtrion GmbH
+endless	Endless Mobile, Inc.
+energymicro	Silicon Laboratories (formerly Energy Micro AS)
+engicam	Engicam S.r.l.
+epcos	EPCOS AG
+epfl	Ecole Polytechnique Fédérale de Lausanne
+epson	Seiko Epson Corp.
+est	ESTeem Wireless Modems
+ettus	NI Ettus Research
+eukrea  Eukréa Electromatique
+everest	Everest Semiconductor Co. Ltd.
+everspin	Everspin Technologies, Inc.
+exar	Exar Corporation
+excito	Excito
+ezchip	EZchip Semiconductor
+facebook	Facebook
+fairphone	Fairphone B.V.
+faraday	Faraday Technology Corporation
+fastrax	Fastrax Oy
+fcs	Fairchild Semiconductor
+feiyang	Shenzhen Fly Young Technology Co.,LTD.
+firefly	Firefly
+focaltech	FocalTech Systems Co.,Ltd
+friendlyarm	Guangzhou FriendlyARM Computer Tech Co., Ltd
+fsl	Freescale Semiconductor
+fujitsu	Fujitsu Ltd.
+gateworks	Gateworks Corporation
+gcw Game Consoles Worldwide
+ge	General Electric Company
+geekbuying	GeekBuying
+gef	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+GEFanuc	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+geniatech	Geniatech, Inc.
+giantec	Giantec Semiconductor, Inc.
+giantplus	Giantplus Technology Co., Ltd.
+globalscale	Globalscale Technologies, Inc.
+globaltop	GlobalTop Technology, Inc.
+gmt	Global Mixed-mode Technology, Inc.
+goodix	Shenzhen Huiding Technology Co., Ltd.
+google	Google, Inc.
+grinn	Grinn
+grmn	Garmin Limited
+gumstix	Gumstix, Inc.
+gw	Gateworks Corporation
+hannstar	HannStar Display Corporation
+haoyu	Haoyu Microelectronic Co. Ltd.
+hardkernel	Hardkernel Co., Ltd
+hideep	HiDeep Inc.
+himax	Himax Technologies, Inc.
+hisilicon	Hisilicon Limited.
+hit	Hitachi Ltd.
+hitex	Hitex Development Tools
+holt	Holt Integrated Circuits, Inc.
+honeywell	Honeywell
+hp	Hewlett Packard
+holtek	Holtek Semiconductor, Inc.
+hwacom	HwaCom Systems Inc.
+i2se	I2SE GmbH
+ibm	International Business Machines (IBM)
+icplus	IC Plus Corp.
+idt	Integrated Device Technologies, Inc.
+ifi	Ingenieurburo Fur Ic-Technologie (I/F/I)
+ilitek	ILI Technology Corporation (ILITEK)
+img	Imagination Technologies Ltd.
+infineon Infineon Technologies
+inforce	Inforce Computing
+ingenic	Ingenic Semiconductor
+innolux	Innolux Corporation
+inside-secure	INSIDE Secure
+intel	Intel Corporation
+intercontrol	Inter Control Group
+invensense	InvenSense Inc.
+inversepath	Inverse Path
+iom	Iomega Corporation
+isee	ISEE 2007 S.L.
+isil	Intersil
+issi	Integrated Silicon Solutions Inc.
+itead	ITEAD Intelligent Systems Co.Ltd
+iwave  iWave Systems Technologies Pvt. Ltd.
+jdi	Japan Display Inc.
+jedec	JEDEC Solid State Technology Association
+jianda	Jiandangjing Technology Co., Ltd.
+karo	Ka-Ro electronics GmbH
+keithkoep	Keith & Koep GmbH
+keymile	Keymile GmbH
+khadas	Khadas
+kiebackpeter    Kieback & Peter GmbH
+kinetic Kinetic Technologies
+kingdisplay	King & Display Technology Co., Ltd.
+kingnovel	Kingnovel Technology Co., Ltd.
+koe	Kaohsiung Opto-Electronics Inc.
+kosagi	Sutajio Ko-Usagi PTE Ltd.
+kyo	Kyocera Corporation
+lacie	LaCie
+laird	Laird PLC
+lantiq	Lantiq Semiconductor
+lattice	Lattice Semiconductor
+lego	LEGO Systems A/S
+lemaker	Shenzhen LeMaker Technology Co., Ltd.
+lenovo	Lenovo Group Ltd.
+lg	LG Corporation
+libretech	Shenzhen Libre Technology Co., Ltd
+licheepi	Lichee Pi
+linaro	Linaro Limited
+linksys	Belkin International, Inc. (Linksys)
+linux	Linux-specific binding
+linx	Linx Technologies
+lltc	Linear Technology Corporation
+logicpd	Logic PD, Inc.
+lsi	LSI Corp. (LSI Logic)
+lwn	Liebherr-Werk Nenzing GmbH
+macnica	Macnica Americas
+marvell	Marvell Technology Group Ltd.
+maxim	Maxim Integrated Products
+mbvl	Mobiveil Inc.
+mcube	mCube
+meas	Measurement Specialties
+mediatek	MediaTek Inc.
+megachips	MegaChips
+mele	Shenzhen MeLE Digital Technology Ltd.
+melexis	Melexis N.V.
+melfas	MELFAS Inc.
+mellanox	Mellanox Technologies
+memsic	MEMSIC Inc.
+merrii	Merrii Technology Co., Ltd.
+micrel	Micrel Inc.
+microchip	Microchip Technology Inc.
+microcrystal	Micro Crystal AG
+micron	Micron Technology Inc.
+mikroe		MikroElektronika d.o.o.
+minix	MINIX Technology Ltd.
+miramems	MiraMEMS Sensing Technology Co., Ltd.
+mitsubishi	Mitsubishi Electric Corporation
+mosaixtech	Mosaix Technologies, Inc.
+motorola	Motorola, Inc.
+moxa	Moxa Inc.
+mpl	MPL AG
+mqmaker	mqmaker Inc.
+mscc	Microsemi Corporation
+msi	Micro-Star International Co. Ltd.
+mti	Imagination Technologies Ltd. (formerly MIPS Technologies Inc.)
+multi-inno	Multi-Inno Technology Co.,Ltd
+mundoreader	Mundo Reader S.L.
+murata	Murata Manufacturing Co., Ltd.
+mxicy	Macronix International Co., Ltd.
+myir	MYIR Tech Limited
+national	National Semiconductor
+nec	NEC LCD Technologies, Ltd.
+neonode		Neonode Inc.
+netgear	NETGEAR
+netlogic	Broadcom Corporation (formerly NetLogic Microsystems)
+netron-dy	Netron DY
+netxeon		Shenzhen Netxeon Technology CO., LTD
+nexbox	Nexbox
+nextthing	Next Thing Co.
+newhaven	Newhaven Display International
+ni	National Instruments
+nintendo	Nintendo
+nlt	NLT Technologies, Ltd.
+nokia	Nokia
+nordic	Nordic Semiconductor
+novtech NovTech, Inc.
+nutsboard	NutsBoard
+nuvoton	Nuvoton Technology Corporation
+nvd	New Vision Display
+nvidia	NVIDIA
+nxp	NXP Semiconductors
+okaya	Okaya Electric America, Inc.
+oki	Oki Electric Industry Co., Ltd.
+olimex	OLIMEX Ltd.
+olpc	One Laptop Per Child
+onion	Onion Corporation
+onnn	ON Semiconductor Corp.
+ontat	On Tat Industrial Company
+opalkelly	Opal Kelly Incorporated
+opencores	OpenCores.org
+openrisc	OpenRISC.io
+option	Option NV
+oranth	Shenzhen Oranth Technology Co., Ltd.
+ORCL	Oracle Corporation
+orisetech	Orise Technology
+ortustech	Ortus Technology Co., Ltd.
+ovti	OmniVision Technologies
+oxsemi	Oxford Semiconductor, Ltd.
+panasonic	Panasonic Corporation
+parade	Parade Technologies Inc.
+pda	Precision Design Associates, Inc.
+pericom	Pericom Technology Inc.
+pervasive	Pervasive Displays, Inc.
+phicomm PHICOMM Co., Ltd.
+phytec	PHYTEC Messtechnik GmbH
+picochip	Picochip Ltd
+pine64	Pine64
+pixcir  PIXCIR MICROELECTRONICS Co., Ltd
+plantower Plantower Co., Ltd
+plathome	Plat'Home Co., Ltd.
+plda	PLDA
+plx	Broadcom Corporation (formerly PLX Technology)
+pni	PNI Sensor Corporation
+portwell	Portwell Inc.
+poslab	Poslab Technology Co., Ltd.
+powervr	PowerVR (deprecated, use img)
+probox2	PROBOX2 (by W2COMP Co., Ltd.)
+pulsedlight	PulsedLight, Inc
+qca	Qualcomm Atheros, Inc.
+qcom	Qualcomm Technologies, Inc
+qemu	QEMU, a generic and open source machine emulator and virtualizer
+qi	Qi Hardware
+qiaodian	QiaoDian XianShi Corporation
+qnap	QNAP Systems, Inc.
+radxa	Radxa
+raidsonic	RaidSonic Technology GmbH
+ralink	Mediatek/Ralink Technology Corp.
+ramtron	Ramtron International
+raspberrypi	Raspberry Pi Foundation
+raydium	Raydium Semiconductor Corp.
+rda	Unisoc Communications, Inc.
+realtek Realtek Semiconductor Corp.
+renesas	Renesas Electronics Corporation
+richtek	Richtek Technology Corporation
+ricoh	Ricoh Co. Ltd.
+rikomagic	Rikomagic Tech Corp. Ltd
+riscv	RISC-V Foundation
+rockchip	Fuzhou Rockchip Electronics Co., Ltd
+rohm	ROHM Semiconductor Co., Ltd
+roofull	Shenzhen Roofull Technology Co, Ltd
+samsung	Samsung Semiconductor
+samtec	Samtec/Softing company
+sancloud	Sancloud Ltd
+sandisk	Sandisk Corporation
+sbs	Smart Battery System
+schindler	Schindler
+seagate	Seagate Technology PLC
+semtech	Semtech Corporation
+sensirion	Sensirion AG
+sff	Small Form Factor Committee
+sgd	Solomon Goldentek Display Corporation
+sgx	SGX Sensortech
+sharp	Sharp Corporation
+shimafuji	Shimafuji Electric, Inc.
+si-en	Si-En Technology Ltd.
+sifive	SiFive, Inc.
+sigma	Sigma Designs, Inc.
+sii	Seiko Instruments, Inc.
+sil	Silicon Image
+silabs	Silicon Laboratories
+silead	Silead Inc.
+silergy	Silergy Corp.
+siliconmitus	Silicon Mitus, Inc.
+simtek
+sirf	SiRF Technology, Inc.
+sis	Silicon Integrated Systems Corp.
+sitronix	Sitronix Technology Corporation
+skyworks	Skyworks Solutions, Inc.
+smsc	Standard Microsystems Corporation
+snps	Synopsys, Inc.
+socionext	Socionext Inc.
+solidrun	SolidRun
+solomon        Solomon Systech Limited
+sony	Sony Corporation
+spansion	Spansion Inc.
+sprd	Spreadtrum Communications Inc.
+sst	Silicon Storage Technology, Inc.
+st	STMicroelectronics
+starry	Starry Electronic Technology (ShenZhen) Co., LTD
+startek	Startek
+ste	ST-Ericsson
+stericsson	ST-Ericsson
+summit	Summit microelectronics
+sunchip	Shenzhen Sunchip Technology Co., Ltd
+SUNW	Sun Microsystems, Inc
+swir	Sierra Wireless
+syna	Synaptics Inc.
+synology	Synology, Inc.
+tbs	TBS Technologies
+tbs-biometrics	Touchless Biometric Systems AG
+tcg	Trusted Computing Group
+tcl	Toby Churchill Ltd.
+technexion	TechNexion
+technologic	Technologic Systems
+tempo	Tempo Semiconductor
+techstar	Shenzhen Techstar Electronics Co., Ltd.
+terasic	Terasic Inc.
+thine	THine Electronics, Inc.
+ti	Texas Instruments
+tianma	Tianma Micro-electronics Co., Ltd.
+tlm	Trusted Logic Mobility
+tmt	Tecon Microprocessor Technologies, LLC.
+topeet  Topeet
+toradex	Toradex AG
+toshiba	Toshiba Corporation
+toumaz	Toumaz
+tpk	TPK U.S.A. LLC
+tplink	TP-LINK Technologies Co., Ltd.
+tpo	TPO
+tronfy	Tronfy
+tronsmart	Tronsmart
+truly	Truly Semiconductors Limited
+tsd	Theobroma Systems Design und Consulting GmbH
+tyan	Tyan Computer Corporation
+u-blox	u-blox
+ucrobotics	uCRobotics
+ubnt	Ubiquiti Networks
+udoo	Udoo
+uniwest	United Western Technologies Corp (UniWest)
+upisemi	uPI Semiconductor Corp.
+urt	United Radiant Technology Corporation
+usi	Universal Scientific Industrial Co., Ltd.
+v3	V3 Semiconductor
+vamrs	Vamrs Ltd.
+variscite	Variscite Ltd.
+via	VIA Technologies, Inc.
+virtio	Virtual I/O Device Specification, developed by the OASIS consortium
+vishay	Vishay Intertechnology, Inc
+vitesse	Vitesse Semiconductor Corporation
+vivante	Vivante Corporation
+vocore VoCore Studio
+voipac	Voipac Technologies s.r.o.
+vot	Vision Optical Technology Co., Ltd.
+wd	Western Digital Corp.
+wetek	WeTek Electronics, limited.
+wexler	Wexler
+whwave  Shenzhen whwave Electronics, Inc.
+wi2wi	Wi2Wi, Inc.
+winbond Winbond Electronics corp.
+winstar	Winstar Display Corp.
+wlf	Wolfson Microelectronics
+wm	Wondermedia Technologies, Inc.
+x-powers	X-Powers
+xes	Extreme Engineering Solutions (X-ES)
+xillybus	Xillybus Ltd.
+xlnx	Xilinx
+xunlong	Shenzhen Xunlong Software CO.,Limited
+ysoft	Y Soft Corporation a.s.
+zarlink	Zarlink Semiconductor
+zeitec	ZEITEC Semiconductor Co., LTD.
+zidoo	Shenzhen Zidoo Technology Co., Ltd.
+zii	Zodiac Inflight Innovations
+zte	ZTE Corp.
+zyxel	ZyXEL Communications Corp.
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/bindings/vendor-prefixes.yaml linux-5.10.52-v7l+/Documentation/devicetree/bindings/vendor-prefixes.yaml
--- linux-5.10.52-orig/Documentation/devicetree/bindings/vendor-prefixes.yaml	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/devicetree/bindings/vendor-prefixes.yaml	2021-07-25 16:45:33.898828515 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:162 @
     description: Beckhoff Automation GmbH & Co. KG
   "^bitmain,.*":
     description: Bitmain Technologies
+  "^blokaslabs,.*":
+    description: Vilniaus Blokas UAB
   "^boe,.*":
     description: BOE Technology Group Co., Ltd.
   "^bosch,.*":
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/devicetree/configfs-overlays.txt linux-5.10.52-v7l+/Documentation/devicetree/configfs-overlays.txt
--- linux-5.10.52-orig/Documentation/devicetree/configfs-overlays.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/devicetree/configfs-overlays.txt	2021-07-25 16:45:33.908828347 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+Howto use the configfs overlay interface.
+
+A device-tree configfs entry is created in /config/device-tree/overlays
+and and it is manipulated using standard file system I/O.
+Note that this is a debug level interface, for use by developers and
+not necessarily something accessed by normal users due to the
+security implications of having direct access to the kernel's device tree.
+
+* To create an overlay you mkdir the directory:
+
+	# mkdir /config/device-tree/overlays/foo
+
+* Either you echo the overlay firmware file to the path property file.
+
+	# echo foo.dtbo >/config/device-tree/overlays/foo/path
+
+* Or you cat the contents of the overlay to the dtbo file
+
+	# cat foo.dtbo >/config/device-tree/overlays/foo/dtbo
+
+The overlay file will be applied, and devices will be created/destroyed
+as required.
+
+To remove it simply rmdir the directory.
+
+	# rmdir /config/device-tree/overlays/foo
+
+The rationalle of the dual interface (firmware & direct copy) is that each is
+better suited to different use patterns. The firmware interface is what's
+intended to be used by hardware managers in the kernel, while the copy interface
+make sense for developers (since it avoids problems with namespaces).
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/hwmon/rpi-poe-fan linux-5.10.52-v7l+/Documentation/hwmon/rpi-poe-fan
--- linux-5.10.52-orig/Documentation/hwmon/rpi-poe-fan	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/hwmon/rpi-poe-fan	2021-07-25 16:45:34.078825497 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+Kernel driver rpi-poe-fan
+=====================
+
+This driver enables the use of the Raspberry Pi PoE HAT fan.
+
+Author: Serge Schneider <serge@raspberrypi.org>
+
+Description
+-----------
+
+The driver implements a simple interface for driving the Raspberry Pi PoE
+(Power over Ethernet) HAT fan. The driver passes commands to the Raspberry Pi
+firmware through the mailbox property interface. The firmware then forwards
+the commands to the board over I2C on the ID_EEPROM pins. The driver exposes
+the fan to the user space through the hwmon sysfs interface.
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/drivers/index.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/drivers/index.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/drivers/index.rst	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/drivers/index.rst	2021-07-25 16:45:34.368820635 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:36 @
 
 	cx2341x-uapi
 	imx-uapi
+	bcm2835-isp
 	max2175
 	meye-uapi
 	omap3isp-uapi
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst	2021-07-25 16:45:34.418819797 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4114 @
     * - __u32
       - ``data_bit_offset``
       - Offset (in bits) to the video data in the current slice data.
+    * - __u32
+      - ``slice_segment_addr``
+      -
     * - __u8
       - ``nal_unit_type``
       -
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4194 @
       - ``num_rps_poc_lt_curr``
       - The number of reference pictures in the long-term set.
     * - __u8
-      - ``padding[7]``
+      - ``padding[5]``
       - Applications and drivers must set this to zero.
     * - struct :c:type:`v4l2_hevc_dpb_entry`
       - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4325 @
       - ``padding[6]``
       - Applications and drivers must set this to zero.
 
+``V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (struct)``
+    Specifies the scaling matrix (as extracted from the bitstream) for
+    the associated HEVC slice data. The bitstream parameters are
+    defined according to :ref:`hevc`, section 7.4.5 "Scaling list
+    data semantics". For further documentation, refer to the above
+    specification, unless there is an explicit comment stating
+    otherwise.
+
+    .. note::
+
+       This compound control is not yet part of the public kernel API and
+       it is expected to change.
+
+.. c:type:: v4l2_ctrl_hevc_scaling_matrix
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_scaling_matrix
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u8
+      - ``scaling_list_4x4[6][16]``
+      -
+    * - __u8
+      - ``scaling_list_8x8[6][64]``
+      -
+    * - __u8
+      - ``scaling_list_16x16[6][64]``
+      -
+    * - __u8
+      - ``scaling_list_32x32[2][64]``
+      -
+    * - __u8
+      - ``scaling_list_dc_coef_16x16[6]``
+      -
+    * - __u8
+      - ``scaling_list_dc_coef_32x32[2]``
+      -
+
 ``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (enum)``
     Specifies the decoding mode to use. Currently exposes slice-based and
     frame-based decoding but new modes might be added later on.
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/meta-formats.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/meta-formats.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/meta-formats.rst	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/meta-formats.rst	2021-07-25 16:45:34.428819629 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:15 @
 .. toctree::
     :maxdepth: 1
 
+    pixfmt-meta-bcm2835-isp-stats
     pixfmt-meta-d4xx
     pixfmt-meta-intel-ipu3
     pixfmt-meta-rkisp1
+    pixfmt-meta-sensor-data
     pixfmt-meta-uvc
     pixfmt-meta-vsp1-hgo
     pixfmt-meta-vsp1-hgt
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst	2021-07-25 16:45:34.428819629 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:203 @
         * ``V4L2_CID_MPEG_VIDEO_HEVC_SPS``
         * ``V4L2_CID_MPEG_VIDEO_HEVC_PPS``
         * ``V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS``
+        * ``V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX``
 	See the :ref:`associated Codec Control IDs <v4l2-mpeg-hevc>`.
 	Buffers associated with this pixel format must contain the appropriate
 	number of macroblocks to decode a full corresponding frame.
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst	2021-07-25 16:45:34.428819629 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
+.. _v4l2-meta-fmt-bcm2835-isp-stats:
+
+*****************************************
+V4L2_META_FMT_BCM2835_ISP_STATS  ('BSTA')
+*****************************************
+
+BCM2835 ISP Statistics
+
+Description
+===========
+
+The BCM2835 ISP hardware calculate image statistics for an input Bayer frame.
+These statistics are obtained from the "bcm2835-isp0-capture3" device node
+using the :c:type:`v4l2_meta_format` interface. They are formatted as described
+by the :c:type:`bcm2835_isp_stats` structure below.
+
+.. code-block:: c
+
+	#define DEFAULT_AWB_REGIONS_X 16
+	#define DEFAULT_AWB_REGIONS_Y 12
+
+	#define NUM_HISTOGRAMS 2
+	#define NUM_HISTOGRAM_BINS 128
+	#define AWB_REGIONS (DEFAULT_AWB_REGIONS_X * DEFAULT_AWB_REGIONS_Y)
+	#define FLOATING_REGIONS 16
+	#define AGC_REGIONS 16
+	#define FOCUS_REGIONS 12
+
+.. kernel-doc:: include/uapi/linux/bcm2835-isp.h
+   :functions: bcm2835_isp_stats_hist bcm2835_isp_stats_region
+	             bcm2835_isp_stats_focus bcm2835_isp_stats
+
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-meta-sensor-data.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-meta-sensor-data.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-meta-sensor-data.rst	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-meta-sensor-data.rst	2021-07-25 16:45:34.428819629 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
+.. _v4l2-meta-fmt-sensor-data:
+
+***********************************
+V4L2_META_FMT_SENSOR_DATA  ('SENS')
+***********************************
+
+Sensor Ancillary Metadata
+
+Description
+===========
+
+This format describes ancillary data generated by a camera sensor and
+transmitted over a stream on the camera bus. Sensor vendors generally have their
+own custom format for this ancillary data. Some vendors follow a generic
+CSI-2/SMIA embedded data format as described in the `CSI-2 specification.
+<https://mipi.org/specifications/csi-2>`_
+
+The size of the embedded buffer is defined as a single line with a pixel width
+width specified in bytes. This is obtained by a call to the
+:c:type:`VIDIOC_SUBDEV_G_FMT` ioctl on the sensor subdevice where the ``pad``
+field in :c:type:`v4l2_subdev_format` is set to 1.  Note that this size is fixed
+and cannot be modified with a call to :c:type:`VIDIOC_SUBDEV_S_FMT`.
+
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-nv12-col128.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-nv12-col128.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-nv12-col128.rst	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-nv12-col128.rst	2021-07-25 16:45:34.428819629 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
+.. _V4L2_PIX_FMT_NV12_COL128:
+.. _V4L2_PIX_FMT_NV12_10_COL128:
+
+********************************************************************************
+V4L2_PIX_FMT_NV12_COL128, V4L2_PIX_FMT_NV12_10_COL128
+********************************************************************************
+
+
+V4L2_PIX_FMT_NV21_COL128
+Formats with ½ horizontal and vertical chroma resolution. This format
+has two planes - one for luminance and one for chrominance. Chroma
+samples are interleaved. The difference to ``V4L2_PIX_FMT_NV12`` is the
+memory layout. The image is split into columns of 128 bytes wide rather than
+being in raster order.
+
+V4L2_PIX_FMT_NV12_10_COL128
+Follows the same pattern as ``V4L2_PIX_FMT_NV21_COL128`` with 128 byte, but is
+a 10bit format with 3 10-bit samples being packed into 4 bytes. Each 128 byte
+wide column therefore contains 96 samples.
+
+
+Description
+===========
+
+This is the two-plane versions of the YUV 4:2:0 format where data is
+grouped into 128 byte wide columns. The three components are separated into
+two sub-images or planes. The Y plane has one byte per pixel and pixels
+are grouped into 128 byte wide columns. The CbCr plane has the same width,
+in bytes, as the Y plane (and the image), but is half as tall in pixels.
+The chroma plane is also in 128 byte columns, reflecting 64 Cb and 64 Cr
+samples.
+
+The chroma samples for a column follow the luma samples. If there is any
+paddding, then that will be reflected via the selection API.
+The luma height must be a multiple of 2 lines.
+
+The normal bytesperline is effectively fixed at 128. However the format
+requires knowledge of the stride between columns, therefore the bytesperline
+value has been repurposed to denote the number of 128 byte long lines between
+the start of each column.
+
+**Byte Order.**
+
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths: 12 12 12 12 12 4 12 12 12 12
+
+    * - start + 0:
+      - Y'\ :sub:`0,0`
+      - Y'\ :sub:`0,1`
+      - Y'\ :sub:`0,2`
+      - Y'\ :sub:`0,3`
+      - ...
+      - Y'\ :sub:`0,124`
+      - Y'\ :sub:`0,125`
+      - Y'\ :sub:`0,126`
+      - Y'\ :sub:`0,127`
+    * - start + 128:
+      - Y'\ :sub:`1,0`
+      - Y'\ :sub:`1,1`
+      - Y'\ :sub:`1,2`
+      - Y'\ :sub:`1,3`
+      - ...
+      - Y'\ :sub:`1,124`
+      - Y'\ :sub:`1,125`
+      - Y'\ :sub:`1,126`
+      - Y'\ :sub:`1,127`
+    * - start + 256:
+      - Y'\ :sub:`2,0`
+      - Y'\ :sub:`2,1`
+      - Y'\ :sub:`2,2`
+      - Y'\ :sub:`2,3`
+      - ...
+      - Y'\ :sub:`2,124`
+      - Y'\ :sub:`2,125`
+      - Y'\ :sub:`2,126`
+      - Y'\ :sub:`2,127`
+    * - ...
+      - ...
+      - ...
+      - ...
+      - ...
+      - ...
+      - ...
+      - ...
+    * - start + ((height-1) * 128):
+      - Y'\ :sub:`height-1,0`
+      - Y'\ :sub:`height-1,1`
+      - Y'\ :sub:`height-1,2`
+      - Y'\ :sub:`height-1,3`
+      - ...
+      - Y'\ :sub:`height-1,124`
+      - Y'\ :sub:`height-1,125`
+      - Y'\ :sub:`height-1,126`
+      - Y'\ :sub:`height-1,127`
+    * - start + ((height) * 128):
+      - Cb\ :sub:`0,0`
+      - Cr\ :sub:`0,0`
+      - Cb\ :sub:`0,1`
+      - Cr\ :sub:`0,1`
+      - ...
+      - Cb\ :sub:`0,62`
+      - Cr\ :sub:`0,62`
+      - Cb\ :sub:`0,63`
+      - Cr\ :sub:`0,63`
+    * - start + ((height+1) * 128):
+      - Cb\ :sub:`1,0`
+      - Cr\ :sub:`1,0`
+      - Cb\ :sub:`1,1`
+      - Cr\ :sub:`1,1`
+      - ...
+      - Cb\ :sub:`1,62`
+      - Cr\ :sub:`1,62`
+      - Cb\ :sub:`1,63`
+      - Cr\ :sub:`1,63`
+    * - ...
+      - ...
+      - ...
+      - ...
+      - ...
+      - ...
+      - ...
+      - ...
+    * - start + ((height+(height/2)-1) * 128):
+      - Cb\ :sub:`(height/2)-1,0`
+      - Cr\ :sub:`(height/2)-1,0`
+      - Cb\ :sub:`(height/2)-1,1`
+      - Cr\ :sub:`(height/2)-1,1`
+      - ...
+      - Cb\ :sub:`(height/2)-1,62`
+      - Cr\ :sub:`(height/2)-1,62`
+      - Cb\ :sub:`(height/2)-1,63`
+      - Cr\ :sub:`(height/2)-1,63`
+    * - start + (bytesperline * 128):
+      - Y'\ :sub:`0,128`
+      - Y'\ :sub:`0,129`
+      - Y'\ :sub:`0,130`
+      - Y'\ :sub:`0,131`
+      - ...
+      - Y'\ :sub:`0,252`
+      - Y'\ :sub:`0,253`
+      - Y'\ :sub:`0,254`
+      - Y'\ :sub:`0,255`
+    * - ...
+      - ...
+      - ...
+      - ...
+      - ...
+      - ...
+      - ...
+      - ...
+
+V4L2_PIX_FMT_NV12_10_COL128 uses the same 128 byte column structure, but
+encodes 10-bit YUV.
+3 10-bit values are packed into 4 bytes as bits 9:0, 19:10, and 29:20, with
+bits 30 & 31 unused. For the luma plane, bits 9:0 are Y0, 19:10 are Y1, and
+29:20 are Y2. For the chroma plane the samples always come in pairs of Cr
+and Cb, so it needs to be considered 6 values packed in 8 bytes.
+
+Bit-packed representation.
+
+.. raw:: latex
+
+    \small
+
+.. tabularcolumns:: |p{1.2cm}||p{1.2cm}||p{1.2cm}||p{1.2cm}|p{3.2cm}|p{3.2cm}|
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths: 8 8 8 8
+
+    * - Y'\ :sub:`00[7:0]`
+      - Y'\ :sub:`01[5:0] (bits 7--2)` Y'\ :sub:`00[9:8]`\ (bits 1--0)
+      - Y'\ :sub:`02[3:0] (bits 7--4)` Y'\ :sub:`01[9:6]`\ (bits 3--0)
+      - unused (bits 7--6)` Y'\ :sub:`02[9:4]`\ (bits 5--0)
+
+.. raw:: latex
+
+    \small
+
+.. tabularcolumns:: |p{1.2cm}||p{1.2cm}||p{1.2cm}||p{1.2cm}|p{3.2cm}|p{3.2cm}|
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths: 12 12 12 12 12 12 12 12
+
+    * - Cb\ :sub:`00[7:0]`
+      - Cr\ :sub:`00[5:0]`\ (bits 7--2) Cb\ :sub:`00[9:8]`\ (bits 1--0)
+      - Cb\ :sub:`01[3:0]`\ (bits 7--4) Cr\ :sub:`00[9:6]`\ (bits 3--0)
+      - unused (bits 7--6) Cb\ :sub:`02[9:4]`\ (bits 5--0)
+      - Cr\ :sub:`01[7:0]`
+      - Cb\ :sub:`02[5:0]`\ (bits 7--2) Cr\ :sub:`01[9:8]`\ (bits 1--0)
+      - Cr\ :sub:`02[3:0]`\ (bits 7--4) Cb\ :sub:`02[9:6]`\ (bits 3--0)
+      - unused (bits 7--6) Cr\ :sub:`02[9:4]`\ (bits 5--0)
+
+.. raw:: latex
+
+    \normalsize
+
+
+
+
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst	2021-07-25 16:45:34.428819629 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6 @
 .. _V4L2-PIX-FMT-NV12:
 .. _V4L2-PIX-FMT-NV21:
 
-******************************************************
-V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21')
-******************************************************
+********************************************************************************
+V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21'), V4L2_PIX_FMT_NV12_COL128
+********************************************************************************
 
 
 V4L2_PIX_FMT_NV21
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:34 @
 If the Y plane has pad bytes after each row, then the CbCr plane has as
 many pad bytes after its rows.
 
+``V4L2_PIX_FMT_NV12_COL128`` is the tiled version of
+``V4L2_PIX_FMT_NV12`` with the image broken down into 128 pixel wide columns of
+Y followed by the associated combined CbCr plane.
+The normal bytesperline is effectively fixed at 128. However the format
+requires knowledge of the stride between columns, therefore the bytesperline
+value has been repurposed to denote the number of 128 byte long lines between
+the start of each column.
+
 **Byte Order.**
 Each cell is one byte.
 
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-y12p.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-y12p.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-y12p.rst	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-y12p.rst	2021-07-25 16:45:34.438819462 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
+.. _V4L2-PIX-FMT-Y12P:
+
+******************************
+V4L2_PIX_FMT_Y12P ('Y12P')
+******************************
+
+Grey-scale image as a MIPI RAW12 packed array
+
+
+Description
+===========
+
+This is a packed grey-scale image format with a depth of 12 bits per
+pixel. Two consecutive pixels are packed into 3 bytes. The first 2 bytes
+contain the 8 high order bits of the pixels, and the 3rd byte contains the 4
+least significants bits of each pixel, in the same order.
+
+**Byte Order.**
+Each cell is one byte.
+
+.. tabularcolumns:: |p{2.2cm}|p{1.2cm}|p{1.2cm}|p{3.1cm}|
+
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       2 1 1 1
+
+
+    -  -  start + 0:
+       -  Y'\ :sub:`00high`
+       -  Y'\ :sub:`01high`
+       -  Y'\ :sub:`01low`\ (bits 7--4)
+
+          Y'\ :sub:`00low`\ (bits 3--0)
+
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-y14p.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-y14p.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/pixfmt-y14p.rst	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/pixfmt-y14p.rst	2021-07-25 16:45:34.438819462 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
+.. _V4L2-PIX-FMT-Y14P:
+
+**************************
+V4L2_PIX_FMT_Y14P ('Y14P')
+**************************
+
+Grey-scale image as a MIPI RAW14 packed array
+
+
+Description
+===========
+
+This is a packed grey-scale image format with a depth of 14 bits per
+pixel. Every four consecutive samples are packed into seven bytes. Each
+of the first four bytes contain the eight high order bits of the pixels,
+and the three following bytes contains the six least significants bits of
+each pixel, in the same order.
+
+**Byte Order.**
+Each cell is one byte.
+
+.. tabularcolumns:: |p{1.8cm}|p{1.0cm}|p{1.0cm}|p{1.0cm}|p{1.1cm}|p{3.3cm}|p{3.3cm}|p{3.3cm}|
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       2 1 1 1 1 3 3 3
+
+
+    -  -  start + 0:
+       -  Y'\ :sub:`00high`
+       -  Y'\ :sub:`01high`
+       -  Y'\ :sub:`02high`
+       -  Y'\ :sub:`03high`
+       -  Y'\ :sub:`01low bits 1--0`\ (bits 7--6)
+
+	  Y'\ :sub:`00low bits 5--0`\ (bits 5--0)
+
+       -  Y'\ :sub:`02low bits 3--0`\ (bits 7--4)
+
+	  Y'\ :sub:`01low bits 5--2`\ (bits 3--0)
+
+       -  Y'\ :sub:`03low bits 5--0`\ (bits 7--2)
+
+	  Y'\ :sub:`02low bits 5--4`\ (bits 1--0)
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/subdev-formats.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/subdev-formats.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/subdev-formats.rst	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/subdev-formats.rst	2021-07-25 16:45:34.448819294 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:911 @
       - g\ :sub:`5`
       - g\ :sub:`4`
       - g\ :sub:`3`
+    * .. _MEDIA-BUS-FMT-BGR666-1X18:
+
+      - MEDIA_BUS_FMT_RGB666_1X18
+      - 0x101f
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      - b\ :sub:`5`
+      - b\ :sub:`4`
+      - b\ :sub:`3`
+      - b\ :sub:`2`
+      - b\ :sub:`1`
+      - b\ :sub:`0`
+      - g\ :sub:`5`
+      - g\ :sub:`4`
+      - g\ :sub:`3`
+      - g\ :sub:`2`
+      - g\ :sub:`1`
+      - g\ :sub:`0`
+      - r\ :sub:`5`
+      - r\ :sub:`4`
+      - r\ :sub:`3`
+      - r\ :sub:`2`
+      - r\ :sub:`1`
+      - r\ :sub:`0`
     * .. _MEDIA-BUS-FMT-RGB666-1X18:
 
       - MEDIA_BUS_FMT_RGB666_1X18
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1022 @
       - g\ :sub:`2`
       - g\ :sub:`1`
       - g\ :sub:`0`
+    * .. _MEDIA-BUS-FMT-BGR666-1X24_CPADHI:
+
+      - MEDIA_BUS_FMT_BGR666_1X24_CPADHI
+      - 0x101e
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      - 0
+      - 0
+      - b\ :sub:`5`
+      - b\ :sub:`4`
+      - b\ :sub:`3`
+      - b\ :sub:`2`
+      - b\ :sub:`1`
+      - b\ :sub:`0`
+      - 0
+      - 0
+      - g\ :sub:`5`
+      - g\ :sub:`4`
+      - g\ :sub:`3`
+      - g\ :sub:`2`
+      - g\ :sub:`1`
+      - g\ :sub:`0`
+      - 0
+      - 0
+      - r\ :sub:`5`
+      - r\ :sub:`4`
+      - r\ :sub:`3`
+      - r\ :sub:`2`
+      - r\ :sub:`1`
+      - r\ :sub:`0`
     * .. _MEDIA-BUS-FMT-RGB666-1X24_CPADHI:
 
       - MEDIA_BUS_FMT_RGB666_1X24_CPADHI
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:7976 @
       - 0x5001
       - Interleaved raw UYVY and JPEG image format with embedded meta-data
 	used by Samsung S3C73MX camera sensors.
+
+
+
+.. _v4l2-mbus-sensor-data:
+
+Sensor Ancillary Metadata Formats
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This section lists ancillary data generated by a camera sensor and
+transmitted over a stream on the camera bus.
+
+The following table lists the existing sensor ancillary metadata formats:
+
+
+.. _v4l2-mbus-pixelcode-sensor-metadata:
+
+.. tabularcolumns:: |p{8.0cm}|p{1.4cm}|p{7.7cm}|
+
+.. flat-table:: Sensor ancillary metadata formats
+    :header-rows:  1
+    :stub-columns: 0
+
+    * - Identifier
+      - Code
+      - Comments
+    * .. _MEDIA_BUS_FMT_SENSOR_DATA:
+
+      - MEDIA_BUS_FMT_SENSOR_DATA
+      - 0x7001
+      - Sensor vendor specific ancillary metadata. Some vendors follow a generic
+        CSI-2/SMIA embedded data format as described in the `CSI-2 specification.
+	<https://mipi.org/specifications/csi-2>`_
+
diff -Nur --no-dereference linux-5.10.52-orig/Documentation/userspace-api/media/v4l/yuv-formats.rst linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/yuv-formats.rst
--- linux-5.10.52-orig/Documentation/userspace-api/media/v4l/yuv-formats.rst	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/Documentation/userspace-api/media/v4l/yuv-formats.rst	2021-07-25 16:45:34.468818959 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:31 @
     pixfmt-grey
     pixfmt-y10
     pixfmt-y12
+    pixfmt-y12p
     pixfmt-y14
+    pixfmt-y14p
     pixfmt-y10b
     pixfmt-y10p
     pixfmt-y16
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:56 @
     pixfmt-nv12
     pixfmt-nv12m
     pixfmt-nv12mt
+    pixfmt-nv12-col128
     pixfmt-nv16
     pixfmt-nv16m
     pixfmt-nv24
diff -Nur --no-dereference linux-5.10.52-orig/drivers/bluetooth/hci_h5.c linux-5.10.52-v7l+/drivers/bluetooth/hci_h5.c
--- linux-5.10.52-orig/drivers/bluetooth/hci_h5.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/bluetooth/hci_h5.c	2021-07-25 16:45:44.408652309 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:346 @
 		h5_link_control(hu, conf_req, 3);
 	} else if (memcmp(data, conf_req, 2) == 0) {
 		h5_link_control(hu, conf_rsp, 2);
-		h5_link_control(hu, conf_req, 3);
+		if (h5->state != H5_ACTIVE)
+		    h5_link_control(hu, conf_req, 3);
 	} else if (memcmp(data, conf_rsp, 2) == 0) {
 		if (H5_HDR_LEN(hdr) > 2)
 			h5->tx_win = (data[2] & 0x07);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/broadcom/bcm2835-gpiomem.c linux-5.10.52-v7l+/drivers/char/broadcom/bcm2835-gpiomem.c
--- linux-5.10.52-orig/drivers/char/broadcom/bcm2835-gpiomem.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/char/broadcom/bcm2835-gpiomem.c	2021-07-25 16:45:44.568649626 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/**
+ * 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 <luke@raspberrypi.org>
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/pagemap.h>
+#include <linux/io.h>
+
+#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 <luke@raspberrypi.org>");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/broadcom/bcm2835_smi_dev.c linux-5.10.52-v7l+/drivers/char/broadcom/bcm2835_smi_dev.c
--- linux-5.10.52-orig/drivers/char/broadcom/bcm2835_smi_dev.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/char/broadcom/bcm2835_smi_dev.c	2021-07-25 16:45:44.568649626 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/**
+ * Character device driver for Broadcom Secondary Memory Interface
+ *
+ * Written by Luke Wren <luke@raspberrypi.org>
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+
+#include <linux/broadcom/bcm2835_smi.h>
+
+#define DEVICE_NAME "bcm2835-smi-dev"
+#define DRIVER_NAME "smi-dev-bcm2835"
+#define DEVICE_MINOR 0
+
+static struct cdev bcm2835_smi_cdev;
+static dev_t bcm2835_smi_devid;
+static struct class *bcm2835_smi_class;
+static struct device *bcm2835_smi_dev;
+
+struct bcm2835_smi_dev_instance {
+	struct device *dev;
+};
+
+static struct bcm2835_smi_instance *smi_inst;
+static struct bcm2835_smi_dev_instance *inst;
+
+static const char *const ioctl_names[] = {
+	"READ_SETTINGS",
+	"WRITE_SETTINGS",
+	"ADDRESS"
+};
+
+/****************************************************************************
+*
+*   SMI chardev file ops
+*
+***************************************************************************/
+static long
+bcm2835_smi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long ret = 0;
+
+	dev_info(inst->dev, "serving ioctl...");
+
+	switch (cmd) {
+	case BCM2835_SMI_IOC_GET_SETTINGS:{
+		struct smi_settings *settings;
+
+		dev_info(inst->dev, "Reading SMI settings to user.");
+		settings = bcm2835_smi_get_settings_from_regs(smi_inst);
+		if (copy_to_user((void *)arg, settings,
+				 sizeof(struct smi_settings)))
+			dev_err(inst->dev, "settings copy failed.");
+		break;
+	}
+	case BCM2835_SMI_IOC_WRITE_SETTINGS:{
+		struct smi_settings *settings;
+
+		dev_info(inst->dev, "Setting user's SMI settings.");
+		settings = bcm2835_smi_get_settings_from_regs(smi_inst);
+		if (copy_from_user(settings, (void *)arg,
+				   sizeof(struct smi_settings)))
+			dev_err(inst->dev, "settings copy failed.");
+		else
+			bcm2835_smi_set_regs_from_settings(smi_inst);
+		break;
+	}
+	case BCM2835_SMI_IOC_ADDRESS:
+		dev_info(inst->dev, "SMI address set: 0x%02x", (int)arg);
+		bcm2835_smi_set_address(smi_inst, arg);
+		break;
+	default:
+		dev_err(inst->dev, "invalid ioctl cmd: %d", cmd);
+		ret = -ENOTTY;
+		break;
+	}
+
+	return ret;
+}
+
+static int bcm2835_smi_open(struct inode *inode, struct file *file)
+{
+	int dev = iminor(inode);
+
+	dev_dbg(inst->dev, "SMI device opened.");
+
+	if (dev != DEVICE_MINOR) {
+		dev_err(inst->dev,
+			"bcm2835_smi_release: Unknown minor device: %d",
+			dev);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int bcm2835_smi_release(struct inode *inode, struct file *file)
+{
+	int dev = iminor(inode);
+
+	if (dev != DEVICE_MINOR) {
+		dev_err(inst->dev,
+			"bcm2835_smi_release: Unknown minor device %d", dev);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static ssize_t dma_bounce_user(
+	enum dma_transfer_direction dma_dir,
+	char __user *user_ptr,
+	size_t count,
+	struct bcm2835_smi_bounce_info *bounce)
+{
+	int chunk_size;
+	int chunk_no = 0;
+	int count_left = count;
+
+	while (count_left) {
+		int rv;
+		void *buf;
+
+		/* Wait for current chunk to complete: */
+		if (down_timeout(&bounce->callback_sem,
+			msecs_to_jiffies(1000))) {
+			dev_err(inst->dev, "DMA bounce timed out");
+			count -= (count_left);
+			break;
+		}
+
+		if (bounce->callback_sem.count >= DMA_BOUNCE_BUFFER_COUNT - 1)
+			dev_err(inst->dev, "WARNING: Ring buffer overflow");
+		chunk_size = count_left > DMA_BOUNCE_BUFFER_SIZE ?
+			DMA_BOUNCE_BUFFER_SIZE : count_left;
+		buf = bounce->buffer[chunk_no % DMA_BOUNCE_BUFFER_COUNT];
+		if (dma_dir == DMA_DEV_TO_MEM)
+			rv = copy_to_user(user_ptr, buf, chunk_size);
+		else
+			rv = copy_from_user(buf, user_ptr, chunk_size);
+		if (rv)
+			dev_err(inst->dev, "copy_*_user() failed!: %d", rv);
+		user_ptr += chunk_size;
+		count_left -= chunk_size;
+		chunk_no++;
+	}
+	return count;
+}
+
+static ssize_t
+bcm2835_read_file(struct file *f, char __user *user_ptr,
+		  size_t count, loff_t *offs)
+{
+	int odd_bytes;
+
+	dev_dbg(inst->dev, "User reading %zu bytes from SMI.", count);
+	/* We don't want to DMA a number of bytes % 4 != 0 (32 bit FIFO) */
+	if (count > DMA_THRESHOLD_BYTES)
+		odd_bytes = count & 0x3;
+	else
+		odd_bytes = count;
+	count -= odd_bytes;
+	if (count) {
+		struct bcm2835_smi_bounce_info *bounce;
+
+		count = bcm2835_smi_user_dma(smi_inst,
+			DMA_DEV_TO_MEM, user_ptr, count,
+			&bounce);
+		if (count)
+			count = dma_bounce_user(DMA_DEV_TO_MEM, user_ptr,
+				count, bounce);
+	}
+	if (odd_bytes) {
+		/* Read from FIFO directly if not using DMA */
+		uint8_t buf[DMA_THRESHOLD_BYTES];
+
+		bcm2835_smi_read_buf(smi_inst, buf, odd_bytes);
+		if (copy_to_user(user_ptr, buf, odd_bytes))
+			dev_err(inst->dev, "copy_to_user() failed.");
+		count += odd_bytes;
+
+	}
+	return count;
+}
+
+static ssize_t
+bcm2835_write_file(struct file *f, const char __user *user_ptr,
+		   size_t count, loff_t *offs)
+{
+	int odd_bytes;
+
+	dev_dbg(inst->dev, "User writing %zu bytes to SMI.", count);
+	if (count > DMA_THRESHOLD_BYTES)
+		odd_bytes = count & 0x3;
+	else
+		odd_bytes = count;
+	count -= odd_bytes;
+	if (count) {
+		struct bcm2835_smi_bounce_info *bounce;
+
+		count = bcm2835_smi_user_dma(smi_inst,
+			DMA_MEM_TO_DEV, (char __user *)user_ptr, count,
+			&bounce);
+		if (count)
+			count = dma_bounce_user(DMA_MEM_TO_DEV,
+				(char __user *)user_ptr,
+				count, bounce);
+	}
+	if (odd_bytes) {
+		uint8_t buf[DMA_THRESHOLD_BYTES];
+
+		if (copy_from_user(buf, user_ptr, odd_bytes))
+			dev_err(inst->dev, "copy_from_user() failed.");
+		else
+			bcm2835_smi_write_buf(smi_inst, buf, odd_bytes);
+		count += odd_bytes;
+	}
+	return count;
+}
+
+static const struct file_operations
+bcm2835_smi_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = bcm2835_smi_ioctl,
+	.open = bcm2835_smi_open,
+	.release = bcm2835_smi_release,
+	.read = bcm2835_read_file,
+	.write = bcm2835_write_file,
+};
+
+
+/****************************************************************************
+*
+*   bcm2835_smi_probe - called when the driver is loaded.
+*
+***************************************************************************/
+
+static int bcm2835_smi_dev_probe(struct platform_device *pdev)
+{
+	int err;
+	void *ptr_err;
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node, *smi_node;
+
+	if (!node) {
+		dev_err(dev, "No device tree node supplied!");
+		return -EINVAL;
+	}
+
+	smi_node = of_parse_phandle(node, "smi_handle", 0);
+
+	if (!smi_node) {
+		dev_err(dev, "No such property: smi_handle");
+		return -ENXIO;
+	}
+
+	smi_inst = bcm2835_smi_get(smi_node);
+
+	if (!smi_inst)
+		return -EPROBE_DEFER;
+
+	/* Allocate buffers and instance data */
+
+	inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL);
+
+	if (!inst)
+		return -ENOMEM;
+
+	inst->dev = dev;
+
+	/* Create character device entries */
+
+	err = alloc_chrdev_region(&bcm2835_smi_devid,
+				  DEVICE_MINOR, 1, DEVICE_NAME);
+	if (err != 0) {
+		dev_err(inst->dev, "unable to allocate device number");
+		return -ENOMEM;
+	}
+	cdev_init(&bcm2835_smi_cdev, &bcm2835_smi_fops);
+	bcm2835_smi_cdev.owner = THIS_MODULE;
+	err = cdev_add(&bcm2835_smi_cdev, bcm2835_smi_devid, 1);
+	if (err != 0) {
+		dev_err(inst->dev, "unable to register device");
+		err = -ENOMEM;
+		goto failed_cdev_add;
+	}
+
+	/* Create sysfs entries */
+
+	bcm2835_smi_class = class_create(THIS_MODULE, DEVICE_NAME);
+	ptr_err = bcm2835_smi_class;
+	if (IS_ERR(ptr_err))
+		goto failed_class_create;
+
+	bcm2835_smi_dev = device_create(bcm2835_smi_class, NULL,
+					bcm2835_smi_devid, NULL,
+					"smi");
+	ptr_err = bcm2835_smi_dev;
+	if (IS_ERR(ptr_err))
+		goto failed_device_create;
+
+	dev_info(inst->dev, "initialised");
+
+	return 0;
+
+failed_device_create:
+	class_destroy(bcm2835_smi_class);
+failed_class_create:
+	cdev_del(&bcm2835_smi_cdev);
+	err = PTR_ERR(ptr_err);
+failed_cdev_add:
+	unregister_chrdev_region(bcm2835_smi_devid, 1);
+	dev_err(dev, "could not load bcm2835_smi_dev");
+	return err;
+}
+
+/****************************************************************************
+*
+*   bcm2835_smi_remove - called when the driver is unloaded.
+*
+***************************************************************************/
+
+static int bcm2835_smi_dev_remove(struct platform_device *pdev)
+{
+	device_destroy(bcm2835_smi_class, bcm2835_smi_devid);
+	class_destroy(bcm2835_smi_class);
+	cdev_del(&bcm2835_smi_cdev);
+	unregister_chrdev_region(bcm2835_smi_devid, 1);
+
+	dev_info(inst->dev, "SMI character dev removed - OK");
+	return 0;
+}
+
+/****************************************************************************
+*
+*   Register the driver with device tree
+*
+***************************************************************************/
+
+static const struct of_device_id bcm2835_smi_dev_of_match[] = {
+	{.compatible = "brcm,bcm2835-smi-dev",},
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, bcm2835_smi_dev_of_match);
+
+static struct platform_driver bcm2835_smi_dev_driver = {
+	.probe = bcm2835_smi_dev_probe,
+	.remove = bcm2835_smi_dev_remove,
+	.driver = {
+		   .name = DRIVER_NAME,
+		   .owner = THIS_MODULE,
+		   .of_match_table = bcm2835_smi_dev_of_match,
+		   },
+};
+
+module_platform_driver(bcm2835_smi_dev_driver);
+
+MODULE_ALIAS("platform:smi-dev-bcm2835");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(
+	"Character device driver for BCM2835's secondary memory interface");
+MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/broadcom/Kconfig linux-5.10.52-v7l+/drivers/char/broadcom/Kconfig
--- linux-5.10.52-orig/drivers/char/broadcom/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/char/broadcom/Kconfig	2021-07-25 16:45:44.568649626 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+#
+# Broadcom char driver config
+#
+
+menuconfig BRCM_CHAR_DRIVERS
+	bool "Broadcom Char Drivers"
+	help
+	  Broadcom's char drivers
+
+if BRCM_CHAR_DRIVERS
+
+config BCM2708_VCMEM
+	bool "Videocore Memory"
+        default y
+        help
+          Helper for videocore memory access and total size allocation.
+
+config BCM_VCIO
+	tristate "Mailbox userspace access"
+	depends on BCM2835_MBOX
+	help
+	  Gives access to the mailbox property channel from userspace.
+
+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
+	default m
+	help
+		This driver provides a character device interface (ioctl + read/write) to
+		Broadcom's Secondary Memory interface. The low-level functionality is provided
+		by the SMI driver itself.
+
+config RPIVID_MEM
+	tristate "Character device driver for the Raspberry Pi RPIVid video decoder hardware"
+	default n
+	help
+		This driver provides a character device interface for memory-map operations
+		so userspace tools can access the control and status registers of the
+		Raspberry Pi RPiVid video decoder hardware.
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/broadcom/Makefile linux-5.10.52-v7l+/drivers/char/broadcom/Makefile
--- linux-5.10.52-orig/drivers/char/broadcom/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/char/broadcom/Makefile	2021-07-25 16:45:44.568649626 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2 @
+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
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/broadcom/rpivid-mem.c linux-5.10.52-v7l+/drivers/char/broadcom/rpivid-mem.c
--- linux-5.10.52-orig/drivers/char/broadcom/rpivid-mem.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/char/broadcom/rpivid-mem.c	2021-07-25 16:45:44.588649291 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/**
+ * rpivid-mem.c - character device access to the RPiVid decoder registers
+ *
+ * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
+ * register blocks such that ffmpeg plugins can access the hardware.
+ *
+ * Jonathan Bell <jonathan@raspberrypi.org>
+ * Copyright (c) 2019, 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/pagemap.h>
+#include <linux/io.h>
+
+#define DRIVER_NAME "rpivid-mem"
+#define DEVICE_MINOR 0
+
+struct rpivid_mem_priv {
+	dev_t devid;
+	struct class *class;
+	struct cdev rpivid_mem_cdev;
+	unsigned long regs_phys;
+	unsigned long mem_window_len;
+	struct device *dev;
+	const char *name;
+};
+
+static int rpivid_mem_open(struct inode *inode, struct file *file)
+{
+	int dev = iminor(inode);
+	int ret = 0;
+	struct rpivid_mem_priv *priv;
+
+	if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
+		ret = -ENXIO;
+
+	priv = container_of(inode->i_cdev, struct rpivid_mem_priv,
+				rpivid_mem_cdev);
+	if (!priv)
+		return -EINVAL;
+	file->private_data = priv;
+	return ret;
+}
+
+static int rpivid_mem_release(struct inode *inode, struct file *file)
+{
+	int dev = iminor(inode);
+	int ret = 0;
+
+	if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
+		ret = -ENXIO;
+
+	return ret;
+}
+
+static const struct vm_operations_struct rpivid_mem_vm_ops = {
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+	.access = generic_access_phys
+#endif
+};
+
+static int rpivid_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct rpivid_mem_priv *priv;
+	unsigned long pages;
+	unsigned long len;
+
+	priv = file->private_data;
+	pages = priv->regs_phys >> PAGE_SHIFT;
+	/*
+	 * The address decode is far larger than the actual number of registers.
+	 * Just map the whole lot in.
+	 */
+	len = min(vma->vm_end - vma->vm_start, priv->mem_window_len);
+	vma->vm_page_prot = phys_mem_access_prot(file, pages, len,
+						 vma->vm_page_prot);
+	vma->vm_ops = &rpivid_mem_vm_ops;
+	if (remap_pfn_range(vma, vma->vm_start,
+			    pages, len,
+			    vma->vm_page_prot)) {
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static const struct file_operations
+rpivid_mem_fops = {
+	.owner = THIS_MODULE,
+	.open = rpivid_mem_open,
+	.release = rpivid_mem_release,
+	.mmap = rpivid_mem_mmap,
+};
+
+static const struct of_device_id rpivid_mem_of_match[];
+static int rpivid_mem_probe(struct platform_device *pdev)
+{
+	int err;
+	const struct of_device_id *id;
+	struct device *dev = &pdev->dev;
+	struct resource *ioresource;
+	struct rpivid_mem_priv *priv;
+
+	/* Allocate buffers and instance data */
+
+	priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL);
+
+	if (!priv) {
+		err = -ENOMEM;
+		goto failed_inst_alloc;
+	}
+	platform_set_drvdata(pdev, priv);
+
+	priv->dev = dev;
+	id = of_match_device(rpivid_mem_of_match, dev);
+	if (!id)
+		return -EINVAL;
+	priv->name = id->data;
+
+	ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (ioresource) {
+		priv->regs_phys = ioresource->start;
+		priv->mem_window_len = (ioresource->end + 1) - ioresource->start;
+	} else {
+		dev_err(priv->dev, "failed to get IO resource");
+		err = -ENOENT;
+		goto failed_get_resource;
+	}
+
+	/* Create character device entries */
+
+	err = alloc_chrdev_region(&priv->devid,
+				  DEVICE_MINOR, 2, priv->name);
+	if (err != 0) {
+		dev_err(priv->dev, "unable to allocate device number");
+		goto failed_alloc_chrdev;
+	}
+	cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops);
+	priv->rpivid_mem_cdev.owner = THIS_MODULE;
+	err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 2);
+	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, "%s initialised: Registers at 0x%08lx length 0x%08lx",
+		priv->name, priv->regs_phys, priv->mem_window_len);
+
+	return 0;
+
+failed_device_create:
+	class_destroy(priv->class);
+failed_class_create:
+	cdev_del(&priv->rpivid_mem_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 rpivid_mem");
+	return err;
+}
+
+static int rpivid_mem_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rpivid_mem_priv *priv = platform_get_drvdata(pdev);
+
+	device_destroy(priv->class, priv->devid);
+	class_destroy(priv->class);
+	cdev_del(&priv->rpivid_mem_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 rpivid_mem_of_match[] = {
+	{
+		.compatible = "raspberrypi,rpivid-hevc-decoder",
+		.data = "rpivid-hevcmem",
+	},
+	{
+		.compatible = "raspberrypi,rpivid-h264-decoder",
+		.data = "rpivid-h264mem",
+	},
+	{
+		.compatible = "raspberrypi,rpivid-vp9-decoder",
+		.data = "rpivid-vp9mem",
+	},
+	/* The "intc" is included as this block of hardware contains the
+	 * "frame done" status flags.
+	 */
+	{
+		.compatible = "raspberrypi,rpivid-local-intc",
+		.data = "rpivid-intcmem",
+	},
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, rpivid_mem_of_match);
+
+static struct platform_driver rpivid_mem_driver = {
+	.probe = rpivid_mem_probe,
+	.remove = rpivid_mem_remove,
+	.driver = {
+		   .name = DRIVER_NAME,
+		   .owner = THIS_MODULE,
+		   .of_match_table = rpivid_mem_of_match,
+		   },
+};
+
+module_platform_driver(rpivid_mem_driver);
+
+MODULE_ALIAS("platform:rpivid-mem");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for accessing RPiVid decoder registers from userspace");
+MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.org>");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/broadcom/vcio.c linux-5.10.52-v7l+/drivers/char/broadcom/vcio.c
--- linux-5.10.52-orig/drivers/char/broadcom/vcio.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/char/broadcom/vcio.c	2021-07-25 16:45:44.588649291 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ *  Copyright (C) 2010 Broadcom
+ *  Copyright (C) 2015 Noralf Trønnes
+ *
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define MBOX_CHAN_PROPERTY 8
+
+#define VCIO_IOC_MAGIC 100
+#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
+#ifdef CONFIG_COMPAT
+#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
+#endif
+
+static struct {
+	dev_t devt;
+	struct cdev cdev;
+	struct class *class;
+	struct rpi_firmware *fw;
+} vcio;
+
+static int vcio_user_property_list(void *user)
+{
+	u32 *buf, size;
+	int ret;
+
+	/* The first 32-bit is the size of the buffer */
+	if (copy_from_user(&size, user, sizeof(size)))
+		return -EFAULT;
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, user, size)) {
+		kfree(buf);
+		return -EFAULT;
+	}
+
+	/* Strip off protocol encapsulation */
+	ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
+	if (ret) {
+		kfree(buf);
+		return ret;
+	}
+
+	buf[1] = RPI_FIRMWARE_STATUS_SUCCESS;
+	if (copy_to_user(user, buf, size))
+		ret = -EFAULT;
+
+	kfree(buf);
+
+	return ret;
+}
+
+static int vcio_device_open(struct inode *inode, struct file *file)
+{
+	try_module_get(THIS_MODULE);
+
+	return 0;
+}
+
+static int vcio_device_release(struct inode *inode, struct file *file)
+{
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
+			      unsigned long ioctl_param)
+{
+	switch (ioctl_num) {
+	case IOCTL_MBOX_PROPERTY:
+		return vcio_user_property_list((void *)ioctl_param);
+	default:
+		pr_err("unknown ioctl: %x\n", ioctl_num);
+		return -EINVAL;
+	}
+}
+
+#ifdef CONFIG_COMPAT
+static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
+				     unsigned long ioctl_param)
+{
+	switch (ioctl_num) {
+	case IOCTL_MBOX_PROPERTY32:
+		return vcio_user_property_list(compat_ptr(ioctl_param));
+	default:
+		pr_err("unknown ioctl: %x\n", ioctl_num);
+		return -EINVAL;
+	}
+}
+#endif
+
+const struct file_operations vcio_fops = {
+	.unlocked_ioctl = vcio_device_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = vcio_device_compat_ioctl,
+#endif
+	.open = vcio_device_open,
+	.release = vcio_device_release,
+};
+
+static int __init vcio_init(void)
+{
+	struct device_node *np;
+	static struct device *dev;
+	int ret;
+
+	np = of_find_compatible_node(NULL, NULL,
+				     "raspberrypi,bcm2835-firmware");
+	if (!of_device_is_available(np))
+		return -ENODEV;
+
+	vcio.fw = rpi_firmware_get(np);
+	if (!vcio.fw)
+		return -ENODEV;
+
+	ret = alloc_chrdev_region(&vcio.devt, 0, 1, "vcio");
+	if (ret) {
+		pr_err("failed to allocate device number\n");
+		return ret;
+	}
+
+	cdev_init(&vcio.cdev, &vcio_fops);
+	vcio.cdev.owner = THIS_MODULE;
+	ret = cdev_add(&vcio.cdev, vcio.devt, 1);
+	if (ret) {
+		pr_err("failed to register device\n");
+		goto err_unregister_chardev;
+	}
+
+	/*
+	 * Create sysfs entries
+	 * 'bcm2708_vcio' is used for backwards compatibility so we don't break
+	 * userspace. Raspian has a udev rule that changes the permissions.
+	 */
+	vcio.class = class_create(THIS_MODULE, "bcm2708_vcio");
+	if (IS_ERR(vcio.class)) {
+		ret = PTR_ERR(vcio.class);
+		pr_err("failed to create class\n");
+		goto err_cdev_del;
+	}
+
+	dev = device_create(vcio.class, NULL, vcio.devt, NULL, "vcio");
+	if (IS_ERR(dev)) {
+		ret = PTR_ERR(dev);
+		pr_err("failed to create device\n");
+		goto err_class_destroy;
+	}
+
+	return 0;
+
+err_class_destroy:
+	class_destroy(vcio.class);
+err_cdev_del:
+	cdev_del(&vcio.cdev);
+err_unregister_chardev:
+	unregister_chrdev_region(vcio.devt, 1);
+
+	return ret;
+}
+module_init(vcio_init);
+
+static void __exit vcio_exit(void)
+{
+	device_destroy(vcio.class, vcio.devt);
+	class_destroy(vcio.class);
+	cdev_del(&vcio.cdev);
+	unregister_chrdev_region(vcio.devt, 1);
+}
+module_exit(vcio_exit);
+
+MODULE_AUTHOR("Gray Girling");
+MODULE_AUTHOR("Noralf Trønnes");
+MODULE_DESCRIPTION("Mailbox userspace access");
+MODULE_LICENSE("GPL");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/broadcom/vc_mem.c linux-5.10.52-v7l+/drivers/char/broadcom/vc_mem.c
--- linux-5.10.52-orig/drivers/char/broadcom/vc_mem.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/char/broadcom/vc_mem.c	2021-07-25 16:45:44.588649291 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Copyright 2010 - 2011 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/dma-mapping.h>
+#include <linux/broadcom/vc_mem.h>
+
+#define DRIVER_NAME  "vc-mem"
+
+/* Device (/dev) related variables */
+static dev_t vc_mem_devnum;
+static struct class *vc_mem_class;
+static struct cdev vc_mem_cdev;
+static int vc_mem_inited;
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *vc_mem_debugfs_entry;
+#endif
+
+/*
+ * Videocore memory addresses and size
+ *
+ * Drivers that wish to know the videocore memory addresses and sizes should
+ * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
+ * headers. This allows the other drivers to not be tied down to a a certain
+ * address/size at compile time.
+ *
+ * In the future, the goal is to have the videocore memory virtual address and
+ * size be calculated at boot time rather than at compile time. The decision of
+ * where the videocore memory resides and its size would be in the hands of the
+ * bootloader (and/or kernel). When that happens, the values of these variables
+ * would be calculated and assigned in the init function.
+ */
+/* In the 2835 VC in mapped above ARM, but ARM has full access to VC space */
+unsigned long mm_vc_mem_phys_addr;
+EXPORT_SYMBOL(mm_vc_mem_phys_addr);
+unsigned int mm_vc_mem_size;
+EXPORT_SYMBOL(mm_vc_mem_size);
+unsigned int mm_vc_mem_base;
+EXPORT_SYMBOL(mm_vc_mem_base);
+
+static uint phys_addr;
+static uint mem_size;
+static uint mem_base;
+
+static int
+vc_mem_open(struct inode *inode, struct file *file)
+{
+	(void)inode;
+
+	pr_debug("%s: called file = 0x%p\n", __func__, file);
+
+	return 0;
+}
+
+static int
+vc_mem_release(struct inode *inode, struct file *file)
+{
+	(void)inode;
+
+	pr_debug("%s: called file = 0x%p\n", __func__, file);
+
+	return 0;
+}
+
+static void
+vc_mem_get_size(void)
+{
+}
+
+static void
+vc_mem_get_base(void)
+{
+}
+
+int
+vc_mem_get_current_size(void)
+{
+	return mm_vc_mem_size;
+}
+EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
+
+static long
+vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+
+	(void) cmd;
+	(void) arg;
+
+	pr_debug("%s: called file = 0x%p, cmd %08x\n", __func__, file, cmd);
+
+	switch (cmd) {
+	case VC_MEM_IOC_MEM_PHYS_ADDR:
+		{
+			pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
+				__func__, (void *)mm_vc_mem_phys_addr);
+
+			if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
+					 sizeof(mm_vc_mem_phys_addr))) {
+				rc = -EFAULT;
+			}
+			break;
+		}
+	case VC_MEM_IOC_MEM_SIZE:
+		{
+			/* Get the videocore memory size first */
+			vc_mem_get_size();
+
+			pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%x\n", __func__,
+				 mm_vc_mem_size);
+
+			if (copy_to_user((void *)arg, &mm_vc_mem_size,
+					 sizeof(mm_vc_mem_size))) {
+				rc = -EFAULT;
+			}
+			break;
+		}
+	case VC_MEM_IOC_MEM_BASE:
+		{
+			/* Get the videocore memory base */
+			vc_mem_get_base();
+
+			pr_debug("%s: VC_MEM_IOC_MEM_BASE=%x\n", __func__,
+				 mm_vc_mem_base);
+
+			if (copy_to_user((void *)arg, &mm_vc_mem_base,
+					 sizeof(mm_vc_mem_base))) {
+				rc = -EFAULT;
+			}
+			break;
+		}
+	case VC_MEM_IOC_MEM_LOAD:
+		{
+			/* Get the videocore memory base */
+			vc_mem_get_base();
+
+			pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%x\n", __func__,
+				mm_vc_mem_base);
+
+			if (copy_to_user((void *)arg, &mm_vc_mem_base,
+					 sizeof(mm_vc_mem_base))) {
+				rc = -EFAULT;
+			}
+			break;
+		}
+	default:
+		{
+			return -ENOTTY;
+		}
+	}
+	pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
+
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+vc_mem_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case VC_MEM_IOC_MEM_PHYS_ADDR32:
+		pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR32=0x%p\n",
+			 __func__, (void *)mm_vc_mem_phys_addr);
+
+		/* This isn't correct, but will cover us for now as
+		 * VideoCore is 32bit only.
+		 */
+		if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
+				 sizeof(compat_ulong_t)))
+			rc = -EFAULT;
+
+		break;
+
+	default:
+		rc = vc_mem_ioctl(file, cmd, arg);
+		break;
+	}
+
+	return rc;
+}
+#endif
+
+static int
+vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	int rc = 0;
+	unsigned long length = vma->vm_end - vma->vm_start;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+	pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
+		 __func__, (long)vma->vm_start, (long)vma->vm_end,
+		 (long)vma->vm_pgoff);
+
+	if (offset + length > mm_vc_mem_size) {
+		pr_err("%s: length %ld is too big\n", __func__, length);
+		return -EINVAL;
+	}
+	/* Do not cache the memory map */
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	rc = remap_pfn_range(vma, vma->vm_start,
+			     (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
+			     vma->vm_pgoff, length, vma->vm_page_prot);
+	if (rc)
+		pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
+
+	return rc;
+}
+
+/* File Operations for the driver. */
+static const struct file_operations vc_mem_fops = {
+	.owner = THIS_MODULE,
+	.open = vc_mem_open,
+	.release = vc_mem_release,
+	.unlocked_ioctl = vc_mem_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = vc_mem_compat_ioctl,
+#endif
+	.mmap = vc_mem_mmap,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static void vc_mem_debugfs_deinit(void)
+{
+	debugfs_remove_recursive(vc_mem_debugfs_entry);
+	vc_mem_debugfs_entry = NULL;
+}
+
+
+static int vc_mem_debugfs_init(
+	struct device *dev)
+{
+	vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
+	if (!vc_mem_debugfs_entry) {
+		dev_warn(dev, "could not create debugfs entry\n");
+		return -EFAULT;
+	}
+
+	debugfs_create_x32("vc_mem_phys_addr",
+				0444,
+				vc_mem_debugfs_entry,
+				(u32 *)&mm_vc_mem_phys_addr);
+	debugfs_create_x32("vc_mem_size",
+				0444,
+				vc_mem_debugfs_entry,
+				(u32 *)&mm_vc_mem_size);
+	debugfs_create_x32("vc_mem_base",
+				0444,
+				vc_mem_debugfs_entry,
+				(u32 *)&mm_vc_mem_base);
+
+	return 0;
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
+/* Module load/unload functions */
+
+static int __init
+vc_mem_init(void)
+{
+	int rc = -EFAULT;
+	struct device *dev;
+
+	pr_debug("%s: called\n", __func__);
+
+	mm_vc_mem_phys_addr = phys_addr;
+	mm_vc_mem_size = mem_size;
+	mm_vc_mem_base = mem_base;
+
+	vc_mem_get_size();
+
+	pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
+		mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size,
+		mm_vc_mem_size / (1024 * 1024));
+
+	rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME);
+	if (rc < 0) {
+		pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
+		       __func__, rc);
+		goto out_err;
+	}
+
+	cdev_init(&vc_mem_cdev, &vc_mem_fops);
+	rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1);
+	if (rc) {
+		pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
+		goto out_unregister;
+	}
+
+	vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
+	if (IS_ERR(vc_mem_class)) {
+		rc = PTR_ERR(vc_mem_class);
+		pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
+		goto out_cdev_del;
+	}
+
+	dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
+			    DRIVER_NAME);
+	if (IS_ERR(dev)) {
+		rc = PTR_ERR(dev);
+		pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
+		goto out_class_destroy;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	/* don't fail if the debug entries cannot be created */
+	vc_mem_debugfs_init(dev);
+#endif
+
+	vc_mem_inited = 1;
+	return 0;
+
+	device_destroy(vc_mem_class, vc_mem_devnum);
+
+out_class_destroy:
+	class_destroy(vc_mem_class);
+	vc_mem_class = NULL;
+
+out_cdev_del:
+	cdev_del(&vc_mem_cdev);
+
+out_unregister:
+	unregister_chrdev_region(vc_mem_devnum, 1);
+
+out_err:
+	return -1;
+}
+
+static void __exit
+vc_mem_exit(void)
+{
+	pr_debug("%s: called\n", __func__);
+
+	if (vc_mem_inited) {
+#if CONFIG_DEBUG_FS
+		vc_mem_debugfs_deinit();
+#endif
+		device_destroy(vc_mem_class, vc_mem_devnum);
+		class_destroy(vc_mem_class);
+		cdev_del(&vc_mem_cdev);
+		unregister_chrdev_region(vc_mem_devnum, 1);
+	}
+}
+
+module_init(vc_mem_init);
+module_exit(vc_mem_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Broadcom Corporation");
+
+module_param(phys_addr, uint, 0644);
+module_param(mem_size, uint, 0644);
+module_param(mem_base, uint, 0644);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/hw_random/bcm2835-rng.c linux-5.10.52-v7l+/drivers/char/hw_random/bcm2835-rng.c
--- linux-5.10.52-orig/drivers/char/hw_random/bcm2835-rng.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/char/hw_random/bcm2835-rng.c	2021-07-25 16:45:44.588649291 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:105 @
 	}
 
 	/* set warm-up count & enable */
-	rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
-	rng_writel(priv, RNG_RBGEN, RNG_CTRL);
+	if (!(rng_readl(priv, RNG_CTRL) & RNG_RBGEN)) {
+		rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
+		rng_writel(priv, RNG_RBGEN, RNG_CTRL);
+	}
 
 	return ret;
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/hw_random/iproc-rng200.c linux-5.10.52-v7l+/drivers/char/hw_random/iproc-rng200.c
--- linux-5.10.52-orig/drivers/char/hw_random/iproc-rng200.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/char/hw_random/iproc-rng200.c	2021-07-25 16:45:44.608648956 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:32 @
 #define RNG_CTRL_RNG_RBGEN_MASK				0x00001FFF
 #define RNG_CTRL_RNG_RBGEN_ENABLE			0x00000001
 #define RNG_CTRL_RNG_RBGEN_DISABLE			0x00000000
+#define RNG_CTRL_RNG_DIV_CTRL_SHIFT			13
 
 #define RNG_SOFT_RESET_OFFSET				0x04
 #define RNG_SOFT_RESET					0x00000001
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:40 @
 #define RBG_SOFT_RESET_OFFSET				0x08
 #define RBG_SOFT_RESET					0x00000001
 
+#define RNG_TOTAL_BIT_COUNT_OFFSET			0x0C
+
+#define RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET		0x10
+
 #define RNG_INT_STATUS_OFFSET				0x18
 #define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK	0x80000000
 #define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK	0x00020000
 #define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK		0x00000020
 #define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK	0x00000001
 
+#define RNG_INT_ENABLE_OFFSET				0x1C
+
 #define RNG_FIFO_DATA_OFFSET				0x20
 
 #define RNG_FIFO_COUNT_OFFSET				0x24
 #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK		0x000000FF
+#define RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT		8
 
 struct iproc_rng200_dev {
 	struct hwrng rng;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:177 @
 	return 0;
 }
 
+static int bcm2711_rng200_read(struct hwrng *rng, void *buf, size_t max,
+			       bool wait)
+{
+	struct iproc_rng200_dev *priv = to_rng_priv(rng);
+	u32 max_words = max / sizeof(u32);
+	u32 num_words, count, val;
+
+	/* ensure warm up period has elapsed */
+	while (1) {
+		val = ioread32(priv->base + RNG_TOTAL_BIT_COUNT_OFFSET);
+		if (val > 16)
+			break;
+		cpu_relax();
+	}
+
+	/* ensure fifo is not empty */
+	while (1) {
+		num_words = ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) &
+			    RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK;
+		if (num_words)
+			break;
+		if (!wait)
+			return 0;
+		cpu_relax();
+	}
+
+	if (num_words > max_words)
+		num_words = max_words;
+
+	for (count = 0; count < num_words; count++) {
+		((u32 *)buf)[count] = ioread32(priv->base +
+					       RNG_FIFO_DATA_OFFSET);
+	}
+
+	return num_words * sizeof(u32);
+}
+
+static int bcm2711_rng200_init(struct hwrng *rng)
+{
+	struct iproc_rng200_dev *priv = to_rng_priv(rng);
+	uint32_t val;
+
+	if (ioread32(priv->base + RNG_CTRL_OFFSET) & RNG_CTRL_RNG_RBGEN_MASK)
+		return 0;
+
+	/* initial numbers generated are "less random" so will be discarded */
+	val = 0x40000;
+	iowrite32(val, priv->base + RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET);
+	/* min fifo count to generate full interrupt */
+	val = 2 << RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT;
+	iowrite32(val, priv->base + RNG_FIFO_COUNT_OFFSET);
+	/* enable the rng - 1Mhz sample rate */
+	val = (0x3 << RNG_CTRL_RNG_DIV_CTRL_SHIFT) | RNG_CTRL_RNG_RBGEN_MASK;
+	iowrite32(val, priv->base + RNG_CTRL_OFFSET);
+
+	return 0;
+}
+
 static void iproc_rng200_cleanup(struct hwrng *rng)
 {
 	struct iproc_rng200_dev *priv = to_rng_priv(rng);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:264 @
 		return PTR_ERR(priv->base);
 	}
 
-	priv->rng.name = "iproc-rng200";
-	priv->rng.read = iproc_rng200_read;
-	priv->rng.init = iproc_rng200_init;
+	priv->rng.name = pdev->name;
 	priv->rng.cleanup = iproc_rng200_cleanup;
 
+	if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-rng200")) {
+		priv->rng.init = bcm2711_rng200_init;
+		priv->rng.read = bcm2711_rng200_read;
+	} else {
+		priv->rng.init = iproc_rng200_init;
+		priv->rng.read = iproc_rng200_read;
+	}
+
 	/* Register driver */
 	ret = devm_hwrng_register(dev, &priv->rng);
 	if (ret) {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/hw_random/Kconfig linux-5.10.52-v7l+/drivers/char/hw_random/Kconfig
--- linux-5.10.52-orig/drivers/char/hw_random/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/char/hw_random/Kconfig	2021-07-25 16:45:44.588649291 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:107 @
 	default HW_RANDOM
 	help
 	  This driver provides kernel-side support for the RNG200
-	  hardware found on the Broadcom iProc and STB SoCs.
+	  hardware found on the Broadcom iProc, BCM2711 and STB SoCs.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called iproc-rng200
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/Kconfig linux-5.10.52-v7l+/drivers/char/Kconfig
--- linux-5.10.52-orig/drivers/char/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/char/Kconfig	2021-07-25 16:45:44.528650297 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:8 @
 
 menu "Character devices"
 
+source "drivers/char/broadcom/Kconfig"
+
 source "drivers/tty/Kconfig"
 
 config TTY_PRINTK
diff -Nur --no-dereference linux-5.10.52-orig/drivers/char/Makefile linux-5.10.52-v7l+/drivers/char/Makefile
--- linux-5.10.52-orig/drivers/char/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/char/Makefile	2021-07-25 16:45:44.528650297 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:50 @
 obj-$(CONFIG_XILLYBUS)		+= xillybus/
 obj-$(CONFIG_POWERNV_OP_PANEL)	+= powernv-op-panel.o
 obj-$(CONFIG_ADI)		+= adi.o
+obj-$(CONFIG_BRCM_CHAR_DRIVERS) += broadcom/
diff -Nur --no-dereference linux-5.10.52-orig/drivers/clk/bcm/clk-bcm2835.c linux-5.10.52-v7l+/drivers/clk/bcm/clk-bcm2835.c
--- linux-5.10.52-orig/drivers/clk/bcm/clk-bcm2835.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/clk/bcm/clk-bcm2835.c	2021-07-25 16:45:44.828645267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:38 @
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <dt-bindings/clock/bcm2835.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
 
 #define CM_PASSWORD		0x5a000000
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:299 @
 #define SOC_BCM2711		BIT(1)
 #define SOC_ALL			(SOC_BCM2835 | SOC_BCM2711)
 
+#define VCMSG_ID_CORE_CLOCK     4
+
 /*
  * Names of clocks used within the driver that need to be replaced
  * with an external parent's name.  This array is in the order that
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:319 @
 struct bcm2835_cprman {
 	struct device *dev;
 	void __iomem *regs;
+	struct rpi_firmware *fw;
 	spinlock_t regs_lock; /* spinlock for all clocks */
 	unsigned int soc;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:647 @
 	spin_unlock(&cprman->regs_lock);
 
 	/* Wait for the PLL to lock. */
-	timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
-	while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
-		if (ktime_after(ktime_get(), timeout)) {
-			dev_err(cprman->dev, "%s: couldn't lock PLL\n",
-				clk_hw_get_name(hw));
-			return -ETIMEDOUT;
-		}
+	if (strcmp(data->name, "pllh")) {
+		timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
+		while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
+			if (ktime_after(ktime_get(), timeout)) {
+				dev_err(cprman->dev, "%s: couldn't lock PLL\n",
+					clk_hw_get_name(hw));
+				return -ETIMEDOUT;
+			}
 
-		cpu_relax();
+			cpu_relax();
+		}
 	}
 
 	cprman_write(cprman, data->a2w_ctrl_reg,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1025 @
 	return bcm2835_clock_rate_from_divisor(clock, parent_rate, div);
 }
 
+static unsigned long bcm2835_clock_get_rate_vpu(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct bcm2835_cprman *cprman = clock->cprman;
+
+	if (cprman->fw) {
+		struct {
+			u32 id;
+			u32 val;
+		} packet;
+
+		packet.id = VCMSG_ID_CORE_CLOCK;
+		packet.val = 0;
+
+		if (!rpi_firmware_property(cprman->fw,
+					   RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
+					   &packet, sizeof(packet)))
+			return packet.val;
+	}
+
+	return bcm2835_clock_get_rate(hw, parent_rate);
+}
+
 static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock)
 {
 	struct bcm2835_cprman *cprman = clock->cprman;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1107 @
 	return 0;
 }
 
-static int bcm2835_clock_set_rate(struct clk_hw *hw,
-				  unsigned long rate, unsigned long parent_rate)
+static int bcm2835_clock_set_rate_and_parent(struct clk_hw *hw,
+					     unsigned long rate,
+					     unsigned long parent_rate,
+					     u8 parent)
 {
 	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
 	struct bcm2835_cprman *cprman = clock->cprman;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1120 @
 
 	spin_lock(&cprman->regs_lock);
 
-	/*
-	 * Setting up frac support
-	 *
-	 * In principle it is recommended to stop/start the clock first,
-	 * but as we set CLK_SET_RATE_GATE during registration of the
-	 * clock this requirement should be take care of by the
-	 * clk-framework.
-	 */
-	ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC;
+	ctl = cprman_read(cprman, data->ctl_reg);
+
+	/* If the clock is running, we have to pause clock generation while
+	 * updating the control and div regs.  This is glitchless (no clock
+	 * signals generated faster than the rate) but each reg access is two
+	 * OSC cycles so the clock will slow down for a moment.
+	 */
+	if (ctl & CM_ENABLE) {
+		cprman_write(cprman, data->ctl_reg, ctl & ~CM_ENABLE);
+		bcm2835_clock_wait_busy(clock);
+	}
+
+	if (parent != 0xff) {
+		ctl &= ~(CM_SRC_MASK << CM_SRC_SHIFT);
+		ctl |= parent << CM_SRC_SHIFT;
+	}
+
+	ctl &= ~CM_FRAC;
 	ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
 	cprman_write(cprman, data->ctl_reg, ctl);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1148 @
 	return 0;
 }
 
+static int bcm2835_clock_set_rate(struct clk_hw *hw,
+				  unsigned long rate, unsigned long parent_rate)
+{
+	return bcm2835_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff);
+}
+
 static bool
 bcm2835_clk_is_pllc(struct clk_hw *hw)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1337 @
 	.unprepare = bcm2835_clock_off,
 	.recalc_rate = bcm2835_clock_get_rate,
 	.set_rate = bcm2835_clock_set_rate,
+	.set_rate_and_parent = bcm2835_clock_set_rate_and_parent,
 	.determine_rate = bcm2835_clock_determine_rate,
 	.set_parent = bcm2835_clock_set_parent,
 	.get_parent = bcm2835_clock_get_parent,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1355 @
  */
 static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
 	.is_prepared = bcm2835_vpu_clock_is_on,
-	.recalc_rate = bcm2835_clock_get_rate,
+	.recalc_rate = bcm2835_clock_get_rate_vpu,
 	.set_rate = bcm2835_clock_set_rate,
 	.determine_rate = bcm2835_clock_determine_rate,
 	.set_parent = bcm2835_clock_set_parent,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1363 @
 	.debug_init = bcm2835_clock_debug_init,
 };
 
+static bool bcm2835_clk_is_claimed(const char *name);
+
 static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
 					   const void *data)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1382 @
 	init.ops = &bcm2835_pll_clk_ops;
 	init.flags = pll_data->flags | CLK_IGNORE_UNUSED;
 
+	if (!bcm2835_clk_is_claimed(pll_data->name))
+		init.flags |= CLK_IS_CRITICAL;
+
 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 	if (!pll)
 		return NULL;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1440 @
 	divider->div.hw.init = &init;
 	divider->div.table = NULL;
 
+	if (!(cprman_read(cprman, divider_data->cm_reg) & divider_data->hold_mask)) {
+		if (!bcm2835_clk_is_claimed(divider_data->source_pll))
+			init.flags |= CLK_IS_CRITICAL;
+		if (!bcm2835_clk_is_claimed(divider_data->name))
+			divider->div.flags |= CLK_IS_CRITICAL;
+	}
+
 	divider->cprman = cprman;
 	divider->data = divider_data;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1501 @
 	init.flags = clock_data->flags | CLK_IGNORE_UNUSED;
 
 	/*
+	 * Some GPIO clocks for ethernet/wifi PLLs are marked as
+	 * critical (since some platforms use them), but if the
+	 * firmware didn't have them turned on then they clearly
+	 * aren't actually critical.
+	 */
+	if ((cprman_read(cprman, clock_data->ctl_reg) & CM_ENABLE) == 0)
+		init.flags &= ~CLK_IS_CRITICAL;
+
+	/*
 	 * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate
 	 * rate changes on at least of the parents.
 	 */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1520 @
 		init.ops = &bcm2835_vpu_clock_clk_ops;
 	} else {
 		init.ops = &bcm2835_clock_clk_ops;
-		init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
 
 		/* If the clock wasn't actually enabled at boot, it's not
 		 * critical.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1744 @
 		.hold_mask = CM_PLLA_HOLDCORE,
 		.fixed_divider = 1,
 		.flags = CLK_SET_RATE_PARENT),
-	[BCM2835_PLLA_PER]	= REGISTER_PLL_DIV(
-		SOC_ALL,
-		.name = "plla_per",
-		.source_pll = "plla",
-		.cm_reg = CM_PLLA,
-		.a2w_reg = A2W_PLLA_PER,
-		.load_mask = CM_PLLA_LOADPER,
-		.hold_mask = CM_PLLA_HOLDPER,
-		.fixed_divider = 1,
-		.flags = CLK_SET_RATE_PARENT),
+
+	/*
+	 * PLLA_PER is used for gpu clocks. Controlled by firmware, see
+	 * clk-raspberrypi.c.
+	 */
+
 	[BCM2835_PLLA_DSI0]	= REGISTER_PLL_DIV(
 		SOC_ALL,
 		.name = "plla_dsi0",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2050 @
 		.int_bits = 6,
 		.frac_bits = 0,
 		.tcnt_mux = 3),
-	[BCM2835_CLOCK_V3D]	= REGISTER_VPU_CLK(
-		SOC_ALL,
-		.name = "v3d",
-		.ctl_reg = CM_V3DCTL,
-		.div_reg = CM_V3DDIV,
-		.int_bits = 4,
-		.frac_bits = 8,
-		.tcnt_mux = 4),
+
+	/*
+	 * CLOCK_V3D is used for v3d clock. Controlled by firmware, see
+	 * clk-raspberrypi.c.
+	 */
+
 	/*
 	 * VPU clock.  This doesn't have an enable bit, since it drives
 	 * the bus for everything else, and is special so it doesn't need
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2281 @
 		.ctl_reg = CM_PERIICTL),
 };
 
+static bool bcm2835_clk_claimed[ARRAY_SIZE(clk_desc_array)];
+
 /*
  * Permanently take a reference on the parent of the SDRAM clock.
  *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2302 @
 	return clk_prepare_enable(parent);
 }
 
+static bool bcm2835_clk_is_claimed(const char *name)
+{
+	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 bcm2835_clk_claimed[i];
+		}
+	}
+
+	return false;
+}
+
 static int bcm2835_clk_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2325 @
 	const struct bcm2835_clk_desc *desc;
 	const size_t asize = ARRAY_SIZE(clk_desc_array);
 	const struct cprman_plat_data *pdata;
+	struct device_node *fw_node;
 	size_t i;
+	u32 clk_id;
 	int ret;
 
 	pdata = of_device_get_match_data(&pdev->dev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2346 @
 	if (IS_ERR(cprman->regs))
 		return PTR_ERR(cprman->regs);
 
+	fw_node = of_parse_phandle(dev->of_node, "firmware", 0);
+	if (fw_node) {
+		struct rpi_firmware *fw = rpi_firmware_get(NULL);
+		if (!fw)
+			return -EPROBE_DEFER;
+		cprman->fw = fw;
+	}
+
+	memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed));
+	for (i = 0;
+	     !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks",
+					 i, &clk_id);
+	     i++)
+		bcm2835_clk_claimed[clk_id]= true;
+
 	memcpy(cprman->real_parent_names, cprman_parent_names,
 	       sizeof(cprman_parent_names));
 	of_clk_parent_fill(dev->of_node, cprman->real_parent_names,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2394 @
 	if (ret)
 		return ret;
 
-	return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
+	ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
 				      &cprman->onecell);
+	if (ret)
+		return ret;
+
+	/* note that we have registered all the clocks */
+	dev_dbg(dev, "registered %zd clocks\n", asize);
+
+	return 0;
 }
 
 static const struct cprman_plat_data cprman_bcm2835_plat_data = {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2428 @
 	.probe          = bcm2835_clk_probe,
 };
 
-builtin_platform_driver(bcm2835_clk_driver);
+static int __init __bcm2835_clk_driver_init(void)
+{
+	return platform_driver_register(&bcm2835_clk_driver);
+}
+postcore_initcall(__bcm2835_clk_driver_init);
 
 MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
 MODULE_DESCRIPTION("BCM2835 clock driver");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/clk/bcm/clk-raspberrypi.c linux-5.10.52-v7l+/drivers/clk/bcm/clk-raspberrypi.c
--- linux-5.10.52-orig/drivers/clk/bcm/clk-raspberrypi.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/clk/bcm/clk-raspberrypi.c	2021-07-25 16:45:44.828645267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:100 @
 	struct raspberrypi_firmware_prop msg = {
 		.id = cpu_to_le32(data->id),
 		.val = cpu_to_le32(*val),
-		.disable_turbo = cpu_to_le32(1),
+		.disable_turbo = cpu_to_le32(0),
 	};
 	int ret;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:274 @
 		case RPI_FIRMWARE_CORE_CLK_ID:
 		case RPI_FIRMWARE_M2MC_CLK_ID:
 		case RPI_FIRMWARE_V3D_CLK_ID:
+		case RPI_FIRMWARE_HEVC_CLK_ID:
 		case RPI_FIRMWARE_PIXEL_BVB_CLK_ID:
 			hw = raspberrypi_clk_register(rpi, clks->parent,
 						      clks->id);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/clk/clk-allo-dac.c linux-5.10.52-v7l+/drivers/clk/clk-allo-dac.c
--- linux-5.10.52-orig/drivers/clk/clk-allo-dac.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/clk/clk-allo-dac.c	2021-07-25 16:45:44.848644932 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Clock Driver for Allo DAC
+ *
+ * Author:	Baswaraj K <jaikumar@cem-solutions.net>
+ *		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 <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+/* 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");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/clk/clk.c linux-5.10.52-v7l+/drivers/clk/clk.c
--- linux-5.10.52-orig/drivers/clk/clk.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/clk/clk.c	2021-07-25 16:45:44.918643758 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:80 @
 	unsigned int		protect_count;
 	unsigned long		min_rate;
 	unsigned long		max_rate;
+	unsigned long		default_request_rate;
 	unsigned long		accuracy;
 	int			phase;
 	struct clk_duty		duty;
 	struct hlist_head	children;
 	struct hlist_node	child_node;
 	struct hlist_head	clks;
+	struct list_head	pending_requests;
 	unsigned int		notifier_count;
 #ifdef CONFIG_DEBUG_FS
 	struct dentry		*dentry;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:110 @
 	struct hlist_node clks_node;
 };
 
+struct clk_request {
+	struct list_head list;
+	struct clk *clk;
+	unsigned long rate;
+};
+
 /***           runtime pm          ***/
 static int clk_pm_runtime_get(struct clk_core *core)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1319 @
 	if (!core)
 		return 0;
 
+	req->rate = clamp(req->rate, req->min_rate, req->max_rate);
+
 	/*
 	 * At this point, core protection will be disabled if
 	 * - if the provider is not protected at all
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1426 @
 {
 	int ret;
 	struct clk_rate_request req;
+	struct clk_request *clk_req;
 
 	clk_core_get_boundaries(hw->core, &req.min_rate, &req.max_rate);
 	req.rate = rate;
 
+	list_for_each_entry(clk_req, &hw->core->pending_requests, list)
+		req.min_rate = max(clk_req->rate, req.min_rate);
+
 	ret = clk_core_round_rate_nolock(hw->core, &req);
 	if (ret)
 		return 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1454 @
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
 	struct clk_rate_request req;
+	struct clk_request *clk_req;
 	int ret;
 
 	if (!clk)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1468 @
 	clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate);
 	req.rate = rate;
 
+	list_for_each_entry(clk_req, &clk->core->pending_requests, list)
+		req.min_rate = max(clk_req->rate, req.min_rate);
+
 	ret = clk_core_round_rate_nolock(clk->core, &req);
 
 	if (clk->exclusive_count)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1938 @
 	unsigned long new_rate;
 	unsigned long min_rate;
 	unsigned long max_rate;
+	struct clk_request *req;
 	int p_index = 0;
 	long ret;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1953 @
 
 	clk_core_get_boundaries(core, &min_rate, &max_rate);
 
+	list_for_each_entry(req, &core->pending_requests, list)
+		min_rate = max(req->rate, min_rate);
+
 	/* find the closest rate and parent clk/rate */
 	if (clk_core_can_round(core)) {
 		struct clk_rate_request req;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2160 @
 {
 	int ret, cnt;
 	struct clk_rate_request req;
+	struct clk_request *clk_req;
 
 	lockdep_assert_held(&prepare_lock);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2175 @
 	clk_core_get_boundaries(core, &req.min_rate, &req.max_rate);
 	req.rate = req_rate;
 
+	list_for_each_entry(clk_req, &core->pending_requests, list)
+		req.min_rate = max(clk_req->rate, req.min_rate);
+
 	ret = clk_core_round_rate_nolock(core, &req);
 
 	/* restore the protection */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2271 @
 
 	ret = clk_core_set_rate_nolock(clk->core, rate);
 
+	if (!list_empty(&clk->core->pending_requests))
+		clk->core->default_request_rate = rate;
+
 	if (clk->exclusive_count)
 		clk_core_rate_protect(clk->core);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2434 @
 EXPORT_SYMBOL_GPL(clk_set_max_rate);
 
 /**
+ * clk_request_start - Request a rate to be enforced temporarily
+ * @clk: the clk to act on
+ * @rate: the new rate asked for
+ *
+ * This function will create a request to temporarily increase the rate
+ * of the clock to a given rate to a certain minimum.
+ *
+ * This is meant as a best effort mechanism and while the rate of the
+ * clock will be guaranteed to be equal or higher than the requested
+ * rate, there's none on what the actual rate will be due to other
+ * factors (other requests previously set, clock boundaries, etc.).
+ *
+ * Once the request is marked as done through clk_request_done(), the
+ * rate will be reverted back to what the rate was before the request.
+ *
+ * The reported boundaries of the clock will also be adjusted so that
+ * clk_round_rate() take those requests into account. A call to
+ * clk_set_rate() during a request will affect the rate the clock will
+ * return to after the requests on that clock are done.
+ *
+ * Returns 0 on success, an ERR_PTR otherwise.
+ */
+struct clk_request *clk_request_start(struct clk *clk, unsigned long rate)
+{
+	struct clk_request *req;
+	int ret;
+
+	if (!clk)
+		return ERR_PTR(-EINVAL);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return ERR_PTR(-ENOMEM);
+
+	clk_prepare_lock();
+
+	req->clk = clk;
+	req->rate = rate;
+
+	if (list_empty(&clk->core->pending_requests))
+		clk->core->default_request_rate = clk_core_get_rate_recalc(clk->core);
+
+	ret = clk_core_set_rate_nolock(clk->core, rate);
+	if (ret) {
+		clk_prepare_unlock();
+		kfree(req);
+		return ERR_PTR(ret);
+	}
+
+	list_add_tail(&req->list, &clk->core->pending_requests);
+	clk_prepare_unlock();
+
+	return req;
+}
+EXPORT_SYMBOL_GPL(clk_request_start);
+
+/**
+ * clk_request_done - Mark a clk_request as done
+ * @req: the request to mark done
+ *
+ * This function will remove the rate request from the clock and adjust
+ * the clock rate back to either to what it was before the request
+ * started, or if there's any other request on that clock to a proper
+ * rate for them.
+ */
+void clk_request_done(struct clk_request *req)
+{
+	struct clk_core *core;
+
+	if (!req)
+		return;
+	core = req->clk->core;
+
+	clk_prepare_lock();
+
+	list_del(&req->list);
+
+	if (list_empty(&core->pending_requests)) {
+		clk_core_set_rate_nolock(core, core->default_request_rate);
+		core->default_request_rate = 0;
+	} else {
+		struct clk_request *cur_req;
+		unsigned long new_rate = 0;
+
+		list_for_each_entry(cur_req, &core->pending_requests, list)
+			new_rate = max(new_rate, cur_req->rate);
+
+		clk_core_set_rate_nolock(core, new_rate);
+	}
+
+	clk_prepare_unlock();
+
+	kfree(req);
+}
+EXPORT_SYMBOL_GPL(clk_request_done);
+
+/**
  * clk_get_parent - return the parent of a clk
  * @clk: the clk whose parent gets returned
  *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3940 @
 		goto fail_parents;
 
 	INIT_HLIST_HEAD(&core->clks);
+	INIT_LIST_HEAD(&core->pending_requests);
 
 	/*
 	 * Don't call clk_hw_create_clk() here because that would pin the
diff -Nur --no-dereference linux-5.10.52-orig/drivers/clk/clk-hifiberry-dachd.c linux-5.10.52-v7l+/drivers/clk/clk-hifiberry-dachd.c
--- linux-5.10.52-orig/drivers/clk/clk-hifiberry-dachd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/clk/clk-hifiberry-dachd.c	2021-07-25 16:45:44.868644597 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Clock Driver for HiFiBerry DAC+ HD
+ *
+ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
+ *         Copyright 2020
+ *
+ * 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 <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#define NO_PLL_RESET			0
+#define PLL_RESET			1
+#define HIFIBERRY_PLL_MAX_REGISTER	256
+#define DEFAULT_RATE			44100
+
+static struct reg_default hifiberry_pll_reg_defaults[] = {
+	{0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00},
+	{0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C},
+	{0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C},
+	{0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00},
+	{0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00},
+	{0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01},
+	{0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00},
+	{0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00},
+	{0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00},
+	{0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00},
+	{0xB7, 0x92},
+	{0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13},
+	{0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0},
+	{0x3D, 0x7A},
+	{0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42},
+	{ 177, 0xAC},
+};
+static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
+static int num_common_pll_regs;
+static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
+static int num_dedicated_192k_pll_regs;
+static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
+static int num_dedicated_96k_pll_regs;
+static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
+static int num_dedicated_48k_pll_regs;
+static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
+static int num_dedicated_176k4_pll_regs;
+static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
+static int num_dedicated_88k2_pll_regs;
+static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
+static int num_dedicated_44k1_pll_regs;
+
+/**
+ * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk
+ * @hw: clk_hw for the common clk framework
+ */
+struct clk_hifiberry_drvdata {
+	struct regmap *regmap;
+	struct clk *clk;
+	struct clk_hw hw;
+	unsigned long rate;
+};
+
+#define to_hifiberry_clk(_hw) \
+	container_of(_hw, struct clk_hifiberry_drvdata, hw)
+
+static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap,
+				struct reg_default *regs,
+				int num, int do_pll_reset)
+{
+	int i;
+	int ret = 0;
+	char pll_soft_reset[] = { 177, 0xAC, };
+
+	for (i = 0; i < num; i++) {
+		ret |= regmap_write(regmap, regs[i].reg, regs[i].def);
+		if (ret)
+			return ret;
+	}
+	if (do_pll_reset) {
+		ret |= regmap_write(regmap, pll_soft_reset[0],
+						pll_soft_reset[1]);
+		mdelay(10);
+	}
+	return ret;
+}
+
+static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw,
+	unsigned long parent_rate)
+{
+	return to_hifiberry_clk(hw)->rate;
+}
+
+static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw,
+	unsigned long rate, unsigned long *parent_rate)
+{
+	return rate;
+}
+
+static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw,
+	unsigned long rate, unsigned long parent_rate)
+{
+	int ret;
+	struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw);
+
+	switch (rate) {
+	case 44100:
+		ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
+			dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs,
+			PLL_RESET);
+		break;
+	case 88200:
+		ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
+			dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs,
+			PLL_RESET);
+		break;
+	case 176400:
+		ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
+			dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs,
+			PLL_RESET);
+		break;
+	case 48000:
+		ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
+			dedicated_48k_pll_regs,	num_dedicated_48k_pll_regs,
+			PLL_RESET);
+		break;
+	case 96000:
+		ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
+			dedicated_96k_pll_regs,	num_dedicated_96k_pll_regs,
+			PLL_RESET);
+		break;
+	case 192000:
+		ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
+			dedicated_192k_pll_regs, num_dedicated_192k_pll_regs,
+			PLL_RESET);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	to_hifiberry_clk(hw)->rate = rate;
+
+	return ret;
+}
+
+const struct clk_ops clk_hifiberry_dachd_rate_ops = {
+	.recalc_rate = clk_hifiberry_dachd_recalc_rate,
+	.round_rate = clk_hifiberry_dachd_round_rate,
+	.set_rate = clk_hifiberry_dachd_set_rate,
+};
+
+static int clk_hifiberry_get_prop_values(struct device *dev,
+					char *prop_name,
+					struct reg_default *regs)
+{
+	int ret;
+	int i;
+	u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER];
+
+	ret = of_property_read_variable_u8_array(dev->of_node, prop_name,
+			tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER);
+	if (ret < 0)
+		return ret;
+	if (ret & 1) {
+		dev_err(dev,
+			"%s <%s> -> #%i odd number of bytes for reg/val pairs!",
+			__func__,
+			prop_name,
+			ret);
+		return -EINVAL;
+	}
+	ret /= 2;
+	for (i = 0; i < ret; i++) {
+		regs[i].reg = (u32)tmp[2 * i];
+		regs[i].def = (u32)tmp[2 * i + 1];
+	}
+	return ret;
+}
+
+
+static int clk_hifiberry_dachd_dt_parse(struct device *dev)
+{
+	num_common_pll_regs = clk_hifiberry_get_prop_values(dev,
+				"common_pll_regs", common_pll_regs);
+	num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev,
+				"44k1_pll_regs", dedicated_44k1_pll_regs);
+	num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev,
+				"88k2_pll_regs", dedicated_88k2_pll_regs);
+	num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev,
+				"176k4_pll_regs", dedicated_176k4_pll_regs);
+	num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev,
+				"48k_pll_regs", dedicated_48k_pll_regs);
+	num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev,
+				"96k_pll_regs", dedicated_96k_pll_regs);
+	num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev,
+				"192k_pll_regs", dedicated_192k_pll_regs);
+	return 0;
+}
+
+
+static int clk_hifiberry_dachd_remove(struct device *dev)
+{
+	of_clk_del_provider(dev->of_node);
+	return 0;
+}
+
+const struct regmap_config hifiberry_pll_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = HIFIBERRY_PLL_MAX_REGISTER,
+	.reg_defaults = hifiberry_pll_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(hifiberry_pll_regmap);
+
+
+static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct clk_hifiberry_drvdata *hdclk;
+	int ret = 0;
+	struct clk_init_data init;
+	struct device *dev = &i2c->dev;
+	struct device_node *dev_node = dev->of_node;
+	struct regmap_config config = hifiberry_pll_regmap;
+
+	hdclk = devm_kzalloc(&i2c->dev,
+			sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL);
+	if (!hdclk)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, hdclk);
+
+	hdclk->regmap = devm_regmap_init_i2c(i2c, &config);
+
+	if (IS_ERR(hdclk->regmap))
+		return PTR_ERR(hdclk->regmap);
+
+	/* start PLL to allow detection of DAC */
+	ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap,
+				hifiberry_pll_reg_defaults,
+				ARRAY_SIZE(hifiberry_pll_reg_defaults),
+				PLL_RESET);
+	if (ret)
+		return ret;
+
+	clk_hifiberry_dachd_dt_parse(dev);
+
+	/* restart PLL with configs from DTB */
+	ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs,
+					num_common_pll_regs, PLL_RESET);
+	if (ret)
+		return ret;
+
+	init.name = "clk-hifiberry-dachd";
+	init.ops = &clk_hifiberry_dachd_rate_ops;
+	init.flags = 0;
+	init.parent_names = NULL;
+	init.num_parents = 0;
+
+	hdclk->hw.init = &init;
+
+	hdclk->clk = devm_clk_register(dev, &hdclk->hw);
+	if (IS_ERR(hdclk->clk)) {
+		dev_err(dev, "unable to register %s\n",	init.name);
+		return PTR_ERR(hdclk->clk);
+	}
+
+	ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk);
+	if (ret != 0) {
+		dev_err(dev, "Cannot of_clk_add_provider");
+		return ret;
+	}
+
+	ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE);
+	if (ret != 0) {
+		dev_err(dev, "Cannot set rate : %d\n",	ret);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c)
+{
+	clk_hifiberry_dachd_remove(&i2c->dev);
+	return 0;
+}
+
+static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = {
+	{ "dachd-clk", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id);
+
+static const struct of_device_id clk_hifiberry_dachd_of_match[] = {
+	{ .compatible = "hifiberry,dachd-clk", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match);
+
+static struct i2c_driver clk_hifiberry_dachd_i2c_driver = {
+	.probe		= clk_hifiberry_dachd_i2c_probe,
+	.remove		= clk_hifiberry_dachd_i2c_remove,
+	.id_table	= clk_hifiberry_dachd_i2c_id,
+	.driver		= {
+		.name	= "dachd-clk",
+		.of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match),
+	},
+};
+
+module_i2c_driver(clk_hifiberry_dachd_i2c_driver);
+
+
+MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver");
+MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:clk-hifiberry-dachd");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/clk/clk-hifiberry-dacpro.c linux-5.10.52-v7l+/drivers/clk/clk-hifiberry-dacpro.c
--- linux-5.10.52-orig/drivers/clk/clk-hifiberry-dacpro.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/clk/clk-hifiberry-dacpro.c	2021-07-25 16:45:44.868644597 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Clock Driver for HiFiBerry DAC Pro
+ *
+ * Author: Stuart MacLean
+ *         Copyright 2015
+ *
+ * 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 <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+/* 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 hifiberry_dacpro_clk - Common struct to the HiFiBerry DAC Pro
+ * @hw: clk_hw for the common clk framework
+ * @mode: 0 => CLK44EN, 1 => CLK48EN
+ */
+struct clk_hifiberry_hw {
+	struct clk_hw hw;
+	uint8_t mode;
+};
+
+#define to_hifiberry_clk(_hw) container_of(_hw, struct clk_hifiberry_hw, hw)
+
+static const struct of_device_id clk_hifiberry_dacpro_dt_ids[] = {
+	{ .compatible = "hifiberry,dacpro-clk",},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, clk_hifiberry_dacpro_dt_ids);
+
+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;
+}
+
+static long clk_hifiberry_dacpro_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_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);
+
+	actual_rate = (unsigned long)clk_hifiberry_dacpro_round_rate(hw, rate,
+		&parent_rate);
+	clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1;
+	return 0;
+}
+
+
+const struct clk_ops clk_hifiberry_dacpro_rate_ops = {
+	.recalc_rate = clk_hifiberry_dacpro_recalc_rate,
+	.round_rate = clk_hifiberry_dacpro_round_rate,
+	.set_rate = clk_hifiberry_dacpro_set_rate,
+};
+
+static int clk_hifiberry_dacpro_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct clk_hifiberry_hw *proclk;
+	struct clk *clk;
+	struct device *dev;
+	struct clk_init_data init;
+
+	dev = &pdev->dev;
+
+	proclk = kzalloc(sizeof(struct clk_hifiberry_hw), GFP_KERNEL);
+	if (!proclk)
+		return -ENOMEM;
+
+	init.name = "clk-hifiberry-dacpro";
+	init.ops = &clk_hifiberry_dacpro_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_hifiberry_dacpro_remove(struct platform_device *pdev)
+{
+	of_clk_del_provider(pdev->dev.of_node);
+	return 0;
+}
+
+static struct platform_driver clk_hifiberry_dacpro_driver = {
+	.probe = clk_hifiberry_dacpro_probe,
+	.remove = clk_hifiberry_dacpro_remove,
+	.driver = {
+		.name = "clk-hifiberry-dacpro",
+		.of_match_table = clk_hifiberry_dacpro_dt_ids,
+	},
+};
+
+static int __init clk_hifiberry_dacpro_init(void)
+{
+	return platform_driver_register(&clk_hifiberry_dacpro_driver);
+}
+core_initcall(clk_hifiberry_dacpro_init);
+
+static void __exit clk_hifiberry_dacpro_exit(void)
+{
+	platform_driver_unregister(&clk_hifiberry_dacpro_driver);
+}
+module_exit(clk_hifiberry_dacpro_exit);
+
+MODULE_DESCRIPTION("HiFiBerry DAC Pro clock driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:clk-hifiberry-dacpro");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/clk/Kconfig linux-5.10.52-v7l+/drivers/clk/Kconfig
--- linux-5.10.52-orig/drivers/clk/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/clk/Kconfig	2021-07-25 16:45:44.768646273 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:89 @
 	  multi-function device has one fixed-rate oscillator, clocked
 	  at 32KHz.
 
+config COMMON_CLK_HIFIBERRY_DACPLUSHD
+	tristate
+
+config COMMON_CLK_HIFIBERRY_DACPRO
+	tristate
+
 config COMMON_CLK_SCMI
 	tristate "Clock driver controlled via SCMI interface"
 	depends on ARM_SCMI_PROTOCOL || COMPILE_TEST
diff -Nur --no-dereference linux-5.10.52-orig/drivers/clk/Makefile linux-5.10.52-v7l+/drivers/clk/Makefile
--- linux-5.10.52-orig/drivers/clk/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/clk/Makefile	2021-07-25 16:45:44.768646273 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:21 @
 
 # 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_MACH_ASM9260)		+= clk-asm9260.o
 obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN)	+= clk-axi-clkgen.o
 obj-$(CONFIG_ARCH_AXXIA)		+= clk-axm5516.o
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:41 @
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_CLK_HSDK)			+= clk-hsdk-pll.o
 obj-$(CONFIG_COMMON_CLK_LOCHNAGAR)	+= clk-lochnagar.o
+obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPRO)	+= clk-hifiberry-dacpro.o
+obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPLUSHD)	+= clk-hifiberry-dachd.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
 obj-$(CONFIG_COMMON_CLK_MAX9485)	+= clk-max9485.o
 obj-$(CONFIG_ARCH_MILBEAUT_M10V)	+= clk-milbeaut.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/dma/bcm2708-dmaengine.c linux-5.10.52-v7l+/drivers/dma/bcm2708-dmaengine.c
--- linux-5.10.52-orig/drivers/dma/bcm2708-dmaengine.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/dma/bcm2708-dmaengine.c	2021-07-25 16:45:46.338619951 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * BCM2708 legacy DMA API
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_data/dma-bcm2708.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+#include "virt-dma.h"
+
+#define CACHE_LINE_MASK 31
+#define DEFAULT_DMACHAN_BITMAP 0x10  /* channel 4 only */
+
+/* valid only for channels 0 - 14, 15 has its own base address */
+#define BCM2708_DMA_CHAN(n)	((n) << 8) /* base address */
+#define BCM2708_DMA_CHANIO(dma_base, n) \
+	((void __iomem *)((char *)(dma_base) + BCM2708_DMA_CHAN(n)))
+
+struct vc_dmaman {
+	void __iomem *dma_base;
+	u32 chan_available; /* bitmap of available channels */
+	u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */
+	struct mutex lock;
+};
+
+static struct device *dmaman_dev;	/* we assume there's only one! */
+static struct vc_dmaman *g_dmaman;	/* DMA manager */
+
+/* DMA Auxiliary Functions */
+
+/* A DMA buffer on an arbitrary boundary may separate a cache line into a
+   section inside the DMA buffer and another section outside it.
+   Even if we flush DMA buffers from the cache there is always the chance that
+   during a DMA someone will access the part of a cache line that is outside
+   the DMA buffer - which will then bring in unwelcome data.
+   Without being able to dictate our own buffer pools we must insist that
+   DMA buffers consist of a whole number of cache lines.
+*/
+extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len)
+{
+	int i;
+
+	for (i = 0; i < sg_len; i++) {
+		if (sg_ptr[i].offset & CACHE_LINE_MASK ||
+		    sg_ptr[i].length & CACHE_LINE_MASK)
+			return 0;
+	}
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma);
+
+extern void bcm_dma_start(void __iomem *dma_chan_base,
+			  dma_addr_t control_block)
+{
+	dsb(sy);	/* ARM data synchronization (push) operation */
+
+	writel(control_block, dma_chan_base + BCM2708_DMA_ADDR);
+	writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS);
+}
+EXPORT_SYMBOL_GPL(bcm_dma_start);
+
+extern void bcm_dma_wait_idle(void __iomem *dma_chan_base)
+{
+	dsb(sy);
+
+	/* ugly busy wait only option for now */
+	while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE)
+		cpu_relax();
+}
+EXPORT_SYMBOL_GPL(bcm_dma_wait_idle);
+
+extern bool bcm_dma_is_busy(void __iomem *dma_chan_base)
+{
+	dsb(sy);
+
+	return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_is_busy);
+
+/* Complete an ongoing DMA (assuming its results are to be ignored)
+   Does nothing if there is no DMA in progress.
+   This routine waits for the current AXI transfer to complete before
+   terminating the current DMA. If the current transfer is hung on a DREQ used
+   by an uncooperative peripheral the AXI transfer may never complete.	In this
+   case the routine times out and return a non-zero error code.
+   Use of this routine doesn't guarantee that the ongoing or aborted DMA
+   does not produce an interrupt.
+*/
+extern int bcm_dma_abort(void __iomem *dma_chan_base)
+{
+	unsigned long int cs;
+	int rc = 0;
+
+	cs = readl(dma_chan_base + BCM2708_DMA_CS);
+
+	if (BCM2708_DMA_ACTIVE & cs) {
+		long int timeout = 10000;
+
+		/* write 0 to the active bit - pause the DMA */
+		writel(0, dma_chan_base + BCM2708_DMA_CS);
+
+		/* wait for any current AXI transfer to complete */
+		while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0)
+			cs = readl(dma_chan_base + BCM2708_DMA_CS);
+
+		if (0 != (cs & BCM2708_DMA_ISPAUSED)) {
+			/* we'll un-pause when we set of our next DMA */
+			rc = -ETIMEDOUT;
+
+		} else if (BCM2708_DMA_ACTIVE & cs) {
+			/* terminate the control block chain */
+			writel(0, dma_chan_base + BCM2708_DMA_NEXTCB);
+
+			/* abort the whole DMA */
+			writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE,
+			       dma_chan_base + BCM2708_DMA_CS);
+		}
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_abort);
+
+ /* DMA Manager Device Methods */
+
+static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base,
+			   u32 chans_available)
+{
+	dmaman->dma_base = dma_base;
+	dmaman->chan_available = chans_available;
+	dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c;  /* 2 & 3 */
+	dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01;  /* 0 */
+	dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe;  /* 1 to 7 */
+	dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00;  /* 8 to 14 */
+}
+
+static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman,
+				unsigned required_feature_set)
+{
+	u32 chans;
+	int chan = 0;
+	int feature;
+
+	chans = dmaman->chan_available;
+	for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++)
+		/* select the subset of available channels with the desired
+		   features */
+		if (required_feature_set & (1 << feature))
+			chans &= dmaman->has_feature[feature];
+
+	if (!chans)
+		return -ENOENT;
+
+	/* return the ordinal of the first channel in the bitmap */
+	while (chans != 0 && (chans & 1) == 0) {
+		chans >>= 1;
+		chan++;
+	}
+	/* claim the channel */
+	dmaman->chan_available &= ~(1 << chan);
+
+	return chan;
+}
+
+static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan)
+{
+	if (chan < 0)
+		return -EINVAL;
+
+	if ((1 << chan) & dmaman->chan_available)
+		return -EIDRM;
+
+	dmaman->chan_available |= (1 << chan);
+
+	return 0;
+}
+
+/* DMA Manager Monitor */
+
+extern int bcm_dma_chan_alloc(unsigned required_feature_set,
+			      void __iomem **out_dma_base, int *out_dma_irq)
+{
+	struct vc_dmaman *dmaman = g_dmaman;
+	struct platform_device *pdev = to_platform_device(dmaman_dev);
+	struct resource *r;
+	int chan;
+
+	if (!dmaman_dev)
+		return -ENODEV;
+
+	mutex_lock(&dmaman->lock);
+	chan = vc_dmaman_chan_alloc(dmaman, required_feature_set);
+	if (chan < 0)
+		goto out;
+
+	r = platform_get_resource(pdev, IORESOURCE_IRQ, (unsigned int)chan);
+	if (!r) {
+		dev_err(dmaman_dev, "failed to get irq for DMA channel %d\n",
+			chan);
+		vc_dmaman_chan_free(dmaman, chan);
+		chan = -ENOENT;
+		goto out;
+	}
+
+	*out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, chan);
+	*out_dma_irq = r->start;
+	dev_dbg(dmaman_dev,
+		"Legacy API allocated channel=%d, base=%p, irq=%i\n",
+		chan, *out_dma_base, *out_dma_irq);
+
+out:
+	mutex_unlock(&dmaman->lock);
+
+	return chan;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc);
+
+extern int bcm_dma_chan_free(int channel)
+{
+	struct vc_dmaman *dmaman = g_dmaman;
+	int rc;
+
+	if (!dmaman_dev)
+		return -ENODEV;
+
+	mutex_lock(&dmaman->lock);
+	rc = vc_dmaman_chan_free(dmaman, channel);
+	mutex_unlock(&dmaman->lock);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_chan_free);
+
+int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base,
+		     u32 chans_available)
+{
+	struct device *dev = &pdev->dev;
+	struct vc_dmaman *dmaman;
+
+	dmaman = devm_kzalloc(dev, sizeof(*dmaman), GFP_KERNEL);
+	if (!dmaman)
+		return -ENOMEM;
+
+	mutex_init(&dmaman->lock);
+	vc_dmaman_init(dmaman, base, chans_available);
+	g_dmaman = dmaman;
+	dmaman_dev = dev;
+
+	dev_info(dev, "DMA legacy API manager, dmachans=0x%x\n",
+		 chans_available);
+
+	return 0;
+}
+EXPORT_SYMBOL(bcm_dmaman_probe);
+
+int bcm_dmaman_remove(struct platform_device *pdev)
+{
+	dmaman_dev = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL(bcm_dmaman_remove);
+
+MODULE_LICENSE("GPL");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/dma/bcm2835-dma.c linux-5.10.52-v7l+/drivers/dma/bcm2835-dma.c
--- linux-5.10.52-orig/drivers/dma/bcm2835-dma.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/dma/bcm2835-dma.c	2021-07-25 16:45:46.358619616 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:28 @
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/platform_data/dma-bcm2708.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:40 @
 
 #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
 #define BCM2835_DMA_CHAN_NAME_SIZE 8
+#define BCM2835_DMA_BULK_MASK  BIT(0)
+#define BCM2711_DMA_MEMCPY_CHAN 14
+
+struct bcm2835_dma_cfg_data {
+	u64	dma_mask;
+	u32	chan_40bit_mask;
+};
 
 /**
  * struct bcm2835_dmadev - BCM2835 DMA controller
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:59 @
 	struct dma_device ddev;
 	void __iomem *base;
 	dma_addr_t zero_page;
+	const struct bcm2835_dma_cfg_data *cfg_data;
 };
 
 struct bcm2835_dma_cb {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:72 @
 	uint32_t pad[2];
 };
 
+struct bcm2711_dma40_scb {
+	uint32_t ti;
+	uint32_t src;
+	uint32_t srci;
+	uint32_t dst;
+	uint32_t dsti;
+	uint32_t len;
+	uint32_t next_cb;
+	uint32_t rsvd;
+};
+
 struct bcm2835_cb_entry {
 	struct bcm2835_dma_cb *cb;
 	dma_addr_t paddr;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:103 @
 	unsigned int irq_flags;
 
 	bool is_lite_channel;
+	bool is_40bit_channel;
 };
 
 struct bcm2835_desc {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:161 @
 #define BCM2835_DMA_S_DREQ	BIT(10) /* enable SREQ for source */
 #define BCM2835_DMA_S_IGNORE	BIT(11) /* ignore source reads - read 0 */
 #define BCM2835_DMA_BURST_LENGTH(x) ((x & 15) << 12)
+#define BCM2835_DMA_CS_FLAGS(x) (x & (BCM2835_DMA_PRIORITY(15) | \
+				      BCM2835_DMA_PANIC_PRIORITY(15) | \
+				      BCM2835_DMA_WAIT_FOR_WRITES | \
+				      BCM2835_DMA_DIS_DEBUG))
 #define BCM2835_DMA_PER_MAP(x)	((x & 31) << 16) /* REQ source */
 #define BCM2835_DMA_WAIT(x)	((x & 31) << 21) /* add DMA-wait cycles */
 #define BCM2835_DMA_NO_WIDE_BURSTS BIT(26) /* no 2 beat write bursts */
 
+/* A fake bit to request that the driver doesn't set the WAIT_RESP bit. */
+#define BCM2835_DMA_NO_WAIT_RESP BIT(27)
+#define WAIT_RESP(x) ((x & BCM2835_DMA_NO_WAIT_RESP) ? \
+		      0 : BCM2835_DMA_WAIT_RESP)
+
+/* A fake bit to request that the driver requires wide reads */
+#define BCM2835_DMA_WIDE_SOURCE BIT(24)
+#define WIDE_SOURCE(x) ((x & BCM2835_DMA_WIDE_SOURCE) ? \
+		      BCM2835_DMA_S_WIDTH : 0)
+
+/* A fake bit to request that the driver requires wide writes */
+#define BCM2835_DMA_WIDE_DEST BIT(25)
+#define WIDE_DEST(x) ((x & BCM2835_DMA_WIDE_DEST) ? \
+		      BCM2835_DMA_D_WIDTH : 0)
+
+
 /* debug register bits */
 #define BCM2835_DMA_DEBUG_LAST_NOT_SET_ERR	BIT(0)
 #define BCM2835_DMA_DEBUG_FIFO_ERR		BIT(1)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:209 @
 #define BCM2835_DMA_DATA_TYPE_S128	16
 
 /* Valid only for channels 0 - 14, 15 has its own base address */
-#define BCM2835_DMA_CHAN(n)	((n) << 8) /* Base address */
+#define BCM2835_DMA_CHAN_SIZE	0x100
+#define BCM2835_DMA_CHAN(n)	((n) * BCM2835_DMA_CHAN_SIZE) /* Base address */
 #define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
 
 /* the max dma length for different channels */
 #define MAX_DMA_LEN SZ_1G
 #define MAX_LITE_DMA_LEN (SZ_64K - 4)
 
+/* 40-bit DMA support */
+#define BCM2711_DMA40_CS	0x00
+#define BCM2711_DMA40_CB	0x04
+#define BCM2711_DMA40_DEBUG	0x0c
+#define BCM2711_DMA40_TI	0x10
+#define BCM2711_DMA40_SRC	0x14
+#define BCM2711_DMA40_SRCI	0x18
+#define BCM2711_DMA40_DEST	0x1c
+#define BCM2711_DMA40_DESTI	0x20
+#define BCM2711_DMA40_LEN	0x24
+#define BCM2711_DMA40_NEXT_CB	0x28
+#define BCM2711_DMA40_DEBUG2	0x2c
+
+#define BCM2711_DMA40_ACTIVE		BIT(0)
+#define BCM2711_DMA40_END		BIT(1)
+#define BCM2711_DMA40_INT		BIT(2)
+#define BCM2711_DMA40_DREQ		BIT(3)  /* DREQ state */
+#define BCM2711_DMA40_RD_PAUSED		BIT(4)  /* Reading is paused */
+#define BCM2711_DMA40_WR_PAUSED		BIT(5)  /* Writing is paused */
+#define BCM2711_DMA40_DREQ_PAUSED	BIT(6)  /* Is paused by DREQ flow control */
+#define BCM2711_DMA40_WAITING_FOR_WRITES BIT(7)  /* Waiting for last write */
+#define BCM2711_DMA40_ERR		BIT(10)
+#define BCM2711_DMA40_QOS(x)		(((x) & 0x1f) << 16)
+#define BCM2711_DMA40_PANIC_QOS(x)	(((x) & 0x1f) << 20)
+#define BCM2711_DMA40_WAIT_FOR_WRITES	BIT(28)
+#define BCM2711_DMA40_DISDEBUG		BIT(29)
+#define BCM2711_DMA40_ABORT		BIT(30)
+#define BCM2711_DMA40_HALT		BIT(31)
+#define BCM2711_DMA40_CS_FLAGS(x) (x & (BCM2711_DMA40_QOS(15) | \
+					BCM2711_DMA40_PANIC_QOS(15) | \
+					BCM2711_DMA40_WAIT_FOR_WRITES |	\
+					BCM2711_DMA40_DISDEBUG))
+
+/* Transfer information bits */
+#define BCM2711_DMA40_INTEN		BIT(0)
+#define BCM2711_DMA40_TDMODE		BIT(1) /* 2D-Mode */
+#define BCM2711_DMA40_WAIT_RESP		BIT(2) /* wait for AXI write to be acked */
+#define BCM2711_DMA40_WAIT_RD_RESP	BIT(3) /* wait for AXI read to complete */
+#define BCM2711_DMA40_PER_MAP(x)	((x & 31) << 9) /* REQ source */
+#define BCM2711_DMA40_S_DREQ		BIT(14) /* enable SREQ for source */
+#define BCM2711_DMA40_D_DREQ		BIT(15) /* enable DREQ for destination */
+#define BCM2711_DMA40_S_WAIT(x)		((x & 0xff) << 16) /* add DMA read-wait cycles */
+#define BCM2711_DMA40_D_WAIT(x)		((x & 0xff) << 24) /* add DMA write-wait cycles */
+
+/* debug register bits */
+#define BCM2711_DMA40_DEBUG_WRITE_ERR		BIT(0)
+#define BCM2711_DMA40_DEBUG_FIFO_ERR		BIT(1)
+#define BCM2711_DMA40_DEBUG_READ_ERR		BIT(2)
+#define BCM2711_DMA40_DEBUG_READ_CB_ERR		BIT(3)
+#define BCM2711_DMA40_DEBUG_IN_ON_ERR		BIT(8)
+#define BCM2711_DMA40_DEBUG_ABORT_ON_ERR	BIT(9)
+#define BCM2711_DMA40_DEBUG_HALT_ON_ERR		BIT(10)
+#define BCM2711_DMA40_DEBUG_DISABLE_CLK_GATE	BIT(11)
+#define BCM2711_DMA40_DEBUG_RSTATE_SHIFT	14
+#define BCM2711_DMA40_DEBUG_RSTATE_BITS		4
+#define BCM2711_DMA40_DEBUG_WSTATE_SHIFT	18
+#define BCM2711_DMA40_DEBUG_WSTATE_BITS		4
+#define BCM2711_DMA40_DEBUG_RESET		BIT(23)
+#define BCM2711_DMA40_DEBUG_ID_SHIFT		24
+#define BCM2711_DMA40_DEBUG_ID_BITS		4
+#define BCM2711_DMA40_DEBUG_VERSION_SHIFT	28
+#define BCM2711_DMA40_DEBUG_VERSION_BITS	4
+
+/* Valid only for channels 0 - 3 (11 - 14) */
+#define BCM2711_DMA40_CHAN(n)	(((n) + 11) << 8) /* Base address */
+#define BCM2711_DMA40_CHANIO(base, n) ((base) + BCM2711_DMA_CHAN(n))
+
+/* the max dma length for different channels */
+#define MAX_DMA40_LEN SZ_1G
+
+#define BCM2711_DMA40_BURST_LEN(x)	((min(x,16) - 1) << 8)
+#define BCM2711_DMA40_INC		BIT(12)
+#define BCM2711_DMA40_SIZE_32		(0 << 13)
+#define BCM2711_DMA40_SIZE_64		(1 << 13)
+#define BCM2711_DMA40_SIZE_128		(2 << 13)
+#define BCM2711_DMA40_SIZE_256		(3 << 13)
+#define BCM2711_DMA40_IGNORE		BIT(15)
+#define BCM2711_DMA40_STRIDE(x)		((x) << 16) /* For 2D mode */
+
+#define BCM2711_DMA40_MEMCPY_FLAGS \
+	(BCM2711_DMA40_QOS(0) | \
+	 BCM2711_DMA40_PANIC_QOS(0) | \
+	 BCM2711_DMA40_WAIT_FOR_WRITES | \
+	 BCM2711_DMA40_DISDEBUG)
+
+#define BCM2711_DMA40_MEMCPY_XFER_INFO \
+	(BCM2711_DMA40_SIZE_128 | \
+	 BCM2711_DMA40_INC | \
+	 BCM2711_DMA40_BURST_LEN(16))
+
+struct bcm2835_dmadev *memcpy_parent;
+static void __iomem *memcpy_chan;
+static struct bcm2711_dma40_scb *memcpy_scb;
+static dma_addr_t memcpy_scb_dma;
+DEFINE_SPINLOCK(memcpy_lock);
+
+static const struct bcm2835_dma_cfg_data bcm2835_dma_cfg = {
+	.chan_40bit_mask = 0,
+	.dma_mask = DMA_BIT_MASK(32),
+};
+
+static const struct bcm2835_dma_cfg_data bcm2711_dma_cfg = {
+	.chan_40bit_mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
+	.dma_mask = DMA_BIT_MASK(36),
+};
+
 static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
 {
 	/* lite and normal channels have different max frame length */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:352 @
 	return container_of(t, struct bcm2835_desc, vd.tx);
 }
 
+static inline uint32_t to_bcm2711_ti(uint32_t info)
+{
+	return ((info & BCM2835_DMA_INT_EN) ? BCM2711_DMA40_INTEN : 0) |
+		((info & BCM2835_DMA_WAIT_RESP) ? BCM2711_DMA40_WAIT_RESP : 0) |
+		((info & BCM2835_DMA_S_DREQ) ?
+		 (BCM2711_DMA40_S_DREQ | BCM2711_DMA40_WAIT_RD_RESP) : 0) |
+		((info & BCM2835_DMA_D_DREQ) ? BCM2711_DMA40_D_DREQ : 0) |
+		BCM2711_DMA40_PER_MAP((info >> 16) & 0x1f);
+}
+
+static inline uint32_t to_bcm2711_srci(uint32_t info)
+{
+	return ((info & BCM2835_DMA_S_INC) ? BCM2711_DMA40_INC : 0);
+}
+
+static inline uint32_t to_bcm2711_dsti(uint32_t info)
+{
+	return ((info & BCM2835_DMA_D_INC) ? BCM2711_DMA40_INC : 0);
+}
+
+static inline uint32_t to_bcm2711_cbaddr(dma_addr_t addr)
+{
+	BUG_ON(addr & 0x1f);
+	return (addr >> 5);
+}
+
 static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
 {
 	size_t i;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:396 @
 }
 
 static void bcm2835_dma_create_cb_set_length(
-	struct bcm2835_chan *chan,
+	struct bcm2835_chan *c,
 	struct bcm2835_dma_cb *control_block,
 	size_t len,
 	size_t period_len,
 	size_t *total_len,
 	u32 finalextrainfo)
 {
-	size_t max_len = bcm2835_dma_max_frame_length(chan);
+	size_t max_len = bcm2835_dma_max_frame_length(c);
+	uint32_t cb_len;
 
 	/* set the length taking lite-channel limitations into account */
-	control_block->length = min_t(u32, len, max_len);
+	cb_len = min_t(u32, len, max_len);
 
-	/* finished if we have no period_length */
-	if (!period_len)
-		return;
+	if (period_len) {
+		/*
+		 * period_len means: that we need to generate
+		 * transfers that are terminating at every
+		 * multiple of period_len - this is typically
+		 * used to set the interrupt flag in info
+		 * which is required during cyclic transfers
+		 */
 
-	/*
-	 * period_len means: that we need to generate
-	 * transfers that are terminating at every
-	 * multiple of period_len - this is typically
-	 * used to set the interrupt flag in info
-	 * which is required during cyclic transfers
-	 */
+		/* have we filled in period_length yet? */
+		if (*total_len + cb_len < period_len) {
+			/* update number of bytes in this period so far */
+			*total_len += cb_len;
+		} else {
+			/* calculate the length that remains to reach period_len */
+			cb_len = period_len - *total_len;
 
-	/* have we filled in period_length yet? */
-	if (*total_len + control_block->length < period_len) {
-		/* update number of bytes in this period so far */
-		*total_len += control_block->length;
-		return;
+			/* reset total_length for next period */
+			*total_len = 0;
+		}
 	}
 
-	/* calculate the length that remains to reach period_length */
-	control_block->length = period_len - *total_len;
-
-	/* reset total_length for next period */
-	*total_len = 0;
-
-	/* add extrainfo bits in info */
-	control_block->info |= finalextrainfo;
+	if (c->is_40bit_channel) {
+		struct bcm2711_dma40_scb *scb =
+			(struct bcm2711_dma40_scb *)control_block;
+
+		scb->len = cb_len;
+		/* add extrainfo bits to ti */
+		scb->ti |= to_bcm2711_ti(finalextrainfo);
+	} else {
+		control_block->length = cb_len;
+		/* add extrainfo bits to info */
+		control_block->info |= finalextrainfo;
+	}
 }
 
 static inline size_t bcm2835_dma_count_frames_for_sg(
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:465 @
 /**
  * bcm2835_dma_create_cb_chain - create a control block and fills data in
  *
- * @chan:           the @dma_chan for which we run this
+ * @c:              the @bcm2835_chan for which we run this
  * @direction:      the direction in which we transfer
  * @cyclic:         it is a cyclic transfer
  * @info:           the default info bits to apply per controlblock
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:483 @
  * @gfp:            the GFP flag to use for allocation
  */
 static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
-	struct dma_chan *chan, enum dma_transfer_direction direction,
+	struct bcm2835_chan *c, enum dma_transfer_direction direction,
 	bool cyclic, u32 info, u32 finalextrainfo, size_t frames,
 	dma_addr_t src, dma_addr_t dst, size_t buf_len,
 	size_t period_len, gfp_t gfp)
 {
-	struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
 	size_t len = buf_len, total_len;
 	size_t frame;
 	struct bcm2835_desc *d;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:519 @
 
 		/* fill in the control block */
 		control_block = cb_entry->cb;
-		control_block->info = info;
-		control_block->src = src;
-		control_block->dst = dst;
-		control_block->stride = 0;
-		control_block->next = 0;
+		if (c->is_40bit_channel) {
+			struct bcm2711_dma40_scb *scb =
+				(struct bcm2711_dma40_scb *)control_block;
+			scb->ti = to_bcm2711_ti(info);
+			scb->src = lower_32_bits(src);
+			scb->srci= upper_32_bits(src) | to_bcm2711_srci(info);
+			scb->dst = lower_32_bits(dst);
+			scb->dsti = upper_32_bits(dst) | to_bcm2711_dsti(info);
+			scb->next_cb = 0;
+		} else {
+			control_block->info = info;
+			control_block->src = src;
+			control_block->dst = dst;
+			control_block->stride = 0;
+			control_block->next = 0;
+		}
+
 		/* set up length in control_block if requested */
 		if (buf_len) {
 			/* calculate length honoring period_length */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:549 @
 		}
 
 		/* link this the last controlblock */
-		if (frame)
+		if (frame && c->is_40bit_channel)
+			((struct bcm2711_dma40_scb *)
+			 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;
 
 		/* update src and dst and length */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:563 @
 			dst += control_block->length;
 
 		/* Length of total transfer */
-		d->size += control_block->length;
+		if (c->is_40bit_channel)
+			d->size += ((struct bcm2711_dma40_scb *)control_block)->len;
+		else
+			d->size += control_block->length;
 	}
 
 	/* the last frame requires extra flags */
-	d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
+	if (c->is_40bit_channel) {
+		struct bcm2711_dma40_scb *scb =
+			(struct bcm2711_dma40_scb *)d->cb_list[d->frames-1].cb;
+
+		scb->ti |= to_bcm2711_ti(finalextrainfo);
+	} else {
+		d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
+	}
 
 	/* detect a size missmatch */
 	if (buf_len && (d->size != buf_len))
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:591 @
 }
 
 static void bcm2835_dma_fill_cb_chain_with_sg(
-	struct dma_chan *chan,
+	struct bcm2835_chan *c,
 	enum dma_transfer_direction direction,
 	struct bcm2835_cb_entry *cb,
 	struct scatterlist *sgl,
 	unsigned int sg_len)
 {
-	struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
 	size_t len, max_len;
 	unsigned int i;
 	dma_addr_t addr;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:604 @
 
 	max_len = bcm2835_dma_max_frame_length(c);
 	for_each_sg(sgl, sgent, sg_len, i) {
-		for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
-		     len > 0;
-		     addr += cb->cb->length, len -= cb->cb->length, cb++) {
-			if (direction == DMA_DEV_TO_MEM)
-				cb->cb->dst = addr;
-			else
-				cb->cb->src = addr;
-			cb->cb->length = min(len, max_len);
+		if (c->is_40bit_channel) {
+			struct bcm2711_dma40_scb *scb;
+
+			for (addr = sg_dma_address(sgent),
+				     len = sg_dma_len(sgent);
+				     len > 0;
+			     addr += scb->len, len -= scb->len, cb++) {
+				scb = (struct bcm2711_dma40_scb *)cb->cb;
+				if (direction == DMA_DEV_TO_MEM) {
+					scb->dst = lower_32_bits(addr);
+					scb->dsti = upper_32_bits(addr) | BCM2711_DMA40_INC;
+				} else {
+					scb->src = lower_32_bits(addr);
+					scb->srci = upper_32_bits(addr) | BCM2711_DMA40_INC;
+				}
+				scb->len = min(len, max_len);
+			}
+		} else {
+			for (addr = sg_dma_address(sgent),
+				     len = sg_dma_len(sgent);
+			     len > 0;
+			     addr += cb->cb->length, len -= cb->cb->length,
+			     cb++) {
+				if (direction == DMA_DEV_TO_MEM)
+					cb->cb->dst = addr;
+				else
+					cb->cb->src = addr;
+				cb->cb->length = min(len, max_len);
+			}
 		}
 	}
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:641 @
 {
 	void __iomem *chan_base = c->chan_base;
 	long int timeout = 10000;
+	u32 wait_mask = BCM2835_DMA_WAITING_FOR_WRITES;
+
+	if (c->is_40bit_channel)
+		wait_mask = BCM2711_DMA40_WAITING_FOR_WRITES;
 
 	/*
 	 * A zero control block address means the channel is idle.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:657 @
 	writel(0, chan_base + BCM2835_DMA_CS);
 
 	/* Wait for any current AXI transfer to complete */
-	while ((readl(chan_base + BCM2835_DMA_CS) &
-		BCM2835_DMA_WAITING_FOR_WRITES) && --timeout)
+	while ((readl(chan_base + BCM2835_DMA_CS) & wait_mask) && --timeout)
 		cpu_relax();
 
 	/* Peripheral might be stuck and fail to signal AXI write responses */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:682 @
 
 	c->desc = d = to_bcm2835_dma_desc(&vd->tx);
 
-	writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
-	writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
+	if (c->is_40bit_channel) {
+		writel(to_bcm2711_cbaddr(d->cb_list[0].paddr),
+		       c->chan_base + BCM2711_DMA40_CB);
+		writel(BCM2711_DMA40_ACTIVE | 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(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
+		       c->chan_base + BCM2835_DMA_CS);
+	}
 }
 
 static irqreturn_t bcm2835_dma_callback(int irq, void *data)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:718 @
 	 * if this IRQ handler is threaded.) If the channel is finished, it
 	 * will remain idle despite the ACTIVE flag being set.
 	 */
-	writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE,
+	writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
 	       c->chan_base + BCM2835_DMA_CS);
 
 	d = c->desc;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:821 @
 		struct bcm2835_desc *d = c->desc;
 		dma_addr_t pos;
 
-		if (d->dir == DMA_MEM_TO_DEV)
+		if (d->dir == DMA_MEM_TO_DEV && c->is_40bit_channel)
+			pos = readl(c->chan_base + BCM2711_DMA40_SRC) +
+				((readl(c->chan_base + BCM2711_DMA40_SRCI) &
+				  0xff) << 8);
+		else if (d->dir == DMA_MEM_TO_DEV && !c->is_40bit_channel)
 			pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD);
-		else if (d->dir == DMA_DEV_TO_MEM)
+		else if (d->dir == DMA_DEV_TO_MEM && c->is_40bit_channel)
+			pos = readl(c->chan_base + BCM2711_DMA40_DEST) +
+				((readl(c->chan_base + BCM2711_DMA40_DESTI) &
+				  0xff) << 8);
+		else if (d->dir == DMA_DEV_TO_MEM && !c->is_40bit_channel)
 			pos = readl(c->chan_base + BCM2835_DMA_DEST_AD);
 		else
 			pos = 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:864 @
 {
 	struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
 	struct bcm2835_desc *d;
-	u32 info = BCM2835_DMA_D_INC | BCM2835_DMA_S_INC;
-	u32 extra = BCM2835_DMA_INT_EN | BCM2835_DMA_WAIT_RESP;
+	u32 info = BCM2835_DMA_D_INC | BCM2835_DMA_S_INC | WAIT_RESP(c->dreq) |
+		   WIDE_SOURCE(c->dreq) | WIDE_DEST(c->dreq);
+	u32 extra = BCM2835_DMA_INT_EN;
 	size_t max_len = bcm2835_dma_max_frame_length(c);
 	size_t frames;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:878 @
 	frames = bcm2835_dma_frames_for_length(len, max_len);
 
 	/* allocate the CB chain - this also fills in the pointers */
-	d = bcm2835_dma_create_cb_chain(chan, DMA_MEM_TO_MEM, false,
+	d = bcm2835_dma_create_cb_chain(c, DMA_MEM_TO_MEM, false,
 					info, extra, frames,
 					src, dst, len, 0, GFP_KERNEL);
 	if (!d)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:896 @
 	struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
 	struct bcm2835_desc *d;
 	dma_addr_t src = 0, dst = 0;
-	u32 info = BCM2835_DMA_WAIT_RESP;
+	u32 info = WAIT_RESP(c->dreq) |
+		   WIDE_SOURCE(c->dreq) | WIDE_DEST(c->dreq);
 	u32 extra = BCM2835_DMA_INT_EN;
 	size_t frames;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:914 @
 		if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
 			return NULL;
 		src = c->cfg.src_addr;
+		/*
+		 * One would think it ought to be possible to get the physical
+		 * to dma address mapping information from the dma-ranges DT
+		 * property, but I've not found a way yet that doesn't involve
+		 * open-coding the whole thing.
+		 */
+		if (c->is_40bit_channel)
+		    src |= 0x400000000ull;
 		info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
 	} else {
 		if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
 			return NULL;
 		dst = c->cfg.dst_addr;
+		if (c->is_40bit_channel)
+		    dst |= 0x400000000ull;
 		info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
 	}
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:936 @
 	frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len);
 
 	/* allocate the CB chain */
-	d = bcm2835_dma_create_cb_chain(chan, direction, false,
+	d = bcm2835_dma_create_cb_chain(c, direction, false,
 					info, extra,
 					frames, src, dst, 0, 0,
 					GFP_NOWAIT);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:944 @
 		return NULL;
 
 	/* fill in frames with scatterlist pointers */
-	bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list,
+	bcm2835_dma_fill_cb_chain_with_sg(c, direction, d->cb_list,
 					  sgl, sg_len);
 
 	return vchan_tx_prep(&c->vc, &d->vd, flags);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:959 @
 	struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
 	struct bcm2835_desc *d;
 	dma_addr_t src, dst;
-	u32 info = BCM2835_DMA_WAIT_RESP;
+	u32 info = WAIT_RESP(c->dreq) | WIDE_SOURCE(c->dreq) | WIDE_DEST(c->dreq);
 	u32 extra = 0;
 	size_t max_len = bcm2835_dma_max_frame_length(c);
 	size_t frames;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:998 @
 		if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
 			return NULL;
 		src = c->cfg.src_addr;
+		if (c->is_40bit_channel)
+		    src |= 0x400000000ull;
 		dst = buf_addr;
 		info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
 	} else {
 		if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
 			return NULL;
 		dst = c->cfg.dst_addr;
+		if (c->is_40bit_channel)
+		    dst |= 0x400000000ull;
 		src = buf_addr;
 		info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1027 @
 	 * note that we need to use GFP_NOWAIT, as the ALSA i2s dmaengine
 	 * implementation calls prep_dma_cyclic with interrupts disabled.
 	 */
-	d = bcm2835_dma_create_cb_chain(chan, direction, true,
+	d = bcm2835_dma_create_cb_chain(c, direction, true,
 					info, extra,
 					frames, src, dst, buf_len,
 					period_len, GFP_NOWAIT);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1035 @
 		return NULL;
 
 	/* wrap around into a loop */
-	d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr;
+	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);
+	else
+		d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr;
 
 	return vchan_tx_prep(&c->vc, &d->vd, flags);
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1101 @
 	c->irq_number = irq;
 	c->irq_flags = irq_flags;
 
-	/* check in DEBUG register if this is a LITE channel */
-	if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
-		BCM2835_DMA_DEBUG_LITE)
+	/* check for 40bit and lite channels */
+	if (d->cfg_data->chan_40bit_mask & BIT(chan_id))
+		c->is_40bit_channel = true;
+	else if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
+		 BCM2835_DMA_DEBUG_LITE)
 		c->is_lite_channel = true;
 
 	return 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1125 @
 			     DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
 }
 
+int bcm2711_dma40_memcpy_init(void)
+{
+	if (!memcpy_parent)
+		return -EPROBE_DEFER;
+
+	if (!memcpy_chan)
+		return -EINVAL;
+
+	if (!memcpy_scb)
+		return -ENOMEM;
+
+	return 0;
+}
+EXPORT_SYMBOL(bcm2711_dma40_memcpy_init);
+
+void bcm2711_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
+{
+	struct bcm2711_dma40_scb *scb = memcpy_scb;
+	unsigned long flags;
+
+	if (!scb) {
+		pr_err("bcm2711_dma40_memcpy not initialised!\n");
+		return;
+	}
+
+	spin_lock_irqsave(&memcpy_lock, flags);
+
+	scb->ti = 0;
+	scb->src = lower_32_bits(src);
+	scb->srci = upper_32_bits(src) | BCM2711_DMA40_MEMCPY_XFER_INFO;
+	scb->dst = lower_32_bits(dst);
+	scb->dsti = upper_32_bits(dst) | BCM2711_DMA40_MEMCPY_XFER_INFO;
+	scb->len = size;
+	scb->next_cb = 0;
+
+	writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2711_DMA40_CB);
+	writel(BCM2711_DMA40_MEMCPY_FLAGS + BCM2711_DMA40_ACTIVE,
+	       memcpy_chan + BCM2711_DMA40_CS);
+
+	/* Poll for completion */
+	while (!(readl(memcpy_chan + BCM2711_DMA40_CS) & BCM2711_DMA40_END))
+		cpu_relax();
+
+	writel(BCM2711_DMA40_END, memcpy_chan + BCM2711_DMA40_CS);
+
+	spin_unlock_irqrestore(&memcpy_lock, flags);
+}
+EXPORT_SYMBOL(bcm2711_dma40_memcpy);
+
 static const struct of_device_id bcm2835_dma_of_match[] = {
-	{ .compatible = "brcm,bcm2835-dma", },
+	{ .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
+	{ .compatible = "brcm,bcm2711-dma", .data = &bcm2711_dma_cfg },
 	{},
 };
 MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1199 @
 
 static int bcm2835_dma_probe(struct platform_device *pdev)
 {
+	const struct bcm2835_dma_cfg_data *cfg_data;
+	const struct of_device_id *of_id;
 	struct bcm2835_dmadev *od;
 	struct resource *res;
 	void __iomem *base;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1210 @
 	int irq_flags;
 	uint32_t chans_available;
 	char chan_name[BCM2835_DMA_CHAN_NAME_SIZE];
+	int chan_count, chan_start, chan_end;
+
+	of_id = of_match_node(bcm2835_dma_of_match, pdev->dev.of_node);
+	if (!of_id) {
+		dev_err(&pdev->dev, "Failed to match compatible string\n");
+		return -EINVAL;
+	}
+
+	cfg_data = of_id->data;
 
 	if (!pdev->dev.dma_mask)
 		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
 
-	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+	rc = dma_set_mask_and_coherent(&pdev->dev, cfg_data->dma_mask);
 	if (rc) {
 		dev_err(&pdev->dev, "Unable to set DMA mask\n");
 		return rc;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1240 @
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
+	/* The set of channels can be split across multiple instances. */
+	chan_start = ((u32)(uintptr_t)base / BCM2835_DMA_CHAN_SIZE) & 0xf;
+	base -= BCM2835_DMA_CHAN(chan_start);
+	chan_count = resource_size(res) / BCM2835_DMA_CHAN_SIZE;
+	chan_end = min(chan_start + chan_count,
+			 BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1);
+
 	od->base = base;
 
 	dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1282 @
 		return -ENOMEM;
 	}
 
+	of_id = of_match_node(bcm2835_dma_of_match, pdev->dev.of_node);
+	if (!of_id) {
+		dev_err(&pdev->dev, "Failed to match compatible string\n");
+		return -EINVAL;
+	}
+
+	od->cfg_data = cfg_data;
+
 	/* Request DMA channel mask from device tree */
 	if (of_property_read_u32(pdev->dev.of_node,
 			"brcm,dma-channel-mask",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1299 @
 		goto err_no_dma;
 	}
 
+#ifdef CONFIG_DMA_BCM2708
+	/* One channel is reserved for the legacy API */
+	if (chans_available & BCM2835_DMA_BULK_MASK) {
+		rc = bcm_dmaman_probe(pdev, base,
+				      chans_available & BCM2835_DMA_BULK_MASK);
+		if (rc)
+			dev_err(&pdev->dev,
+				"Failed to initialize the legacy API\n");
+
+		chans_available &= ~BCM2835_DMA_BULK_MASK;
+	}
+#endif
+
+	/* And possibly one for the 40-bit DMA memcpy API */
+	if (chans_available & od->cfg_data->chan_40bit_mask &
+	    BIT(BCM2711_DMA_MEMCPY_CHAN)) {
+		memcpy_parent = od;
+		memcpy_chan = BCM2835_DMA_CHANIO(base, BCM2711_DMA_MEMCPY_CHAN);
+		memcpy_scb = dma_alloc_coherent(memcpy_parent->ddev.dev,
+						sizeof(*memcpy_scb),
+						&memcpy_scb_dma, GFP_KERNEL);
+		if (!memcpy_scb)
+			dev_warn(&pdev->dev,
+				 "Failed to allocated memcpy scb\n");
+
+		chans_available &= ~BIT(BCM2711_DMA_MEMCPY_CHAN);
+	}
+
 	/* get irqs for each channel that we support */
-	for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
+	for (i = chan_start; i < chan_end; i++) {
 		/* skip masked out channels */
 		if (!(chans_available & (1 << i))) {
 			irq[i] = -1;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1351 @
 		irq[i] = platform_get_irq(pdev, i < 11 ? i : 11);
 	}
 
+	chan_count = 0;
+
 	/* get irqs for each channel */
-	for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
+	for (i = chan_start; i < chan_end; i++) {
 		/* skip channels without irq */
 		if (irq[i] < 0)
 			continue;
 
 		/* check if there are other channels that also use this irq */
+		/* FIXME: This will fail if interrupts are shared across
+		   instances */
 		irq_flags = 0;
 		for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++)
 			if ((i != j) && (irq[j] == irq[i])) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1373 @
 		rc = bcm2835_dma_chan_init(od, i, irq[i], irq_flags);
 		if (rc)
 			goto err_no_dma;
+		chan_count++;
 	}
 
-	dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i);
+	dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", chan_count);
 
 	/* Device-tree DMA controller registration */
 	rc = of_dma_controller_register(pdev->dev.of_node,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1406 @
 {
 	struct bcm2835_dmadev *od = platform_get_drvdata(pdev);
 
+	bcm_dmaman_remove(pdev);
 	dma_async_device_unregister(&od->ddev);
+	if (memcpy_parent == od) {
+		dma_free_coherent(&pdev->dev, sizeof(*memcpy_scb), memcpy_scb,
+				  memcpy_scb_dma);
+		memcpy_parent = NULL;
+		memcpy_scb = NULL;
+		memcpy_chan = NULL;
+	}
 	bcm2835_dma_free(od);
 
 	return 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1429 @
 	},
 };
 
-module_platform_driver(bcm2835_dma_driver);
+static int bcm2835_dma_init(void)
+{
+	return platform_driver_register(&bcm2835_dma_driver);
+}
+
+static void bcm2835_dma_exit(void)
+{
+	platform_driver_unregister(&bcm2835_dma_driver);
+}
+
+/*
+ * Load after serial driver (arch_initcall) so we see the messages if it fails,
+ * but before drivers (module_init) that need a DMA channel.
+ */
+subsys_initcall(bcm2835_dma_init);
+module_exit(bcm2835_dma_exit);
 
 MODULE_ALIAS("platform:bcm2835-dma");
 MODULE_DESCRIPTION("BCM2835 DMA engine driver");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/dma/Kconfig linux-5.10.52-v7l+/drivers/dma/Kconfig
--- linux-5.10.52-orig/drivers/dma/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/dma/Kconfig	2021-07-25 16:45:46.318620287 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:655 @
 	  UniPhier platform. This DMA controller can transfer data from
 	  memory to memory, memory to peripheral and peripheral to memory.
 
+config DMA_BCM2708
+	tristate "BCM2708 DMA legacy API support"
+	depends on DMA_BCM2835
+
 config XGENE_DMA
 	tristate "APM X-Gene DMA support"
 	depends on ARCH_XGENE || COMPILE_TEST
diff -Nur --no-dereference linux-5.10.52-orig/drivers/dma/Makefile linux-5.10.52-v7l+/drivers/dma/Makefile
--- linux-5.10.52-orig/drivers/dma/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/dma/Makefile	2021-07-25 16:45:46.318620287 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:24 @
 obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o
 obj-$(CONFIG_BCM_SBA_RAID) += bcm-sba-raid.o
 obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
+obj-$(CONFIG_DMA_BCM2708) += bcm2708-dmaengine.o
 obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
 obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o
 obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/firmware/raspberrypi.c linux-5.10.52-v7l+/drivers/firmware/raspberrypi.c
--- linux-5.10.52-orig/drivers/firmware/raspberrypi.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/firmware/raspberrypi.c	2021-07-25 16:45:46.948609724 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:14 @
 #include <linux/module.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/reboot.h>
 #include <linux/slab.h>
 #include <soc/bcm2835/raspberrypi-firmware.h>
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:31 @
 	struct mbox_chan *chan; /* The property channel. */
 	struct completion c;
 	u32 enabled;
+	u32 get_throttled;
 };
 
+static struct platform_device *g_pdev;
+
 static DEFINE_MUTEX(transaction_lock);
 
 static void response_callback(struct mbox_client *cl, void *msg)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:48 @
  * Sends a request to the firmware through the BCM2835 mailbox driver,
  * and synchronously waits for the reply.
  */
-static int
+int
 rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data)
 {
 	u32 message = MBOX_MSG(chan, data);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:73 @
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(rpi_firmware_transaction);
 
 /**
  * rpi_firmware_property_list - Submit firmware property list
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:178 @
 
 	kfree(data);
 
+	if ((tag == RPI_FIRMWARE_GET_THROTTLED) &&
+	     memcmp(&fw->get_throttled, tag_data, sizeof(fw->get_throttled))) {
+		memcpy(&fw->get_throttled, tag_data, sizeof(fw->get_throttled));
+		sysfs_notify(&fw->cl.dev->kobj, NULL, "get_throttled");
+	}
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(rpi_firmware_property);
 
+static int rpi_firmware_notify_reboot(struct notifier_block *nb,
+				      unsigned long action,
+				      void *data)
+{
+	struct rpi_firmware *fw;
+	struct platform_device *pdev = g_pdev;
+	u32 reboot_flags = 0;
+
+	if (!pdev)
+		return 0;
+
+	fw = platform_get_drvdata(pdev);
+	if (!fw)
+		return 0;
+
+	// The partition id is the first parameter followed by zero or
+	// more flags separated by spaces indicating the reason for the reboot.
+	//
+	// 'tryboot': Sets a one-shot flag which is cleared upon reboot and
+	//            causes the tryboot.txt to be loaded instead of config.txt
+	//            by the bootloader and the start.elf firmware.
+	//
+	//            This is intended to allow automatic fallback to a known
+	//            good image if an OS/FW upgrade fails.
+	//
+	// N.B. The firmware mechanism for storing reboot flags may vary
+	// on different Raspberry Pi models.
+	if (data && strstr(data, " tryboot"))
+		reboot_flags |= 0x1;
+
+	// The mailbox might have been called earlier, directly via vcmailbox
+	// so only overwrite if reboot flags are passed to the reboot command.
+	if (reboot_flags)
+		(void)rpi_firmware_property(fw, RPI_FIRMWARE_SET_REBOOT_FLAGS,
+				&reboot_flags, sizeof(reboot_flags));
+
+	(void)rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_REBOOT, NULL, 0);
+
+	return 0;
+}
+
+static ssize_t get_throttled_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct rpi_firmware *fw = dev_get_drvdata(dev);
+
+	WARN_ONCE(1, "deprecated, use hwmon sysfs instead\n");
+
+	return sprintf(buf, "%x\n", fw->get_throttled);
+}
+
+static DEVICE_ATTR_RO(get_throttled);
+
+static struct attribute *rpi_firmware_dev_attrs[] = {
+	&dev_attr_get_throttled.attr,
+	NULL,
+};
+
+static const struct attribute_group rpi_firmware_dev_group = {
+	.attrs = rpi_firmware_dev_attrs,
+};
+
 static void
 rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
 {
 	time64_t date_and_time;
 	u32 packet;
+	static const char * const variant_strs[] = {
+		"unknown",
+		"start",
+		"start_x",
+		"start_db",
+		"start_cd",
+	};
+	const char *variant_str = "cmd unsupported";
+	u32 variant;
 	int ret = rpi_firmware_property(fw,
 					RPI_FIRMWARE_GET_FIRMWARE_REVISION,
 					&packet, sizeof(packet));
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:273 @
 
 	/* This is not compatible with y2038 */
 	date_and_time = packet;
-	dev_info(fw->cl.dev, "Attached to firmware from %ptT\n", &date_and_time);
+
+	ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_FIRMWARE_VARIANT,
+				    &variant, sizeof(variant));
+
+	if (!ret) {
+		if (variant >= ARRAY_SIZE(variant_strs))
+			variant = 0;
+		variant_str = variant_strs[variant];
+	}
+
+	dev_info(fw->cl.dev,
+		 "Attached to firmware from %ptT, variant %s\n",
+		 &date_and_time, variant_str);
+}
+
+static void
+rpi_firmware_print_firmware_hash(struct rpi_firmware *fw)
+{
+	u32 hash[5];
+	int ret = rpi_firmware_property(fw,
+					RPI_FIRMWARE_GET_FIRMWARE_HASH,
+					hash, sizeof(hash));
+
+	if (ret)
+		return;
+
+	dev_info(fw->cl.dev,
+		 "Firmware hash is %08x%08x%08x%08x%08x\n",
+		 hash[0], hash[1], hash[2], hash[3], hash[4]);
 }
 
 static void
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:316 @
 
 	rpi_hwmon = platform_device_register_data(dev, "raspberrypi-hwmon",
 						  -1, NULL, 0);
+
+	if (!IS_ERR_OR_NULL(rpi_hwmon)) {
+		if (devm_device_add_group(dev, &rpi_firmware_dev_group))
+			dev_err(dev, "Failed to create get_trottled attr\n");
+	}
 }
 
 static void rpi_register_clk_driver(struct device *dev)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:367 @
 	init_completion(&fw->c);
 
 	platform_set_drvdata(pdev, fw);
+	g_pdev = pdev;
 
 	rpi_firmware_print_firmware_revision(fw);
+	rpi_firmware_print_firmware_hash(fw);
 	rpi_register_hwmon_driver(dev, fw);
 	rpi_register_clk_driver(dev);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:396 @
 	platform_device_unregister(rpi_clk);
 	rpi_clk = NULL;
 	mbox_free_channel(fw->chan);
+	g_pdev = NULL;
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:409 @
  */
 struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
 {
-	struct platform_device *pdev = of_find_device_by_node(firmware_node);
+	struct platform_device *pdev = g_pdev;
 
 	if (!pdev)
 		return NULL;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:433 @
 	.shutdown	= rpi_firmware_shutdown,
 	.remove		= rpi_firmware_remove,
 };
-module_platform_driver(rpi_firmware_driver);
+
+static struct notifier_block rpi_firmware_reboot_notifier = {
+	.notifier_call = rpi_firmware_notify_reboot,
+};
+
+static int __init rpi_firmware_init(void)
+{
+	int ret = register_reboot_notifier(&rpi_firmware_reboot_notifier);
+	if (ret)
+		goto out1;
+	ret = platform_driver_register(&rpi_firmware_driver);
+	if (ret)
+		goto out2;
+
+	return 0;
+
+out2:
+	unregister_reboot_notifier(&rpi_firmware_reboot_notifier);
+out1:
+	return ret;
+}
+core_initcall(rpi_firmware_init);
+
+static void __init rpi_firmware_exit(void)
+{
+	platform_driver_unregister(&rpi_firmware_driver);
+	unregister_reboot_notifier(&rpi_firmware_reboot_notifier);
+}
+module_exit(rpi_firmware_exit);
 
 MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
 MODULE_DESCRIPTION("Raspberry Pi firmware driver");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpio/gpio-bcm-virt.c linux-5.10.52-v7l+/drivers/gpio/gpio-bcm-virt.c
--- linux-5.10.52-orig/drivers/gpio/gpio-bcm-virt.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpio/gpio-bcm-virt.c	2021-07-25 16:45:47.068607712 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ *  brcmvirt GPIO driver
+ *
+ *  Copyright (C) 2012,2013 Dom Cobley <popcornmix@gmail.com>
+ *  Based on gpio-clps711x.c by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define MODULE_NAME "brcmvirt-gpio"
+#define NUM_GPIO 2
+
+struct brcmvirt_gpio {
+	struct gpio_chip	gc;
+	u32 __iomem		*ts_base;
+	/* two packed 16-bit counts of enabled and disables
+           Allows host to detect a brief enable that was missed */
+	u32			enables_disables[NUM_GPIO];
+	dma_addr_t		bus_addr;
+};
+
+static int brcmvirt_gpio_dir_in(struct gpio_chip *gc, unsigned off)
+{
+	struct brcmvirt_gpio *gpio;
+	gpio = container_of(gc, struct brcmvirt_gpio, gc);
+	return -EINVAL;
+}
+
+static int brcmvirt_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val)
+{
+	struct brcmvirt_gpio *gpio;
+	gpio = container_of(gc, struct brcmvirt_gpio, gc);
+	return 0;
+}
+
+static int brcmvirt_gpio_get(struct gpio_chip *gc, unsigned off)
+{
+	struct brcmvirt_gpio *gpio;
+	unsigned v;
+	gpio = container_of(gc, struct brcmvirt_gpio, gc);
+	v = readl(gpio->ts_base + off);
+	return (v >> off) & 1;
+}
+
+static void brcmvirt_gpio_set(struct gpio_chip *gc, unsigned off, int val)
+{
+	struct brcmvirt_gpio *gpio;
+	u16 enables, disables;
+	s16 diff;
+	bool lit;
+	gpio = container_of(gc, struct brcmvirt_gpio, gc);
+	enables  = gpio->enables_disables[off] >> 16;
+	disables = gpio->enables_disables[off] >>  0;
+	diff = (s16)(enables - disables);
+	lit = diff > 0;
+	if ((val && lit) || (!val && !lit))
+		return;
+	if (val)
+		enables++;
+	else
+		disables++;
+	diff = (s16)(enables - disables);
+	BUG_ON(diff != 0 && diff != 1);
+	gpio->enables_disables[off] = (enables << 16) | (disables << 0);
+	writel(gpio->enables_disables[off], gpio->ts_base + off);
+}
+
+static int brcmvirt_gpio_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *fw_node;
+	struct rpi_firmware *fw;
+	struct brcmvirt_gpio *ucb;
+	u32 gpiovirtbuf;
+
+	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;
+
+	ucb = devm_kzalloc(dev, sizeof *ucb, GFP_KERNEL);
+	if (!ucb) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	ucb->ts_base = dma_alloc_coherent(dev, PAGE_SIZE, &ucb->bus_addr, GFP_KERNEL);
+	if (!ucb->ts_base) {
+		pr_err("[%s]: failed to dma_alloc_coherent(%ld)\n",
+				__func__, PAGE_SIZE);
+		err = -ENOMEM;
+		goto out;
+	}
+
+	gpiovirtbuf = (u32)ucb->bus_addr;
+	err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF,
+				    &gpiovirtbuf, sizeof(gpiovirtbuf));
+
+	if (err || gpiovirtbuf != 0) {
+		dev_warn(dev, "Failed to set gpiovirtbuf, trying to get err:%x\n", err);
+		dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
+		ucb->ts_base = 0;
+		ucb->bus_addr = 0;
+	}
+
+	if (!ucb->ts_base) {
+		err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF,
+					    &gpiovirtbuf, sizeof(gpiovirtbuf));
+
+		if (err) {
+			dev_err(dev, "Failed to get gpiovirtbuf\n");
+			goto out;
+		}
+
+		if (!gpiovirtbuf) {
+			dev_err(dev, "No virtgpio buffer\n");
+			err = -ENOENT;
+			goto out;
+		}
+
+		// mmap the physical memory
+		gpiovirtbuf &= ~0xc0000000;
+		ucb->ts_base = ioremap(gpiovirtbuf, 4096);
+		if (ucb->ts_base == NULL) {
+			dev_err(dev, "Failed to map physical address\n");
+			err = -ENOENT;
+			goto out;
+		}
+		ucb->bus_addr = 0;
+	}
+	ucb->gc.label = MODULE_NAME;
+	ucb->gc.owner = THIS_MODULE;
+	//ucb->gc.dev = dev;
+	ucb->gc.of_node = np;
+	ucb->gc.base = 100;
+	ucb->gc.ngpio = NUM_GPIO;
+
+	ucb->gc.direction_input = brcmvirt_gpio_dir_in;
+	ucb->gc.direction_output = brcmvirt_gpio_dir_out;
+	ucb->gc.get = brcmvirt_gpio_get;
+	ucb->gc.set = brcmvirt_gpio_set;
+	ucb->gc.can_sleep = true;
+
+	err = gpiochip_add(&ucb->gc);
+	if (err)
+		goto out;
+
+	platform_set_drvdata(pdev, ucb);
+
+	return 0;
+out:
+	if (ucb->bus_addr) {
+		dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
+		ucb->bus_addr = 0;
+		ucb->ts_base = NULL;
+	} else if (ucb->ts_base) {
+		iounmap(ucb->ts_base);
+		ucb->ts_base = NULL;
+	}
+	return err;
+}
+
+static int brcmvirt_gpio_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int err = 0;
+	struct brcmvirt_gpio *ucb = platform_get_drvdata(pdev);
+
+	gpiochip_remove(&ucb->gc);
+	if (ucb->bus_addr)
+		dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
+	else if (ucb->ts_base)
+		iounmap(ucb->ts_base);
+	return err;
+}
+
+static const struct of_device_id __maybe_unused brcmvirt_gpio_ids[] = {
+	{ .compatible = "brcm,bcm2835-virtgpio" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, brcmvirt_gpio_ids);
+
+static struct platform_driver brcmvirt_gpio_driver = {
+	.driver	= {
+		.name		= MODULE_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= of_match_ptr(brcmvirt_gpio_ids),
+	},
+	.probe	= brcmvirt_gpio_probe,
+	.remove	= brcmvirt_gpio_remove,
+};
+module_platform_driver(brcmvirt_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dom Cobley <popcornmix@gmail.com>");
+MODULE_DESCRIPTION("brcmvirt GPIO driver");
+MODULE_ALIAS("platform:brcmvirt-gpio");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpio/gpio-fsm.c linux-5.10.52-v7l+/drivers/gpio/gpio-fsm.c
--- linux-5.10.52-orig/drivers/gpio/gpio-fsm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpio/gpio-fsm.c	2021-07-25 16:45:47.108607042 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  GPIO FSM driver
+ *
+ *  This driver implements simple state machines that allow real GPIOs to be
+ *  controlled in response to inputs from other GPIOs - real and soft/virtual -
+ *  and time delays. It can:
+ *  + create dummy GPIOs for drivers that demand them
+ *  + drive multiple GPIOs from a single input,  with optional delays
+ *  + add a debounce circuit to an input
+ *  + drive pattern sequences onto LEDs
+ *  etc.
+ *
+ *  Copyright (C) 2020 Raspberry Pi (Trading) Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#include <dt-bindings/gpio/gpio-fsm.h>
+
+#define MODULE_NAME "gpio-fsm"
+
+#define GF_IO_TYPE(x) ((u32)(x) & 0xffff)
+#define GF_IO_INDEX(x) ((u32)(x) >> 16)
+
+enum {
+	SIGNAL_GPIO,
+	SIGNAL_SOFT
+};
+
+enum {
+	INPUT_GPIO,
+	INPUT_SOFT
+};
+
+enum {
+	SYM_UNDEFINED,
+	SYM_NAME,
+	SYM_SET,
+	SYM_START,
+	SYM_SHUTDOWN,
+
+	SYM_MAX
+};
+
+struct soft_gpio {
+	int dir;
+	int value;
+};
+
+struct input_gpio_state {
+	struct gpio_fsm *gf;
+	struct gpio_desc  *desc;
+	struct fsm_state *target;
+	int index;
+	int value;
+	int irq;
+	bool enabled;
+	bool active_low;
+};
+
+struct gpio_event {
+	int index;
+	int value;
+	struct fsm_state *target;
+};
+
+struct symtab_entry {
+	const char *name;
+	void *value;
+	struct symtab_entry *next;
+};
+
+struct output_signal {
+	u8 type;
+	u8 value;
+	u16 index;
+};
+
+struct fsm_state {
+	const char *name;
+	struct output_signal *signals;
+	struct gpio_event *gpio_events;
+	struct gpio_event *soft_events;
+	struct fsm_state *delay_target;
+	struct fsm_state *shutdown_target;
+	unsigned int num_signals;
+	unsigned int num_gpio_events;
+	unsigned int num_soft_events;
+	unsigned int delay_ms;
+	unsigned int shutdown_ms;
+};
+
+struct gpio_fsm {
+	struct gpio_chip gc;
+	struct device *dev;
+	spinlock_t spinlock;
+	struct work_struct work;
+	struct timer_list timer;
+	wait_queue_head_t shutdown_event;
+	struct fsm_state *states;
+	struct input_gpio_state *input_gpio_states;
+	struct gpio_descs *input_gpios;
+	struct gpio_descs *output_gpios;
+	struct soft_gpio *soft_gpios;
+	struct fsm_state *start_state;
+	struct fsm_state *shutdown_state;
+	unsigned int num_states;
+	unsigned int num_output_gpios;
+	unsigned int num_input_gpios;
+	unsigned int num_soft_gpios;
+	unsigned int shutdown_timeout_ms;
+	unsigned int shutdown_jiffies;
+
+	struct fsm_state *current_state;
+	struct fsm_state *next_state;
+	struct fsm_state *delay_target_state;
+	unsigned int delay_jiffies;
+	int delay_ms;
+	unsigned int debug;
+	bool shutting_down;
+	struct symtab_entry *symtab;
+};
+
+static struct symtab_entry *do_add_symbol(struct symtab_entry **symtab,
+					  const char *name, void *value)
+{
+	struct symtab_entry **p = symtab;
+
+	while (*p && strcmp((*p)->name, name))
+		p = &(*p)->next;
+
+	if (*p) {
+		/* This is an existing symbol */
+		if ((*p)->value) {
+			/* Already defined */
+			if (value) {
+				if ((uintptr_t)value < SYM_MAX)
+					return ERR_PTR(-EINVAL);
+				else
+					return ERR_PTR(-EEXIST);
+			}
+		} else {
+			/* Undefined */
+			(*p)->value = value;
+		}
+	} else {
+		/* This is a new symbol */
+		*p = kmalloc(sizeof(struct symtab_entry), GFP_KERNEL);
+		if (*p) {
+			(*p)->name = name;
+			(*p)->value = value;
+			(*p)->next = NULL;
+		}
+	}
+	return *p;
+}
+
+static int add_symbol(struct symtab_entry **symtab,
+		      const char *name, void *value)
+{
+	struct symtab_entry *sym = do_add_symbol(symtab, name, value);
+
+	return PTR_ERR_OR_ZERO(sym);
+}
+
+static struct symtab_entry *get_symbol(struct symtab_entry **symtab,
+				       const char *name)
+{
+	struct symtab_entry *sym = do_add_symbol(symtab, name, NULL);
+
+	if (IS_ERR(sym))
+		return NULL;
+	return sym;
+}
+
+static void free_symbols(struct symtab_entry **symtab)
+{
+	struct symtab_entry *sym = *symtab;
+	void *p;
+
+	*symtab = NULL;
+	while (sym) {
+		p = sym;
+		sym = sym->next;
+		kfree(p);
+	}
+}
+
+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 : "<unset>");
+
+	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_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);
+}
+
+static void gpio_fsm_enter_state(struct gpio_fsm *gf,
+				   struct fsm_state *state)
+{
+	struct input_gpio_state *inp_state;
+	struct output_signal *signal;
+	struct gpio_event *event;
+	struct gpio_desc *gpiod;
+	struct soft_gpio *soft;
+	int value;
+	int i;
+
+	dev_dbg(gf->dev, "enter_state(%s)\n", state->name);
+
+	gf->current_state = state;
+
+	// 1. Apply any listed signals
+	for (i = 0; i < state->num_signals; i++) {
+		signal = &state->signals[i];
+
+		if (gf->debug)
+			dev_info(gf->dev, "  set %s %d->%d\n",
+				 (signal->type == SIGNAL_GPIO) ? "GF_OUT" :
+				 "GF_SOFT",
+				 signal->index, signal->value);
+		switch (signal->type) {
+		case SIGNAL_GPIO:
+			gpiod = gf->output_gpios->desc[signal->index];
+			gpiod_set_value_cansleep(gpiod, signal->value);
+			break;
+		case SIGNAL_SOFT:
+			soft = &gf->soft_gpios[signal->index];
+			gpio_fsm_set_soft(gf, signal->index, signal->value);
+			break;
+		}
+	}
+
+	// 2. Exit if successfully reached shutdown state
+	if (gf->shutting_down && state == state->shutdown_target) {
+		wake_up(&gf->shutdown_event);
+		return;
+	}
+
+	// 3. Schedule a timer callback if shutting down
+	if (state->shutdown_target) {
+		// Remember the absolute shutdown time in case remove is called
+		// at a later time.
+		gf->shutdown_jiffies =
+			jiffies + msecs_to_jiffies(state->shutdown_ms);
+
+		if (gf->shutting_down) {
+			gf->delay_jiffies = gf->shutdown_jiffies;
+			gf->delay_target_state = state->shutdown_target;
+			gf->delay_ms = state->shutdown_ms;
+			mod_timer(&gf->timer, gf->delay_jiffies);
+		}
+	}
+
+	// During shutdown, skip everything else
+	if (gf->shutting_down)
+		return;
+
+	// Otherwise record what the shutdown time would be
+	gf->shutdown_jiffies = jiffies + msecs_to_jiffies(state->shutdown_ms);
+
+	// 4. Check soft inputs for transitions to take
+	for (i = 0; i < state->num_soft_events; i++) {
+		event = &state->soft_events[i];
+		if (gf->soft_gpios[event->index].value == event->value) {
+			if (gf->debug)
+				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);
+			return;
+		}
+	}
+
+	// 5. Check GPIOs for transitions to take, enabling the IRQs
+	for (i = 0; i < state->num_gpio_events; i++) {
+		event = &state->gpio_events[i];
+		inp_state = &gf->input_gpio_states[event->index];
+		inp_state->target = event->target;
+		inp_state->value = event->value;
+		inp_state->enabled = true;
+
+		value = gpiod_get_value(gf->input_gpios->desc[event->index]);
+
+		// Clear stale event state
+		disable_irq(inp_state->irq);
+
+		irq_set_irq_type(inp_state->irq,
+				 (inp_state->value ^ inp_state->active_low) ?
+				 IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING);
+		enable_irq(inp_state->irq);
+
+		if (value == event->value && inp_state->target) {
+			if (gf->debug)
+				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);
+			return;
+		}
+	}
+
+	// 6. Schedule a timer callback if delay_target
+	if (state->delay_target) {
+		gf->delay_target_state = state->delay_target;
+		gf->delay_jiffies = jiffies +
+			msecs_to_jiffies(state->delay_ms);
+		gf->delay_ms = state->delay_ms;
+		mod_timer(&gf->timer, gf->delay_jiffies);
+	}
+}
+
+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);
+}
+
+static irqreturn_t gpio_fsm_gpio_irq_handler(int irq, void *dev_id)
+{
+	struct input_gpio_state *inp_state = dev_id;
+	struct gpio_fsm *gf = inp_state->gf;
+	struct fsm_state *target;
+
+	target = inp_state->target;
+	if (!target)
+		return IRQ_NONE;
+
+	/* If the IRQ has fired then the desired state _must_ have occurred */
+	inp_state->enabled = false;
+	irq_set_irq_type(inp_state->irq, IRQF_TRIGGER_NONE);
+	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);
+	return IRQ_HANDLED;
+}
+
+static void gpio_fsm_timer(struct timer_list *timer)
+{
+	struct gpio_fsm *gf = container_of(timer, struct gpio_fsm, timer);
+	struct fsm_state *target;
+
+	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);
+}
+
+int gpio_fsm_parse_signals(struct gpio_fsm *gf, struct fsm_state *state,
+			     struct property *prop)
+{
+	const __be32 *cells = prop->value;
+	struct output_signal *signal;
+	u32 io;
+	u32 type;
+	u32 index;
+	u32 value;
+	int ret = 0;
+	int i;
+
+	if (prop->length % 8) {
+		dev_err(gf->dev, "malformed set in state %s\n",
+			state->name);
+		return -EINVAL;
+	}
+
+	state->num_signals = prop->length/8;
+	state->signals = devm_kcalloc(gf->dev, state->num_signals,
+				      sizeof(struct output_signal),
+				      GFP_KERNEL);
+	for (i = 0; i < state->num_signals; i++) {
+		signal = &state->signals[i];
+		io = be32_to_cpu(cells[0]);
+		type = GF_IO_TYPE(io);
+		index = GF_IO_INDEX(io);
+		value = be32_to_cpu(cells[1]);
+
+		if (type != GF_OUT && type != GF_SOFT) {
+			dev_err(gf->dev,
+				"invalid set type %d in state %s\n",
+				type, state->name);
+			ret = -EINVAL;
+			break;
+		}
+		if (type == GF_OUT && index >= gf->num_output_gpios) {
+			dev_err(gf->dev,
+				"invalid GF_OUT number %d in state %s\n",
+				index, state->name);
+			ret = -EINVAL;
+			break;
+		}
+		if (type == GF_SOFT && index >= gf->num_soft_gpios) {
+			dev_err(gf->dev,
+				"invalid GF_SOFT number %d in state %s\n",
+				index, state->name);
+			ret = -EINVAL;
+			break;
+		}
+		if (value != 0 && value != 1) {
+			dev_err(gf->dev,
+				"invalid set value %d in state %s\n",
+				value, state->name);
+			ret = -EINVAL;
+			break;
+		}
+		signal->type = (type == GF_OUT) ? SIGNAL_GPIO : SIGNAL_SOFT;
+		signal->index = index;
+		signal->value = value;
+		cells += 2;
+	}
+
+	return ret;
+}
+
+struct gpio_event *new_event(struct gpio_event **events, int *num_events)
+{
+	int num = ++(*num_events);
+	*events = krealloc(*events, num * sizeof(struct gpio_event),
+			   GFP_KERNEL);
+	return *events ? *events + (num - 1) : NULL;
+}
+
+int gpio_fsm_parse_events(struct gpio_fsm *gf, struct fsm_state *state,
+			    struct property *prop)
+{
+	const __be32 *cells = prop->value;
+	struct symtab_entry *sym;
+	int num_cells;
+	int ret = 0;
+	int i;
+
+	if (prop->length % 8) {
+		dev_err(gf->dev,
+			"malformed transitions from state %s to state %s\n",
+			state->name, prop->name);
+		return -EINVAL;
+	}
+
+	sym = get_symbol(&gf->symtab, prop->name);
+	num_cells = prop->length / 4;
+	i = 0;
+	while (i < num_cells) {
+		struct gpio_event *gp_ev;
+		u32 event, param;
+		u32 index;
+
+		event = be32_to_cpu(cells[i++]);
+		param = be32_to_cpu(cells[i++]);
+		index = GF_IO_INDEX(event);
+
+		switch (GF_IO_TYPE(event)) {
+		case GF_IN:
+			if (index >= gf->num_input_gpios) {
+				dev_err(gf->dev,
+					"invalid GF_IN %d in transitions from state %s to state %s\n",
+					index, state->name, prop->name);
+				return -EINVAL;
+			}
+			if (param > 1) {
+				dev_err(gf->dev,
+					"invalid GF_IN value %d in transitions from state %s to state %s\n",
+					param, state->name, prop->name);
+				return -EINVAL;
+			}
+			gp_ev = new_event(&state->gpio_events,
+					  &state->num_gpio_events);
+			if (!gp_ev)
+				return -ENOMEM;
+			gp_ev->index = index;
+			gp_ev->value = param;
+			gp_ev->target = (struct fsm_state *)sym;
+			break;
+
+		case GF_SOFT:
+			if (index >= gf->num_soft_gpios) {
+				dev_err(gf->dev,
+					"invalid GF_SOFT %d in transitions from state %s to state %s\n",
+					index, state->name, prop->name);
+				return -EINVAL;
+			}
+			if (param > 1) {
+				dev_err(gf->dev,
+					"invalid GF_SOFT value %d in transitions from state %s to state %s\n",
+					param, state->name, prop->name);
+				return -EINVAL;
+			}
+			gp_ev = new_event(&state->soft_events,
+					  &state->num_soft_events);
+			if (!gp_ev)
+				return -ENOMEM;
+			gp_ev->index = index;
+			gp_ev->value = param;
+			gp_ev->target = (struct fsm_state *)sym;
+			break;
+
+		case GF_DELAY:
+			if (state->delay_target) {
+				dev_err(gf->dev,
+					"state %s has multiple GF_DELAYs\n",
+					state->name);
+				return -EINVAL;
+			}
+			state->delay_target = (struct fsm_state *)sym;
+			state->delay_ms = param;
+			break;
+
+		case GF_SHUTDOWN:
+			if (state->shutdown_target == state) {
+				dev_err(gf->dev,
+					"shutdown state %s has GF_SHUTDOWN\n",
+					state->name);
+				return -EINVAL;
+			} else if (state->shutdown_target) {
+				dev_err(gf->dev,
+					"state %s has multiple GF_SHUTDOWNs\n",
+					state->name);
+				return -EINVAL;
+			}
+			state->shutdown_target =
+				(struct fsm_state *)sym;
+			state->shutdown_ms = param;
+			break;
+
+		default:
+			dev_err(gf->dev,
+				"invalid event %08x in transitions from state %s to state %s\n",
+				event, state->name, prop->name);
+			return -EINVAL;
+		}
+	}
+	if (i != num_cells) {
+		dev_err(gf->dev,
+			"malformed transitions from state %s to state %s\n",
+			state->name, prop->name);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+int gpio_fsm_parse_state(struct gpio_fsm *gf,
+			   struct fsm_state *state,
+			   struct device_node *np)
+{
+	struct symtab_entry *sym;
+	struct property *prop;
+	int ret;
+
+	state->name = np->name;
+	ret = add_symbol(&gf->symtab, np->name, state);
+	if (ret) {
+		switch (ret) {
+		case -EINVAL:
+			dev_err(gf->dev, "'%s' is not a valid state name\n",
+				np->name);
+			break;
+		case -EEXIST:
+			dev_err(gf->dev, "state %s already defined\n",
+				np->name);
+			break;
+		default:
+			dev_err(gf->dev, "error %d adding state %s symbol\n",
+				ret, np->name);
+			break;
+		}
+		return ret;
+	}
+
+	for_each_property_of_node(np, prop) {
+		sym = get_symbol(&gf->symtab, prop->name);
+		if (!sym) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		switch ((uintptr_t)sym->value) {
+		case SYM_SET:
+			ret = gpio_fsm_parse_signals(gf, state, prop);
+			break;
+		case SYM_START:
+			if (gf->start_state) {
+				dev_err(gf->dev, "multiple start states\n");
+				ret = -EINVAL;
+			} else {
+				gf->start_state = state;
+			}
+			break;
+		case SYM_SHUTDOWN:
+			state->shutdown_target = state;
+			gf->shutdown_state = state;
+			break;
+		case SYM_NAME:
+			/* Ignore */
+			break;
+		default:
+			/* A set of transition events to this state */
+			ret = gpio_fsm_parse_events(gf, state, prop);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void dump_all(struct gpio_fsm *gf)
+{
+	int i, j;
+
+	dev_info(gf->dev, "Input GPIOs:\n");
+	for (i = 0; i < gf->num_input_gpios; i++)
+		dev_info(gf->dev, "  %d: %p\n", i,
+			 gf->input_gpios->desc[i]);
+
+	dev_info(gf->dev, "Output GPIOs:\n");
+	for (i = 0; i < gf->num_output_gpios; i++)
+		dev_info(gf->dev, "  %d: %p\n", i,
+			 gf->output_gpios->desc[i]);
+
+	dev_info(gf->dev, "Soft GPIOs:\n");
+	for (i = 0; i < gf->num_soft_gpios; i++)
+		dev_info(gf->dev, "  %d: %s %d\n", i,
+			 (gf->soft_gpios[i].dir == GPIOF_DIR_IN) ? "IN" : "OUT",
+			 gf->soft_gpios[i].value);
+
+	dev_info(gf->dev, "Start state: %s\n",
+		 gf->start_state ? gf->start_state->name : "-");
+
+	dev_info(gf->dev, "Shutdown timeout: %d ms\n",
+		 gf->shutdown_timeout_ms);
+
+	for (i = 0; i < gf->num_states; i++) {
+		struct fsm_state *state = &gf->states[i];
+
+		dev_info(gf->dev, "State %s:\n", state->name);
+
+		if (state->shutdown_target == state)
+			dev_info(gf->dev, "  Shutdown state\n");
+
+		dev_info(gf->dev, "  Signals:\n");
+		for (j = 0; j < state->num_signals; j++) {
+			struct output_signal *signal = &state->signals[j];
+
+			dev_info(gf->dev, "    %d: %s %d=%d\n", j,
+				 (signal->type == SIGNAL_GPIO) ? "GPIO" :
+								 "SOFT",
+				 signal->index, signal->value);
+		}
+
+		dev_info(gf->dev, "  GPIO events:\n");
+		for (j = 0; j < state->num_gpio_events; j++) {
+			struct gpio_event *event = &state->gpio_events[j];
+
+			dev_info(gf->dev, "    %d: %d=%d -> %s\n", j,
+				 event->index, event->value,
+				 event->target->name);
+		}
+
+		dev_info(gf->dev, "  Soft events:\n");
+		for (j = 0; j < state->num_soft_events; j++) {
+			struct gpio_event *event = &state->soft_events[j];
+
+			dev_info(gf->dev, "    %d: %d=%d -> %s\n", j,
+				 event->index, event->value,
+				 event->target->name);
+		}
+
+		if (state->delay_target)
+			dev_info(gf->dev, "  Delay: %d ms -> %s\n",
+				 state->delay_ms, state->delay_target->name);
+
+		if (state->shutdown_target && state->shutdown_target != state)
+			dev_info(gf->dev, "  Shutdown: %d ms -> %s\n",
+				 state->shutdown_ms,
+				 state->shutdown_target->name);
+	}
+	dev_info(gf->dev, "\n");
+}
+
+static int resolve_sym_to_state(struct gpio_fsm *gf, struct fsm_state **pstate)
+{
+	struct symtab_entry *sym = (struct symtab_entry *)*pstate;
+
+	if (!sym)
+		return -ENOMEM;
+
+	*pstate = sym->value;
+
+	if (!*pstate) {
+		dev_err(gf->dev, "state %s not defined\n",
+			sym->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+/*
+ * /sys/class/gpio-fsm/<fsm-name>/
+ *   /state ... the current state
+ */
+
+static ssize_t state_show(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	const struct gpio_fsm *gf = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", gf->current_state->name);
+}
+static DEVICE_ATTR_RO(state);
+
+static ssize_t delay_state_show(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	const struct gpio_fsm *gf = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n",
+		       gf->delay_target_state ? gf->delay_target_state->name :
+		       "-");
+}
+
+static DEVICE_ATTR_RO(delay_state);
+
+static ssize_t delay_ms_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	const struct gpio_fsm *gf = dev_get_drvdata(dev);
+	int jiffies_left;
+
+	jiffies_left = gf->delay_jiffies - jiffies;
+	return sprintf(buf,
+		       gf->delay_target_state ? "%u\n" : "-\n",
+		       jiffies_to_msecs(jiffies_left));
+}
+static DEVICE_ATTR_RO(delay_ms);
+
+static struct attribute *gpio_fsm_attrs[] = {
+	&dev_attr_state.attr,
+	&dev_attr_delay_state.attr,
+	&dev_attr_delay_ms.attr,
+	NULL,
+};
+
+static const struct attribute_group gpio_fsm_group = {
+	.attrs = gpio_fsm_attrs,
+	//.is_visible = gpio_is_visible,
+};
+
+static const struct attribute_group *gpio_fsm_groups[] = {
+	&gpio_fsm_group,
+	NULL
+};
+
+static struct attribute *gpio_fsm_class_attrs[] = {
+	// There are no top-level attributes
+	NULL,
+};
+ATTRIBUTE_GROUPS(gpio_fsm_class);
+
+static struct class gpio_fsm_class = {
+	.name =		MODULE_NAME,
+	.owner =	THIS_MODULE,
+
+	.class_groups = gpio_fsm_class_groups,
+};
+
+static int gpio_fsm_probe(struct platform_device *pdev)
+{
+	struct input_gpio_state *inp_state;
+	struct device *dev = &pdev->dev;
+	struct device *sysfs_dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *cp;
+	struct gpio_fsm *gf;
+	u32 debug = 0;
+	int num_states;
+	u32 num_soft_gpios;
+	int ret;
+	int i;
+	static const char *const reserved_symbols[] = {
+		[SYM_NAME] = "name",
+		[SYM_SET] = "set",
+		[SYM_START] = "start_state",
+		[SYM_SHUTDOWN] = "shutdown_state",
+	};
+
+	if (of_property_read_u32(np, "num-swgpios", &num_soft_gpios) &&
+	    of_property_read_u32(np, "num-soft-gpios", &num_soft_gpios)) {
+		dev_err(dev, "missing 'num-swgpios' property\n");
+		return -EINVAL;
+	}
+
+	of_property_read_u32(np, "debug", &debug);
+
+	gf = devm_kzalloc(dev, sizeof(*gf), GFP_KERNEL);
+	if (!gf)
+		return -ENOMEM;
+
+	gf->dev = dev;
+	gf->debug = debug;
+
+	if (of_property_read_u32(np, "shutdown-timeout-ms",
+				 &gf->shutdown_timeout_ms))
+		gf->shutdown_timeout_ms = 5000;
+
+	gf->num_soft_gpios = num_soft_gpios;
+	gf->soft_gpios = devm_kcalloc(dev, num_soft_gpios,
+				      sizeof(struct soft_gpio), GFP_KERNEL);
+	if (!gf->soft_gpios)
+		return -ENOMEM;
+	for (i = 0; i < num_soft_gpios; i++) {
+		struct soft_gpio *sg = &gf->soft_gpios[i];
+
+		sg->dir = GPIOF_DIR_IN;
+		sg->value = 0;
+	}
+
+	gf->input_gpios = devm_gpiod_get_array_optional(dev, "input", GPIOD_IN);
+	if (IS_ERR(gf->input_gpios)) {
+		ret = PTR_ERR(gf->input_gpios);
+		dev_err(dev, "failed to get input gpios from DT - %d\n", ret);
+		return ret;
+	}
+	gf->num_input_gpios = (gf->input_gpios ? gf->input_gpios->ndescs : 0);
+
+	gf->input_gpio_states = devm_kcalloc(dev, gf->num_input_gpios,
+					     sizeof(struct input_gpio_state),
+					     GFP_KERNEL);
+	if (!gf->input_gpio_states)
+		return -ENOMEM;
+	for (i = 0; i < gf->num_input_gpios; i++) {
+		inp_state = &gf->input_gpio_states[i];
+		inp_state->desc = gf->input_gpios->desc[i];
+		inp_state->gf = gf;
+		inp_state->index = i;
+		inp_state->irq = gpiod_to_irq(inp_state->desc);
+		inp_state->active_low = gpiod_is_active_low(inp_state->desc);
+		if (inp_state->irq >= 0)
+			ret = devm_request_irq(gf->dev, inp_state->irq,
+					       gpio_fsm_gpio_irq_handler,
+					       IRQF_TRIGGER_NONE,
+					       dev_name(dev),
+					       inp_state);
+		else
+			ret = inp_state->irq;
+
+		if (ret) {
+			dev_err(dev,
+				"failed to get IRQ for input gpio - %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	gf->output_gpios = devm_gpiod_get_array_optional(dev, "output",
+							 GPIOD_OUT_LOW);
+	if (IS_ERR(gf->output_gpios)) {
+		ret = PTR_ERR(gf->output_gpios);
+		dev_err(dev, "failed to get output gpios from DT - %d\n", ret);
+		return ret;
+	}
+	gf->num_output_gpios = (gf->output_gpios ? gf->output_gpios->ndescs :
+				0);
+
+	num_states = of_get_child_count(np);
+	if (!num_states) {
+		dev_err(dev, "no states declared\n");
+		return -EINVAL;
+	}
+	gf->states = devm_kcalloc(dev, num_states,
+				  sizeof(struct fsm_state), GFP_KERNEL);
+	if (!gf->states)
+		return -ENOMEM;
+
+	// add reserved words to the symbol table
+	for (i = 0; i < ARRAY_SIZE(reserved_symbols); i++) {
+		if (reserved_symbols[i])
+			add_symbol(&gf->symtab, reserved_symbols[i],
+				   (void *)(uintptr_t)i);
+	}
+
+	// parse the state
+	for_each_child_of_node(np, cp) {
+		struct fsm_state *state = &gf->states[gf->num_states];
+
+		ret = gpio_fsm_parse_state(gf, state, cp);
+		if (ret)
+			return ret;
+		gf->num_states++;
+	}
+
+	if (!gf->start_state) {
+		dev_err(gf->dev, "no start state defined\n");
+		return -EINVAL;
+	}
+
+	// resolve symbol pointers into state pointers
+	for (i = 0; !ret && i < gf->num_states; i++) {
+		struct fsm_state *state = &gf->states[i];
+		int j;
+
+		for (j = 0; !ret && j < state->num_gpio_events; j++) {
+			struct gpio_event *ev = &state->gpio_events[j];
+
+			ret = resolve_sym_to_state(gf, &ev->target);
+		}
+
+		for (j = 0; !ret && j < state->num_soft_events; j++) {
+			struct gpio_event *ev = &state->soft_events[j];
+
+			ret = resolve_sym_to_state(gf, &ev->target);
+		}
+
+		if (!ret) {
+			resolve_sym_to_state(gf, &state->delay_target);
+			if (state->shutdown_target != state)
+				resolve_sym_to_state(gf,
+						     &state->shutdown_target);
+		}
+	}
+
+	if (!ret && gf->debug > 1)
+		dump_all(gf);
+
+	free_symbols(&gf->symtab);
+
+	if (ret)
+		return ret;
+
+	gf->gc.parent = dev;
+	gf->gc.label = np->name;
+	gf->gc.owner = THIS_MODULE;
+	gf->gc.of_node = np;
+	gf->gc.base = -1;
+	gf->gc.ngpio = num_soft_gpios;
+
+	gf->gc.get_direction = gpio_fsm_get_direction;
+	gf->gc.direction_input = gpio_fsm_direction_input;
+	gf->gc.direction_output = gpio_fsm_direction_output;
+	gf->gc.get = gpio_fsm_get;
+	gf->gc.set = gpio_fsm_set;
+	gf->gc.can_sleep = true;
+	spin_lock_init(&gf->spinlock);
+	INIT_WORK(&gf->work, gpio_fsm_work);
+	timer_setup(&gf->timer, gpio_fsm_timer, 0);
+	init_waitqueue_head(&gf->shutdown_event);
+
+	platform_set_drvdata(pdev, gf);
+
+	sysfs_dev = device_create_with_groups(&gpio_fsm_class, dev,
+					      MKDEV(0, 0), gf,
+					      gpio_fsm_groups,
+					      "%s", np->name);
+	if (IS_ERR(sysfs_dev))
+		dev_err(gf->dev, "Error creating sysfs entry\n");
+
+	if (gf->debug)
+		dev_info(gf->dev, "Start -> %s\n", gf->start_state->name);
+
+	gpio_fsm_go_to_state(gf, gf->start_state);
+
+	return devm_gpiochip_add_data(dev, &gf->gc, gf);
+}
+
+static int gpio_fsm_remove(struct platform_device *pdev)
+{
+	struct gpio_fsm *gf = platform_get_drvdata(pdev);
+	int i;
+
+	if (gf->shutdown_state) {
+		if (gf->debug)
+			dev_info(gf->dev, "Shutting down...\n");
+
+		spin_lock(&gf->spinlock);
+		gf->shutting_down = true;
+		if (gf->current_state->shutdown_target &&
+		    gf->current_state->shutdown_target != gf->current_state) {
+			gf->delay_target_state =
+				gf->current_state->shutdown_target;
+			mod_timer(&gf->timer, gf->shutdown_jiffies);
+		}
+		spin_unlock(&gf->spinlock);
+
+		wait_event_timeout(gf->shutdown_event,
+				   gf->current_state->shutdown_target ==
+				   gf->current_state,
+				   msecs_to_jiffies(gf->shutdown_timeout_ms));
+		/* On failure to reach a shutdown state, jump to one */
+		if (gf->current_state->shutdown_target != gf->current_state)
+			gpio_fsm_enter_state(gf, gf->shutdown_state);
+	}
+	cancel_work_sync(&gf->work);
+	del_timer_sync(&gf->timer);
+
+	/* Events aren't allocated from managed storage */
+	for (i = 0; i < gf->num_states; i++) {
+		kfree(gf->states[i].gpio_events);
+		kfree(gf->states[i].soft_events);
+	}
+	if (gf->debug)
+		dev_info(gf->dev, "Exiting\n");
+
+	return 0;
+}
+
+static void gpio_fsm_shutdown(struct platform_device *pdev)
+{
+	gpio_fsm_remove(pdev);
+}
+
+static const struct of_device_id gpio_fsm_ids[] = {
+	{ .compatible = "rpi,gpio-fsm" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gpio_fsm_ids);
+
+static struct platform_driver gpio_fsm_driver = {
+	.driver	= {
+		.name		= MODULE_NAME,
+		.of_match_table	= of_match_ptr(gpio_fsm_ids),
+	},
+	.probe = gpio_fsm_probe,
+	.remove = gpio_fsm_remove,
+	.shutdown = gpio_fsm_shutdown,
+};
+
+static int gpio_fsm_init(void)
+{
+	int ret;
+
+	ret = class_register(&gpio_fsm_class);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&gpio_fsm_driver);
+	if (ret)
+		class_unregister(&gpio_fsm_class);
+
+	return ret;
+}
+module_init(gpio_fsm_init);
+
+static void gpio_fsm_exit(void)
+{
+	platform_driver_unregister(&gpio_fsm_driver);
+	class_unregister(&gpio_fsm_class);
+}
+module_exit(gpio_fsm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>");
+MODULE_DESCRIPTION("GPIO FSM driver");
+MODULE_ALIAS("platform:gpio-fsm");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpio/gpiolib.c linux-5.10.52-v7l+/drivers/gpio/gpiolib.c
--- linux-5.10.52-orig/drivers/gpio/gpiolib.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpio/gpiolib.c	2021-07-25 16:45:47.458601174 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:54 @
 #define	extra_checks	0
 #endif
 
+#define dont_test_bit(b,d) (0)
+
 /* Device and char device-related information */
 static DEFINE_IDA(gpio_ida);
 static dev_t gpio_devt;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2449 @
 		value = !!value;
 
 	/* GPIOs used for enabled IRQs shall not be set as output */
-	if (test_bit(FLAG_USED_AS_IRQ, &desc->flags) &&
-	    test_bit(FLAG_IRQ_IS_ENABLED, &desc->flags)) {
+	if (dont_test_bit(FLAG_USED_AS_IRQ, &desc->flags) &&
+	    dont_test_bit(FLAG_IRQ_IS_ENABLED, &desc->flags)) {
 		gpiod_err(desc,
 			  "%s: tried to set a GPIO tied to an IRQ as output\n",
 			  __func__);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3255 @
 	}
 
 	/* To be valid for IRQ the line needs to be input or open drain */
-	if (test_bit(FLAG_IS_OUT, &desc->flags) &&
-	    !test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
+	if (dont_test_bit(FLAG_IS_OUT, &desc->flags) &&
+	    !dont_test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
 		chip_err(gc,
 			 "%s: tried to flag a GPIO set as output for IRQ\n",
 			 __func__);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpio/Kconfig linux-5.10.52-v7l+/drivers/gpio/Kconfig
--- linux-5.10.52-orig/drivers/gpio/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpio/Kconfig	2021-07-25 16:45:47.058607880 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:196 @
 	help
 	  Say yes here to enable GPIO support for Broadcom XGS iProc SoCs.
 
+config GPIO_BCM_VIRT
+	bool "Broadcom Virt GPIO"
+	depends on OF_GPIO && RASPBERRYPI_FIRMWARE && (ARCH_BCM2835 || COMPILE_TEST)
+	help
+	  Turn on virtual GPIO support for Broadcom BCM283X chips.
+
 config GPIO_BRCMSTB
 	tristate "BRCMSTB GPIO support"
 	default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1167 @
 	  several HTC phones.  It provides basic support for input
 	  pins, output pins, and irqs.
 
+config GPIO_FSM
+	tristate "GPIO FSM support"
+	help
+	  The GPIO FSM driver allows the creation of state machines for
+	  manipulating GPIOs (both real and virtual), with state transitions
+	  triggered by GPIO edges or delays.
+
+	  If unsure, say N.
+
 config GPIO_JANZ_TTL
 	tristate "Janz VMOD-TTL Digital IO Module"
 	depends on MFD_JANZ_CMODIO
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpio/Makefile linux-5.10.52-v7l+/drivers/gpio/Makefile
--- linux-5.10.52-orig/drivers/gpio/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpio/Makefile	2021-07-25 16:45:47.058607880 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:41 @
 obj-$(CONFIG_GPIO_ATH79)		+= gpio-ath79.o
 obj-$(CONFIG_GPIO_BCM_KONA)		+= gpio-bcm-kona.o
 obj-$(CONFIG_GPIO_BCM_XGS_IPROC)	+= gpio-xgs-iproc.o
+obj-$(CONFIG_GPIO_BCM_VIRT)		+= gpio-bcm-virt.o
 obj-$(CONFIG_GPIO_BD70528)		+= gpio-bd70528.o
 obj-$(CONFIG_GPIO_BD71828)		+= gpio-bd71828.o
 obj-$(CONFIG_GPIO_BD9571MWV)		+= gpio-bd9571mwv.o
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:63 @
 obj-$(CONFIG_GPIO_EXAR)			+= gpio-exar.o
 obj-$(CONFIG_GPIO_F7188X)		+= gpio-f7188x.o
 obj-$(CONFIG_GPIO_FTGPIO010)		+= gpio-ftgpio010.o
+obj-$(CONFIG_GPIO_FSM)			+= gpio-fsm.o
 obj-$(CONFIG_GPIO_GE_FPGA)		+= gpio-ge.o
 obj-$(CONFIG_GPIO_GPIO_MM)		+= gpio-gpio-mm.o
 obj-$(CONFIG_GPIO_GRGPIO)		+= gpio-grgpio.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c linux-5.10.52-v7l+/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
--- linux-5.10.52-orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c	2021-07-25 16:45:48.548582900 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4991 @
 static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
 	.reset = dm_crtc_reset_state,
 	.destroy = amdgpu_dm_crtc_destroy,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 	.set_config = drm_atomic_helper_set_config,
 	.page_flip = drm_atomic_helper_page_flip,
 	.atomic_duplicate_state = dm_crtc_duplicate_state,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5474 @
 	return 0;
 }
 
-static bool
-is_hdr_metadata_different(const struct drm_connector_state *old_state,
-			  const struct drm_connector_state *new_state)
-{
-	struct drm_property_blob *old_blob = old_state->hdr_output_metadata;
-	struct drm_property_blob *new_blob = new_state->hdr_output_metadata;
-
-	if (old_blob != new_blob) {
-		if (old_blob && new_blob &&
-		    old_blob->length == new_blob->length)
-			return memcmp(old_blob->data, new_blob->data,
-				      old_blob->length);
-
-		return true;
-	}
-
-	return false;
-}
-
 static int
 amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
 				 struct drm_atomic_state *state)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5489 @
 	if (!crtc)
 		return 0;
 
-	if (is_hdr_metadata_different(old_con_state, new_con_state)) {
+	if (!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state)) {
 		struct dc_info_packet hdr_infopacket;
 
 		ret = fill_hdr_info_packet(new_con_state, &hdr_infopacket);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5584 @
 }
 
 static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
-				       struct drm_crtc_state *state)
+				       struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct amdgpu_device *adev = drm_to_adev(crtc->dev);
 	struct dc *dc = adev->dm.dc;
-	struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(state);
+	struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
 	int ret = -EINVAL;
 
-	dm_update_crtc_active_planes(crtc, state);
+	dm_update_crtc_active_planes(crtc, crtc_state);
 
 	if (unlikely(!dm_crtc_state->stream &&
-		     modeset_required(state, NULL, dm_crtc_state->stream))) {
+		     modeset_required(crtc_state, NULL, dm_crtc_state->stream))) {
 		WARN_ON(1);
 		return ret;
 	}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5607 @
 	 * planes are disabled, which is not supported by the hardware. And there is legacy
 	 * userspace which stops using the HW cursor altogether in response to the resulting EINVAL.
 	 */
-	if (state->enable &&
-	    !(state->plane_mask & drm_plane_mask(crtc->primary)))
+	if (crtc_state->enable &&
+	    !(crtc_state->plane_mask & drm_plane_mask(crtc->primary)))
 		return -EINVAL;
 
 	/* In some use cases, like reset, no stream is attached */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6507 @
 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
 	    connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
 	    connector_type == DRM_MODE_CONNECTOR_eDP) {
-		drm_object_attach_property(
-			&aconnector->base.base,
-			dm->ddev->mode_config.hdr_output_metadata_property, 0);
+		drm_connector_attach_hdr_output_metadata_property(&aconnector->base);
 
 		if (!aconnector->mst_port)
 			drm_connector_attach_vrr_capable_property(&aconnector->base);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c linux-5.10.52-v7l+/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
--- linux-5.10.52-orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c	2021-07-25 16:45:48.548582900 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:27 @
  */
 
 #include <linux/version.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_dp_helper.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:256 @
 
 static struct drm_encoder *
 dm_mst_atomic_best_encoder(struct drm_connector *connector,
-			   struct drm_connector_state *connector_state)
+			   struct drm_atomic_state *state)
 {
+	struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state,
+											 connector);
 	struct drm_device *dev = connector->dev;
 	struct amdgpu_device *adev = drm_to_adev(dev);
 	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(connector_state->crtc);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/arc/arcpgu_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/arc/arcpgu_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/arc/arcpgu_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/arc/arcpgu_crtc.c	2021-07-25 16:45:59.918392277 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:119 @
 }
 
 static void arc_pgu_crtc_atomic_enable(struct drm_crtc *crtc,
-				       struct drm_crtc_state *old_state)
+				       struct drm_atomic_state *state)
 {
 	struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:130 @
 }
 
 static void arc_pgu_crtc_atomic_disable(struct drm_crtc *crtc,
-					struct drm_crtc_state *old_state)
+					struct drm_atomic_state *state)
 {
 	struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc);
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c	2021-07-25 16:45:59.918392277 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:77 @
  */
 static int
 komeda_crtc_atomic_check(struct drm_crtc *crtc,
-			 struct drm_crtc_state *state)
+			 struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct komeda_crtc *kcrtc = to_kcrtc(crtc);
-	struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(state);
+	struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc_state);
 	int err;
 
-	if (drm_atomic_crtc_needs_modeset(state))
+	if (drm_atomic_crtc_needs_modeset(crtc_state))
 		komeda_crtc_update_clock_ratio(kcrtc_st);
 
-	if (state->active) {
+	if (crtc_state->active) {
 		err = komeda_build_display_data_flow(kcrtc, kcrtc_st);
 		if (err)
 			return err;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:278 @
 
 static void
 komeda_crtc_atomic_enable(struct drm_crtc *crtc,
-			  struct drm_crtc_state *old)
+			  struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state,
+								   crtc);
 	pm_runtime_get_sync(crtc->dev->dev);
 	komeda_crtc_prepare(to_kcrtc(crtc));
 	drm_crtc_vblank_on(crtc);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:326 @
 
 static void
 komeda_crtc_atomic_disable(struct drm_crtc *crtc,
-			   struct drm_crtc_state *old)
+			   struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state,
+								   crtc);
 	struct komeda_crtc *kcrtc = to_kcrtc(crtc);
 	struct komeda_crtc_state *old_st = to_kcrtc_st(old);
 	struct komeda_pipeline *master = kcrtc->master;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:388 @
 
 static void
 komeda_crtc_atomic_flush(struct drm_crtc *crtc,
-			 struct drm_crtc_state *old)
+			 struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state,
+								   crtc);
 	/* commit with modeset will be handled in enable/disable */
 	if (drm_atomic_crtc_needs_modeset(crtc->state))
 		return;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:551 @
 }
 
 static const struct drm_crtc_funcs komeda_crtc_funcs = {
-	.gamma_set		= drm_atomic_helper_legacy_gamma_set,
 	.destroy		= drm_crtc_cleanup,
 	.set_config		= drm_atomic_helper_set_config,
 	.page_flip		= drm_atomic_helper_page_flip,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/arm/hdlcd_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/arm/hdlcd_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/arm/hdlcd_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/arm/hdlcd_crtc.c	2021-07-25 16:45:59.928392109 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:171 @
 }
 
 static void hdlcd_crtc_atomic_enable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:182 @
 }
 
 static void hdlcd_crtc_atomic_disable(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_state)
+				      struct drm_atomic_state *state)
 {
 	struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:208 @
 }
 
 static void hdlcd_crtc_atomic_begin(struct drm_crtc *crtc,
-				    struct drm_crtc_state *state)
+				    struct drm_atomic_state *state)
 {
 	struct drm_pending_vblank_event *event = crtc->state->event;
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/arm/malidp_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/arm/malidp_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/arm/malidp_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/arm/malidp_crtc.c	2021-07-25 16:45:59.928392109 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:49 @
 }
 
 static void malidp_crtc_atomic_enable(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_state)
+				      struct drm_atomic_state *state)
 {
 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
 	struct malidp_hw_device *hwdev = malidp->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:73 @
 }
 
 static void malidp_crtc_atomic_disable(struct drm_crtc *crtc,
-				       struct drm_crtc_state *old_state)
+				       struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
 	struct malidp_hw_device *hwdev = malidp->dev;
 	int err;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:340 @
 }
 
 static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
-				    struct drm_crtc_state *state)
+				    struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
 	struct malidp_hw_device *hwdev = malidp->dev;
 	struct drm_plane *plane;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:378 @
 	 */
 
 	/* first count the number of rotated planes */
-	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
+	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
 		struct drm_framebuffer *fb = pstate->fb;
 
 		if ((pstate->rotation & MALIDP_ROTATED_MASK) || fb->modifier)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:394 @
 		rot_mem_free += hwdev->rotation_memory[1];
 
 	/* now validate the rotation memory requirements */
-	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
+	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
 		struct malidp_plane *mp = to_malidp_plane(plane);
 		struct malidp_plane_state *ms = to_malidp_plane_state(pstate);
 		struct drm_framebuffer *fb = pstate->fb;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:422 @
 	}
 
 	/* If only the writeback routing has changed, we don't need a modeset */
-	if (state->connectors_changed) {
+	if (crtc_state->connectors_changed) {
 		u32 old_mask = crtc->state->connector_mask;
-		u32 new_mask = state->connector_mask;
+		u32 new_mask = crtc_state->connector_mask;
 
 		if ((old_mask ^ new_mask) ==
 		    (1 << drm_connector_index(&malidp->mw_connector.base)))
-			state->connectors_changed = false;
+			crtc_state->connectors_changed = false;
 	}
 
-	ret = malidp_crtc_atomic_check_gamma(crtc, state);
-	ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state);
-	ret = ret ? ret : malidp_crtc_atomic_check_scaling(crtc, state);
+	ret = malidp_crtc_atomic_check_gamma(crtc, crtc_state);
+	ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, crtc_state);
+	ret = ret ? ret : malidp_crtc_atomic_check_scaling(crtc, crtc_state);
 
 	return ret;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:513 @
 }
 
 static const struct drm_crtc_funcs malidp_crtc_funcs = {
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 	.destroy = drm_crtc_cleanup,
 	.set_config = drm_atomic_helper_set_config,
 	.page_flip = drm_atomic_helper_page_flip,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/armada/armada_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/armada/armada_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/armada/armada_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/armada/armada_crtc.c	2021-07-25 16:45:59.928392109 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:416 @
 }
 
 static int armada_drm_crtc_atomic_check(struct drm_crtc *crtc,
-					struct drm_crtc_state *state)
+					struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
 
-	if (state->gamma_lut && drm_color_lut_size(state->gamma_lut) != 256)
+	if (crtc_state->gamma_lut && drm_color_lut_size(crtc_state->gamma_lut) != 256)
 		return -EINVAL;
 
-	if (state->color_mgmt_changed)
-		state->planes_changed = true;
+	if (crtc_state->color_mgmt_changed)
+		crtc_state->planes_changed = true;
 
 	return 0;
 }
 
 static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,
-					 struct drm_crtc_state *old_crtc_state)
+					 struct drm_atomic_state *state)
 {
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:446 @
 }
 
 static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc,
-					 struct drm_crtc_state *old_crtc_state)
+					 struct drm_atomic_state *state)
 {
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:472 @
 }
 
 static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc,
-					   struct drm_crtc_state *old_state)
+					   struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
 	struct drm_pending_vblank_event *event;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:510 @
 }
 
 static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc,
-					  struct drm_crtc_state *old_state)
+					  struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
 
 	DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:819 @
 	.cursor_set	= armada_drm_crtc_cursor_set,
 	.cursor_move	= armada_drm_crtc_cursor_move,
 	.destroy	= armada_drm_crtc_destroy,
-	.gamma_set	= drm_atomic_helper_legacy_gamma_set,
 	.set_config	= drm_atomic_helper_set_config,
 	.page_flip	= drm_atomic_helper_page_flip,
 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/ast/ast_mode.c linux-5.10.52-v7l+/drivers/gpu/drm/ast/ast_mode.c
--- linux-5.10.52-orig/drivers/gpu/drm/ast/ast_mode.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/ast/ast_mode.c	2021-07-25 16:45:59.938391942 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:754 @
 }
 
 static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
-					struct drm_crtc_state *state)
+					struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct drm_device *dev = crtc->dev;
 	struct ast_crtc_state *ast_state;
 	const struct drm_format_info *format;
 	bool succ;
 
-	if (!state->enable)
+	if (!crtc_state->enable)
 		return 0; /* no mode checks if CRTC is being disabled */
 
-	ast_state = to_ast_crtc_state(state);
+	ast_state = to_ast_crtc_state(crtc_state);
 
 	format = ast_state->format;
 	if (drm_WARN_ON_ONCE(dev, !format))
 		return -EINVAL; /* BUG: We didn't set format in primary check(). */
 
-	succ = ast_get_vbios_mode_info(format, &state->mode,
-				       &state->adjusted_mode,
+	succ = ast_get_vbios_mode_info(format, &crtc_state->mode,
+				       &crtc_state->adjusted_mode,
 				       &ast_state->vbios_mode_info);
 	if (!succ)
 		return -EINVAL;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:798 @
 
 static void
 ast_crtc_helper_atomic_enable(struct drm_crtc *crtc,
-			      struct drm_crtc_state *old_crtc_state)
+			      struct drm_atomic_state *state)
 {
 	struct drm_device *dev = crtc->dev;
 	struct ast_private *ast = to_ast_private(dev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:821 @
 
 static void
 ast_crtc_helper_atomic_disable(struct drm_crtc *crtc,
-			       struct drm_crtc_state *old_crtc_state)
+			       struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct drm_device *dev = crtc->dev;
 	struct ast_private *ast = to_ast_private(dev);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:901 @
 
 static const struct drm_crtc_funcs ast_crtc_funcs = {
 	.reset = ast_crtc_reset,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 	.destroy = drm_crtc_cleanup,
 	.set_config = drm_atomic_helper_set_config,
 	.page_flip = drm_atomic_helper_page_flip,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c	2021-07-25 16:45:59.938391942 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:168 @
 }
 
 static void atmel_hlcdc_crtc_atomic_disable(struct drm_crtc *c,
-					    struct drm_crtc_state *old_state)
+					    struct drm_atomic_state *state)
 {
 	struct drm_device *dev = c->dev;
 	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:203 @
 }
 
 static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
-					   struct drm_crtc_state *old_state)
+					   struct drm_atomic_state *state)
 {
 	struct drm_device *dev = c->dev;
 	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:328 @
 }
 
 static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
-					 struct drm_crtc_state *s)
+					 struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *s = drm_atomic_get_new_crtc_state(state, c);
 	int ret;
 
 	ret = atmel_hlcdc_crtc_select_output_mode(s);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:345 @
 }
 
 static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c,
-					  struct drm_crtc_state *old_s)
+					  struct drm_atomic_state *state)
 {
 	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:360 @
 }
 
 static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc,
-					  struct drm_crtc_state *old_s)
+					  struct drm_atomic_state *state)
 {
 	/* TODO: write common plane control register if available */
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:476 @
 	.atomic_destroy_state = atmel_hlcdc_crtc_destroy_state,
 	.enable_vblank = atmel_hlcdc_crtc_enable_vblank,
 	.disable_vblank = atmel_hlcdc_crtc_disable_vblank,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 };
 
 int atmel_hlcdc_crtc_create(struct drm_device *dev)
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c linux-5.10.52-v7l+/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
--- linux-5.10.52-orig/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c	2021-07-25 16:45:59.958391607 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2398 @
 	return ret;
 }
 
-static bool hdr_metadata_equal(const struct drm_connector_state *old_state,
-			       const struct drm_connector_state *new_state)
-{
-	struct drm_property_blob *old_blob = old_state->hdr_output_metadata;
-	struct drm_property_blob *new_blob = new_state->hdr_output_metadata;
-
-	if (!old_blob || !new_blob)
-		return old_blob == new_blob;
-
-	if (old_blob->length != new_blob->length)
-		return false;
-
-	return !memcmp(old_blob->data, new_blob->data, old_blob->length);
-}
-
 static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
 					  struct drm_atomic_state *state)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2411 @
 	if (!crtc)
 		return 0;
 
-	if (!hdr_metadata_equal(old_state, new_state)) {
+	if (!drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) {
 		crtc_state = drm_atomic_get_crtc_state(state, crtc);
 		if (IS_ERR(crtc_state))
 			return PTR_ERR(crtc_state);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2480 @
 	drm_connector_attach_max_bpc_property(connector, 8, 16);
 
 	if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe)
-		drm_object_attach_property(&connector->base,
-			connector->dev->mode_config.hdr_output_metadata_property, 0);
+		drm_connector_attach_hdr_output_metadata_property(connector);
 
 	drm_connector_attach_encoder(connector, hdmi->bridge.encoder);
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/drm_atomic_helper.c linux-5.10.52-v7l+/drivers/gpu/drm/drm_atomic_helper.c
--- linux-5.10.52-orig/drivers/gpu/drm/drm_atomic_helper.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/drm_atomic_helper.c	2021-07-25 16:45:59.968391439 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:125 @
 			continue;
 
 		if (funcs->atomic_best_encoder)
-			new_encoder = funcs->atomic_best_encoder(connector, new_conn_state);
+			new_encoder = funcs->atomic_best_encoder(connector,
+								 state);
 		else if (funcs->best_encoder)
 			new_encoder = funcs->best_encoder(connector);
 		else
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:349 @
 	funcs = connector->helper_private;
 
 	if (funcs->atomic_best_encoder)
-		new_encoder = funcs->atomic_best_encoder(connector,
-							 new_connector_state);
+		new_encoder = funcs->atomic_best_encoder(connector, state);
 	else if (funcs->best_encoder)
 		new_encoder = funcs->best_encoder(connector);
 	else
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:433 @
 		new_crtc_state =
 			drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
 
+		if (!new_crtc_state->mode_changed &&
+		    !new_crtc_state->connectors_changed) {
+			continue;
+		}
+
 		/*
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call ->mode_fixup twice.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:926 @
 		if (!funcs || !funcs->atomic_check)
 			continue;
 
-		ret = funcs->atomic_check(crtc, new_crtc_state);
+		ret = funcs->atomic_check(crtc, state);
 		if (ret) {
 			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic driver check failed\n",
 					 crtc->base.id, crtc->name);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1101 @
 		if (new_crtc_state->enable && funcs->prepare)
 			funcs->prepare(crtc);
 		else if (funcs->atomic_disable)
-			funcs->atomic_disable(crtc, old_crtc_state);
+			funcs->atomic_disable(crtc, old_state);
 		else if (funcs->disable)
 			funcs->disable(crtc);
 		else if (funcs->dpms)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1321 @
 
 		if (new_conn_state->writeback_job && new_conn_state->writeback_job->fb) {
 			WARN_ON(connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK);
-			funcs->atomic_commit(connector, new_conn_state);
+			funcs->atomic_commit(connector, old_state);
 		}
 	}
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1366 @
 			DRM_DEBUG_ATOMIC("enabling [CRTC:%d:%s]\n",
 					 crtc->base.id, crtc->name);
 			if (funcs->atomic_enable)
-				funcs->atomic_enable(crtc, old_crtc_state);
+				funcs->atomic_enable(crtc, old_state);
 			else if (funcs->commit)
 				funcs->commit(crtc);
 		}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2042 @
  * should always call this function from their
  * &drm_mode_config_funcs.atomic_commit hook.
  *
+ * Drivers that need to extend the commit setup to private objects can use the
+ * &drm_mode_config_helper_funcs.atomic_commit_setup hook.
+ *
  * To be able to use this support drivers need to use a few more helper
  * functions. drm_atomic_helper_wait_for_dependencies() must be called before
  * actually committing the hardware state, and for nonblocking commits this call
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2088 @
 	struct drm_plane *plane;
 	struct drm_plane_state *old_plane_state, *new_plane_state;
 	struct drm_crtc_commit *commit;
+	const struct drm_mode_config_helper_funcs *funcs;
 	int i, ret;
 
+	funcs = state->dev->mode_config.helper_private;
+
 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
 		commit = kzalloc(sizeof(*commit), GFP_KERNEL);
 		if (!commit)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2169 @
 		new_plane_state->commit = drm_crtc_commit_get(commit);
 	}
 
+	if (funcs && funcs->atomic_commit_setup)
+		return funcs->atomic_commit_setup(state);
+
 	return 0;
 }
 EXPORT_SYMBOL(drm_atomic_helper_setup_commit);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2524 @
 		if (active_only && !new_crtc_state->active)
 			continue;
 
-		funcs->atomic_begin(crtc, old_crtc_state);
+		funcs->atomic_begin(crtc, old_state);
 	}
 
 	for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2582 @
 		if (active_only && !new_crtc_state->active)
 			continue;
 
-		funcs->atomic_flush(crtc, old_crtc_state);
+		funcs->atomic_flush(crtc, old_state);
 	}
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2620 @
 
 	crtc_funcs = crtc->helper_private;
 	if (crtc_funcs && crtc_funcs->atomic_begin)
-		crtc_funcs->atomic_begin(crtc, old_crtc_state);
+		crtc_funcs->atomic_begin(crtc, old_state);
 
 	drm_for_each_plane_mask(plane, crtc->dev, plane_mask) {
 		struct drm_plane_state *old_plane_state =
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2646 @
 	}
 
 	if (crtc_funcs && crtc_funcs->atomic_flush)
-		crtc_funcs->atomic_flush(crtc, old_crtc_state);
+		crtc_funcs->atomic_flush(crtc, old_state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3503 @
 EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
 
 /**
- * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
- * @crtc: CRTC object
- * @red: red correction table
- * @green: green correction table
- * @blue: green correction table
- * @size: size of the tables
- * @ctx: lock acquire context
- *
- * Implements support for legacy gamma correction table for drivers
- * that support color management through the DEGAMMA_LUT/GAMMA_LUT
- * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for
- * how the atomic color management and gamma tables work.
- */
-int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
-				       u16 *red, u16 *green, u16 *blue,
-				       uint32_t size,
-				       struct drm_modeset_acquire_ctx *ctx)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_atomic_state *state;
-	struct drm_crtc_state *crtc_state;
-	struct drm_property_blob *blob = NULL;
-	struct drm_color_lut *blob_data;
-	int i, ret = 0;
-	bool replaced;
-
-	state = drm_atomic_state_alloc(crtc->dev);
-	if (!state)
-		return -ENOMEM;
-
-	blob = drm_property_create_blob(dev,
-					sizeof(struct drm_color_lut) * size,
-					NULL);
-	if (IS_ERR(blob)) {
-		ret = PTR_ERR(blob);
-		blob = NULL;
-		goto fail;
-	}
-
-	/* Prepare GAMMA_LUT with the legacy values. */
-	blob_data = blob->data;
-	for (i = 0; i < size; i++) {
-		blob_data[i].red = red[i];
-		blob_data[i].green = green[i];
-		blob_data[i].blue = blue[i];
-	}
-
-	state->acquire_ctx = ctx;
-	crtc_state = drm_atomic_get_crtc_state(state, crtc);
-	if (IS_ERR(crtc_state)) {
-		ret = PTR_ERR(crtc_state);
-		goto fail;
-	}
-
-	/* Reset DEGAMMA_LUT and CTM properties. */
-	replaced  = drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
-	replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
-	replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob);
-	crtc_state->color_mgmt_changed |= replaced;
-
-	ret = drm_atomic_commit(state);
-
-fail:
-	drm_atomic_state_put(state);
-	drm_property_blob_put(blob);
-	return ret;
-}
-EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
-
-/**
  * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to
  *						  the input end of a bridge
  * @bridge: bridge control structure
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/drm_color_mgmt.c linux-5.10.52-v7l+/drivers/gpu/drm/drm_color_mgmt.c
--- linux-5.10.52-orig/drivers/gpu/drm/drm_color_mgmt.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/drm_color_mgmt.c	2021-07-25 16:45:59.978391271 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:25 @
 
 #include <linux/uaccess.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_color_mgmt.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:93 @
  *	modes) appropriately.
  *
  * There is also support for a legacy gamma table, which is set up by calling
- * drm_mode_crtc_set_gamma_size(). Drivers which support both should use
- * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the
- * "GAMMA_LUT" property above.
+ * drm_mode_crtc_set_gamma_size(). The DRM core will then alias the legacy gamma
+ * ramp with "GAMMA_LUT".
  *
  * Support for different non RGB color encodings is controlled through
  * &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:159 @
  * optional. The gamma and degamma properties are only attached if
  * their size is not 0 and ctm_property is only attached if has_ctm is
  * true.
- *
- * Drivers should use drm_atomic_helper_legacy_gamma_set() to implement the
- * legacy &drm_crtc_funcs.gamma_set callback.
  */
 void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
 				uint degamma_lut_size,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:232 @
 EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
 
 /**
+ * drm_crtc_supports_legacy_gamma - does the crtc support legacy gamma correction table
+ * @crtc: CRTC object
+ *
+ * Returns true/false if the given crtc supports setting the legacy gamma
+ * correction table.
+ */
+static bool drm_crtc_supports_legacy_gamma(struct drm_crtc *crtc)
+{
+	u32 gamma_id = crtc->dev->mode_config.gamma_lut_property->base.id;
+
+	if (!crtc->gamma_size)
+		return false;
+
+	if (crtc->funcs->gamma_set)
+		return true;
+
+	return !!drm_mode_obj_find_prop_id(&crtc->base, gamma_id);
+}
+
+/**
+ * drm_crtc_legacy_gamma_set - set the legacy gamma correction table
+ * @crtc: CRTC object
+ * @red: red correction table
+ * @green: green correction table
+ * @blue: green correction table
+ * @size: size of the tables
+ * @ctx: lock acquire context
+ *
+ * Implements support for legacy gamma correction table for drivers
+ * that have set drm_crtc_funcs.gamma_set or that support color management
+ * through the DEGAMMA_LUT/GAMMA_LUT properties. See
+ * drm_crtc_enable_color_mgmt() and the containing chapter for
+ * how the atomic color management and gamma tables work.
+ *
+ * This function sets the gamma using drm_crtc_funcs.gamma_set if set, or
+ * alternatively using crtc color management properties.
+ */
+static int drm_crtc_legacy_gamma_set(struct drm_crtc *crtc,
+				     u16 *red, u16 *green, u16 *blue,
+				     u32 size,
+				     struct drm_modeset_acquire_ctx *ctx)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_atomic_state *state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_property_blob *blob;
+	struct drm_color_lut *blob_data;
+	int i, ret = 0;
+	bool replaced;
+
+	if (crtc->funcs->gamma_set)
+		return crtc->funcs->gamma_set(crtc, red, green, blue, size, ctx);
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state)
+		return -ENOMEM;
+
+	blob = drm_property_create_blob(dev,
+					sizeof(struct drm_color_lut) * size,
+					NULL);
+	if (IS_ERR(blob)) {
+		ret = PTR_ERR(blob);
+		blob = NULL;
+		goto fail;
+	}
+
+	/* Prepare GAMMA_LUT with the legacy values. */
+	blob_data = blob->data;
+	for (i = 0; i < size; i++) {
+		blob_data[i].red = red[i];
+		blob_data[i].green = green[i];
+		blob_data[i].blue = blue[i];
+	}
+
+	state->acquire_ctx = ctx;
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		goto fail;
+	}
+
+	/* Set GAMMA_LUT and reset DEGAMMA_LUT and CTM */
+	replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
+	replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
+	replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob);
+	crtc_state->color_mgmt_changed |= replaced;
+
+	ret = drm_atomic_commit(state);
+
+fail:
+	drm_atomic_state_put(state);
+	drm_property_blob_put(blob);
+	return ret;
+}
+
+/**
  * drm_mode_gamma_set_ioctl - set the gamma table
  * @dev: DRM device
  * @data: ioctl data
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:358 @
 	if (!crtc)
 		return -ENOENT;
 
-	if (crtc->funcs->gamma_set == NULL)
+	if (!drm_crtc_supports_legacy_gamma(crtc))
 		return -ENOSYS;
 
 	/* memcpy into gamma store */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:386 @
 		goto out;
 	}
 
-	ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
-				     crtc->gamma_size, &ctx);
+	ret = drm_crtc_legacy_gamma_set(crtc, r_base, g_base, b_base,
+					crtc->gamma_size, &ctx);
 
 out:
 	DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/drm_connector.c linux-5.10.52-v7l+/drivers/gpu/drm/drm_connector.c
--- linux-5.10.52-orig/drivers/gpu/drm/drm_connector.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/drm_connector.c	2021-07-25 16:45:59.978391271 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:97 @
 	{ DRM_MODE_CONNECTOR_DPI, "DPI" },
 	{ DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" },
 	{ DRM_MODE_CONNECTOR_SPI, "SPI" },
+	{ DRM_MODE_CONNECTOR_USB, "USB" },
 };
 
 void drm_connector_ida_init(void)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2148 @
 EXPORT_SYMBOL(drm_connector_attach_max_bpc_property);
 
 /**
+ * drm_connector_attach_hdr_output_metadata_property - attach "HDR_OUTPUT_METADA" property
+ * @connector: connector to attach the property on.
+ *
+ * This is used to allow the userspace to send HDR Metadata to the
+ * driver.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_property *prop = dev->mode_config.hdr_output_metadata_property;
+
+	drm_object_attach_property(&connector->base, prop, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_hdr_output_metadata_property);
+
+/**
+ * drm_connector_attach_colorspace_property - attach "Colorspace" property
+ * @connector: connector to attach the property on.
+ *
+ * This is used to allow the userspace to signal the output colorspace
+ * to the driver.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_connector_attach_colorspace_property(struct drm_connector *connector)
+{
+	struct drm_property *prop = connector->colorspace_property;
+
+	drm_object_attach_property(&connector->base, prop, DRM_MODE_COLORIMETRY_DEFAULT);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
+
+/**
+ * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
+ * @old_state: old connector state to compare
+ * @new_state: new connector state to compare
+ *
+ * This is used by HDR-enabled drivers to test whether the HDR metadata
+ * have changed between two different connector state (and thus probably
+ * requires a full blown mode change).
+ *
+ * Returns:
+ * True if the metadata are equal, False otherwise
+ */
+bool drm_connector_atomic_hdr_metadata_equal(struct drm_connector_state *old_state,
+					     struct drm_connector_state *new_state)
+{
+	struct drm_property_blob *old_blob = old_state->hdr_output_metadata;
+	struct drm_property_blob *new_blob = new_state->hdr_output_metadata;
+
+	if (!old_blob || !new_blob)
+		return old_blob == new_blob;
+
+	if (old_blob->length != new_blob->length)
+		return false;
+
+	return !memcmp(old_blob->data, new_blob->data, old_blob->length);
+}
+EXPORT_SYMBOL(drm_connector_atomic_hdr_metadata_equal);
+
+/**
  * drm_connector_set_vrr_capable_property - sets the variable refresh rate
  * capable property for a connector
  * @connector: drm connector
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/drm_fourcc.c linux-5.10.52-v7l+/drivers/gpu/drm/drm_fourcc.c
--- linux-5.10.52-orig/drivers/gpu/drm/drm_fourcc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/drm_fourcc.c	2021-07-25 16:45:59.998390936 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:289 @
 		  .num_planes = 3, .char_per_block = { 2, 2, 2 },
 		  .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
 		  .vsub = 0, .is_yuv = true },
+		{ .format = DRM_FORMAT_P030,            .depth = 0,  .num_planes = 2,
+		  .char_per_block = { 4, 4, 0 }, .block_w = { 3, 0, 0 }, .block_h = { 1, 0, 0 },
+		  .hsub = 2, .vsub = 2, .is_yuv = true},
 	};
 
 	unsigned int i;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/drm_framebuffer.c linux-5.10.52-v7l+/drivers/gpu/drm/drm_framebuffer.c
--- linux-5.10.52-orig/drivers/gpu/drm/drm_framebuffer.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/drm_framebuffer.c	2021-07-25 16:45:59.998390936 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:220 @
 		if (min_pitch > UINT_MAX)
 			return -ERANGE;
 
-		if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
-			return -ERANGE;
+		if (r->modifier[i] == DRM_FORMAT_MOD_LINEAR) {
+			if ((uint64_t)height * r->pitches[i] + r->offsets[i] >
+								UINT_MAX)
+				return -ERANGE;
 
-		if (block_size && r->pitches[i] < min_pitch) {
-			DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
-			return -EINVAL;
+			if (block_size && r->pitches[i] < min_pitch) {
+				DRM_DEBUG_KMS("bad pitch %u for plane %d\n",
+					      r->pitches[i], i);
+				return -EINVAL;
+			}
 		}
 
 		if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/drm_simple_kms_helper.c linux-5.10.52-v7l+/drivers/gpu/drm/drm_simple_kms_helper.c
--- linux-5.10.52-orig/drivers/gpu/drm/drm_simple_kms_helper.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/drm_simple_kms_helper.c	2021-07-25 16:46:00.008390768 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:89 @
 }
 
 static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
-				     struct drm_crtc_state *state)
+				     struct drm_atomic_state *state)
 {
-	bool has_primary = state->plane_mask &
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+	bool has_primary = crtc_state->plane_mask &
 			   drm_plane_mask(crtc->primary);
 
 	/* We always want to have an active plane with an active CRTC */
-	if (has_primary != state->enable)
+	if (has_primary != crtc_state->enable)
 		return -EINVAL;
 
-	return drm_atomic_add_affected_planes(state->state, crtc);
+	return drm_atomic_add_affected_planes(state, crtc);
 }
 
 static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
-				       struct drm_crtc_state *old_state)
+				       struct drm_atomic_state *state)
 {
 	struct drm_plane *plane;
 	struct drm_simple_display_pipe *pipe;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:118 @
 }
 
 static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
-					struct drm_crtc_state *old_state)
+					struct drm_atomic_state *state)
 {
 	struct drm_simple_display_pipe *pipe;
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/exynos/exynos_drm_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/exynos/exynos_drm_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/exynos/exynos_drm_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/exynos/exynos_drm_crtc.c	2021-07-25 16:46:00.028390433 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:22 @
 #include "exynos_drm_plane.h"
 
 static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc,
-					  struct drm_crtc_state *old_state)
+					  struct drm_atomic_state *state)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:33 @
 }
 
 static void exynos_drm_crtc_atomic_disable(struct drm_crtc *crtc,
-					   struct drm_crtc_state *old_state)
+					   struct drm_atomic_state *state)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:52 @
 }
 
 static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
-				     struct drm_crtc_state *state)
+				     struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
-	if (!state->enable)
+	if (!crtc_state->enable)
 		return 0;
 
 	if (exynos_crtc->ops->atomic_check)
-		return exynos_crtc->ops->atomic_check(exynos_crtc, state);
+		return exynos_crtc->ops->atomic_check(exynos_crtc, crtc_state);
 
 	return 0;
 }
 
 static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_crtc_state)
+				     struct drm_atomic_state *state)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:77 @
 }
 
 static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_crtc_state)
+				     struct drm_atomic_state *state)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c	2021-07-25 16:46:00.048390098 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:24 @
 #include "fsl_dcu_drm_plane.h"
 
 static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc,
-					  struct drm_crtc_state *old_crtc_state)
+					  struct drm_atomic_state *state)
 {
 	struct drm_device *dev = crtc->dev;
 	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:46 @
 }
 
 static void fsl_dcu_drm_crtc_atomic_disable(struct drm_crtc *crtc,
-					struct drm_crtc_state *old_crtc_state)
+					struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct drm_device *dev = crtc->dev;
 	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:67 @
 }
 
 static void fsl_dcu_drm_crtc_atomic_enable(struct drm_crtc *crtc,
-					   struct drm_crtc_state *old_state)
+					   struct drm_atomic_state *state)
 {
 	struct drm_device *dev = crtc->dev;
 	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/gud/gud_connector.c linux-5.10.52-v7l+/drivers/gpu/drm/gud/gud_connector.c
--- linux-5.10.52-orig/drivers/gpu/drm/gud/gud_connector.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpu/drm/gud/gud_connector.c	2021-07-25 16:46:00.078389595 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2020 Noralf Trønnes
+ */
+
+#include <linux/backlight.h>
+#include <linux/workqueue.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_file.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <drm/gud.h>
+
+#include "gud_internal.h"
+
+struct gud_connector {
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct backlight_device *backlight;
+	struct work_struct backlight_work;
+
+	/* Supported properties */
+	u16 *properties;
+	unsigned int num_properties;
+
+	/* Initial gadget tv state if applicable, applied on state reset */
+	struct drm_tv_connector_state initial_tv_state;
+
+	/*
+	 * Initial gadget backlight brightness if applicable, applied on state reset.
+	 * The value -ENODEV is used to signal no backlight.
+	 */
+	int initial_brightness;
+};
+
+static inline struct gud_connector *to_gud_connector(struct drm_connector *connector)
+{
+	return container_of(connector, struct gud_connector, connector);
+}
+
+static void gud_conn_err(struct drm_connector *connector, const char *msg, int ret)
+{
+	dev_err(connector->dev->dev, "%s: %s (ret=%d)\n", connector->name, msg, ret);
+}
+
+/*
+ * Use a worker to avoid taking kms locks inside the backlight lock.
+ * Other display drivers use backlight within their kms locks.
+ * This avoids inconsistent locking rules, which would upset lockdep.
+ */
+static void gud_connector_backlight_update_status_work(struct work_struct *work)
+{
+	struct gud_connector *gconn = container_of(work, struct gud_connector, backlight_work);
+	struct drm_connector *connector = &gconn->connector;
+	struct drm_connector_state *connector_state;
+	struct drm_device *drm = connector->dev;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_atomic_state *state;
+	int idx, ret;
+
+	if (!drm_dev_enter(drm, &idx))
+		return;
+
+	state = drm_atomic_state_alloc(drm);
+	if (!state) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	drm_modeset_acquire_init(&ctx, 0);
+	state->acquire_ctx = &ctx;
+retry:
+	connector_state = drm_atomic_get_connector_state(state, connector);
+	if (IS_ERR(connector_state)) {
+		ret = PTR_ERR(connector_state);
+		goto out;
+	}
+
+	/* Reuse tv.brightness to avoid having to subclass */
+	connector_state->tv.brightness = gconn->backlight->props.brightness;
+
+	ret = drm_atomic_commit(state);
+out:
+	if (ret == -EDEADLK) {
+		drm_atomic_state_clear(state);
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+
+	drm_atomic_state_put(state);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+exit:
+	drm_dev_exit(idx);
+
+	if (ret)
+		dev_err(drm->dev, "Failed to update backlight, err=%d\n", ret);
+}
+
+static int gud_connector_backlight_update_status(struct backlight_device *bd)
+{
+	struct drm_connector *connector = bl_get_data(bd);
+	struct gud_connector *gconn = to_gud_connector(connector);
+
+	/* The USB timeout is 5 seconds so use system_long_wq for worst case scenario */
+	queue_work(system_long_wq, &gconn->backlight_work);
+
+	return 0;
+}
+
+static const struct backlight_ops gud_connector_backlight_ops = {
+	.update_status	= gud_connector_backlight_update_status,
+};
+
+static int gud_connector_backlight_register(struct gud_connector *gconn)
+{
+	struct drm_connector *connector = &gconn->connector;
+	struct backlight_device *bd;
+	const char *name;
+	const struct backlight_properties props = {
+		.type = BACKLIGHT_RAW,
+		.scale = BACKLIGHT_SCALE_NON_LINEAR,
+		.max_brightness = 100,
+		.brightness = gconn->initial_brightness,
+	};
+
+	name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
+			 connector->dev->primary->index, connector->name);
+	if (!name)
+		return -ENOMEM;
+
+	bd = backlight_device_register(name, connector->kdev, connector,
+				       &gud_connector_backlight_ops, &props);
+	kfree(name);
+	if (IS_ERR(bd))
+		return PTR_ERR(bd);
+
+	gconn->backlight = bd;
+
+	return 0;
+}
+
+static int gud_connector_detect(struct drm_connector *connector,
+				struct drm_modeset_acquire_ctx *ctx, bool force)
+{
+	struct gud_device *gdrm = to_gud_device(connector->dev);
+	int idx, ret;
+	u8 status;
+
+	if (!drm_dev_enter(connector->dev, &idx))
+		return connector_status_disconnected;
+
+	if (force) {
+		ret = gud_usb_set(gdrm, GUD_REQ_SET_CONNECTOR_FORCE_DETECT,
+				  connector->index, NULL, 0);
+		if (ret) {
+			ret = connector_status_unknown;
+			goto exit;
+		}
+	}
+
+	ret = gud_usb_get_u8(gdrm, GUD_REQ_GET_CONNECTOR_STATUS, connector->index, &status);
+	if (ret) {
+		ret = connector_status_unknown;
+		goto exit;
+	}
+
+	switch (status & GUD_CONNECTOR_STATUS_CONNECTED_MASK) {
+	case GUD_CONNECTOR_STATUS_DISCONNECTED:
+		ret = connector_status_disconnected;
+		break;
+	case GUD_CONNECTOR_STATUS_CONNECTED:
+		ret = connector_status_connected;
+		break;
+	default:
+		ret = connector_status_unknown;
+		break;
+	}
+
+	if (status & GUD_CONNECTOR_STATUS_CHANGED)
+		connector->epoch_counter += 1;
+exit:
+	drm_dev_exit(idx);
+
+	return ret;
+}
+
+struct gud_connector_get_edid_ctx {
+	void *buf;
+	size_t len;
+	bool edid_override;
+};
+
+static int gud_connector_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
+{
+	struct gud_connector_get_edid_ctx *ctx = data;
+	size_t start = block * EDID_LENGTH;
+
+	ctx->edid_override = false;
+
+	if (start + len > ctx->len)
+		return -1;
+
+	memcpy(buf, ctx->buf + start, len);
+
+	return 0;
+}
+
+static int gud_connector_get_modes(struct drm_connector *connector)
+{
+	struct gud_device *gdrm = to_gud_device(connector->dev);
+	struct gud_display_mode_req *reqmodes = NULL;
+	struct gud_connector_get_edid_ctx edid_ctx;
+	unsigned int i, num_modes = 0;
+	struct edid *edid = NULL;
+	int idx, ret;
+
+	if (!drm_dev_enter(connector->dev, &idx))
+		return 0;
+
+	edid_ctx.edid_override = true;
+	edid_ctx.buf = kmalloc(GUD_CONNECTOR_MAX_EDID_LEN, GFP_KERNEL);
+	if (!edid_ctx.buf)
+		goto out;
+
+	ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_EDID, connector->index,
+			  edid_ctx.buf, GUD_CONNECTOR_MAX_EDID_LEN);
+	if (ret > 0 && ret % EDID_LENGTH) {
+		gud_conn_err(connector, "Invalid EDID size", ret);
+	} else if (ret > 0) {
+		edid_ctx.len = ret;
+		edid = drm_do_get_edid(connector, gud_connector_get_edid_block, &edid_ctx);
+	}
+
+	kfree(edid_ctx.buf);
+	drm_connector_update_edid_property(connector, edid);
+
+	if (edid && edid_ctx.edid_override)
+		goto out;
+
+	reqmodes = kmalloc_array(GUD_CONNECTOR_MAX_NUM_MODES, sizeof(*reqmodes), GFP_KERNEL);
+	if (!reqmodes)
+		goto out;
+
+	ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_MODES, connector->index,
+			  reqmodes, GUD_CONNECTOR_MAX_NUM_MODES * sizeof(*reqmodes));
+	if (ret <= 0)
+		goto out;
+	if (ret % sizeof(*reqmodes)) {
+		gud_conn_err(connector, "Invalid display mode array size", ret);
+		goto out;
+	}
+
+	num_modes = ret / sizeof(*reqmodes);
+
+	for (i = 0; i < num_modes; i++) {
+		struct drm_display_mode *mode;
+
+		mode = drm_mode_create(connector->dev);
+		if (!mode) {
+			num_modes = i;
+			goto out;
+		}
+
+		gud_to_display_mode(mode, &reqmodes[i]);
+		drm_mode_probed_add(connector, mode);
+	}
+out:
+	if (!num_modes)
+		num_modes = drm_add_edid_modes(connector, edid);
+
+	kfree(reqmodes);
+	kfree(edid);
+	drm_dev_exit(idx);
+
+	return num_modes;
+}
+
+static int gud_connector_atomic_check(struct drm_connector *connector,
+				      struct drm_atomic_state *state)
+{
+	struct drm_connector_state *new_state;
+	struct drm_crtc_state *new_crtc_state;
+	struct drm_connector_state *old_state;
+
+	new_state = drm_atomic_get_new_connector_state(state, connector);
+	if (!new_state->crtc)
+		return 0;
+
+	old_state = drm_atomic_get_old_connector_state(state, connector);
+	new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
+
+	if (old_state->tv.margins.left != new_state->tv.margins.left ||
+	    old_state->tv.margins.right != new_state->tv.margins.right ||
+	    old_state->tv.margins.top != new_state->tv.margins.top ||
+	    old_state->tv.margins.bottom != new_state->tv.margins.bottom ||
+	    old_state->tv.mode != new_state->tv.mode ||
+	    old_state->tv.brightness != new_state->tv.brightness ||
+	    old_state->tv.contrast != new_state->tv.contrast ||
+	    old_state->tv.flicker_reduction != new_state->tv.flicker_reduction ||
+	    old_state->tv.overscan != new_state->tv.overscan ||
+	    old_state->tv.saturation != new_state->tv.saturation ||
+	    old_state->tv.hue != new_state->tv.hue)
+		new_crtc_state->connectors_changed = true;
+
+	return 0;
+}
+
+static const struct drm_connector_helper_funcs gud_connector_helper_funcs = {
+	.detect_ctx = gud_connector_detect,
+	.get_modes = gud_connector_get_modes,
+	.atomic_check = gud_connector_atomic_check,
+};
+
+static int gud_connector_late_register(struct drm_connector *connector)
+{
+	struct gud_connector *gconn = to_gud_connector(connector);
+
+	if (gconn->initial_brightness < 0)
+		return 0;
+
+	return gud_connector_backlight_register(gconn);
+}
+
+static void gud_connector_early_unregister(struct drm_connector *connector)
+{
+	struct gud_connector *gconn = to_gud_connector(connector);
+
+	backlight_device_unregister(gconn->backlight);
+	cancel_work_sync(&gconn->backlight_work);
+}
+
+static void gud_connector_destroy(struct drm_connector *connector)
+{
+	struct gud_connector *gconn = to_gud_connector(connector);
+
+	drm_connector_cleanup(connector);
+	kfree(gconn->properties);
+	kfree(gconn);
+}
+
+static void gud_connector_reset(struct drm_connector *connector)
+{
+	struct gud_connector *gconn = to_gud_connector(connector);
+
+	drm_atomic_helper_connector_reset(connector);
+	connector->state->tv = gconn->initial_tv_state;
+	/* Set margins from command line */
+	drm_atomic_helper_connector_tv_reset(connector);
+	if (gconn->initial_brightness >= 0)
+		connector->state->tv.brightness = gconn->initial_brightness;
+}
+
+static const struct drm_connector_funcs gud_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.late_register = gud_connector_late_register,
+	.early_unregister = gud_connector_early_unregister,
+	.destroy = gud_connector_destroy,
+	.reset = gud_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+/*
+ * The tv.mode property is shared among the connectors and its enum names are
+ * driver specific. This means that if more than one connector uses tv.mode,
+ * the enum names has to be the same.
+ */
+static int gud_connector_add_tv_mode(struct gud_device *gdrm, struct drm_connector *connector)
+{
+	size_t buf_len = GUD_CONNECTOR_TV_MODE_MAX_NUM * GUD_CONNECTOR_TV_MODE_NAME_LEN;
+	const char *modes[GUD_CONNECTOR_TV_MODE_MAX_NUM];
+	unsigned int i, num_modes;
+	char *buf;
+	int ret;
+
+	buf = kmalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_TV_MODE_VALUES,
+			  connector->index, buf, buf_len);
+	if (ret < 0)
+		goto free;
+	if (!ret || ret % GUD_CONNECTOR_TV_MODE_NAME_LEN) {
+		ret = -EIO;
+		goto free;
+	}
+
+	num_modes = ret / GUD_CONNECTOR_TV_MODE_NAME_LEN;
+	for (i = 0; i < num_modes; i++)
+		modes[i] = &buf[i * GUD_CONNECTOR_TV_MODE_NAME_LEN];
+
+	ret = drm_mode_create_tv_properties(connector->dev, num_modes, modes);
+free:
+	kfree(buf);
+	if (ret < 0)
+		gud_conn_err(connector, "Failed to add TV modes", ret);
+
+	return ret;
+}
+
+static struct drm_property *
+gud_connector_property_lookup(struct drm_connector *connector, u16 prop)
+{
+	struct drm_mode_config *config = &connector->dev->mode_config;
+
+	switch (prop) {
+	case GUD_PROPERTY_TV_LEFT_MARGIN:
+		return config->tv_left_margin_property;
+	case GUD_PROPERTY_TV_RIGHT_MARGIN:
+		return config->tv_right_margin_property;
+	case GUD_PROPERTY_TV_TOP_MARGIN:
+		return config->tv_top_margin_property;
+	case GUD_PROPERTY_TV_BOTTOM_MARGIN:
+		return config->tv_bottom_margin_property;
+	case GUD_PROPERTY_TV_MODE:
+		return config->tv_mode_property;
+	case GUD_PROPERTY_TV_BRIGHTNESS:
+		return config->tv_brightness_property;
+	case GUD_PROPERTY_TV_CONTRAST:
+		return config->tv_contrast_property;
+	case GUD_PROPERTY_TV_FLICKER_REDUCTION:
+		return config->tv_flicker_reduction_property;
+	case GUD_PROPERTY_TV_OVERSCAN:
+		return config->tv_overscan_property;
+	case GUD_PROPERTY_TV_SATURATION:
+		return config->tv_saturation_property;
+	case GUD_PROPERTY_TV_HUE:
+		return config->tv_hue_property;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+static unsigned int *gud_connector_tv_state_val(u16 prop, struct drm_tv_connector_state *state)
+{
+	switch (prop) {
+	case GUD_PROPERTY_TV_LEFT_MARGIN:
+		return &state->margins.left;
+	case GUD_PROPERTY_TV_RIGHT_MARGIN:
+		return &state->margins.right;
+	case GUD_PROPERTY_TV_TOP_MARGIN:
+		return &state->margins.top;
+	case GUD_PROPERTY_TV_BOTTOM_MARGIN:
+		return &state->margins.bottom;
+	case GUD_PROPERTY_TV_MODE:
+		return &state->mode;
+	case GUD_PROPERTY_TV_BRIGHTNESS:
+		return &state->brightness;
+	case GUD_PROPERTY_TV_CONTRAST:
+		return &state->contrast;
+	case GUD_PROPERTY_TV_FLICKER_REDUCTION:
+		return &state->flicker_reduction;
+	case GUD_PROPERTY_TV_OVERSCAN:
+		return &state->overscan;
+	case GUD_PROPERTY_TV_SATURATION:
+		return &state->saturation;
+	case GUD_PROPERTY_TV_HUE:
+		return &state->hue;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_connector *gconn)
+{
+	struct drm_connector *connector = &gconn->connector;
+	struct drm_device *drm = &gdrm->drm;
+	struct gud_property_req *properties;
+	unsigned int i, num_properties;
+	int ret;
+
+	properties = kcalloc(GUD_CONNECTOR_PROPERTIES_MAX_NUM, sizeof(*properties), GFP_KERNEL);
+	if (!properties)
+		return -ENOMEM;
+
+	ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_PROPERTIES, connector->index,
+			  properties, GUD_CONNECTOR_PROPERTIES_MAX_NUM * sizeof(*properties));
+	if (ret <= 0)
+		goto out;
+	if (ret % sizeof(*properties)) {
+		ret = -EIO;
+		goto out;
+	}
+
+	num_properties = ret / sizeof(*properties);
+	ret = 0;
+
+	gconn->properties = kcalloc(num_properties, sizeof(*gconn->properties), GFP_KERNEL);
+	if (!gconn->properties) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < num_properties; i++) {
+		u16 prop = le16_to_cpu(properties[i].prop);
+		u64 val = le64_to_cpu(properties[i].val);
+		struct drm_property *property;
+		unsigned int *state_val;
+
+		drm_dbg(drm, "property: %u = %llu(0x%llx)\n", prop, val, val);
+
+		switch (prop) {
+		case GUD_PROPERTY_TV_LEFT_MARGIN:
+			fallthrough;
+		case GUD_PROPERTY_TV_RIGHT_MARGIN:
+			fallthrough;
+		case GUD_PROPERTY_TV_TOP_MARGIN:
+			fallthrough;
+		case GUD_PROPERTY_TV_BOTTOM_MARGIN:
+			ret = drm_mode_create_tv_margin_properties(drm);
+			if (ret)
+				goto out;
+			break;
+		case GUD_PROPERTY_TV_MODE:
+			ret = gud_connector_add_tv_mode(gdrm, connector);
+			if (ret)
+				goto out;
+			break;
+		case GUD_PROPERTY_TV_BRIGHTNESS:
+			fallthrough;
+		case GUD_PROPERTY_TV_CONTRAST:
+			fallthrough;
+		case GUD_PROPERTY_TV_FLICKER_REDUCTION:
+			fallthrough;
+		case GUD_PROPERTY_TV_OVERSCAN:
+			fallthrough;
+		case GUD_PROPERTY_TV_SATURATION:
+			fallthrough;
+		case GUD_PROPERTY_TV_HUE:
+			/* This is a no-op if already added. */
+			ret = drm_mode_create_tv_properties(drm, 0, NULL);
+			if (ret)
+				goto out;
+			break;
+		case GUD_PROPERTY_BACKLIGHT_BRIGHTNESS:
+			if (val > 100) {
+				ret = -EINVAL;
+				goto out;
+			}
+			gconn->initial_brightness = val;
+			break;
+		default:
+			/* New ones might show up in future devices, skip those we don't know. */
+			drm_dbg(drm, "Ignoring unknown property: %u\n", prop);
+			continue;
+		}
+
+		gconn->properties[gconn->num_properties++] = prop;
+
+		if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS)
+			continue; /* not a DRM property */
+
+		property = gud_connector_property_lookup(connector, prop);
+		if (WARN_ON(IS_ERR(property)))
+			continue;
+
+		state_val = gud_connector_tv_state_val(prop, &gconn->initial_tv_state);
+		if (WARN_ON(IS_ERR(state_val)))
+			continue;
+
+		*state_val = val;
+		drm_object_attach_property(&connector->base, property, 0);
+	}
+out:
+	kfree(properties);
+
+	return ret;
+}
+
+int gud_connector_fill_properties(struct drm_connector_state *connector_state,
+				  struct gud_property_req *properties)
+{
+	struct gud_connector *gconn = to_gud_connector(connector_state->connector);
+	unsigned int i;
+
+	for (i = 0; i < gconn->num_properties; i++) {
+		u16 prop = gconn->properties[i];
+		u64 val;
+
+		if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS) {
+			val = connector_state->tv.brightness;
+		} else {
+			unsigned int *state_val;
+
+			state_val = gud_connector_tv_state_val(prop, &connector_state->tv);
+			if (WARN_ON_ONCE(IS_ERR(state_val)))
+				return PTR_ERR(state_val);
+
+			val = *state_val;
+		}
+
+		properties[i].prop = cpu_to_le16(prop);
+		properties[i].val = cpu_to_le64(val);
+	}
+
+	return gconn->num_properties;
+}
+
+static int gud_connector_create(struct gud_device *gdrm, unsigned int index,
+				struct gud_connector_descriptor_req *desc)
+{
+	struct drm_device *drm = &gdrm->drm;
+	struct gud_connector *gconn;
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	int ret, connector_type;
+	u32 flags;
+
+	gconn = kzalloc(sizeof(*gconn), GFP_KERNEL);
+	if (!gconn)
+		return -ENOMEM;
+
+	INIT_WORK(&gconn->backlight_work, gud_connector_backlight_update_status_work);
+	gconn->initial_brightness = -ENODEV;
+	flags = le32_to_cpu(desc->flags);
+	connector = &gconn->connector;
+
+	drm_dbg(drm, "Connector: index=%u type=%u flags=0x%x\n", index, desc->connector_type, flags);
+
+	switch (desc->connector_type) {
+	case GUD_CONNECTOR_TYPE_PANEL:
+		connector_type = DRM_MODE_CONNECTOR_USB;
+		break;
+	case GUD_CONNECTOR_TYPE_VGA:
+		connector_type = DRM_MODE_CONNECTOR_VGA;
+		break;
+	case GUD_CONNECTOR_TYPE_DVI:
+		connector_type = DRM_MODE_CONNECTOR_DVID;
+		break;
+	case GUD_CONNECTOR_TYPE_COMPOSITE:
+		connector_type = DRM_MODE_CONNECTOR_Composite;
+		break;
+	case GUD_CONNECTOR_TYPE_SVIDEO:
+		connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+		break;
+	case GUD_CONNECTOR_TYPE_COMPONENT:
+		connector_type = DRM_MODE_CONNECTOR_Component;
+		break;
+	case GUD_CONNECTOR_TYPE_DISPLAYPORT:
+		connector_type = DRM_MODE_CONNECTOR_DisplayPort;
+		break;
+	case GUD_CONNECTOR_TYPE_HDMI:
+		connector_type = DRM_MODE_CONNECTOR_HDMIA;
+		break;
+	default: /* future types */
+		connector_type = DRM_MODE_CONNECTOR_USB;
+		break;
+	}
+
+	drm_connector_helper_add(connector, &gud_connector_helper_funcs);
+	ret = drm_connector_init(drm, connector, &gud_connector_funcs, connector_type);
+	if (ret) {
+		kfree(connector);
+		return ret;
+	}
+
+	if (WARN_ON(connector->index != index))
+		return -EINVAL;
+
+	if (flags & GUD_CONNECTOR_FLAGS_POLL_STATUS)
+		connector->polled = (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT);
+	if (flags & GUD_CONNECTOR_FLAGS_INTERLACE)
+		connector->interlace_allowed = true;
+	if (flags & GUD_CONNECTOR_FLAGS_DOUBLESCAN)
+		connector->doublescan_allowed = true;
+
+	ret = gud_connector_add_properties(gdrm, gconn);
+	if (ret) {
+		gud_conn_err(connector, "Failed to add properties", ret);
+		return ret;
+	}
+
+	/* The first connector is attached to the existing simple pipe encoder */
+	if (!connector->index) {
+		encoder = &gdrm->pipe.encoder;
+	} else {
+		encoder = &gconn->encoder;
+
+		ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
+		if (ret)
+			return ret;
+
+		encoder->possible_crtcs = 1;
+	}
+
+	return drm_connector_attach_encoder(connector, encoder);
+}
+
+int gud_get_connectors(struct gud_device *gdrm)
+{
+	struct gud_connector_descriptor_req *descs;
+	unsigned int i, num_connectors;
+	int ret;
+
+	descs = kmalloc_array(GUD_CONNECTORS_MAX_NUM, sizeof(*descs), GFP_KERNEL);
+	if (!descs)
+		return -ENOMEM;
+
+	ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTORS, 0,
+			  descs, GUD_CONNECTORS_MAX_NUM * sizeof(*descs));
+	if (ret < 0)
+		goto free;
+	if (!ret || ret % sizeof(*descs)) {
+		ret = -EIO;
+		goto free;
+	}
+
+	num_connectors = ret / sizeof(*descs);
+
+	for (i = 0; i < num_connectors; i++) {
+		ret = gud_connector_create(gdrm, i, &descs[i]);
+		if (ret)
+			goto free;
+	}
+free:
+	kfree(descs);
+
+	return ret;
+}
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/gud/gud_drv.c linux-5.10.52-v7l+/drivers/gpu/drm/gud/gud_drv.c
--- linux-5.10.52-orig/drivers/gpu/drm/gud/gud_drv.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpu/drm/gud/gud_drv.c	2021-07-25 16:46:00.078389595 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2020 Noralf Trønnes
+ */
+
+#include <linux/dma-buf.h>
+#include <linux/dma-mapping.h>
+#include <linux/lz4.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/string_helpers.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_debugfs.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <drm/gud.h>
+
+#include "gud_internal.h"
+
+/* Only used internally */
+static const struct drm_format_info gud_drm_format_r1 = {
+	.format = GUD_DRM_FORMAT_R1,
+	.num_planes = 1,
+	.char_per_block = { 1, 0, 0 },
+	.block_w = { 8, 0, 0 },
+	.block_h = { 1, 0, 0 },
+	.hsub = 1,
+	.vsub = 1,
+};
+
+static const struct drm_format_info gud_drm_format_xrgb1111 = {
+	.format = GUD_DRM_FORMAT_XRGB1111,
+	.num_planes = 1,
+	.char_per_block = { 1, 0, 0 },
+	.block_w = { 2, 0, 0 },
+	.block_h = { 1, 0, 0 },
+	.hsub = 1,
+	.vsub = 1,
+};
+
+static int gud_usb_control_msg(struct usb_interface *intf, bool in,
+			       u8 request, u16 value, void *buf, size_t len)
+{
+	u8 requesttype = USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
+	u8 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+	struct usb_device *usb = interface_to_usbdev(intf);
+	unsigned int pipe;
+
+	if (len && !buf)
+		return -EINVAL;
+
+	if (in) {
+		pipe = usb_rcvctrlpipe(usb, 0);
+		requesttype |= USB_DIR_IN;
+	} else {
+		pipe = usb_sndctrlpipe(usb, 0);
+		requesttype |= USB_DIR_OUT;
+	}
+
+	return usb_control_msg(usb, pipe, request, requesttype, value,
+			       ifnum, buf, len, USB_CTRL_GET_TIMEOUT);
+}
+
+static int gud_get_display_descriptor(struct usb_interface *intf,
+				      struct gud_display_descriptor_req *desc)
+{
+	void *buf;
+	int ret;
+
+	buf = kmalloc(sizeof(*desc), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = gud_usb_control_msg(intf, true, GUD_REQ_GET_DESCRIPTOR, 0, buf, sizeof(*desc));
+	memcpy(desc, buf, sizeof(*desc));
+	kfree(buf);
+	if (ret < 0)
+		return ret;
+	if (ret != sizeof(*desc))
+		return -EIO;
+
+	if (desc->magic != le32_to_cpu(GUD_DISPLAY_MAGIC))
+		return -ENODATA;
+
+	DRM_DEV_DEBUG_DRIVER(&intf->dev,
+			     "version=%u flags=0x%x compression=0x%x max_buffer_size=%u\n",
+			     desc->version, le32_to_cpu(desc->flags), desc->compression,
+			     le32_to_cpu(desc->max_buffer_size));
+
+	if (!desc->version || !desc->max_width || !desc->max_height ||
+	    le32_to_cpu(desc->min_width) > le32_to_cpu(desc->max_width) ||
+	    le32_to_cpu(desc->min_height) > le32_to_cpu(desc->max_height))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int gud_status_to_errno(u8 status)
+{
+	switch (status) {
+	case GUD_STATUS_OK:
+		return 0;
+	case GUD_STATUS_BUSY:
+		return -EBUSY;
+	case GUD_STATUS_REQUEST_NOT_SUPPORTED:
+		return -EOPNOTSUPP;
+	case GUD_STATUS_PROTOCOL_ERROR:
+		return -EPROTO;
+	case GUD_STATUS_INVALID_PARAMETER:
+		return -EINVAL;
+	case GUD_STATUS_ERROR:
+		return -EREMOTEIO;
+	default:
+		return -EREMOTEIO;
+	}
+}
+
+static int gud_usb_get_status(struct usb_interface *intf)
+{
+	int ret, status = -EIO;
+	u8 *buf;
+
+	buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = gud_usb_control_msg(intf, true, GUD_REQ_GET_STATUS, 0, buf, sizeof(*buf));
+	if (ret == sizeof(*buf))
+		status = gud_status_to_errno(*buf);
+	kfree(buf);
+
+	if (ret < 0)
+		return ret;
+
+	return status;
+}
+
+static int gud_usb_transfer(struct gud_device *gdrm, bool in, u8 request, u16 index,
+			    void *buf, size_t len)
+{
+	struct usb_interface *intf = to_usb_interface(gdrm->drm.dev);
+	int idx, ret;
+
+	drm_dbg(&gdrm->drm, "%s: request=0x%x index=%u len=%zu\n",
+		in ? "get" : "set", request, index, len);
+
+	if (!drm_dev_enter(&gdrm->drm, &idx))
+		return -ENODEV;
+
+	mutex_lock(&gdrm->ctrl_lock);
+
+	ret = gud_usb_control_msg(intf, in, request, index, buf, len);
+	if (ret == -EPIPE || ((gdrm->flags & GUD_DISPLAY_FLAG_STATUS_ON_SET) && !in && ret >= 0)) {
+		int status;
+
+		status = gud_usb_get_status(intf);
+		if (status < 0) {
+			ret = status;
+		} else if (ret < 0) {
+			dev_err_once(gdrm->drm.dev,
+				     "Unexpected status OK for failed transfer\n");
+			ret = -EPIPE;
+		}
+	}
+
+	if (ret < 0) {
+		drm_dbg(&gdrm->drm, "ret=%d\n", ret);
+		gdrm->stats_num_errors++;
+	}
+
+	mutex_unlock(&gdrm->ctrl_lock);
+	drm_dev_exit(idx);
+
+	return ret;
+}
+
+/*
+ * @buf cannot be allocated on the stack.
+ * Returns number of bytes received or negative error code on failure.
+ */
+int gud_usb_get(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t max_len)
+{
+	return gud_usb_transfer(gdrm, true, request, index, buf, max_len);
+}
+
+/*
+ * @buf can be allocated on the stack or NULL.
+ * Returns zero on success or negative error code on failure.
+ */
+int gud_usb_set(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t len)
+{
+	void *trbuf = NULL;
+	int ret;
+
+	if (buf && len) {
+		trbuf = kmemdup(buf, len, GFP_KERNEL);
+		if (!trbuf)
+			return -ENOMEM;
+	}
+
+	ret = gud_usb_transfer(gdrm, false, request, index, trbuf, len);
+	kfree(trbuf);
+	if (ret < 0)
+		return ret;
+
+	return ret != len ? -EIO : 0;
+}
+
+/*
+ * @val can be allocated on the stack.
+ * Returns zero on success or negative error code on failure.
+ */
+int gud_usb_get_u8(struct gud_device *gdrm, u8 request, u16 index, u8 *val)
+{
+	u8 *buf;
+	int ret;
+
+	buf = kmalloc(sizeof(*val), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = gud_usb_get(gdrm, request, index, buf, sizeof(*val));
+	*val = *buf;
+	kfree(buf);
+	if (ret < 0)
+		return ret;
+
+	return ret != sizeof(*val) ? -EIO : 0;
+}
+
+/* Returns zero on success or negative error code on failure. */
+int gud_usb_set_u8(struct gud_device *gdrm, u8 request, u8 val)
+{
+	return gud_usb_set(gdrm, request, 0, &val, sizeof(val));
+}
+
+static int gud_get_properties(struct gud_device *gdrm)
+{
+	struct gud_property_req *properties;
+	unsigned int i, num_properties;
+	int ret;
+
+	properties = kcalloc(GUD_PROPERTIES_MAX_NUM, sizeof(*properties), GFP_KERNEL);
+	if (!properties)
+		return -ENOMEM;
+
+	ret = gud_usb_get(gdrm, GUD_REQ_GET_PROPERTIES, 0,
+			  properties, GUD_PROPERTIES_MAX_NUM * sizeof(*properties));
+	if (ret <= 0)
+		goto out;
+	if (ret % sizeof(*properties)) {
+		ret = -EIO;
+		goto out;
+	}
+
+	num_properties = ret / sizeof(*properties);
+	ret = 0;
+
+	gdrm->properties = drmm_kcalloc(&gdrm->drm, num_properties, sizeof(*gdrm->properties),
+					GFP_KERNEL);
+	if (!gdrm->properties) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < num_properties; i++) {
+		u16 prop = le16_to_cpu(properties[i].prop);
+		u64 val = le64_to_cpu(properties[i].val);
+
+		switch (prop) {
+		case GUD_PROPERTY_ROTATION:
+			/*
+			 * DRM UAPI matches the protocol so use the value directly,
+			 * but mask out any additions on future devices.
+			 */
+			val &= GUD_ROTATION_MASK;
+			ret = drm_plane_create_rotation_property(&gdrm->pipe.plane,
+								 DRM_MODE_ROTATE_0, val);
+			break;
+		default:
+			/* New ones might show up in future devices, skip those we don't know. */
+			drm_dbg(&gdrm->drm, "Ignoring unknown property: %u\n", prop);
+			continue;
+		}
+
+		if (ret)
+			goto out;
+
+		gdrm->properties[gdrm->num_properties++] = prop;
+	}
+out:
+	kfree(properties);
+
+	return ret;
+}
+
+static struct drm_gem_object *gud_gem_create_object(struct drm_device *dev, size_t size)
+{
+	struct drm_gem_shmem_object *shmem;
+
+	shmem = kzalloc(sizeof(*shmem), GFP_KERNEL);
+	if (!shmem)
+		return NULL;
+
+	shmem->map_cached = true;
+
+	return &shmem->base;
+}
+
+/*
+ * FIXME: Dma-buf sharing requires DMA support by the importing device.
+ *        This function is a workaround to make USB devices work as well.
+ *        See todo.rst for how to fix the issue in the dma-buf framework.
+ */
+static struct drm_gem_object *gud_gem_prime_import(struct drm_device *drm, struct dma_buf *dma_buf)
+{
+	struct gud_device *gdrm = to_gud_device(drm);
+
+	if (!gdrm->dmadev)
+		return ERR_PTR(-ENODEV);
+
+	return drm_gem_prime_import_dev(drm, dma_buf, gdrm->dmadev);
+}
+
+static int gud_stats_debugfs(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = m->private;
+	struct gud_device *gdrm = to_gud_device(node->minor->dev);
+	char buf[10];
+
+	string_get_size(gdrm->bulk_len, 1, STRING_UNITS_2, buf, sizeof(buf));
+	seq_printf(m, "Max buffer size: %s\n", buf);
+	seq_printf(m, "Number of errors:  %u\n", gdrm->stats_num_errors);
+
+	seq_puts(m, "Compression:      ");
+	if (gdrm->compression & GUD_COMPRESSION_LZ4)
+		seq_puts(m, " lz4");
+	if (!gdrm->compression)
+		seq_puts(m, " none");
+	seq_puts(m, "\n");
+
+	if (gdrm->compression) {
+		u64 remainder;
+		u64 ratio = div64_u64_rem(gdrm->stats_length, gdrm->stats_actual_length,
+					  &remainder);
+		u64 ratio_frac = div64_u64(remainder * 10, gdrm->stats_actual_length);
+
+		seq_printf(m, "Compression ratio: %llu.%llu\n", ratio, ratio_frac);
+	}
+
+	return 0;
+}
+
+static const struct drm_info_list gud_debugfs_list[] = {
+	{ "stats", gud_stats_debugfs, 0, NULL },
+};
+
+static void gud_debugfs_init(struct drm_minor *minor)
+{
+	drm_debugfs_create_files(gud_debugfs_list, ARRAY_SIZE(gud_debugfs_list),
+				 minor->debugfs_root, minor);
+}
+
+static const struct drm_simple_display_pipe_funcs gud_pipe_funcs = {
+	.check      = gud_pipe_check,
+	.update	    = gud_pipe_update,
+	.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
+};
+
+static const struct drm_mode_config_funcs gud_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create_with_dirty,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static const u64 gud_pipe_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+DEFINE_DRM_GEM_FOPS(gud_fops);
+
+static struct drm_driver gud_drm_driver = {
+	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
+	.fops			= &gud_fops,
+	DRM_GEM_SHMEM_DRIVER_OPS,
+	.gem_create_object	= gud_gem_create_object,
+	.gem_prime_import	= gud_gem_prime_import,
+	.debugfs_init		= gud_debugfs_init,
+
+	.name			= "gud",
+	.desc			= "Generic USB Display",
+	.date			= "20200422",
+	.major			= 1,
+	.minor			= 0,
+};
+
+static int gud_alloc_bulk_buffer(struct gud_device *gdrm)
+{
+	unsigned int i, num_pages;
+	struct page **pages;
+	void *ptr;
+	int ret;
+
+	gdrm->bulk_buf = vmalloc_32(gdrm->bulk_len);
+	if (!gdrm->bulk_buf)
+		return -ENOMEM;
+
+	num_pages = DIV_ROUND_UP(gdrm->bulk_len, PAGE_SIZE);
+	pages = kmalloc_array(num_pages, sizeof(struct page *), GFP_KERNEL);
+	if (!pages)
+		return -ENOMEM;
+
+	for (i = 0, ptr = gdrm->bulk_buf; i < num_pages; i++, ptr += PAGE_SIZE)
+		pages[i] = vmalloc_to_page(ptr);
+
+	ret = sg_alloc_table_from_pages(&gdrm->bulk_sgt, pages, num_pages,
+					0, gdrm->bulk_len, GFP_KERNEL);
+	kfree(pages);
+
+	return ret;
+}
+
+static void gud_free_buffers_and_mutex(void *data)
+{
+	struct gud_device *gdrm = data;
+
+	vfree(gdrm->compress_buf);
+	gdrm->compress_buf = NULL;
+	sg_free_table(&gdrm->bulk_sgt);
+	vfree(gdrm->bulk_buf);
+	gdrm->bulk_buf = NULL;
+	mutex_destroy(&gdrm->ctrl_lock);
+}
+
+static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	const struct drm_format_info *xrgb8888_emulation_format = NULL;
+	bool rgb565_supported = false, xrgb8888_supported = false;
+	unsigned int num_formats_dev, num_formats = 0;
+	struct usb_endpoint_descriptor *bulk_out;
+	struct gud_display_descriptor_req desc;
+	struct device *dev = &intf->dev;
+	size_t max_buffer_size = 0;
+	struct gud_device *gdrm;
+	struct drm_device *drm;
+	u8 *formats_dev;
+	u32 *formats;
+	int ret, i;
+
+	ret = usb_find_bulk_out_endpoint(intf->cur_altsetting, &bulk_out);
+	if (ret)
+		return ret;
+
+	ret = gud_get_display_descriptor(intf, &desc);
+	if (ret) {
+		DRM_DEV_DEBUG_DRIVER(dev, "Not a display interface: ret=%d\n", ret);
+		return -ENODEV;
+	}
+
+	if (desc.version > 1) {
+		dev_err(dev, "Protocol version %u is not supported\n", desc.version);
+		return -ENODEV;
+	}
+
+	gdrm = devm_drm_dev_alloc(dev, &gud_drm_driver, struct gud_device, drm);
+	if (IS_ERR(gdrm))
+		return PTR_ERR(gdrm);
+
+	drm = &gdrm->drm;
+	drm->mode_config.funcs = &gud_mode_config_funcs;
+	ret = drmm_mode_config_init(drm);
+	if (ret)
+		return ret;
+
+	gdrm->flags = le32_to_cpu(desc.flags);
+	gdrm->compression = desc.compression & GUD_COMPRESSION_LZ4;
+
+	if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE && gdrm->compression)
+		return -EINVAL;
+
+	mutex_init(&gdrm->ctrl_lock);
+	mutex_init(&gdrm->damage_lock);
+	INIT_WORK(&gdrm->work, gud_flush_work);
+	gud_clear_damage(gdrm);
+
+	ret = devm_add_action(dev, gud_free_buffers_and_mutex, gdrm);
+	if (ret)
+		return ret;
+
+	drm->mode_config.min_width = le32_to_cpu(desc.min_width);
+	drm->mode_config.max_width = le32_to_cpu(desc.max_width);
+	drm->mode_config.min_height = le32_to_cpu(desc.min_height);
+	drm->mode_config.max_height = le32_to_cpu(desc.max_height);
+
+	formats_dev = devm_kmalloc(dev, GUD_FORMATS_MAX_NUM, GFP_KERNEL);
+	/* Add room for emulated XRGB8888 */
+	formats = devm_kmalloc_array(dev, GUD_FORMATS_MAX_NUM + 1, sizeof(*formats), GFP_KERNEL);
+	if (!formats_dev || !formats)
+		return -ENOMEM;
+
+	ret = gud_usb_get(gdrm, GUD_REQ_GET_FORMATS, 0, formats_dev, GUD_FORMATS_MAX_NUM);
+	if (ret < 0)
+		return ret;
+
+	num_formats_dev = ret;
+	for (i = 0; i < num_formats_dev; i++) {
+		const struct drm_format_info *info;
+		size_t fmt_buf_size;
+		u32 format;
+
+		format = gud_to_fourcc(formats_dev[i]);
+		if (!format) {
+			drm_dbg(drm, "Unsupported format: 0x%02x\n", formats_dev[i]);
+			continue;
+		}
+
+		if (format == GUD_DRM_FORMAT_R1)
+			info = &gud_drm_format_r1;
+		else if (format == GUD_DRM_FORMAT_XRGB1111)
+			info = &gud_drm_format_xrgb1111;
+		else
+			info = drm_format_info(format);
+
+		switch (format) {
+		case GUD_DRM_FORMAT_R1:
+			fallthrough;
+		case GUD_DRM_FORMAT_XRGB1111:
+			if (!xrgb8888_emulation_format)
+				xrgb8888_emulation_format = info;
+			break;
+		case DRM_FORMAT_RGB565:
+			rgb565_supported = true;
+			if (!xrgb8888_emulation_format)
+				xrgb8888_emulation_format = info;
+			break;
+		case DRM_FORMAT_XRGB8888:
+			xrgb8888_supported = true;
+			break;
+		}
+
+		fmt_buf_size = drm_format_info_min_pitch(info, 0, drm->mode_config.max_width) *
+			       drm->mode_config.max_height;
+		max_buffer_size = max(max_buffer_size, fmt_buf_size);
+
+		if (format == GUD_DRM_FORMAT_R1 || format == GUD_DRM_FORMAT_XRGB1111)
+			continue; /* Internal not for userspace */
+
+		formats[num_formats++] = format;
+	}
+
+	if (!num_formats && !xrgb8888_emulation_format) {
+		dev_err(dev, "No supported pixel formats found\n");
+		return -EINVAL;
+	}
+
+	/* Prefer speed over color depth */
+	if (rgb565_supported)
+		drm->mode_config.preferred_depth = 16;
+
+	if (!xrgb8888_supported && xrgb8888_emulation_format) {
+		gdrm->xrgb8888_emulation_format = xrgb8888_emulation_format;
+		formats[num_formats++] = DRM_FORMAT_XRGB8888;
+	}
+
+	if (desc.max_buffer_size)
+		max_buffer_size = le32_to_cpu(desc.max_buffer_size);
+	/* Prevent a misbehaving device from allocating loads of RAM. 4096x4096@XRGB8888 = 64 MB */
+	if (max_buffer_size > SZ_64M)
+		max_buffer_size = SZ_64M;
+
+	gdrm->bulk_pipe = usb_sndbulkpipe(interface_to_usbdev(intf), usb_endpoint_num(bulk_out));
+	gdrm->bulk_len = max_buffer_size;
+
+	ret = gud_alloc_bulk_buffer(gdrm);
+	if (ret)
+		return ret;
+
+	if (gdrm->compression & GUD_COMPRESSION_LZ4) {
+		gdrm->lz4_comp_mem = devm_kmalloc(dev, LZ4_MEM_COMPRESS, GFP_KERNEL);
+		if (!gdrm->lz4_comp_mem)
+			return -ENOMEM;
+
+		gdrm->compress_buf = vmalloc(gdrm->bulk_len);
+		if (!gdrm->compress_buf)
+			return -ENOMEM;
+	}
+
+	ret = drm_simple_display_pipe_init(drm, &gdrm->pipe, &gud_pipe_funcs,
+					   formats, num_formats,
+					   gud_pipe_modifiers, NULL);
+	if (ret)
+		return ret;
+
+	devm_kfree(dev, formats);
+	devm_kfree(dev, formats_dev);
+
+	ret = gud_get_properties(gdrm);
+	if (ret) {
+		dev_err(dev, "Failed to get properties (error=%d)\n", ret);
+		return ret;
+	}
+
+	drm_plane_enable_fb_damage_clips(&gdrm->pipe.plane);
+
+	ret = gud_get_connectors(gdrm);
+	if (ret) {
+		dev_err(dev, "Failed to get connectors (error=%d)\n", ret);
+		return ret;
+	}
+
+	drm_mode_config_reset(drm);
+
+	usb_set_intfdata(intf, gdrm);
+
+	gdrm->dmadev = usb_intf_get_dma_device(intf);
+	if (!gdrm->dmadev)
+		dev_warn(dev, "buffer sharing not supported");
+
+	ret = drm_dev_register(drm, 0);
+	if (ret) {
+		put_device(gdrm->dmadev);
+		return ret;
+	}
+
+	drm_kms_helper_poll_init(drm);
+
+	drm_fbdev_generic_setup(drm, 0);
+
+	return 0;
+}
+
+static void gud_disconnect(struct usb_interface *interface)
+{
+	struct gud_device *gdrm = usb_get_intfdata(interface);
+	struct drm_device *drm = &gdrm->drm;
+
+	drm_dbg(drm, "%s:\n", __func__);
+
+	drm_kms_helper_poll_fini(drm);
+	drm_dev_unplug(drm);
+	drm_atomic_helper_shutdown(drm);
+	put_device(gdrm->dmadev);
+	gdrm->dmadev = NULL;
+}
+
+static int gud_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct gud_device *gdrm = usb_get_intfdata(intf);
+
+	return drm_mode_config_helper_suspend(&gdrm->drm);
+}
+
+static int gud_resume(struct usb_interface *intf)
+{
+	struct gud_device *gdrm = usb_get_intfdata(intf);
+
+	drm_mode_config_helper_resume(&gdrm->drm);
+
+	return 0;
+}
+
+static const struct usb_device_id gud_id_table[] = {
+	{ USB_DEVICE_INTERFACE_CLASS(0x1d50, 0x614d, USB_CLASS_VENDOR_SPEC) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x16d0, 0x10a9, USB_CLASS_VENDOR_SPEC) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, gud_id_table);
+
+static struct usb_driver gud_usb_driver = {
+	.name		= "gud",
+	.probe		= gud_probe,
+	.disconnect	= gud_disconnect,
+	.id_table	= gud_id_table,
+	.suspend	= gud_suspend,
+	.resume		= gud_resume,
+	.reset_resume	= gud_resume,
+};
+
+module_usb_driver(gud_usb_driver);
+
+MODULE_AUTHOR("Noralf Trønnes");
+MODULE_LICENSE("Dual MIT/GPL");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/gud/gud_internal.h linux-5.10.52-v7l+/drivers/gpu/drm/gud/gud_internal.h
--- linux-5.10.52-orig/drivers/gpu/drm/gud/gud_internal.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpu/drm/gud/gud_internal.h	2021-07-25 16:46:00.078389595 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* SPDX-License-Identifier: MIT */
+
+#ifndef __LINUX_GUD_INTERNAL_H
+#define __LINUX_GUD_INTERNAL_H
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+#include <uapi/drm/drm_fourcc.h>
+
+#include <drm/drm_modes.h>
+#include <drm/drm_simple_kms_helper.h>
+
+struct gud_device {
+	struct drm_device drm;
+	struct drm_simple_display_pipe pipe;
+	struct device *dmadev;
+	struct work_struct work;
+	u32 flags;
+	const struct drm_format_info *xrgb8888_emulation_format;
+
+	u16 *properties;
+	unsigned int num_properties;
+
+	unsigned int bulk_pipe;
+	void *bulk_buf;
+	size_t bulk_len;
+	struct sg_table bulk_sgt;
+
+	u8 compression;
+	void *lz4_comp_mem;
+	void *compress_buf;
+
+	u64 stats_length;
+	u64 stats_actual_length;
+	unsigned int stats_num_errors;
+
+	struct mutex ctrl_lock; /* Serialize get/set and status transfers */
+
+	struct mutex damage_lock; /* Protects the following members: */
+	struct drm_framebuffer *fb;
+	struct drm_rect damage;
+	bool prev_flush_failed;
+};
+
+static inline struct gud_device *to_gud_device(struct drm_device *drm)
+{
+	return container_of(drm, struct gud_device, drm);
+}
+
+static inline struct usb_device *gud_to_usb_device(struct gud_device *gdrm)
+{
+	return interface_to_usbdev(to_usb_interface(gdrm->drm.dev));
+}
+
+int gud_usb_get(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t len);
+int gud_usb_set(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t len);
+int gud_usb_get_u8(struct gud_device *gdrm, u8 request, u16 index, u8 *val);
+int gud_usb_set_u8(struct gud_device *gdrm, u8 request, u8 val);
+
+void gud_clear_damage(struct gud_device *gdrm);
+void gud_flush_work(struct work_struct *work);
+int gud_pipe_check(struct drm_simple_display_pipe *pipe,
+		   struct drm_plane_state *new_plane_state,
+		   struct drm_crtc_state *new_crtc_state);
+void gud_pipe_update(struct drm_simple_display_pipe *pipe,
+		     struct drm_plane_state *old_state);
+int gud_connector_fill_properties(struct drm_connector_state *connector_state,
+				  struct gud_property_req *properties);
+int gud_get_connectors(struct gud_device *gdrm);
+
+/* Driver internal fourcc transfer formats */
+#define GUD_DRM_FORMAT_R1		0x00000122
+#define GUD_DRM_FORMAT_XRGB1111		0x03121722
+
+static inline u8 gud_from_fourcc(u32 fourcc)
+{
+	switch (fourcc) {
+	case GUD_DRM_FORMAT_R1:
+		return GUD_PIXEL_FORMAT_R1;
+	case GUD_DRM_FORMAT_XRGB1111:
+		return GUD_PIXEL_FORMAT_XRGB1111;
+	case DRM_FORMAT_RGB565:
+		return GUD_PIXEL_FORMAT_RGB565;
+	case DRM_FORMAT_XRGB8888:
+		return GUD_PIXEL_FORMAT_XRGB8888;
+	case DRM_FORMAT_ARGB8888:
+		return GUD_PIXEL_FORMAT_ARGB8888;
+	}
+
+	return 0;
+}
+
+static inline u32 gud_to_fourcc(u8 format)
+{
+	switch (format) {
+	case GUD_PIXEL_FORMAT_R1:
+		return GUD_DRM_FORMAT_R1;
+	case GUD_PIXEL_FORMAT_XRGB1111:
+		return GUD_DRM_FORMAT_XRGB1111;
+	case GUD_PIXEL_FORMAT_RGB565:
+		return DRM_FORMAT_RGB565;
+	case GUD_PIXEL_FORMAT_XRGB8888:
+		return DRM_FORMAT_XRGB8888;
+	case GUD_PIXEL_FORMAT_ARGB8888:
+		return DRM_FORMAT_ARGB8888;
+	}
+
+	return 0;
+}
+
+static inline void gud_from_display_mode(struct gud_display_mode_req *dst,
+					 const struct drm_display_mode *src)
+{
+	u32 flags = src->flags & GUD_DISPLAY_MODE_FLAG_USER_MASK;
+
+	if (src->type & DRM_MODE_TYPE_PREFERRED)
+		flags |= GUD_DISPLAY_MODE_FLAG_PREFERRED;
+
+	dst->clock = cpu_to_le32(src->clock);
+	dst->hdisplay = cpu_to_le16(src->hdisplay);
+	dst->hsync_start = cpu_to_le16(src->hsync_start);
+	dst->hsync_end = cpu_to_le16(src->hsync_end);
+	dst->htotal = cpu_to_le16(src->htotal);
+	dst->vdisplay = cpu_to_le16(src->vdisplay);
+	dst->vsync_start = cpu_to_le16(src->vsync_start);
+	dst->vsync_end = cpu_to_le16(src->vsync_end);
+	dst->vtotal = cpu_to_le16(src->vtotal);
+	dst->flags = cpu_to_le32(flags);
+}
+
+static inline void gud_to_display_mode(struct drm_display_mode *dst,
+				       const struct gud_display_mode_req *src)
+{
+	u32 flags = le32_to_cpu(src->flags);
+
+	memset(dst, 0, sizeof(*dst));
+	dst->clock = le32_to_cpu(src->clock);
+	dst->hdisplay = le16_to_cpu(src->hdisplay);
+	dst->hsync_start = le16_to_cpu(src->hsync_start);
+	dst->hsync_end = le16_to_cpu(src->hsync_end);
+	dst->htotal = le16_to_cpu(src->htotal);
+	dst->vdisplay = le16_to_cpu(src->vdisplay);
+	dst->vsync_start = le16_to_cpu(src->vsync_start);
+	dst->vsync_end = le16_to_cpu(src->vsync_end);
+	dst->vtotal = le16_to_cpu(src->vtotal);
+	dst->flags = flags & GUD_DISPLAY_MODE_FLAG_USER_MASK;
+	dst->type = DRM_MODE_TYPE_DRIVER;
+	if (flags & GUD_DISPLAY_MODE_FLAG_PREFERRED)
+		dst->type |= DRM_MODE_TYPE_PREFERRED;
+	drm_mode_set_name(dst);
+}
+
+#endif
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/gud/gud_pipe.c linux-5.10.52-v7l+/drivers/gpu/drm/gud/gud_pipe.c
--- linux-5.10.52-orig/drivers/gpu/drm/gud/gud_pipe.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpu/drm/gud/gud_pipe.c	2021-07-25 16:46:00.078389595 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2020 Noralf Trønnes
+ */
+
+#include <linux/dma-buf.h>
+#include <linux/lz4.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_format_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_print.h>
+#include <drm/drm_rect.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <drm/gud.h>
+
+#include "gud_internal.h"
+
+/*
+ * Some userspace rendering loops runs all displays in the same loop.
+ * This means that a fast display will have to wait for a slow one.
+ * For this reason gud does flushing asynchronous by default.
+ * The down side is that in e.g. a single display setup userspace thinks
+ * the display is insanely fast since the driver reports back immediately
+ * that the flush/pageflip is done. This wastes CPU and power.
+ * Such users might want to set this module parameter to false.
+ */
+static bool gud_async_flush = true;
+module_param_named(async_flush, gud_async_flush, bool, 0644);
+MODULE_PARM_DESC(async_flush, "Enable asynchronous flushing [default=true]");
+
+/*
+ * FIXME: The driver is probably broken on Big Endian machines.
+ * See discussion:
+ * https://lore.kernel.org/dri-devel/CAKb7UvihLX0hgBOP3VBG7O+atwZcUVCPVuBdfmDMpg0NjXe-cQ@mail.gmail.com/
+ */
+
+static bool gud_is_big_endian(void)
+{
+#if defined(__BIG_ENDIAN)
+	return true;
+#else
+	return false;
+#endif
+}
+
+static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format,
+				   void *src, struct drm_framebuffer *fb,
+				   struct drm_rect *rect)
+{
+	unsigned int block_width = drm_format_info_block_width(format, 0);
+	unsigned int bits_per_pixel = 8 / block_width;
+	unsigned int x, y, width, height;
+	u8 pix, *pix8, *block = dst; /* Assign to silence compiler warning */
+	size_t len;
+	void *buf;
+
+	WARN_ON_ONCE(format->char_per_block[0] != 1);
+
+	/* Start on a byte boundary */
+	rect->x1 = ALIGN_DOWN(rect->x1, block_width);
+	width = drm_rect_width(rect);
+	height = drm_rect_height(rect);
+	len = drm_format_info_min_pitch(format, 0, width) * height;
+
+	buf = kmalloc(width * height, GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	drm_fb_xrgb8888_to_gray8(buf, src, fb, rect);
+	pix8 = buf;
+
+	for (y = 0; y < height; y++) {
+		for (x = 0; x < width; x++) {
+			unsigned int pixpos = x % block_width; /* within byte from the left */
+			unsigned int pixshift = (block_width - pixpos - 1) * bits_per_pixel;
+
+			if (!pixpos) {
+				block = dst++;
+				*block = 0;
+			}
+
+			pix = (*pix8++) >> (8 - bits_per_pixel);
+			*block |= pix << pixshift;
+		}
+	}
+
+	kfree(buf);
+
+	return len;
+}
+
+static size_t gud_xrgb8888_to_color(u8 *dst, const struct drm_format_info *format,
+				    void *src, struct drm_framebuffer *fb,
+				    struct drm_rect *rect)
+{
+	unsigned int block_width = drm_format_info_block_width(format, 0);
+	unsigned int bits_per_pixel = 8 / block_width;
+	u8 r, g, b, pix, *block = dst; /* Assign to silence compiler warning */
+	unsigned int x, y, width;
+	u32 *pix32;
+	size_t len;
+
+	/* Start on a byte boundary */
+	rect->x1 = ALIGN_DOWN(rect->x1, block_width);
+	width = drm_rect_width(rect);
+	len = drm_format_info_min_pitch(format, 0, width) * drm_rect_height(rect);
+
+	for (y = rect->y1; y < rect->y2; y++) {
+		pix32 = src + (y * fb->pitches[0]);
+		pix32 += rect->x1;
+
+		for (x = 0; x < width; x++) {
+			unsigned int pixpos = x % block_width; /* within byte from the left */
+			unsigned int pixshift = (block_width - pixpos - 1) * bits_per_pixel;
+
+			if (!pixpos) {
+				block = dst++;
+				*block = 0;
+			}
+
+			r = *pix32 >> 16;
+			g = *pix32 >> 8;
+			b = *pix32++;
+
+			switch (format->format) {
+			case GUD_DRM_FORMAT_XRGB1111:
+				pix = ((r >> 7) << 2) | ((g >> 7) << 1) | (b >> 7);
+				break;
+			default:
+				WARN_ON_ONCE(1);
+				return len;
+			}
+
+			*block |= pix << pixshift;
+		}
+	}
+
+	return len;
+}
+
+static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
+			  const struct drm_format_info *format, struct drm_rect *rect,
+			  struct gud_set_buffer_req *req)
+{
+	struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach;
+	u8 compression = gdrm->compression;
+	void *vmap, *vaddr, *buf;
+	size_t pitch, len;
+	int ret = 0;
+
+	pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(rect));
+	len = pitch * drm_rect_height(rect);
+	if (len > gdrm->bulk_len)
+		return -E2BIG;
+
+	vmap = drm_gem_shmem_vmap(fb->obj[0]);
+	if (!vmap)
+		return -ENOMEM;
+
+	vaddr = vmap + fb->offsets[0];
+
+	if (import_attach) {
+		ret = dma_buf_begin_cpu_access(import_attach->dmabuf, DMA_FROM_DEVICE);
+		if (ret)
+			goto vunmap;
+	}
+retry:
+	if (compression)
+		buf = gdrm->compress_buf;
+	else
+		buf = gdrm->bulk_buf;
+
+	/*
+	 * Imported buffers are assumed to be write-combined and thus uncached
+	 * with slow reads (at least on ARM).
+	 */
+	if (format != fb->format) {
+		if (format->format == GUD_DRM_FORMAT_R1) {
+			len = gud_xrgb8888_to_r124(buf, format, vaddr, fb, rect);
+			if (!len) {
+				ret = -ENOMEM;
+				goto end_cpu_access;
+			}
+		} else if (format->format == DRM_FORMAT_RGB565) {
+			drm_fb_xrgb8888_to_rgb565(buf, vaddr, fb, rect, gud_is_big_endian());
+		} else {
+			len = gud_xrgb8888_to_color(buf, format, vaddr, fb, rect);
+		}
+	} else if (gud_is_big_endian() && format->cpp[0] > 1) {
+		drm_fb_swab(buf, vaddr, fb, rect, !import_attach);
+	} else if (compression && !import_attach && pitch == fb->pitches[0]) {
+		/* can compress directly from the framebuffer */
+		buf = vaddr + rect->y1 * pitch;
+	} else {
+		drm_fb_memcpy(buf, vaddr, fb, rect);
+	}
+
+	memset(req, 0, sizeof(*req));
+	req->x = cpu_to_le32(rect->x1);
+	req->y = cpu_to_le32(rect->y1);
+	req->width = cpu_to_le32(drm_rect_width(rect));
+	req->height = cpu_to_le32(drm_rect_height(rect));
+	req->length = cpu_to_le32(len);
+
+	if (compression & GUD_COMPRESSION_LZ4) {
+		int complen;
+
+		complen = LZ4_compress_default(buf, gdrm->bulk_buf, len, len, gdrm->lz4_comp_mem);
+		if (complen <= 0) {
+			compression = 0;
+			goto retry;
+		}
+
+		req->compression = GUD_COMPRESSION_LZ4;
+		req->compressed_length = cpu_to_le32(complen);
+	}
+
+end_cpu_access:
+	if (import_attach)
+		dma_buf_end_cpu_access(import_attach->dmabuf, DMA_FROM_DEVICE);
+vunmap:
+	drm_gem_shmem_vunmap(fb->obj[0], vmap);
+
+	return ret;
+}
+
+struct gud_usb_bulk_context {
+	struct timer_list timer;
+	struct usb_sg_request sgr;
+};
+
+static void gud_usb_bulk_timeout(struct timer_list *t)
+{
+	struct gud_usb_bulk_context *ctx = from_timer(ctx, t, timer);
+
+	usb_sg_cancel(&ctx->sgr);
+}
+
+static int gud_usb_bulk(struct gud_device *gdrm, size_t len)
+{
+	struct gud_usb_bulk_context ctx;
+	int ret;
+
+	ret = usb_sg_init(&ctx.sgr, gud_to_usb_device(gdrm), gdrm->bulk_pipe, 0,
+			  gdrm->bulk_sgt.sgl, gdrm->bulk_sgt.nents, len, GFP_KERNEL);
+	if (ret)
+		return ret;
+
+	timer_setup_on_stack(&ctx.timer, gud_usb_bulk_timeout, 0);
+	mod_timer(&ctx.timer, jiffies + msecs_to_jiffies(3000));
+
+	usb_sg_wait(&ctx.sgr);
+
+	if (!del_timer_sync(&ctx.timer))
+		ret = -ETIMEDOUT;
+	else if (ctx.sgr.status < 0)
+		ret = ctx.sgr.status;
+	else if (ctx.sgr.bytes != len)
+		ret = -EIO;
+
+	destroy_timer_on_stack(&ctx.timer);
+
+	return ret;
+}
+
+static int gud_flush_rect(struct gud_device *gdrm, struct drm_framebuffer *fb,
+			  const struct drm_format_info *format, struct drm_rect *rect)
+{
+	struct gud_set_buffer_req req;
+	size_t len, trlen;
+	int ret;
+
+	drm_dbg(&gdrm->drm, "Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
+
+	ret = gud_prep_flush(gdrm, fb, format, rect, &req);
+	if (ret)
+		return ret;
+
+	len = le32_to_cpu(req.length);
+
+	if (req.compression)
+		trlen = le32_to_cpu(req.compressed_length);
+	else
+		trlen = len;
+
+	gdrm->stats_length += len;
+	/* Did it wrap around? */
+	if (gdrm->stats_length <= len && gdrm->stats_actual_length) {
+		gdrm->stats_length = len;
+		gdrm->stats_actual_length = 0;
+	}
+	gdrm->stats_actual_length += trlen;
+
+	if (!(gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE) || gdrm->prev_flush_failed) {
+		ret = gud_usb_set(gdrm, GUD_REQ_SET_BUFFER, 0, &req, sizeof(req));
+		if (ret)
+			return ret;
+	}
+
+	ret = gud_usb_bulk(gdrm, trlen);
+	if (ret)
+		gdrm->stats_num_errors++;
+
+	return ret;
+}
+
+void gud_clear_damage(struct gud_device *gdrm)
+{
+	gdrm->damage.x1 = INT_MAX;
+	gdrm->damage.y1 = INT_MAX;
+	gdrm->damage.x2 = 0;
+	gdrm->damage.y2 = 0;
+}
+
+static void gud_add_damage(struct gud_device *gdrm, struct drm_rect *damage)
+{
+	gdrm->damage.x1 = min(gdrm->damage.x1, damage->x1);
+	gdrm->damage.y1 = min(gdrm->damage.y1, damage->y1);
+	gdrm->damage.x2 = max(gdrm->damage.x2, damage->x2);
+	gdrm->damage.y2 = max(gdrm->damage.y2, damage->y2);
+}
+
+static void gud_retry_failed_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
+				   struct drm_rect *damage)
+{
+	/*
+	 * pipe_update waits for the worker when the display mode is going to change.
+	 * This ensures that the width and height is still the same making it safe to
+	 * add back the damage.
+	 */
+
+	mutex_lock(&gdrm->damage_lock);
+	if (!gdrm->fb) {
+		drm_framebuffer_get(fb);
+		gdrm->fb = fb;
+	}
+	gud_add_damage(gdrm, damage);
+	mutex_unlock(&gdrm->damage_lock);
+
+	/* Retry only once to avoid a possible storm in case of continues errors. */
+	if (!gdrm->prev_flush_failed)
+		queue_work(system_long_wq, &gdrm->work);
+	gdrm->prev_flush_failed = true;
+}
+
+void gud_flush_work(struct work_struct *work)
+{
+	struct gud_device *gdrm = container_of(work, struct gud_device, work);
+	const struct drm_format_info *format;
+	struct drm_framebuffer *fb;
+	struct drm_rect damage;
+	unsigned int i, lines;
+	int idx, ret = 0;
+	size_t pitch;
+
+	if (!drm_dev_enter(&gdrm->drm, &idx))
+		return;
+
+	mutex_lock(&gdrm->damage_lock);
+	fb = gdrm->fb;
+	gdrm->fb = NULL;
+	damage = gdrm->damage;
+	gud_clear_damage(gdrm);
+	mutex_unlock(&gdrm->damage_lock);
+
+	if (!fb)
+		goto out;
+
+	format = fb->format;
+	if (format->format == DRM_FORMAT_XRGB8888 && gdrm->xrgb8888_emulation_format)
+		format = gdrm->xrgb8888_emulation_format;
+
+	/* Split update if it's too big */
+	pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(&damage));
+	lines = drm_rect_height(&damage);
+
+	if (gdrm->bulk_len < lines * pitch)
+		lines = gdrm->bulk_len / pitch;
+
+	for (i = 0; i < DIV_ROUND_UP(drm_rect_height(&damage), lines); i++) {
+		struct drm_rect rect = damage;
+
+		rect.y1 += i * lines;
+		rect.y2 = min_t(u32, rect.y1 + lines, damage.y2);
+
+		ret = gud_flush_rect(gdrm, fb, format, &rect);
+		if (ret) {
+			if (ret != -ENODEV && ret != -ECONNRESET &&
+			    ret != -ESHUTDOWN && ret != -EPROTO) {
+				bool prev_flush_failed = gdrm->prev_flush_failed;
+
+				gud_retry_failed_flush(gdrm, fb, &damage);
+				if (!prev_flush_failed)
+					dev_err_ratelimited(fb->dev->dev,
+							    "Failed to flush framebuffer: error=%d\n", ret);
+			}
+			break;
+		}
+
+		gdrm->prev_flush_failed = false;
+	}
+
+	drm_framebuffer_put(fb);
+out:
+	drm_dev_exit(idx);
+}
+
+static void gud_fb_queue_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
+				struct drm_rect *damage)
+{
+	struct drm_framebuffer *old_fb = NULL;
+
+	mutex_lock(&gdrm->damage_lock);
+
+	if (fb != gdrm->fb) {
+		old_fb = gdrm->fb;
+		drm_framebuffer_get(fb);
+		gdrm->fb = fb;
+	}
+
+	gud_add_damage(gdrm, damage);
+
+	mutex_unlock(&gdrm->damage_lock);
+
+	queue_work(system_long_wq, &gdrm->work);
+
+	if (old_fb)
+		drm_framebuffer_put(old_fb);
+}
+
+int gud_pipe_check(struct drm_simple_display_pipe *pipe,
+		   struct drm_plane_state *new_plane_state,
+		   struct drm_crtc_state *new_crtc_state)
+{
+	struct gud_device *gdrm = to_gud_device(pipe->crtc.dev);
+	struct drm_plane_state *old_plane_state = pipe->plane.state;
+	const struct drm_display_mode *mode = &new_crtc_state->mode;
+	struct drm_atomic_state *state = new_plane_state->state;
+	struct drm_framebuffer *old_fb = old_plane_state->fb;
+	struct drm_connector_state *connector_state = NULL;
+	struct drm_framebuffer *fb = new_plane_state->fb;
+	const struct drm_format_info *format = fb->format;
+	struct drm_connector *connector;
+	unsigned int i, num_properties;
+	struct gud_state_req *req;
+	int idx, ret;
+	size_t len;
+
+	if (WARN_ON_ONCE(!fb))
+		return -EINVAL;
+
+	if (old_plane_state->rotation != new_plane_state->rotation)
+		new_crtc_state->mode_changed = true;
+
+	if (old_fb && old_fb->format != format)
+		new_crtc_state->mode_changed = true;
+
+	if (!new_crtc_state->mode_changed && !new_crtc_state->connectors_changed)
+		return 0;
+
+	/* Only one connector is supported */
+	if (hweight32(new_crtc_state->connector_mask) != 1)
+		return -EINVAL;
+
+	if (format->format == DRM_FORMAT_XRGB8888 && gdrm->xrgb8888_emulation_format)
+		format = gdrm->xrgb8888_emulation_format;
+
+	for_each_new_connector_in_state(state, connector, connector_state, i) {
+		if (connector_state->crtc)
+			break;
+	}
+
+	/*
+	 * DRM_IOCTL_MODE_OBJ_SETPROPERTY on the rotation property will not have
+	 * the connector included in the state.
+	 */
+	if (!connector_state) {
+		struct drm_connector_list_iter conn_iter;
+
+		drm_connector_list_iter_begin(pipe->crtc.dev, &conn_iter);
+		drm_for_each_connector_iter(connector, &conn_iter) {
+			if (connector->state->crtc) {
+				connector_state = connector->state;
+				break;
+			}
+		}
+		drm_connector_list_iter_end(&conn_iter);
+	}
+
+	if (WARN_ON_ONCE(!connector_state))
+		return -ENOENT;
+
+	len = struct_size(req, properties,
+			  GUD_PROPERTIES_MAX_NUM + GUD_CONNECTOR_PROPERTIES_MAX_NUM);
+	req = kzalloc(len, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	gud_from_display_mode(&req->mode, mode);
+
+	req->format = gud_from_fourcc(format->format);
+	if (WARN_ON_ONCE(!req->format)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	req->connector = drm_connector_index(connector_state->connector);
+
+	ret = gud_connector_fill_properties(connector_state, req->properties);
+	if (ret < 0)
+		goto out;
+
+	num_properties = ret;
+	for (i = 0; i < gdrm->num_properties; i++) {
+		u16 prop = gdrm->properties[i];
+		u64 val;
+
+		switch (prop) {
+		case GUD_PROPERTY_ROTATION:
+			/* DRM UAPI matches the protocol so use value directly */
+			val = new_plane_state->rotation;
+			break;
+		default:
+			WARN_ON_ONCE(1);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		req->properties[num_properties + i].prop = cpu_to_le16(prop);
+		req->properties[num_properties + i].val = cpu_to_le64(val);
+		num_properties++;
+	}
+
+	if (drm_dev_enter(fb->dev, &idx)) {
+		len = struct_size(req, properties, num_properties);
+		ret = gud_usb_set(gdrm, GUD_REQ_SET_STATE_CHECK, 0, req, len);
+		drm_dev_exit(idx);
+	}  else {
+		ret = -ENODEV;
+	}
+out:
+	kfree(req);
+
+	return ret;
+}
+
+void gud_pipe_update(struct drm_simple_display_pipe *pipe,
+		     struct drm_plane_state *old_state)
+{
+	struct drm_device *drm = pipe->crtc.dev;
+	struct gud_device *gdrm = to_gud_device(drm);
+	struct drm_plane_state *state = pipe->plane.state;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_crtc *crtc = &pipe->crtc;
+	struct drm_rect damage;
+	int idx;
+
+	if (crtc->state->mode_changed || !crtc->state->enable) {
+		cancel_work_sync(&gdrm->work);
+		mutex_lock(&gdrm->damage_lock);
+		if (gdrm->fb) {
+			drm_framebuffer_put(gdrm->fb);
+			gdrm->fb = NULL;
+		}
+		gud_clear_damage(gdrm);
+		mutex_unlock(&gdrm->damage_lock);
+	}
+
+	if (!drm_dev_enter(drm, &idx))
+		return;
+
+	if (!old_state->fb)
+		gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 1);
+
+	if (fb && (crtc->state->mode_changed || crtc->state->connectors_changed))
+		gud_usb_set(gdrm, GUD_REQ_SET_STATE_COMMIT, 0, NULL, 0);
+
+	if (crtc->state->active_changed)
+		gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, crtc->state->active);
+
+	if (drm_atomic_helper_damage_merged(old_state, state, &damage)) {
+		if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE)
+			drm_rect_init(&damage, 0, 0, fb->width, fb->height);
+		gud_fb_queue_damage(gdrm, fb, &damage);
+		if (!gud_async_flush)
+			flush_work(&gdrm->work);
+	}
+
+	if (!crtc->state->enable)
+		gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 0);
+
+	drm_dev_exit(idx);
+}
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/gud/Kconfig linux-5.10.52-v7l+/drivers/gpu/drm/gud/Kconfig
--- linux-5.10.52-orig/drivers/gpu/drm/gud/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpu/drm/gud/Kconfig	2021-07-25 16:46:00.078389595 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# SPDX-License-Identifier: GPL-2.0
+
+config DRM_GUD
+	tristate "GUD USB Display"
+	depends on DRM && USB
+	select LZ4_COMPRESS
+	select DRM_KMS_HELPER
+	select DRM_GEM_SHMEM_HELPER
+	select BACKLIGHT_CLASS_DEVICE
+	help
+	  This is a DRM display driver for GUD USB Displays or display
+	  adapters.
+
+	  If M is selected the module will be called gud.
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/gud/Makefile linux-5.10.52-v7l+/drivers/gpu/drm/gud/Makefile
--- linux-5.10.52-orig/drivers/gpu/drm/gud/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpu/drm/gud/Makefile	2021-07-25 16:46:00.078389595 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+# SPDX-License-Identifier: GPL-2.0
+
+gud-y				:= gud_drv.o gud_pipe.o gud_connector.o
+obj-$(CONFIG_DRM_GUD)		+= gud.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c linux-5.10.52-v7l+/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
--- linux-5.10.52-orig/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c	2021-07-25 16:46:00.078389595 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:175 @
 }
 
 static void hibmc_crtc_atomic_enable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	unsigned int reg;
 	struct hibmc_drm_private *priv = crtc->dev->dev_private;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:194 @
 }
 
 static void hibmc_crtc_atomic_disable(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_state)
+				      struct drm_atomic_state *state)
 {
 	unsigned int reg;
 	struct hibmc_drm_private *priv = crtc->dev->dev_private;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:396 @
 }
 
 static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	unsigned int reg;
 	struct drm_device *dev = crtc->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:416 @
 }
 
 static void hibmc_crtc_atomic_flush(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 
 {
 	unsigned long flags;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c linux-5.10.52-v7l+/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
--- linux-5.10.52-orig/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c	2021-07-25 16:46:00.078389595 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:439 @
 #endif
 
 static void ade_crtc_atomic_enable(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_state)
+				   struct drm_atomic_state *state)
 {
 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:462 @
 }
 
 static void ade_crtc_atomic_disable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:488 @
 }
 
 static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_state)
+				  struct drm_atomic_state *state)
 {
 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:501 @
 }
 
 static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_state)
+				  struct drm_atomic_state *state)
 
 {
 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_atomic.c linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_atomic.c
--- linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_atomic.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_atomic.c	2021-07-25 16:46:00.088389427 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:112 @
 	return -EINVAL;
 }
 
-static bool blob_equal(const struct drm_property_blob *a,
-		       const struct drm_property_blob *b)
-{
-	if (a && b)
-		return a->length == b->length &&
-			!memcmp(a->data, b->data, a->length);
-
-	return !a == !b;
-}
-
 int intel_digital_connector_atomic_check(struct drm_connector *conn,
 					 struct drm_atomic_state *state)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:143 @
 	    new_conn_state->base.picture_aspect_ratio != old_conn_state->base.picture_aspect_ratio ||
 	    new_conn_state->base.content_type != old_conn_state->base.content_type ||
 	    new_conn_state->base.scaling_mode != old_conn_state->base.scaling_mode ||
-	    !blob_equal(new_conn_state->base.hdr_output_metadata,
-			old_conn_state->base.hdr_output_metadata))
+	    !drm_connector_atomic_hdr_metadata_equal(old_state, new_state))
 		crtc_state->mode_changed = true;
 
 	return 0;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_connector.c linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_connector.c
--- linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_connector.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_connector.c	2021-07-25 16:46:00.098389259 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:300 @
 		return;
 	}
 
-	drm_object_attach_property(&connector->base,
-				   connector->colorspace_property, 0);
+	drm_connector_attach_colorspace_property(connector);
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_display.c linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_display.c
--- linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_display.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_display.c	2021-07-25 16:46:00.108389092 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:16565 @
 }
 
 #define INTEL_CRTC_FUNCS \
-	.gamma_set = drm_atomic_helper_legacy_gamma_set, \
 	.set_config = drm_atomic_helper_set_config, \
 	.destroy = intel_crtc_destroy, \
 	.page_flip = drm_atomic_helper_page_flip, \
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_dp_mst.c linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_dp_mst.c
--- linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_dp_mst.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_dp_mst.c	2021-07-25 16:46:00.118388924 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:26 @
  *
  */
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_probe_helper.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:712 @
 }
 
 static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
-							 struct drm_connector_state *state)
+							 struct drm_atomic_state *state)
 {
+	struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state,
+											 connector);
 	struct intel_connector *intel_connector = to_intel_connector(connector);
 	struct intel_dp *intel_dp = intel_connector->mst_port;
-	struct intel_crtc *crtc = to_intel_crtc(state->crtc);
+	struct intel_crtc *crtc = to_intel_crtc(connector_state->crtc);
 
 	return &intel_dp->mst_encoders[crtc->pipe]->base.base;
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_hdmi.c linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_hdmi.c
--- linux-5.10.52-orig/drivers/gpu/drm/i915/display/intel_hdmi.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/i915/display/intel_hdmi.c	2021-07-25 16:46:00.138388589 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2974 @
 	drm_connector_attach_content_type_property(connector);
 
 	if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-		drm_object_attach_property(&connector->base,
-			connector->dev->mode_config.hdr_output_metadata_property, 0);
+		drm_connector_attach_hdr_output_metadata_property(connector);
 
 	if (!HAS_GMCH(dev_priv))
 		drm_connector_attach_max_bpc_property(connector, 8, 12);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/imx/dcss/dcss-crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/imx/dcss/dcss-crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/imx/dcss/dcss-crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/imx/dcss/dcss-crtc.c	2021-07-25 16:46:00.298385906 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6 @
  * Copyright 2019 NXP.
  */
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_vblank.h>
 #include <linux/platform_device.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:56 @
 };
 
 static void dcss_crtc_atomic_begin(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	drm_crtc_vblank_on(crtc);
 }
 
 static void dcss_crtc_atomic_flush(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
 						   base);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:81 @
 }
 
 static void dcss_crtc_atomic_enable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_crtc_state)
+				    struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
 						   base);
 	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:117 @
 }
 
 static void dcss_crtc_atomic_disable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_crtc_state)
+				     struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
 						   base);
 	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/imx/ipuv3-crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/imx/ipuv3-crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/imx/ipuv3-crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/imx/ipuv3-crtc.c	2021-07-25 16:46:00.298385906 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:50 @
 }
 
 static void ipu_crtc_atomic_enable(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_state)
+				   struct drm_atomic_state *state)
 {
 	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:82 @
 }
 
 static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_crtc_state)
+				    struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:230 @
 }
 
 static int ipu_crtc_atomic_check(struct drm_crtc *crtc,
-				 struct drm_crtc_state *state)
+				 struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	u32 primary_plane_mask = drm_plane_mask(crtc->primary);
 
-	if (state->active && (primary_plane_mask & state->plane_mask) == 0)
+	if (crtc_state->active && (primary_plane_mask & crtc_state->plane_mask) == 0)
 		return -EINVAL;
 
 	return 0;
 }
 
 static void ipu_crtc_atomic_begin(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_crtc_state)
+				  struct drm_atomic_state *state)
 {
 	drm_crtc_vblank_on(crtc);
 }
 
 static void ipu_crtc_atomic_flush(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_crtc_state)
+				  struct drm_atomic_state *state)
 {
 	spin_lock_irq(&crtc->dev->event_lock);
 	if (crtc->state->event) {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/ingenic/ingenic-drm-drv.c linux-5.10.52-v7l+/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
--- linux-5.10.52-orig/drivers/gpu/drm/ingenic/ingenic-drm-drv.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/ingenic/ingenic-drm-drv.c	2021-07-25 16:46:00.298385906 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:115 @
 }
 
 static void ingenic_drm_crtc_atomic_enable(struct drm_crtc *crtc,
-					   struct drm_crtc_state *state)
+					   struct drm_atomic_state *state)
 {
 	struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:129 @
 }
 
 static void ingenic_drm_crtc_atomic_disable(struct drm_crtc *crtc,
-					    struct drm_crtc_state *state)
+					    struct drm_atomic_state *state)
 {
 	struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
 	unsigned int var;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:198 @
 }
 
 static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
-					 struct drm_crtc_state *state)
+					 struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
 	struct drm_plane_state *f1_state, *f0_state, *ipu_state = NULL;
 
-	if (drm_atomic_crtc_needs_modeset(state) && priv->soc_info->has_osd) {
-		f1_state = drm_atomic_get_plane_state(state->state, &priv->f1);
+	if (drm_atomic_crtc_needs_modeset(crtc_state) && priv->soc_info->has_osd) {
+		f1_state = drm_atomic_get_plane_state(crtc_state->state,
+						      &priv->f1);
 		if (IS_ERR(f1_state))
 			return PTR_ERR(f1_state);
 
-		f0_state = drm_atomic_get_plane_state(state->state, &priv->f0);
+		f0_state = drm_atomic_get_plane_state(crtc_state->state,
+						      &priv->f0);
 		if (IS_ERR(f0_state))
 			return PTR_ERR(f0_state);
 
 		if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) {
-			ipu_state = drm_atomic_get_plane_state(state->state, priv->ipu_plane);
+			ipu_state = drm_atomic_get_plane_state(crtc_state->state,
+							       priv->ipu_plane);
 			if (IS_ERR(ipu_state))
 				return PTR_ERR(ipu_state);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:256 @
 }
 
 static void ingenic_drm_crtc_atomic_begin(struct drm_crtc *crtc,
-					  struct drm_crtc_state *oldstate)
+					  struct drm_atomic_state *state)
 {
 	struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
 	u32 ctrl = 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:276 @
 }
 
 static void ingenic_drm_crtc_atomic_flush(struct drm_crtc *crtc,
-					  struct drm_crtc_state *oldstate)
+					  struct drm_atomic_state *state)
 {
 	struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
-	struct drm_crtc_state *state = crtc->state;
-	struct drm_pending_vblank_event *event = state->event;
+	struct drm_crtc_state *crtc_state = crtc->state;
+	struct drm_pending_vblank_event *event = crtc_state->event;
 
-	if (drm_atomic_crtc_needs_modeset(state)) {
-		ingenic_drm_crtc_update_timings(priv, &state->mode);
+	if (drm_atomic_crtc_needs_modeset(crtc_state)) {
+		ingenic_drm_crtc_update_timings(priv, &crtc_state->mode);
 
 		clk_set_rate(priv->pix_clk, state->adjusted_mode.clock * 1000);
 	}
 
 	if (event) {
-		state->event = NULL;
+		crtc_state->event = NULL;
 
 		spin_lock_irq(&crtc->dev->event_lock);
 		if (drm_crtc_vblank_get(crtc) == 0)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:650 @
 
 	.enable_vblank		= ingenic_drm_enable_vblank,
 	.disable_vblank		= ingenic_drm_disable_vblank,
-
-	.gamma_set		= drm_atomic_helper_legacy_gamma_set,
 };
 
 static const struct drm_plane_helper_funcs ingenic_drm_plane_helper_funcs = {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/Kconfig linux-5.10.52-v7l+/drivers/gpu/drm/Kconfig
--- linux-5.10.52-orig/drivers/gpu/drm/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/Kconfig	2021-07-25 16:45:47.458601174 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:395 @
 
 source "drivers/gpu/drm/xlnx/Kconfig"
 
+source "drivers/gpu/drm/gud/Kconfig"
+
 # Keep legacy drivers last
 
 menuconfig DRM_LEGACY
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/Makefile linux-5.10.52-v7l+/drivers/gpu/drm/Makefile
--- linux-5.10.52-orig/drivers/gpu/drm/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/Makefile	2021-07-25 16:45:47.458601174 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:127 @
 obj-$(CONFIG_DRM_MCDE) += mcde/
 obj-$(CONFIG_DRM_TIDSS) += tidss/
 obj-y			+= xlnx/
+obj-y			+= gud/
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/mediatek/mtk_drm_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/mediatek/mtk_drm_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/mediatek/mtk_drm_crtc.c	2021-07-25 16:46:00.318385571 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:520 @
 }
 
 static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc,
-				       struct drm_crtc_state *old_state)
+				       struct drm_atomic_state *state)
 {
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
 	struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:545 @
 }
 
 static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc,
-					struct drm_crtc_state *old_state)
+					struct drm_atomic_state *state)
 {
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
 	struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:578 @
 }
 
 static void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_crtc_state)
+				      struct drm_atomic_state *state)
 {
-	struct mtk_crtc_state *state = to_mtk_crtc_state(crtc->state);
+	struct mtk_crtc_state *crtc_state = to_mtk_crtc_state(crtc->state);
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
 
-	if (mtk_crtc->event && state->base.event)
+	if (mtk_crtc->event && crtc_state->base.event)
 		DRM_ERROR("new event while there is still a pending event\n");
 
-	if (state->base.event) {
-		state->base.event->pipe = drm_crtc_index(crtc);
+	if (crtc_state->base.event) {
+		crtc_state->base.event->pipe = drm_crtc_index(crtc);
 		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
-		mtk_crtc->event = state->base.event;
-		state->base.event = NULL;
+		mtk_crtc->event = crtc_state->base.event;
+		crtc_state->base.event = NULL;
 	}
 }
 
 static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_crtc_state)
+				      struct drm_atomic_state *state)
 {
 	struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
 	int i;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:617 @
 	.reset			= mtk_drm_crtc_reset,
 	.atomic_duplicate_state	= mtk_drm_crtc_duplicate_state,
 	.atomic_destroy_state	= mtk_drm_crtc_destroy_state,
-	.gamma_set		= drm_atomic_helper_legacy_gamma_set,
 	.enable_vblank		= mtk_drm_crtc_enable_vblank,
 	.disable_vblank		= mtk_drm_crtc_disable_vblank,
 };
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/meson/meson_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/meson/meson_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/meson/meson_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/meson/meson_crtc.c	2021-07-25 16:46:00.318385571 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:85 @
 };
 
 static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc,
-					  struct drm_crtc_state *old_state)
+					  struct drm_atomic_state *state)
 {
 	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
 	struct drm_crtc_state *crtc_state = crtc->state;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:121 @
 }
 
 static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
 	struct drm_crtc_state *crtc_state = crtc->state;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:149 @
 }
 
 static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc,
-					   struct drm_crtc_state *old_state)
+					   struct drm_atomic_state *state)
 {
 	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
 	struct meson_drm *priv = meson_crtc->priv;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:174 @
 }
 
 static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_state)
+				      struct drm_atomic_state *state)
 {
 	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
 	struct meson_drm *priv = meson_crtc->priv;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:204 @
 }
 
 static void meson_crtc_atomic_begin(struct drm_crtc *crtc,
-				    struct drm_crtc_state *state)
+				    struct drm_atomic_state *state)
 {
 	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
 	unsigned long flags;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:220 @
 }
 
 static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_crtc_state)
+				    struct drm_atomic_state *state)
 {
 	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
 	struct meson_drm *priv = meson_crtc->priv;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c	2021-07-25 16:46:00.378384565 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:14 @
 #include <linux/ktime.h>
 #include <linux/bits.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_flip_work.h>
 #include <drm/drm_mode.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:489 @
 }
 
 static void dpu_crtc_atomic_begin(struct drm_crtc *crtc,
-		struct drm_crtc_state *old_state)
+		struct drm_atomic_state *state)
 {
 	struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
 	struct drm_encoder *encoder;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:530 @
 }
 
 static void dpu_crtc_atomic_flush(struct drm_crtc *crtc,
-		struct drm_crtc_state *old_crtc_state)
+		struct drm_atomic_state *state)
 {
 	struct dpu_crtc *dpu_crtc;
 	struct drm_device *dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:710 @
 }
 
 static void dpu_crtc_disable(struct drm_crtc *crtc,
-			     struct drm_crtc_state *old_crtc_state)
+			     struct drm_atomic_state *state)
 {
 	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
 	struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct drm_encoder *encoder;
 	unsigned long flags;
 	bool release_bandwidth = false;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:776 @
 }
 
 static void dpu_crtc_enable(struct drm_crtc *crtc,
-		struct drm_crtc_state *old_crtc_state)
+		struct drm_atomic_state *state)
 {
 	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
 	struct drm_encoder *encoder;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:818 @
 };
 
 static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
-		struct drm_crtc_state *state)
+		struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
-	struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
+	struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc_state);
 	struct plane_state *pstates;
 
 	const struct drm_plane_state *pstate;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:840 @
 
 	pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL);
 
-	if (!state->enable || !state->active) {
+	if (!crtc_state->enable || !crtc_state->active) {
 		DPU_DEBUG("crtc%d -> enable %d, active %d, skip atomic_check\n",
-				crtc->base.id, state->enable, state->active);
+				crtc->base.id, crtc_state->enable,
+				crtc_state->active);
 		goto end;
 	}
 
-	mode = &state->adjusted_mode;
+	mode = &crtc_state->adjusted_mode;
 	DPU_DEBUG("%s: check", dpu_crtc->name);
 
 	/* force a full mode set if active state changed */
-	if (state->active_changed)
-		state->mode_changed = true;
+	if (crtc_state->active_changed)
+		crtc_state->mode_changed = true;
 
 	memset(pipe_staged, 0, sizeof(pipe_staged));
 
 	if (cstate->num_mixers) {
 		mixer_width = mode->hdisplay / cstate->num_mixers;
 
-		_dpu_crtc_setup_lm_bounds(crtc, state);
+		_dpu_crtc_setup_lm_bounds(crtc, crtc_state);
 	}
 
 	crtc_rect.x2 = mode->hdisplay;
 	crtc_rect.y2 = mode->vdisplay;
 
 	 /* get plane state for all drm planes associated with crtc state */
-	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
+	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
 		struct drm_rect dst, clip = crtc_rect;
 
 		if (IS_ERR_OR_NULL(pstate)) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:972 @
 
 	atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref);
 
-	rc = dpu_core_perf_crtc_check(crtc, state);
+	rc = dpu_core_perf_crtc_check(crtc, crtc_state);
 	if (rc) {
 		DPU_ERROR("crtc%d failed performance check %d\n",
 				crtc->base.id, rc);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c	2021-07-25 16:46:00.408384062 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:267 @
 }
 
 static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
 	struct mdp4_kms *mdp4_kms = get_kms(crtc);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:287 @
 }
 
 static void mdp4_crtc_atomic_enable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
 	struct mdp4_kms *mdp4_kms = get_kms(crtc);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:310 @
 }
 
 static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
-		struct drm_crtc_state *state)
+		struct drm_atomic_state *state)
 {
 	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
 	DBG("%s: check", mdp4_crtc->name);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:319 @
 }
 
 static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
 	DBG("%s: begin", mdp4_crtc->name);
 }
 
 static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c	2021-07-25 16:46:00.408384062 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:10 @
 
 #include <linux/sort.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_mode.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_flip_work.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:487 @
 }
 
 static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
 	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:533 @
 }
 
 static void mdp5_crtc_atomic_enable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
 	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:686 @
 }
 
 static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
-		struct drm_crtc_state *state)
+		struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct mdp5_kms *mdp5_kms = get_kms(crtc);
 	struct drm_plane *plane;
 	struct drm_device *dev = crtc->dev;
 	struct plane_state pstates[STAGE_MAX + 1];
 	const struct mdp5_cfg_hw *hw_cfg;
 	const struct drm_plane_state *pstate;
-	const struct drm_display_mode *mode = &state->adjusted_mode;
+	const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
 	bool cursor_plane = false;
 	bool need_right_mixer = false;
 	int cnt = 0, i;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:705 @
 
 	DBG("%s: check", crtc->name);
 
-	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
+	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
 		if (!pstate->visible)
 			continue;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:737 @
 	if (mode->hdisplay > hw_cfg->lm.max_width)
 		need_right_mixer = true;
 
-	ret = mdp5_crtc_setup_pipeline(crtc, state, need_right_mixer);
+	ret = mdp5_crtc_setup_pipeline(crtc, crtc_state, need_right_mixer);
 	if (ret) {
 		DRM_DEV_ERROR(dev->dev, "couldn't assign mixers %d\n", ret);
 		return ret;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:750 @
 	WARN_ON(cursor_plane &&
 		(pstates[cnt - 1].plane->type != DRM_PLANE_TYPE_CURSOR));
 
-	start = get_start_stage(crtc, state, &pstates[0].state->base);
+	start = get_start_stage(crtc, crtc_state, &pstates[0].state->base);
 
 	/* verify that there are not too many planes attached to crtc
 	 * and that we don't have conflicting mixer stages:
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:775 @
 }
 
 static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	DBG("%s: begin", crtc->name);
 }
 
 static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
 	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/mxsfb/mxsfb_kms.c linux-5.10.52-v7l+/drivers/gpu/drm/mxsfb/mxsfb_kms.c
--- linux-5.10.52-orig/drivers/gpu/drm/mxsfb/mxsfb_kms.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/mxsfb/mxsfb_kms.c	2021-07-25 16:46:00.468383056 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:273 @
 }
 
 static int mxsfb_crtc_atomic_check(struct drm_crtc *crtc,
-				   struct drm_crtc_state *state)
+				   struct drm_atomic_state *state)
 {
-	bool has_primary = state->plane_mask &
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+	bool has_primary = crtc_state->plane_mask &
 			   drm_plane_mask(crtc->primary);
 
 	/* The primary plane has to be enabled when the CRTC is active. */
-	if (state->active && !has_primary)
+	if (crtc_state->active && !has_primary)
 		return -EINVAL;
 
 	/* TODO: Is this needed ? */
-	return drm_atomic_add_affected_planes(state->state, crtc);
+	return drm_atomic_add_affected_planes(state, crtc);
 }
 
 static void mxsfb_crtc_atomic_flush(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	struct drm_pending_vblank_event *event;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:308 @
 }
 
 static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
 	struct drm_device *drm = mxsfb->drm;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:332 @
 }
 
 static void mxsfb_crtc_atomic_disable(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_state)
+				      struct drm_atomic_state *state)
 {
 	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
 	struct drm_device *drm = mxsfb->drm;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/nouveau/dispnv50/disp.c linux-5.10.52-v7l+/drivers/gpu/drm/nouveau/dispnv50/disp.c
--- linux-5.10.52-orig/drivers/gpu/drm/nouveau/dispnv50/disp.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/nouveau/dispnv50/disp.c	2021-07-25 16:46:00.498382553 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:35 @
 #include <linux/hdmi.h>
 #include <linux/component.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_edid.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1165 @
 
 static struct drm_encoder *
 nv50_mstc_atomic_best_encoder(struct drm_connector *connector,
-			      struct drm_connector_state *connector_state)
+			      struct drm_atomic_state *state)
 {
+	struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state,
+											 connector);
 	struct nv50_mstc *mstc = nv50_mstc(connector);
 	struct drm_crtc *crtc = connector_state->crtc;
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/nouveau/dispnv50/head.c linux-5.10.52-v7l+/drivers/gpu/drm/nouveau/dispnv50/head.c
--- linux-5.10.52-orig/drivers/gpu/drm/nouveau/dispnv50/head.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/nouveau/dispnv50/head.c	2021-07-25 16:46:00.498382553 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:33 @
 #include <nvif/event.h>
 #include <nvif/cl0046.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_vblank.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:314 @
 }
 
 static int
-nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
+nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct nouveau_drm *drm = nouveau_drm(crtc->dev);
 	struct nv50_head *head = nv50_head(crtc);
 	struct nv50_head_atom *armh = nv50_head_atom(crtc->state);
-	struct nv50_head_atom *asyh = nv50_head_atom(state);
+	struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
 	struct nouveau_conn_atom *asyc = NULL;
 	struct drm_connector_state *conns;
 	struct drm_connector *conn;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:504 @
 static const struct drm_crtc_funcs
 nv50_head_func = {
 	.reset = nv50_head_reset,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 	.destroy = nv50_head_destroy,
 	.set_config = drm_atomic_helper_set_config,
 	.page_flip = drm_atomic_helper_page_flip,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:518 @
 static const struct drm_crtc_funcs
 nvd9_head_func = {
 	.reset = nv50_head_reset,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 	.destroy = nv50_head_destroy,
 	.set_config = drm_atomic_helper_set_config,
 	.page_flip = drm_atomic_helper_page_flip,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/omapdrm/omap_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/omapdrm/omap_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/omapdrm/omap_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/omapdrm/omap_crtc.c	2021-07-25 16:46:01.408367297 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:439 @
 }
 
 static void omap_crtc_atomic_enable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	struct omap_drm_private *priv = crtc->dev->dev_private;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:465 @
 }
 
 static void omap_crtc_atomic_disable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	struct omap_drm_private *priv = crtc->dev->dev_private;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:572 @
 }
 
 static int omap_crtc_atomic_check(struct drm_crtc *crtc,
-				struct drm_crtc_state *state)
+				struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct drm_plane_state *pri_state;
 
-	if (state->color_mgmt_changed && state->gamma_lut) {
-		unsigned int length = state->gamma_lut->length /
+	if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) {
+		unsigned int length = crtc_state->gamma_lut->length /
 			sizeof(struct drm_color_lut);
 
 		if (length < 2)
 			return -EINVAL;
 	}
 
-	pri_state = drm_atomic_get_new_plane_state(state->state, crtc->primary);
+	pri_state = drm_atomic_get_new_plane_state(state,
+						   crtc->primary);
 	if (pri_state) {
 		struct omap_crtc_state *omap_crtc_state =
-			to_omap_crtc_state(state);
+			to_omap_crtc_state(crtc_state);
 
 		/* Mirror new values for zpos and rotation in omap_crtc_state */
 		omap_crtc_state->zpos = pri_state->zpos;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:604 @
 }
 
 static void omap_crtc_atomic_begin(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 }
 
 static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	struct omap_drm_private *priv = crtc->dev->dev_private;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:744 @
 	.set_config = drm_atomic_helper_set_config,
 	.destroy = omap_crtc_destroy,
 	.page_flip = drm_atomic_helper_page_flip,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 	.atomic_duplicate_state = omap_crtc_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 	.atomic_set_property = omap_crtc_atomic_set_property,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c linux-5.10.52-v7l+/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
--- linux-5.10.52-orig/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c	2021-07-25 16:46:01.418367129 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:208 @
 	if (ret < 0)
 		dev_err(dev, "regulator disable failed, %d\n", ret);
 
-	gpiod_set_value(jdi->enable_gpio, 0);
+	gpiod_set_value_cansleep(jdi->enable_gpio, 0);
 
-	gpiod_set_value(jdi->reset_gpio, 1);
+	gpiod_set_value_cansleep(jdi->reset_gpio, 1);
 
-	gpiod_set_value(jdi->dcdc_en_gpio, 0);
+	gpiod_set_value_cansleep(jdi->dcdc_en_gpio, 0);
 
 	jdi->prepared = false;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:236 @
 
 	msleep(20);
 
-	gpiod_set_value(jdi->dcdc_en_gpio, 1);
+	gpiod_set_value_cansleep(jdi->dcdc_en_gpio, 1);
 	usleep_range(10, 20);
 
-	gpiod_set_value(jdi->reset_gpio, 0);
+	gpiod_set_value_cansleep(jdi->reset_gpio, 0);
 	usleep_range(10, 20);
 
-	gpiod_set_value(jdi->enable_gpio, 1);
+	gpiod_set_value_cansleep(jdi->enable_gpio, 1);
 	usleep_range(10, 20);
 
 	ret = jdi_panel_init(jdi);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:266 @
 	if (ret < 0)
 		dev_err(dev, "regulator disable failed, %d\n", ret);
 
-	gpiod_set_value(jdi->enable_gpio, 0);
+	gpiod_set_value_cansleep(jdi->enable_gpio, 0);
 
-	gpiod_set_value(jdi->reset_gpio, 1);
+	gpiod_set_value_cansleep(jdi->reset_gpio, 1);
 
-	gpiod_set_value(jdi->dcdc_en_gpio, 0);
+	gpiod_set_value_cansleep(jdi->dcdc_en_gpio, 0);
 
 	return ret;
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c linux-5.10.52-v7l+/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
--- linux-5.10.52-orig/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c	2021-07-25 16:46:01.428366962 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:222 @
 
 static int rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg)
 {
-	return i2c_smbus_read_byte_data(ts->i2c, reg);
+	struct i2c_client *client = ts->i2c;
+	struct i2c_msg msgs[1];
+	u8 addr_buf[1] = { reg };
+	u8 data_buf[1] = { 0, };
+	int ret;
+
+	/* Write register address */
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = ARRAY_SIZE(addr_buf);
+	msgs[0].buf = addr_buf;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	usleep_range(100, 300);
+
+	/* Read data from register */
+	msgs[0].addr = client->addr;
+	msgs[0].flags = I2C_M_RD;
+	msgs[0].len = 1;
+	msgs[0].buf = data_buf;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	return data_buf[0];
 }
 
 static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:302 @
 	int i;
 
 	rpi_touchscreen_i2c_write(ts, REG_POWERON, 1);
+	usleep_range(20000, 25000);
 	/* Wait for nPWRDWN to go low to indicate poweron is done. */
 	for (i = 0; i < 100; i++) {
 		if (rpi_touchscreen_i2c_read(ts, REG_PORTB) & 1)
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/panel/panel-simple.c linux-5.10.52-v7l+/drivers/gpu/drm/panel/panel-simple.c
--- linux-5.10.52-orig/drivers/gpu/drm/panel/panel-simple.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/panel/panel-simple.c	2021-07-25 16:46:01.428366962 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2096 @
 	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
 };
 
+static const struct display_timing innolux_at056tn53v1_timing = {
+	.pixelclock = { 39700000, 39700000, 39700000},
+	.hactive = { 640, 640, 640 },
+	.hfront_porch = { 16, 16, 16 },
+	.hback_porch = { 134, 134, 134 },
+	.hsync_len = { 10, 10, 10},
+	.vactive = { 480, 480, 480 },
+	.vfront_porch = { 32, 32, 32},
+	.vback_porch = { 11, 11, 11 },
+	.vsync_len = { 2, 2, 2 },
+	.flags = DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_PHSYNC,
+};
+
+static const struct panel_desc innolux_at056tn53v1 = {
+	.timings = &innolux_at056tn53v1_timing,
+	.num_timings = 1,
+	.bpc = 6,
+	.size = {
+		.width = 112,
+		.height = 84,
+	},
+	.delay = {
+		.prepare = 50,
+		.enable = 200,
+		.disable = 110,
+		.unprepare = 200,
+	},
+	.bus_format = MEDIA_BUS_FMT_BGR666_1X24_CPADHI,
+	.bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE,
+	.connector_type = DRM_MODE_CONNECTOR_DPI,
+};
+
 static const struct drm_display_mode innolux_at070tn92_mode = {
 	.clock = 33333,
 	.hdisplay = 800,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4111 @
 		.compatible = "innolux,at043tn24",
 		.data = &innolux_at043tn24,
 	}, {
+		.compatible = "innolux,at056tn53v1",
+		.data = &innolux_at056tn53v1,
+	}, {
 		.compatible = "innolux,at070tn92",
 		.data = &innolux_at070tn92,
 	}, {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/qxl/qxl_display.c linux-5.10.52-v7l+/drivers/gpu/drm/qxl/qxl_display.c
--- linux-5.10.52-orig/drivers/gpu/drm/qxl/qxl_display.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/qxl/qxl_display.c	2021-07-25 16:46:01.448366626 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:376 @
 }
 
 static void qxl_crtc_atomic_flush(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_crtc_state)
+				  struct drm_atomic_state *state)
 {
 	qxl_crtc_update_monitors_config(crtc, "flush");
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:448 @
 };
 
 static void qxl_crtc_atomic_enable(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_state)
+				   struct drm_atomic_state *state)
 {
 	qxl_crtc_update_monitors_config(crtc, "enable");
 }
 
 static void qxl_crtc_atomic_disable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	qxl_crtc_update_monitors_config(crtc, "disable");
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/rcar-du/rcar_du_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/rcar-du/rcar_du_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/rcar-du/rcar_du_crtc.c	2021-07-25 16:46:01.568364614 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:685 @
  */
 
 static int rcar_du_crtc_atomic_check(struct drm_crtc *crtc,
-				     struct drm_crtc_state *state)
+				     struct drm_atomic_state *state)
 {
-	struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(state);
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+	struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(crtc_state);
 	struct drm_encoder *encoder;
 	int ret;
 
-	ret = rcar_du_cmm_check(crtc, state);
+	ret = rcar_du_cmm_check(crtc, crtc_state);
 	if (ret)
 		return ret;
 
 	/* Store the routes from the CRTC output to the DU outputs. */
 	rstate->outputs = 0;
 
-	drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask) {
+	drm_for_each_encoder_mask(encoder, crtc->dev,
+				  crtc_state->encoder_mask) {
 		struct rcar_du_encoder *renc;
 
 		/* Skip the writeback encoder. */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:716 @
 }
 
 static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
-				       struct drm_crtc_state *old_state)
+				       struct drm_atomic_state *state)
 {
 	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 	struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(crtc->state);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:751 @
 }
 
 static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc,
-					struct drm_crtc_state *old_state)
+					struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
 	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 	struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(old_state);
 	struct rcar_du_device *rcdu = rcrtc->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:782 @
 }
 
 static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_crtc_state)
+				      struct drm_atomic_state *state)
 {
 	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:811 @
 }
 
 static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_crtc_state)
+				      struct drm_atomic_state *state)
 {
 	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 	struct drm_device *dev = rcrtc->crtc.dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1141 @
 	.set_crc_source = rcar_du_crtc_set_crc_source,
 	.verify_crc_source = rcar_du_crtc_verify_crc_source,
 	.get_crc_sources = rcar_du_crtc_get_crc_sources,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 };
 
 /* -----------------------------------------------------------------------------
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/rockchip/rockchip_drm_vop.c linux-5.10.52-v7l+/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
--- linux-5.10.52-orig/drivers/gpu/drm/rockchip/rockchip_drm_vop.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/rockchip/rockchip_drm_vop.c	2021-07-25 16:46:01.578364447 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:696 @
 }
 
 static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	struct vop *vop = to_vop(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1250 @
 }
 
 static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_crtc_state)
+				  struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct vop *vop = to_vop(crtc);
 
 	/*
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1266 @
 }
 
 static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_state)
+				   struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
 	struct vop *vop = to_vop(crtc);
 	const struct vop_data *vop_data = vop->data;
 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1421 @
 }
 
 static int vop_crtc_atomic_check(struct drm_crtc *crtc,
-				 struct drm_crtc_state *crtc_state)
+				 struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct vop *vop = to_vop(crtc);
 	struct drm_plane *plane;
 	struct drm_plane_state *plane_state;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1468 @
 }
 
 static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_crtc_state)
+				  struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct drm_atomic_state *old_state = old_crtc_state->state;
 	struct drm_plane_state *old_plane_state, *new_plane_state;
 	struct vop *vop = to_vop(crtc);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1645 @
 	.disable_vblank = vop_crtc_disable_vblank,
 	.set_crc_source = vop_crtc_set_crc_source,
 	.verify_crc_source = vop_crtc_verify_crc_source,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 };
 
 static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/sti/sti_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/sti/sti_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/sti/sti_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/sti/sti_crtc.c	2021-07-25 16:46:01.588364279 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:26 @
 #include "sti_vtg.h"
 
 static void sti_crtc_atomic_enable(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_state)
+				   struct drm_atomic_state *state)
 {
 	struct sti_mixer *mixer = to_sti_mixer(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:38 @
 }
 
 static void sti_crtc_atomic_disable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	struct sti_mixer *mixer = to_sti_mixer(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:136 @
 }
 
 static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_crtc_state)
+				  struct drm_atomic_state *state)
 {
 	struct drm_device *drm_dev = crtc->dev;
 	struct sti_mixer *mixer = to_sti_mixer(crtc);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/stm/ltdc.c linux-5.10.52-v7l+/drivers/gpu/drm/stm/ltdc.c
--- linux-5.10.52-orig/drivers/gpu/drm/stm/ltdc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/stm/ltdc.c	2021-07-25 16:46:01.598364111 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:423 @
 }
 
 static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
 	struct drm_device *ddev = crtc->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:445 @
 }
 
 static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
 	struct drm_device *ddev = crtc->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:628 @
 }
 
 static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
 	struct drm_device *ddev = crtc->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:745 @
 	.enable_vblank = ltdc_crtc_enable_vblank,
 	.disable_vblank = ltdc_crtc_disable_vblank,
 	.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 };
 
 /*
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/sun4i/sun4i_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/sun4i/sun4i_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/sun4i/sun4i_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/sun4i/sun4i_crtc.c	2021-07-25 16:46:01.598364111 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:18 @
 
 #include <video/videomode.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_modes.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:49 @
 }
 
 static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
-				    struct drm_crtc_state *state)
+				    struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
 	struct sunxi_engine *engine = scrtc->engine;
 	int ret = 0;
 
 	if (engine && engine->ops && engine->ops->atomic_check)
-		ret = engine->ops->atomic_check(engine, state);
+		ret = engine->ops->atomic_check(engine, crtc_state);
 
 	return ret;
 }
 
 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct sunxi_engine *engine = scrtc->engine;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:87 @
 }
 
 static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
 	struct drm_pending_vblank_event *event = crtc->state->event;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:109 @
 }
 
 static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_state)
+				      struct drm_atomic_state *state)
 {
 	struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:130 @
 }
 
 static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/tegra/dc.c linux-5.10.52-v7l+/drivers/gpu/drm/tegra/dc.c
--- linux-5.10.52-orig/drivers/gpu/drm/tegra/dc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/tegra/dc.c	2021-07-25 16:46:01.628363609 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1751 @
 }
 
 static void tegra_crtc_atomic_disable(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_state)
+				      struct drm_atomic_state *state)
 {
 	struct tegra_dc *dc = to_tegra_dc(crtc);
 	u32 value;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1808 @
 }
 
 static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
-	struct tegra_dc_state *state = to_dc_state(crtc->state);
+	struct tegra_dc_state *crtc_state = to_dc_state(crtc->state);
 	struct tegra_dc *dc = to_tegra_dc(crtc);
 	u32 value;
 	int err;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1891 @
 		tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
 
 	/* apply PLL and pixel clock changes */
-	tegra_dc_commit_state(dc, state);
+	tegra_dc_commit_state(dc, crtc_state);
 
 	/* program display mode */
 	tegra_dc_set_timings(dc, mode);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1927 @
 }
 
 static void tegra_crtc_atomic_begin(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_crtc_state)
+				    struct drm_atomic_state *state)
 {
 	unsigned long flags;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1946 @
 }
 
 static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_crtc_state)
+				    struct drm_atomic_state *state)
 {
-	struct tegra_dc_state *state = to_dc_state(crtc->state);
+	struct tegra_dc_state *crtc_state = to_dc_state(crtc->state);
 	struct tegra_dc *dc = to_tegra_dc(crtc);
 	u32 value;
 
-	value = state->planes << 8 | GENERAL_UPDATE;
+	value = crtc_state->planes << 8 | GENERAL_UPDATE;
 	tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
 	value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
 
-	value = state->planes | GENERAL_ACT_REQ;
+	value = crtc_state->planes | GENERAL_ACT_REQ;
 	tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
 	value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/tidss/tidss_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/tidss/tidss_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/tidss/tidss_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/tidss/tidss_crtc.c	2021-07-25 16:46:01.648363273 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:88 @
 /* drm_crtc_helper_funcs */
 
 static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
-				   struct drm_crtc_state *state)
+				   struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	struct drm_device *ddev = crtc->dev;
 	struct tidss_device *tidss = to_tidss(ddev);
 	struct dispc_device *dispc = tidss->dispc;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:102 @
 
 	dev_dbg(ddev->dev, "%s\n", __func__);
 
-	if (!state->enable)
+	if (!crtc_state->enable)
 		return 0;
 
-	mode = &state->adjusted_mode;
+	mode = &crtc_state->adjusted_mode;
 
 	ok = dispc_vp_mode_valid(dispc, hw_videoport, mode);
 	if (ok != MODE_OK) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:114 @
 		return -EINVAL;
 	}
 
-	return dispc_vp_bus_check(dispc, hw_videoport, state);
+	return dispc_vp_bus_check(dispc, hw_videoport, crtc_state);
 }
 
 /*
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:166 @
 }
 
 static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_crtc_state)
+				    struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 	struct drm_device *ddev = crtc->dev;
 	struct tidss_device *tidss = to_tidss(ddev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:219 @
 }
 
 static void tidss_crtc_atomic_enable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
 	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 	struct drm_device *ddev = crtc->dev;
 	struct tidss_device *tidss = to_tidss(ddev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:264 @
 }
 
 static void tidss_crtc_atomic_disable(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_state)
+				      struct drm_atomic_state *state)
 {
 	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 	struct drm_device *ddev = crtc->dev;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/tilcdc/tilcdc_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/tilcdc/tilcdc_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/tilcdc/tilcdc_crtc.c	2021-07-25 16:46:01.658363106 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:487 @
 }
 
 static void tilcdc_crtc_atomic_enable(struct drm_crtc *crtc,
-				      struct drm_crtc_state *old_state)
+				      struct drm_atomic_state *state)
 {
 	tilcdc_crtc_enable(crtc);
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:544 @
 }
 
 static void tilcdc_crtc_atomic_disable(struct drm_crtc *crtc,
-				       struct drm_crtc_state *old_state)
+				       struct drm_atomic_state *state)
 {
 	tilcdc_crtc_disable(crtc);
 }
 
 static void tilcdc_crtc_atomic_flush(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	if (!crtc->state->event)
 		return;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:672 @
 }
 
 static int tilcdc_crtc_atomic_check(struct drm_crtc *crtc,
-				    struct drm_crtc_state *state)
+				    struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
 	/* If we are not active we don't care */
-	if (!state->active)
+	if (!crtc_state->active)
 		return 0;
 
-	if (state->state->planes[0].ptr != crtc->primary ||
-	    state->state->planes[0].state == NULL ||
-	    state->state->planes[0].state->crtc != crtc) {
+	if (state->planes[0].ptr != crtc->primary ||
+	    state->planes[0].state == NULL ||
+	    state->planes[0].state->crtc != crtc) {
 		dev_dbg(crtc->dev->dev, "CRTC primary plane must be present");
 		return -EINVAL;
 	}
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/v3d/Kconfig linux-5.10.52-v7l+/drivers/gpu/drm/v3d/Kconfig
--- linux-5.10.52-orig/drivers/gpu/drm/v3d/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/v3d/Kconfig	2021-07-25 16:46:01.678362770 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
 # SPDX-License-Identifier: GPL-2.0-only
 config DRM_V3D
 	tristate "Broadcom V3D 3.x and newer"
-	depends on ARCH_BCM || ARCH_BCMSTB || COMPILE_TEST
+	depends on ARCH_BCM || ARCH_BCMSTB || ARCH_BCM2835 || COMPILE_TEST
 	depends on DRM
 	depends on COMMON_CLK
 	depends on MMU
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_debugfs.c linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_debugfs.c
--- linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_debugfs.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_debugfs.c	2021-07-25 16:46:01.678362770 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:7 @
 #include <linux/circ_buf.h>
 #include <linux/ctype.h>
 #include <linux/debugfs.h>
-#include <linux/pm_runtime.h>
 #include <linux/seq_file.h>
 
 #include <drm/drm_debugfs.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:132 @
 	struct drm_device *dev = node->minor->dev;
 	struct v3d_dev *v3d = to_v3d_dev(dev);
 	u32 ident0, ident1, ident2, ident3, cores;
-	int ret, core;
+	int core;
 
-	ret = pm_runtime_get_sync(v3d->drm.dev);
-	if (ret < 0)
-		return ret;
 
 	ident0 = V3D_READ(V3D_HUB_IDENT0);
 	ident1 = V3D_READ(V3D_HUB_IDENT1);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:186 @
 			   (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
 	}
 
-	pm_runtime_mark_last_busy(v3d->drm.dev);
-	pm_runtime_put_autosuspend(v3d->drm.dev);
-
 	return 0;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:213 @
 	uint32_t cycles;
 	int core = 0;
 	int measure_ms = 1000;
-	int ret;
-
-	ret = pm_runtime_get_sync(v3d->drm.dev);
-	if (ret < 0)
-		return ret;
 
 	if (v3d->ver >= 40) {
 		V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:236 @
 		   cycles / (measure_ms * 1000),
 		   (cycles / (measure_ms * 100)) % 10);
 
-	pm_runtime_mark_last_busy(v3d->drm.dev);
-	pm_runtime_put_autosuspend(v3d->drm.dev);
 
 	return 0;
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_drv.c linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_drv.c
--- linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_drv.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_drv.c	2021-07-25 16:46:01.678362770 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:73 @
 }
 #endif
 
-static const struct dev_pm_ops v3d_v3d_pm_ops = {
+static const struct dev_pm_ops v3d_pm_ops = {
 	SET_RUNTIME_PM_OPS(v3d_runtime_suspend, v3d_runtime_resume, NULL)
 };
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:82 @
 {
 	struct v3d_dev *v3d = to_v3d_dev(dev);
 	struct drm_v3d_get_param *args = data;
-	int ret;
 	static const u32 reg_map[] = {
 		[DRM_V3D_PARAM_V3D_UIFCFG] = V3D_HUB_UIFCFG,
 		[DRM_V3D_PARAM_V3D_HUB_IDENT1] = V3D_HUB_IDENT1,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:107 @
 		if (args->value != 0)
 			return -EINVAL;
 
-		ret = pm_runtime_get_sync(v3d->drm.dev);
-		if (ret < 0)
-			return ret;
 		if (args->param >= DRM_V3D_PARAM_V3D_CORE0_IDENT0 &&
 		    args->param <= DRM_V3D_PARAM_V3D_CORE0_IDENT2) {
 			args->value = V3D_CORE_READ(0, offset);
 		} else {
 			args->value = V3D_READ(offset);
 		}
-		pm_runtime_mark_last_busy(v3d->drm.dev);
-		pm_runtime_put_autosuspend(v3d->drm.dev);
 		return 0;
 	}
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:224 @
 static const struct of_device_id v3d_of_match[] = {
 	{ .compatible = "brcm,7268-v3d" },
 	{ .compatible = "brcm,7278-v3d" },
+	{ .compatible = "brcm,2711-v3d" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, v3d_of_match);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:266 @
 		return ret;
 
 	mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO);
-	dev->coherent_dma_mask =
-		DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH));
+	dma_set_mask_and_coherent(dev,
+		DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)));
 	v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH);
 
 	ident1 = V3D_READ(V3D_HUB_IDENT1);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:292 @
 		}
 	}
 
+	v3d->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR_OR_NULL(v3d->clk)) {
+		if (PTR_ERR(v3d->clk) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk));
+		return PTR_ERR(v3d->clk);
+	}
+	v3d->clk_up_rate = clk_get_rate(v3d->clk);
+	/* For downclocking, drop it to the minimum frequency we can get from
+	 * the CPRMAN clock generator dividing off our parent.  The divider is
+	 * 4 bits, but ask for just higher than that so that rounding doesn't
+	 * make cprman reject our rate.
+	 */
+	v3d->clk_down_rate =
+		(clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
+
 	if (v3d->ver < 41) {
 		ret = map_regs(v3d, &v3d->gca_regs, "gca");
 		if (ret)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:320 @
 		return -ENOMEM;
 	}
 
-	pm_runtime_use_autosuspend(dev);
-	pm_runtime_set_autosuspend_delay(dev, 50);
-	pm_runtime_enable(dev);
 
 	ret = v3d_gem_init(drm);
 	if (ret)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:333 @
 	if (ret)
 		goto irq_disable;
 
+	ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
+	WARN_ON_ONCE(ret != 0);
+
 	return 0;
 
 irq_disable:
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:368 @
 	.driver		= {
 		.name	= "v3d",
 		.of_match_table = v3d_of_match,
+		.pm = &v3d_pm_ops,
 	},
 };
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_drv.h linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_drv.h
--- linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_drv.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_drv.h	2021-07-25 16:46:01.678362770 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:54 @
 	void __iomem *bridge_regs;
 	void __iomem *gca_regs;
 	struct clk *clk;
+	struct delayed_work clk_down_work;
+	unsigned long clk_up_rate, clk_down_rate;
+	struct mutex clk_lock;
+	u32 clk_refcount;
+	bool clk_up;
+
 	struct reset_control *reset;
 
 	/* Virtual and DMA addresses of the single shared page table. */
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_gem.c linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_gem.c
--- linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_gem.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_gem.c	2021-07-25 16:46:01.678362770 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:7 @
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:23 @
 #include "v3d_trace.h"
 
 static void
+v3d_clock_down_work(struct work_struct *work)
+{
+	struct v3d_dev *v3d =
+		container_of(work, struct v3d_dev, clk_down_work.work);
+	int ret;
+
+	ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
+	v3d->clk_up = false;
+	WARN_ON_ONCE(ret != 0);
+}
+
+static void
+v3d_clock_up_get(struct v3d_dev *v3d)
+{
+	mutex_lock(&v3d->clk_lock);
+	if (v3d->clk_refcount++ == 0) {
+		cancel_delayed_work_sync(&v3d->clk_down_work);
+		if (!v3d->clk_up)  {
+			int ret;
+
+			ret = clk_set_rate(v3d->clk, v3d->clk_up_rate);
+			WARN_ON_ONCE(ret != 0);
+			v3d->clk_up = true;
+		}
+	}
+	mutex_unlock(&v3d->clk_lock);
+}
+
+static void
+v3d_clock_up_put(struct v3d_dev *v3d)
+{
+	mutex_lock(&v3d->clk_lock);
+	if (--v3d->clk_refcount == 0) {
+		schedule_delayed_work(&v3d->clk_down_work,
+				      msecs_to_jiffies(100));
+	}
+	mutex_unlock(&v3d->clk_lock);
+}
+
+
+static void
 v3d_init_core(struct v3d_dev *v3d, int core)
 {
 	/* Set OVRTMUOUT, which means that the texture sampler uniform
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:399 @
 	struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
 	unsigned long index;
 	struct dma_fence *fence;
+	struct v3d_dev *v3d = job->v3d;
 	int i;
 
 	for (i = 0; i < job->bo_count; i++) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:416 @
 	dma_fence_put(job->irq_fence);
 	dma_fence_put(job->done_fence);
 
-	pm_runtime_mark_last_busy(job->v3d->drm.dev);
-	pm_runtime_put_autosuspend(job->v3d->drm.dev);
+	v3d_clock_up_put(v3d);
 
 	kfree(job);
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:484 @
 	job->v3d = v3d;
 	job->free = free;
 
-	ret = pm_runtime_get_sync(v3d->drm.dev);
-	if (ret < 0)
-		return ret;
-
 	xa_init_flags(&job->deps, XA_FLAGS_ALLOC);
 
 	ret = drm_syncobj_find_fence(file_priv, in_sync, 0, 0, &in_fence);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:494 @
 	if (ret)
 		goto fail;
 
+	v3d_clock_up_get(v3d);
 	kref_init(&job->refcount);
 
 	return 0;
 fail:
 	xa_destroy(&job->deps);
-	pm_runtime_put_autosuspend(v3d->drm.dev);
 	return ret;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:920 @
 	mutex_init(&v3d->sched_lock);
 	mutex_init(&v3d->cache_clean_lock);
 
+	mutex_init(&v3d->clk_lock);
+	INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
+
+	/* kick the clock so firmware knows we are using firmware clock interface */
+	v3d_clock_up_get(v3d);
+	v3d_clock_up_put(v3d);
+
 	/* Note: We don't allocate address 0.  Various bits of HW
 	 * treat 0 as special, such as the occlusion query counters
 	 * where 0 means "disabled".
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_irq.c linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_irq.c
--- linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_irq.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_irq.c	2021-07-25 16:46:01.678362770 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:180 @
 			"GMP",
 		};
 		const char *client = "?";
+		static int logged_error;
 
-		V3D_WRITE(V3D_MMU_CTL,
-			  V3D_READ(V3D_MMU_CTL) & (V3D_MMU_CTL_CAP_EXCEEDED |
-						   V3D_MMU_CTL_PT_INVALID |
-						   V3D_MMU_CTL_WRITE_VIOLATION));
+		V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL));
 
 		if (v3d->ver >= 41) {
 			axi_id = axi_id >> 5;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:190 @
 				client = v3d41_axi_ids[axi_id];
 		}
 
+		if (!logged_error)
 		dev_err(v3d->drm.dev, "MMU error from client %s (%d) at 0x%llx%s%s%s\n",
 			client, axi_id, (long long)vio_addr,
 			((intsts & V3D_HUB_INT_MMU_WRV) ?
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:199 @
 			 ", pte invalid" : ""),
 			((intsts & V3D_HUB_INT_MMU_CAP) ?
 			 ", cap exceeded" : ""));
+		logged_error = 1;
 		status = IRQ_HANDLED;
 	}
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:220 @
 		V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
 	V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
 
-	irq1 = platform_get_irq(v3d_to_pdev(v3d), 1);
+	irq1 = platform_get_irq_optional(v3d_to_pdev(v3d), 1);
 	if (irq1 == -EPROBE_DEFER)
 		return irq1;
 	if (irq1 > 0) {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_mmu.c linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_mmu.c
--- linux-5.10.52-orig/drivers/gpu/drm/v3d/v3d_mmu.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/v3d/v3d_mmu.c	2021-07-25 16:46:01.678362770 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:21 @
  * each client.  This is not yet implemented.
  */
 
+#include <linux/pm_runtime.h>
+
 #include "v3d_drv.h"
 #include "v3d_regs.h"
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vboxvideo/vbox_mode.c linux-5.10.52-v7l+/drivers/gpu/drm/vboxvideo/vbox_mode.c
--- linux-5.10.52-orig/drivers/gpu/drm/vboxvideo/vbox_mode.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vboxvideo/vbox_mode.c	2021-07-25 16:46:01.688362603 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:216 @
 }
 
 static void vbox_crtc_atomic_enable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_crtc_state)
+				    struct drm_atomic_state *state)
 {
 }
 
 static void vbox_crtc_atomic_disable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_crtc_state)
+				     struct drm_atomic_state *state)
 {
 }
 
 static void vbox_crtc_atomic_flush(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 }
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/Kconfig linux-5.10.52-v7l+/drivers/gpu/drm/vc4/Kconfig
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/Kconfig	2021-07-25 16:46:01.688362603 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:15 @
 	select SND_PCM
 	select SND_PCM_ELD
 	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select SND_SOC_HDMI_CODEC
 	select DRM_MIPI_DSI
 	help
 	  Choose this option if you have a system that has a Broadcom
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/Makefile linux-5.10.52-v7l+/drivers/gpu/drm/vc4/Makefile
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/Makefile	2021-07-25 16:46:01.688362603 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:12 @
 	vc4_dpi.o \
 	vc4_dsi.o \
 	vc4_fence.o \
+	vc4_firmware_kms.o \
 	vc4_kms.o \
 	vc4_gem.o \
 	vc4_hdmi.o \
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_crtc.c	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:282 @
  * allows drivers to push pixels to more than one encoder from the
  * same CRTC.
  */
-static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc)
+struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
+					 struct drm_crtc_state *state)
 {
-	struct drm_connector *connector;
-	struct drm_connector_list_iter conn_iter;
+	struct drm_encoder *encoder;
 
-	drm_connector_list_iter_begin(crtc->dev, &conn_iter);
-	drm_for_each_connector_iter(connector, &conn_iter) {
-		if (connector->state->crtc == crtc) {
-			drm_connector_list_iter_end(&conn_iter);
-			return connector->encoder;
-		}
-	}
-	drm_connector_list_iter_end(&conn_iter);
+	WARN_ON(hweight32(state->encoder_mask) > 1);
+
+	drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask)
+		return encoder;
 
 	return NULL;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:304 @
 	CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_FIFO_CLR);
 }
 
-static void vc4_crtc_config_pv(struct drm_crtc *crtc)
+static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encoder,
+			       struct drm_atomic_state *state)
 {
 	struct drm_device *dev = crtc->dev;
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
-	struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
 	struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
 	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
 	const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
-	struct drm_crtc_state *state = crtc->state;
-	struct drm_display_mode *mode = &state->adjusted_mode;
+	struct drm_crtc_state *crtc_state = crtc->state;
+	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
 	bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
 	u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
 	bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
 		       vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
-	u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
+	bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1;
+	bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC;
+	u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
 	u8 ppc = pv_data->pixels_per_clock;
+
+	u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end;
+	u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start;
+	u16 vert_fp = mode->crtc_vsync_start - mode->crtc_vdisplay;
+
 	bool debug_dump_regs = false;
 
 	if (debug_dump_regs) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:350 @
 		   VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc,
 				 PV_HORZB_HACTIVE));
 
-	CRTC_WRITE(PV_VERTA,
-		   VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
-				 PV_VERTA_VBP) |
-		   VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
-				 PV_VERTA_VSYNC));
-	CRTC_WRITE(PV_VERTB,
-		   VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
-				 PV_VERTB_VFP) |
-		   VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
-
 	if (interlace) {
+		bool odd_field_first = false;
+		u32 field_delay = mode->htotal * pixel_rep / (2 * ppc);
+		u16 vert_bp_even = vert_bp;
+		u16 vert_fp_even = vert_fp;
+
+		if (is_vec) {
+			/* VEC (composite output) */
+			++field_delay;
+			if (mode->htotal == 858) {
+				/* 525-line mode (NTSC or PAL-M) */
+				odd_field_first = true;
+			}
+		}
+
+		if (odd_field_first)
+			++vert_fp_even;
+		else
+			++vert_bp;
+
 		CRTC_WRITE(PV_VERTA_EVEN,
-			   VC4_SET_FIELD(mode->crtc_vtotal -
-					 mode->crtc_vsync_end - 1,
-					 PV_VERTA_VBP) |
-			   VC4_SET_FIELD(mode->crtc_vsync_end -
-					 mode->crtc_vsync_start,
-					 PV_VERTA_VSYNC));
+			   VC4_SET_FIELD(vert_bp_even, PV_VERTA_VBP) |
+			   VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
 		CRTC_WRITE(PV_VERTB_EVEN,
-			   VC4_SET_FIELD(mode->crtc_vsync_start -
-					 mode->crtc_vdisplay,
-					 PV_VERTB_VFP) |
+			   VC4_SET_FIELD(vert_fp_even, PV_VERTB_VFP) |
 			   VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
 
-		/* We set up first field even mode for HDMI.  VEC's
-		 * NTSC mode would want first field odd instead, once
-		 * we support it (to do so, set ODD_FIRST and put the
-		 * delay in VSYNCD_EVEN instead).
+		/* We set up first field even mode for HDMI and VEC's PAL.
+		 * For NTSC, we need first field odd.
 		 */
 		CRTC_WRITE(PV_V_CONTROL,
 			   PV_VCONTROL_CONTINUOUS |
 			   (is_dsi ? PV_VCONTROL_DSI : 0) |
 			   PV_VCONTROL_INTERLACE |
-			   VC4_SET_FIELD(mode->htotal * pixel_rep / 2,
-					 PV_VCONTROL_ODD_DELAY));
-		CRTC_WRITE(PV_VSYNCD_EVEN, 0);
+			   (odd_field_first
+				   ? PV_VCONTROL_ODD_FIRST
+				   : VC4_SET_FIELD(field_delay,
+						   PV_VCONTROL_ODD_DELAY)));
+		CRTC_WRITE(PV_VSYNCD_EVEN,
+			   (odd_field_first ? field_delay : 0));
 	} else {
 		CRTC_WRITE(PV_V_CONTROL,
 			   PV_VCONTROL_CONTINUOUS |
 			   (is_dsi ? PV_VCONTROL_DSI : 0));
 	}
 
+	CRTC_WRITE(PV_VERTA,
+		   VC4_SET_FIELD(vert_bp, PV_VERTA_VBP) |
+		   VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
+	CRTC_WRITE(PV_VERTB,
+		   VC4_SET_FIELD(vert_fp, PV_VERTB_VFP) |
+		   VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
+
 	if (is_dsi)
 		CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:437 @
 		     SCALER_DISPCTRL_ENABLE);
 }
 
-static int vc4_crtc_disable(struct drm_crtc *crtc, unsigned int channel)
+static int vc4_crtc_disable(struct drm_crtc *crtc,
+			    struct drm_encoder *encoder,
+			    struct drm_atomic_state *state,
+			    unsigned int channel)
 {
-	struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
 	struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
 	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:471 @
 	mdelay(20);
 
 	if (vc4_encoder && vc4_encoder->post_crtc_disable)
-		vc4_encoder->post_crtc_disable(encoder);
+		vc4_encoder->post_crtc_disable(encoder, state);
 
 	vc4_crtc_pixelvalve_reset(crtc);
 	vc4_hvs_stop_channel(dev, channel);
 
 	if (vc4_encoder && vc4_encoder->post_crtc_powerdown)
-		vc4_encoder->post_crtc_powerdown(encoder);
+		vc4_encoder->post_crtc_powerdown(encoder, state);
 
 	return 0;
 }
 
+static struct drm_encoder *vc4_crtc_get_encoder_by_type(struct drm_crtc *crtc,
+							enum vc4_encoder_type type)
+{
+	struct drm_encoder *encoder;
+
+	drm_for_each_encoder(encoder, crtc->dev) {
+		struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
+
+		if (vc4_encoder->type == type)
+			return encoder;
+	}
+
+	return NULL;
+}
+
 int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
 {
 	struct drm_device *drm = crtc->dev;
 	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+	enum vc4_encoder_type encoder_type;
+	const struct vc4_pv_data *pv_data;
+	struct drm_encoder *encoder;
+	unsigned encoder_sel;
 	int channel;
 
 	if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:523 @
 	if (channel < 0)
 		return 0;
 
-	return vc4_crtc_disable(crtc, channel);
+	encoder_sel = VC4_GET_FIELD(CRTC_READ(PV_CONTROL), PV_CONTROL_CLK_SELECT);
+	if (WARN_ON(encoder_sel != 0))
+		return 0;
+
+	pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
+	encoder_type = pv_data->encoder_types[encoder_sel];
+	encoder = vc4_crtc_get_encoder_by_type(crtc, encoder_type);
+	if (WARN_ON(!encoder))
+		return 0;
+
+	return vc4_crtc_disable(crtc, encoder, NULL, channel);
 }
 
 static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
 	struct vc4_crtc_state *old_vc4_state = to_vc4_crtc_state(old_state);
+	struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, old_state);
 	struct drm_device *dev = crtc->dev;
 
+	drm_dbg(dev, "Disabling CRTC %s (%u) connected to Encoder %s (%u)",
+		crtc->name, crtc->base.id, encoder->name, encoder->base.id);
+
 	require_hvs_enabled(dev);
 
 	/* Disable vblank irq handling before crtc is disabled. */
 	drm_crtc_vblank_off(crtc);
 
-	vc4_crtc_disable(crtc, old_vc4_state->assigned_channel);
+	vc4_crtc_disable(crtc, encoder, state, old_vc4_state->assigned_channel);
 
 	/*
 	 * Make sure we issue a vblank event after disabling the CRTC if
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:570 @
 }
 
 static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_state)
+				   struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state,
+									 crtc);
 	struct drm_device *dev = crtc->dev;
 	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-	struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
+	struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, new_state);
 	struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
 
+	drm_dbg(dev, "Enabling CRTC %s (%u) connected to Encoder %s (%u)",
+		crtc->name, crtc->base.id, encoder->name, encoder->base.id);
+
 	require_hvs_enabled(dev);
 
 	/* Enable vblank irq handling before crtc is started otherwise
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:589 @
 	 */
 	drm_crtc_vblank_on(crtc);
 
-	vc4_hvs_atomic_enable(crtc, old_state);
+	vc4_hvs_atomic_enable(crtc, state);
 
 	if (vc4_encoder->pre_crtc_configure)
-		vc4_encoder->pre_crtc_configure(encoder);
+		vc4_encoder->pre_crtc_configure(encoder, state);
 
-	vc4_crtc_config_pv(crtc);
+	vc4_crtc_config_pv(crtc, encoder, state);
 
 	CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_EN);
 
 	if (vc4_encoder->pre_crtc_enable)
-		vc4_encoder->pre_crtc_enable(encoder);
+		vc4_encoder->pre_crtc_enable(encoder, state);
 
 	/* When feeding the transposer block the pixelvalve is unneeded and
 	 * should not be enabled.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:608 @
 		   CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
 
 	if (vc4_encoder->post_crtc_enable)
-		vc4_encoder->post_crtc_enable(encoder);
+		vc4_encoder->post_crtc_enable(encoder, state);
 }
 
 static enum drm_mode_status vc4_crtc_mode_valid(struct drm_crtc *crtc,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:656 @
 }
 
 static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
-				 struct drm_crtc_state *state)
+				 struct drm_atomic_state *state)
 {
-	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
 	struct drm_connector *conn;
 	struct drm_connector_state *conn_state;
+	struct drm_encoder *encoder;
 	int ret, i;
 
 	ret = vc4_hvs_atomic_check(crtc, state);
 	if (ret)
 		return ret;
 
-	for_each_new_connector_in_state(state->state, conn, conn_state, i) {
+	encoder = vc4_get_crtc_encoder(crtc, crtc_state);
+	if (encoder) {
+		const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+		struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
+
+		mode = &crtc_state->adjusted_mode;
+		if (vc4_encoder->type == VC4_ENCODER_TYPE_HDMI0) {
+			vc4_state->hvs_load = max(mode->clock * mode->hdisplay / mode->htotal + 1000,
+						  mode->clock * 9 / 10) * 1000;
+		} else {
+			vc4_state->hvs_load = mode->clock * 1000;
+		}
+	}
+
+	for_each_new_connector_in_state(state, conn, conn_state,
+					i) {
 		if (conn_state->crtc != crtc)
 			continue;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:784 @
 		container_of(cb, struct vc4_async_flip_state, cb);
 	struct drm_crtc *crtc = flip_state->crtc;
 	struct drm_device *dev = crtc->dev;
-	struct vc4_dev *vc4 = to_vc4_dev(dev);
 	struct drm_plane *plane = crtc->primary;
 
 	vc4_plane_async_set_fb(plane, flip_state->fb);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:815 @
 	}
 
 	kfree(flip_state);
-
-	up(&vc4->async_modeset);
 }
 
 /* Implements async (non-vblank-synced) page flips.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:829 @
 			       uint32_t flags)
 {
 	struct drm_device *dev = crtc->dev;
-	struct vc4_dev *vc4 = to_vc4_dev(dev);
 	struct drm_plane *plane = crtc->primary;
 	int ret = 0;
 	struct vc4_async_flip_state *flip_state;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:857 @
 	flip_state->crtc = crtc;
 	flip_state->event = event;
 
-	/* Make sure all other async modesetes have landed. */
-	ret = down_interruptible(&vc4->async_modeset);
-	if (ret) {
-		drm_framebuffer_put(fb);
-		vc4_bo_dec_usecnt(bo);
-		kfree(flip_state);
-		return ret;
-	}
-
 	/* Save the current FB before it's replaced by the new one in
 	 * drm_atomic_set_fb_for_plane(). We'll need the old FB in
 	 * vc4_async_page_flip_complete() to decrement the BO usecnt and keep
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:958 @
 	.reset = vc4_crtc_reset,
 	.atomic_duplicate_state = vc4_crtc_duplicate_state,
 	.atomic_destroy_state = vc4_crtc_destroy_state,
-	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 	.enable_vblank = vc4_enable_vblank,
 	.disable_vblank = vc4_disable_vblank,
 	.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_debugfs.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_debugfs.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_debugfs.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_debugfs.c	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:10 @
 #include <linux/circ_buf.h>
 #include <linux/ctype.h>
 #include <linux/debugfs.h>
+#include <linux/platform_device.h>
 
 #include "vc4_drv.h"
 #include "vc4_regs.h"
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:30 @
 	struct vc4_dev *vc4 = to_vc4_dev(minor->dev);
 	struct vc4_debugfs_info_entry *entry;
 
-	debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR,
-			    minor->debugfs_root, &vc4->load_tracker_enabled);
+	if (vc4->hvs && !of_device_is_compatible(vc4->hvs->pdev->dev.of_node,
+				     "brcm,bcm2711-vc5"))
+		debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR,
+				    minor->debugfs_root, &vc4->load_tracker_enabled);
 
 	list_for_each_entry(entry, &vc4->debugfs_list, link) {
 		drm_debugfs_create_files(&entry->info, 1,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_dpi.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_dpi.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_dpi.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_dpi.c	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:168 @
 			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2,
 					       DPI_FORMAT);
 			break;
+		case MEDIA_BUS_FMT_BGR666_1X24_CPADHI:
+			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2,
+					       DPI_FORMAT);
+			dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER);
+			break;
 		case MEDIA_BUS_FMT_RGB666_1X18:
 			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1,
 					       DPI_FORMAT);
 			break;
+		case MEDIA_BUS_FMT_BGR666_1X18:
+			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1,
+					       DPI_FORMAT);
+			dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER);
+			break;
 		case MEDIA_BUS_FMT_RGB565_1X16:
 			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3,
 					       DPI_FORMAT);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:191 @
 			break;
 		}
 	} else {
-		/* Default to 24bit if no connector found. */
-		dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, DPI_FORMAT);
+		/* Default to 18bit if no connector found. */
+		dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, DPI_FORMAT);
 	}
 
 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_drv.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_drv.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_drv.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_drv.c	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:39 @
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_vblank.h>
 
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
 #include "uapi/drm/vc4_drm.h"
 
 #include "vc4_drv.h"
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:251 @
 	}
 }
 
+const struct of_device_id vc4_dma_range_matches[] = {
+	{ .compatible = "brcm,bcm2835-hvs" },
+	{ .compatible = "brcm,bcm2711-hvs" },
+	{ .compatible = "raspberrypi,rpi-firmware-kms" },
+	{ .compatible = "brcm,bcm2835-v3d" },
+	{ .compatible = "brcm,cygnus-v3d" },
+	{ .compatible = "brcm,vc4-v3d" },
+	{}
+};
+
+/*
+ * we need this helper function for determining presence of fkms
+ * before it's been bound
+ */
+static bool firmware_kms(void)
+{
+	return of_device_is_available(of_find_compatible_node(NULL, NULL,
+	       "raspberrypi,rpi-firmware-kms")) ||
+	       of_device_is_available(of_find_compatible_node(NULL, NULL,
+	       "raspberrypi,rpi-firmware-kms-2711"));
+}
+
 static int vc4_drm_bind(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:290 @
 		vc4_drm_driver.driver_features &= ~DRIVER_RENDER;
 	of_node_put(node);
 
+	node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches,
+					       NULL);
+	if (node) {
+		ret = of_dma_configure(dev, node, true);
+		of_node_put(node);
+
+		if (ret)
+			return ret;
+	}
+
 	vc4 = devm_drm_dev_alloc(dev, &vc4_drm_driver, struct vc4_dev, base);
 	if (IS_ERR(vc4))
 		return PTR_ERR(vc4);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:322 @
 	if (ret)
 		return ret;
 
+	node = of_parse_phandle(dev->of_node, "raspberrypi,firmware", 0);
+	if (node) {
+		vc4->firmware = rpi_firmware_get(node);
+		of_node_put(node);
+
+		if (!vc4->firmware)
+			return -EPROBE_DEFER;
+	}
+
+	drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false);
+
+	if (vc4->firmware && !firmware_kms()) {
+		ret = rpi_firmware_property(vc4->firmware,
+					    RPI_FIRMWARE_NOTIFY_DISPLAY_DONE,
+					    NULL, 0);
+		if (ret)
+			drm_warn(drm, "Couldn't stop firmware display driver: %d\n", ret);
+	}
+
 	ret = component_bind_all(dev, drm);
 	if (ret)
 		return ret;
 
-	ret = vc4_plane_create_additional_planes(drm);
-	if (ret)
-		goto unbind_all;
-
-	drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false);
+	if (!vc4->firmware_kms) {
+		ret = vc4_plane_create_additional_planes(drm);
+		if (ret)
+			goto unbind_all;
+	}
 
 	ret = vc4_kms_load(drm);
 	if (ret < 0)
 		goto unbind_all;
 
-	drm_for_each_crtc(crtc, drm)
-		vc4_crtc_disable_at_boot(crtc);
+	if (!vc4->firmware_kms) {
+		drm_for_each_crtc(crtc, drm)
+			vc4_crtc_disable_at_boot(crtc);
+	}
 
 	ret = drm_dev_register(drm, 0);
 	if (ret < 0)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:388 @
 	.unbind = vc4_drm_unbind,
 };
 
+/*
+ * This list determines the binding order of our components, and we have
+ * a few constraints:
+ *   - The TXP driver needs to be bound before the PixelValves (CRTC)
+ *     but after the HVS to set the possible_crtc field properly
+ *   - The HDMI driver needs to be bound after the HVS so that we can
+ *     lookup the HVS maximum core clock rate and figure out if we
+ *     support 4kp60 or not.
+ */
 static struct platform_driver *const component_drivers[] = {
+	&vc4_hvs_driver,
 	&vc4_hdmi_driver,
 	&vc4_vec_driver,
 	&vc4_dpi_driver,
 	&vc4_dsi_driver,
-	&vc4_hvs_driver,
 	&vc4_txp_driver,
 	&vc4_crtc_driver,
+	&vc4_firmware_kms_driver,
 	&vc4_v3d_driver,
 };
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_drv.h linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_drv.h
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_drv.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_drv.h	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:77 @
 struct vc4_dev {
 	struct drm_device base;
 
+	bool firmware_kms;
+	struct rpi_firmware *firmware;
+
+	struct vc4_hdmi *hdmi;
 	struct vc4_hvs *hvs;
 	struct vc4_v3d *v3d;
 	struct vc4_dpi *dpi;
-	struct vc4_dsi *dsi1;
 	struct vc4_vec *vec;
 	struct vc4_txp *txp;
+	struct vc4_fkms *fkms;
 
 	struct vc4_hang_state *hang_state;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:208 @
 
 	int power_refcount;
 
-	/* Set to true when the load tracker is supported. */
-	bool load_tracker_available;
-
 	/* Set to true when the load tracker is active. */
 	bool load_tracker_enabled;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:219 @
 		struct work_struct reset_work;
 	} hangcheck;
 
-	struct semaphore async_modeset;
-
 	struct drm_modeset_lock ctm_state_lock;
 	struct drm_private_obj ctm_manager;
 	struct drm_private_obj hvs_channels;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:327 @
 	u32 __iomem *dlist;
 
 	struct clk *core_clk;
+	struct clk_request *core_req;
 
 	/* Memory manager for CRTCs to allocate space in the display
 	 * list.  Units are dwords.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:447 @
 	enum vc4_encoder_type type;
 	u32 clock_select;
 
-	void (*pre_crtc_configure)(struct drm_encoder *encoder);
-	void (*pre_crtc_enable)(struct drm_encoder *encoder);
-	void (*post_crtc_enable)(struct drm_encoder *encoder);
+	void (*pre_crtc_configure)(struct drm_encoder *encoder, struct drm_atomic_state *state);
+	void (*pre_crtc_enable)(struct drm_encoder *encoder, struct drm_atomic_state *state);
+	void (*post_crtc_enable)(struct drm_encoder *encoder, struct drm_atomic_state *state);
 
-	void (*post_crtc_disable)(struct drm_encoder *encoder);
-	void (*post_crtc_powerdown)(struct drm_encoder *encoder);
+	void (*post_crtc_disable)(struct drm_encoder *encoder, struct drm_atomic_state *state);
+	void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_state *state);
 };
 
 static inline struct vc4_encoder *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:521 @
 	return container_of(data, struct vc4_pv_data, base);
 }
 
+struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
+					 struct drm_crtc_state *state);
+
 struct vc4_crtc_state {
 	struct drm_crtc_state base;
 	/* Dlist area for this CRTC configuration. */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:539 @
 		unsigned int bottom;
 	} margins;
 
+	unsigned long hvs_load;
+
 	/* Transitional state below, only valid during atomic commits */
 	bool update_muxing;
 };
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:885 @
 /* vc4_fence.c */
 extern const struct dma_fence_ops vc4_fence_ops;
 
+/* vc4_firmware_kms.c */
+extern struct platform_driver vc4_firmware_kms_driver;
+
 /* vc4_gem.c */
 int vc4_gem_init(struct drm_device *dev);
 int vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:928 @
 extern struct platform_driver vc4_hvs_driver;
 void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int output);
 int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output);
-int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state);
-void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
-void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
-void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *state);
+int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state);
+void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state);
+void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state);
+void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state);
 void vc4_hvs_dump_state(struct drm_device *dev);
 void vc4_hvs_unmask_underrun(struct drm_device *dev, int channel);
 void vc4_hvs_mask_underrun(struct drm_device *dev, int channel);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_dsi.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_dsi.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_dsi.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_dsi.c	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:184 @
 
 #define DSI0_TXPKT_PIX_FIFO		0x20 /* AKA PIX_FIFO */
 
-#define DSI0_INT_STAT		0x24
-#define DSI0_INT_EN		0x28
+#define DSI0_INT_STAT			0x24
+#define DSI0_INT_EN			0x28
+# define DSI0_INT_FIFO_ERR		BIT(25)
+# define DSI0_INT_CMDC_DONE_MASK	VC4_MASK(24, 23)
+# define DSI0_INT_CMDC_DONE_SHIFT	23
+#  define DSI0_INT_CMDC_DONE_NO_REPEAT		1
+#  define DSI0_INT_CMDC_DONE_REPEAT		3
+# define DSI0_INT_PHY_DIR_RTF		BIT(22)
+# define DSI0_INT_PHY_D1_ULPS		BIT(21)
+# define DSI0_INT_PHY_D1_STOP		BIT(20)
+# define DSI0_INT_PHY_RXLPDT		BIT(19)
+# define DSI0_INT_PHY_RXTRIG		BIT(18)
+# define DSI0_INT_PHY_D0_ULPS		BIT(17)
+# define DSI0_INT_PHY_D0_LPDT		BIT(16)
+# define DSI0_INT_PHY_D0_FTR		BIT(15)
+# define DSI0_INT_PHY_D0_STOP		BIT(14)
+/* Signaled when the clock lane enters the given state. */
+# define DSI0_INT_PHY_CLK_ULPS		BIT(13)
+# define DSI0_INT_PHY_CLK_HS		BIT(12)
+# define DSI0_INT_PHY_CLK_FTR		BIT(11)
+/* Signaled on timeouts */
+# define DSI0_INT_PR_TO			BIT(10)
+# define DSI0_INT_TA_TO			BIT(9)
+# define DSI0_INT_LPRX_TO		BIT(8)
+# define DSI0_INT_HSTX_TO		BIT(7)
+/* Contention on a line when trying to drive the line low */
+# define DSI0_INT_ERR_CONT_LP1		BIT(6)
+# define DSI0_INT_ERR_CONT_LP0		BIT(5)
+/* Control error: incorrect line state sequence on data lane 0. */
+# define DSI0_INT_ERR_CONTROL		BIT(4)
+# define DSI0_INT_ERR_SYNC_ESC		BIT(3)
+# define DSI0_INT_RX2_PKT		BIT(2)
+# define DSI0_INT_RX1_PKT		BIT(1)
+# define DSI0_INT_CMD_PKT		BIT(0)
+
+#define DSI0_INTERRUPTS_ALWAYS_ENABLED	(DSI0_INT_ERR_SYNC_ESC | \
+					 DSI0_INT_ERR_CONTROL |	 \
+					 DSI0_INT_ERR_CONT_LP0 | \
+					 DSI0_INT_ERR_CONT_LP1 | \
+					 DSI0_INT_HSTX_TO |	 \
+					 DSI0_INT_LPRX_TO |	 \
+					 DSI0_INT_TA_TO |	 \
+					 DSI0_INT_PR_TO)
+
 # define DSI1_INT_PHY_D3_ULPS		BIT(30)
 # define DSI1_INT_PHY_D3_STOP		BIT(29)
 # define DSI1_INT_PHY_D2_ULPS		BIT(28)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:351 @
 # define DSI0_PHY_AFEC0_RESET			BIT(11)
 # define DSI1_PHY_AFEC0_PD_BG			BIT(11)
 # define DSI0_PHY_AFEC0_PD			BIT(10)
-# define DSI1_PHY_AFEC0_PD_DLANE3		BIT(10)
+# define DSI1_PHY_AFEC0_PD_DLANE1		BIT(10)
 # define DSI0_PHY_AFEC0_PD_BG			BIT(9)
 # define DSI1_PHY_AFEC0_PD_DLANE2		BIT(9)
 # define DSI0_PHY_AFEC0_PD_DLANE1		BIT(8)
-# define DSI1_PHY_AFEC0_PD_DLANE1		BIT(8)
+# define DSI1_PHY_AFEC0_PD_DLANE3		BIT(8)
 # define DSI_PHY_AFEC0_PTATADJ_MASK		VC4_MASK(7, 4)
 # define DSI_PHY_AFEC0_PTATADJ_SHIFT		4
 # define DSI_PHY_AFEC0_CTATADJ_MASK		VC4_MASK(3, 0)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:538 @
  */
 #define DSI1_ID			0x8c
 
+struct vc4_dsi_variant {
+	/* Whether we're on bcm2835's DSI0 or DSI1. */
+	unsigned int port;
+
+	bool broken_axi_workaround;
+
+	const char *debugfs_name;
+	const struct debugfs_reg32 *regs;
+	size_t nregs;
+
+};
+
 /* General DSI hardware state. */
 struct vc4_dsi {
 	struct platform_device *pdev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:566 @
 	u32 *reg_dma_mem;
 	dma_addr_t reg_paddr;
 
-	/* Whether we're on bcm2835's DSI0 or DSI1. */
-	int port;
+	const struct vc4_dsi_variant *variant;
 
 	/* DSI channel for the panel we're connected to. */
 	u32 channel;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:642 @
 #define DSI_READ(offset) readl(dsi->regs + (offset))
 #define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val)
 #define DSI_PORT_READ(offset) \
-	DSI_READ(dsi->port ? DSI1_##offset : DSI0_##offset)
+	DSI_READ(dsi->variant->port ? DSI1_##offset : DSI0_##offset)
 #define DSI_PORT_WRITE(offset, val) \
-	DSI_WRITE(dsi->port ? DSI1_##offset : DSI0_##offset, val)
-#define DSI_PORT_BIT(bit) (dsi->port ? DSI1_##bit : DSI0_##bit)
+	DSI_WRITE(dsi->variant->port ? DSI1_##offset : DSI0_##offset, val)
+#define DSI_PORT_BIT(bit) (dsi->variant->port ? DSI1_##bit : DSI0_##bit)
 
 /* VC4 DSI encoder KMS struct */
 struct vc4_dsi_encoder {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:806 @
 	list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) {
 		if (iter->funcs->disable)
 			iter->funcs->disable(iter);
+
+		if (iter == dsi->bridge)
+			break;
 	}
 
 	vc4_dsi_ulps(dsi, true);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:896 @
 
 	ret = pm_runtime_get_sync(dev);
 	if (ret) {
-		DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->port);
+		DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->variant->port);
 		return;
 	}
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:930 @
 	DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT));
 
 	/* Set AFE CTR00/CTR1 to release powerdown of analog. */
-	if (dsi->port == 0) {
+	if (dsi->variant->port == 0) {
 		u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) |
 			     VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ));
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:942 @
 
 		DSI_PORT_WRITE(PHY_AFEC0, afec0);
 
+		/* AFEC reset hold time */
+		mdelay(1);
+
 		DSI_PORT_WRITE(PHY_AFEC1,
 			       VC4_SET_FIELD(6,  DSI0_PHY_AFEC1_IDR_DLANE1) |
 			       VC4_SET_FIELD(6,  DSI0_PHY_AFEC1_IDR_DLANE0) |
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1079 @
 		       DSI_PORT_BIT(PHYC_CLANE_ENABLE) |
 		       ((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ?
 			0 : DSI_PORT_BIT(PHYC_HS_CLK_CONTINUOUS)) |
-		       (dsi->port == 0 ?
+		       (dsi->variant->port == 0 ?
 			VC4_SET_FIELD(lpx - 1, DSI0_PHYC_ESC_CLK_LPDT) :
 			VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT)));
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1105 @
 		       DSI_DISP1_ENABLE);
 
 	/* Ungate the block. */
-	if (dsi->port == 0)
+	if (dsi->variant->port == 0)
 		DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0);
 	else
 		DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN);
 
 	/* Bring AFE out of reset. */
-	if (dsi->port == 0) {
-	} else {
-		DSI_PORT_WRITE(PHY_AFEC0,
-			       DSI_PORT_READ(PHY_AFEC0) &
-			       ~DSI1_PHY_AFEC0_RESET);
-	}
+	DSI_PORT_WRITE(PHY_AFEC0,
+		       DSI_PORT_READ(PHY_AFEC0) &
+		       ~DSI_PORT_BIT(PHY_AFEC0_RESET));
 
 	vc4_dsi_ulps(dsi, false);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1232 @
 	/* Enable the appropriate interrupt for the transfer completion. */
 	dsi->xfer_result = 0;
 	reinit_completion(&dsi->xfer_completion);
-	DSI_PORT_WRITE(INT_STAT, DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF);
-	if (msg->rx_len) {
-		DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
-					DSI1_INT_PHY_DIR_RTF));
+	if (dsi->variant->port == 0) {
+		DSI_PORT_WRITE(INT_STAT,
+			       DSI0_INT_CMDC_DONE_MASK | DSI1_INT_PHY_DIR_RTF);
+		if (msg->rx_len) {
+			DSI_PORT_WRITE(INT_EN, (DSI0_INTERRUPTS_ALWAYS_ENABLED |
+						DSI0_INT_PHY_DIR_RTF));
+		} else {
+			DSI_PORT_WRITE(INT_EN,
+				       (DSI0_INTERRUPTS_ALWAYS_ENABLED |
+					VC4_SET_FIELD(DSI0_INT_CMDC_DONE_NO_REPEAT,
+						      DSI0_INT_CMDC_DONE)));
+		}
 	} else {
-		DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
-					DSI1_INT_TXPKT1_DONE));
+		DSI_PORT_WRITE(INT_STAT,
+			       DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF);
+		if (msg->rx_len) {
+			DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
+						DSI1_INT_PHY_DIR_RTF));
+		} else {
+			DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
+						DSI1_INT_TXPKT1_DONE));
+		}
 	}
 
 	/* Send the packet. */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1270 @
 		ret = dsi->xfer_result;
 	}
 
-	DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED);
+	DSI_PORT_WRITE(INT_EN, DSI_PORT_BIT(INTERRUPTS_ALWAYS_ENABLED));
 
 	if (ret)
 		goto reset_fifo_and_return;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1316 @
 		       DSI_PORT_BIT(CTRL_RESET_FIFOS));
 
 	DSI_PORT_WRITE(TXPKT1C, 0);
-	DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED);
+	DSI_PORT_WRITE(INT_EN, DSI_PORT_BIT(INTERRUPTS_ALWAYS_ENABLED));
 	return ret;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1379 @
 	.mode_fixup = vc4_dsi_encoder_mode_fixup,
 };
 
+static const struct vc4_dsi_variant bcm2711_dsi1_variant = {
+	.port			= 1,
+	.debugfs_name		= "dsi1_regs",
+	.regs			= dsi1_regs,
+	.nregs			= ARRAY_SIZE(dsi1_regs),
+};
+
+static const struct vc4_dsi_variant bcm2835_dsi0_variant = {
+	.port			= 0,
+	.debugfs_name		= "dsi0_regs",
+	.regs			= dsi0_regs,
+	.nregs			= ARRAY_SIZE(dsi0_regs),
+};
+
+static const struct vc4_dsi_variant bcm2835_dsi1_variant = {
+	.port			= 1,
+	.broken_axi_workaround	= true,
+	.debugfs_name		= "dsi1_regs",
+	.regs			= dsi1_regs,
+	.nregs			= ARRAY_SIZE(dsi1_regs),
+};
+
 static const struct of_device_id vc4_dsi_dt_match[] = {
-	{ .compatible = "brcm,bcm2835-dsi1", (void *)(uintptr_t)1 },
+	{ .compatible = "brcm,bcm2711-dsi1", &bcm2711_dsi1_variant },
+	{ .compatible = "brcm,bcm2835-dsi0", &bcm2835_dsi0_variant },
+	{ .compatible = "brcm,bcm2835-dsi1", &bcm2835_dsi1_variant },
 	{}
 };
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1415 @
 	if (!(stat & bit))
 		return;
 
-	DRM_ERROR("DSI%d: %s error\n", dsi->port, type);
+	DRM_ERROR("DSI%d: %s error\n", dsi->variant->port, type);
 	*ret = IRQ_HANDLED;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1449 @
 	DSI_PORT_WRITE(INT_STAT, stat);
 
 	dsi_handle_error(dsi, &ret, stat,
-			 DSI1_INT_ERR_SYNC_ESC, "LPDT sync");
+			 DSI_PORT_BIT(INT_ERR_SYNC_ESC), "LPDT sync");
 	dsi_handle_error(dsi, &ret, stat,
-			 DSI1_INT_ERR_CONTROL, "data lane 0 sequence");
+			 DSI_PORT_BIT(INT_ERR_CONTROL), "data lane 0 sequence");
 	dsi_handle_error(dsi, &ret, stat,
-			 DSI1_INT_ERR_CONT_LP0, "LP0 contention");
+			 DSI_PORT_BIT(INT_ERR_CONT_LP0), "LP0 contention");
 	dsi_handle_error(dsi, &ret, stat,
-			 DSI1_INT_ERR_CONT_LP1, "LP1 contention");
+			 DSI_PORT_BIT(INT_ERR_CONT_LP1), "LP1 contention");
 	dsi_handle_error(dsi, &ret, stat,
-			 DSI1_INT_HSTX_TO, "HSTX timeout");
+			 DSI_PORT_BIT(INT_HSTX_TO), "HSTX timeout");
 	dsi_handle_error(dsi, &ret, stat,
-			 DSI1_INT_LPRX_TO, "LPRX timeout");
+			 DSI_PORT_BIT(INT_LPRX_TO), "LPRX timeout");
 	dsi_handle_error(dsi, &ret, stat,
-			 DSI1_INT_TA_TO, "turnaround timeout");
+			 DSI_PORT_BIT(INT_TA_TO), "turnaround timeout");
 	dsi_handle_error(dsi, &ret, stat,
-			 DSI1_INT_PR_TO, "peripheral reset timeout");
+			 DSI_PORT_BIT(INT_PR_TO), "peripheral reset timeout");
 
-	if (stat & (DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF)) {
+	if (stat & ((dsi->variant->port ? DSI1_INT_TXPKT1_DONE :
+					  DSI0_INT_CMDC_DONE_MASK) |
+		    DSI_PORT_BIT(INT_PHY_DIR_RTF))) {
 		complete(&dsi->xfer_completion);
 		ret = IRQ_HANDLED;
-	} else if (stat & DSI1_INT_HSTX_TO) {
+	} else if (stat & DSI_PORT_BIT(INT_HSTX_TO)) {
 		complete(&dsi->xfer_completion);
 		dsi->xfer_result = -ETIMEDOUT;
 		ret = IRQ_HANDLED;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1490 @
 	struct device *dev = &dsi->pdev->dev;
 	const char *parent_name = __clk_get_name(dsi->pll_phy_clock);
 	static const struct {
-		const char *dsi0_name, *dsi1_name;
+		const char *name;
 		int div;
 	} phy_clocks[] = {
-		{ "dsi0_byte", "dsi1_byte", 8 },
-		{ "dsi0_ddr2", "dsi1_ddr2", 4 },
-		{ "dsi0_ddr", "dsi1_ddr", 2 },
+		{ "byte", 8 },
+		{ "ddr2", 4 },
+		{ "ddr", 2 },
 	};
 	int i;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1511 @
 	for (i = 0; i < ARRAY_SIZE(phy_clocks); i++) {
 		struct clk_fixed_factor *fix = &dsi->phy_clocks[i];
 		struct clk_init_data init;
+		char clk_name[16];
 		int ret;
 
+		snprintf(clk_name, sizeof(clk_name),
+			 "dsi%u_%s", dsi->variant->port, phy_clocks[i].name);
+
 		/* We just use core fixed factor clock ops for the PHY
 		 * clocks.  The clocks are actually gated by the
 		 * PHY_AFEC0_DDRCLK_EN bits, which we should be
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1533 @
 		memset(&init, 0, sizeof(init));
 		init.parent_names = &parent_name;
 		init.num_parents = 1;
-		if (dsi->port == 1)
-			init.name = phy_clocks[i].dsi1_name;
-		else
-			init.name = phy_clocks[i].dsi0_name;
+		init.name = clk_name;
 		init.ops = &clk_fixed_factor_ops;
 
 		ret = devm_clk_hw_register(dev, &fix->hw);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1552 @
 {
 	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_dsi *dsi = dev_get_drvdata(dev);
 	struct vc4_dsi_encoder *vc4_dsi_encoder;
 	struct drm_panel *panel;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1563 @
 	if (!match)
 		return -ENODEV;
 
-	dsi->port = (uintptr_t)match->data;
+	dsi->variant = match->data;
 
 	vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder),
 				       GFP_KERNEL);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1571 @
 		return -ENOMEM;
 
 	INIT_LIST_HEAD(&dsi->bridge_chain);
-	vc4_dsi_encoder->base.type = VC4_ENCODER_TYPE_DSI1;
+	vc4_dsi_encoder->base.type = dsi->variant->port ?
+			VC4_ENCODER_TYPE_DSI1 : VC4_ENCODER_TYPE_DSI0;
 	vc4_dsi_encoder->dsi = dsi;
 	dsi->encoder = &vc4_dsi_encoder->base.base;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1581 @
 		return PTR_ERR(dsi->regs);
 
 	dsi->regset.base = dsi->regs;
-	if (dsi->port == 0) {
-		dsi->regset.regs = dsi0_regs;
-		dsi->regset.nregs = ARRAY_SIZE(dsi0_regs);
-	} else {
-		dsi->regset.regs = dsi1_regs;
-		dsi->regset.nregs = ARRAY_SIZE(dsi1_regs);
-	}
+	dsi->regset.regs = dsi->variant->regs;
+	dsi->regset.nregs = dsi->variant->nregs;
 
 	if (DSI_PORT_READ(ID) != DSI_ID_VALUE) {
 		dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1590 @
 		return -ENODEV;
 	}
 
-	/* DSI1 has a broken AXI slave that doesn't respond to writes
-	 * from the ARM.  It does handle writes from the DMA engine,
+	/* DSI1 on BCM2835/6/7 has a broken AXI slave that doesn't respond to
+	 * writes from the ARM.  It does handle writes from the DMA engine,
 	 * so set up a channel for talking to it.
 	 */
-	if (dsi->port == 1) {
+	if (dsi->variant->broken_axi_workaround) {
 		dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
 						      &dsi->reg_dma_paddr,
 						      GFP_KERNEL);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1700 @
 	if (ret)
 		return ret;
 
-	if (dsi->port == 1)
-		vc4->dsi1 = dsi;
-
 	drm_simple_encoder_init(drm, dsi->encoder, DRM_MODE_ENCODER_DSI);
 	drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1715 @
 	 */
 	list_splice_init(&dsi->encoder->bridge_chain, &dsi->bridge_chain);
 
-	if (dsi->port == 0)
-		vc4_debugfs_add_regset32(drm, "dsi0_regs", &dsi->regset);
-	else
-		vc4_debugfs_add_regset32(drm, "dsi1_regs", &dsi->regset);
+	vc4_debugfs_add_regset32(drm, dsi->variant->debugfs_name, &dsi->regset);
 
 	pm_runtime_enable(dev);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1725 @
 static void vc4_dsi_unbind(struct device *dev, struct device *master,
 			   void *data)
 {
-	struct drm_device *drm = dev_get_drvdata(master);
-	struct vc4_dev *vc4 = to_vc4_dev(drm);
 	struct vc4_dsi *dsi = dev_get_drvdata(dev);
 
 	if (dsi->bridge)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1736 @
 	 */
 	list_splice_init(&dsi->bridge_chain, &dsi->encoder->bridge_chain);
 	drm_encoder_cleanup(dsi->encoder);
-
-	if (dsi->port == 1)
-		vc4->dsi1 = NULL;
 }
 
 static const struct component_ops vc4_dsi_ops = {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_firmware_kms.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_firmware_kms.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_firmware_kms.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_firmware_kms.c	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * 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.
+ */
+
+/**
+ * DOC: VC4 firmware KMS module.
+ *
+ * As a hack to get us from the current closed source driver world
+ * toward a totally open stack, implement KMS on top of the Raspberry
+ * Pi's firmware display stack.
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+
+#include <linux/component.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#include "vc4_drv.h"
+#include "vc4_regs.h"
+#include "vc_image_types.h"
+
+int fkms_max_refresh_rate = 85;
+module_param(fkms_max_refresh_rate, int, 0644);
+MODULE_PARM_DESC(fkms_max_refresh_rate, "Max supported refresh rate");
+
+struct get_display_cfg {
+	u32  max_pixel_clock[2];  //Max pixel clock for each display
+};
+
+struct vc4_fkms {
+	struct get_display_cfg cfg;
+	bool bcm2711;
+};
+
+#define PLANES_PER_CRTC		8
+
+struct set_plane {
+	u8 display;
+	u8 plane_id;
+	u8 vc_image_type;
+	s8 layer;
+
+	u16 width;
+	u16 height;
+
+	u16 pitch;
+	u16 vpitch;
+
+	u32 src_x;	/* 16p16 */
+	u32 src_y;	/* 16p16 */
+
+	u32 src_w;	/* 16p16 */
+	u32 src_h;	/* 16p16 */
+
+	s16 dst_x;
+	s16 dst_y;
+
+	u16 dst_w;
+	u16 dst_h;
+
+	u8 alpha;
+	u8 num_planes;
+	u8 is_vu;
+	u8 color_encoding;
+
+	u32 planes[4];  /* DMA address of each plane */
+
+	u32 transform;
+};
+
+/* Values for the transform field */
+#define TRANSFORM_NO_ROTATE	0
+#define TRANSFORM_ROTATE_180	BIT(1)
+#define TRANSFORM_FLIP_HRIZ	BIT(16)
+#define TRANSFORM_FLIP_VERT	BIT(17)
+
+struct mailbox_set_plane {
+	struct rpi_firmware_property_tag_header tag;
+	struct set_plane plane;
+};
+
+struct mailbox_blank_display {
+	struct rpi_firmware_property_tag_header tag1;
+	u32 display;
+	struct rpi_firmware_property_tag_header tag2;
+	u32 blank;
+};
+
+struct mailbox_display_pwr {
+	struct rpi_firmware_property_tag_header tag1;
+	u32 display;
+	u32 state;
+};
+
+struct mailbox_get_edid {
+	struct rpi_firmware_property_tag_header tag1;
+	u32 block;
+	u32 display_number;
+	u8 edid[128];
+};
+
+struct set_timings {
+	u8 display;
+	u8 padding;
+	u16 video_id_code;
+
+	u32 clock;		/* in kHz */
+
+	u16 hdisplay;
+	u16 hsync_start;
+
+	u16 hsync_end;
+	u16 htotal;
+
+	u16 hskew;
+	u16 vdisplay;
+
+	u16 vsync_start;
+	u16 vsync_end;
+
+	u16 vtotal;
+	u16 vscan;
+
+	u16 vrefresh;
+	u16 padding2;
+
+	u32 flags;
+#define  TIMINGS_FLAGS_H_SYNC_POS	BIT(0)
+#define  TIMINGS_FLAGS_H_SYNC_NEG	0
+#define  TIMINGS_FLAGS_V_SYNC_POS	BIT(1)
+#define  TIMINGS_FLAGS_V_SYNC_NEG	0
+#define  TIMINGS_FLAGS_INTERLACE	BIT(2)
+
+#define TIMINGS_FLAGS_ASPECT_MASK	GENMASK(7, 4)
+#define TIMINGS_FLAGS_ASPECT_NONE	(0 << 4)
+#define TIMINGS_FLAGS_ASPECT_4_3	(1 << 4)
+#define TIMINGS_FLAGS_ASPECT_16_9	(2 << 4)
+#define TIMINGS_FLAGS_ASPECT_64_27	(3 << 4)
+#define TIMINGS_FLAGS_ASPECT_256_135	(4 << 4)
+
+/* Limited range RGB flag. Not set corresponds to full range. */
+#define TIMINGS_FLAGS_RGB_LIMITED	BIT(8)
+/* DVI monitor, therefore disable infoframes. Not set corresponds to HDMI. */
+#define TIMINGS_FLAGS_DVI		BIT(9)
+/* Double clock */
+#define TIMINGS_FLAGS_DBL_CLK		BIT(10)
+};
+
+struct mailbox_set_mode {
+	struct rpi_firmware_property_tag_header tag1;
+	struct set_timings timings;
+};
+
+static const struct vc_image_format {
+	u32 drm;	/* DRM_FORMAT_* */
+	u32 vc_image;	/* VC_IMAGE_* */
+	u32 is_vu;
+} vc_image_formats[] = {
+	{
+		.drm = DRM_FORMAT_XRGB8888,
+		.vc_image = VC_IMAGE_XRGB8888,
+	},
+	{
+		.drm = DRM_FORMAT_ARGB8888,
+		.vc_image = VC_IMAGE_ARGB8888,
+	},
+/*
+ *	FIXME: Need to resolve which DRM format goes to which vc_image format
+ *	for the remaining RGBA and RGBX formats.
+ *	{
+ *		.drm = DRM_FORMAT_ABGR8888,
+ *		.vc_image = VC_IMAGE_RGBA8888,
+ *	},
+ *	{
+ *		.drm = DRM_FORMAT_XBGR8888,
+ *		.vc_image = VC_IMAGE_RGBA8888,
+ *	},
+ */
+	{
+		.drm = DRM_FORMAT_RGB565,
+		.vc_image = VC_IMAGE_RGB565,
+	},
+	{
+		.drm = DRM_FORMAT_RGB888,
+		.vc_image = VC_IMAGE_BGR888,
+	},
+	{
+		.drm = DRM_FORMAT_BGR888,
+		.vc_image = VC_IMAGE_RGB888,
+	},
+	{
+		.drm = DRM_FORMAT_YUV422,
+		.vc_image = VC_IMAGE_YUV422PLANAR,
+	},
+	{
+		.drm = DRM_FORMAT_YUV420,
+		.vc_image = VC_IMAGE_YUV420,
+	},
+	{
+		.drm = DRM_FORMAT_YVU420,
+		.vc_image = VC_IMAGE_YUV420,
+		.is_vu = 1,
+	},
+	{
+		.drm = DRM_FORMAT_NV12,
+		.vc_image = VC_IMAGE_YUV420SP,
+	},
+	{
+		.drm = DRM_FORMAT_NV21,
+		.vc_image = VC_IMAGE_YUV420SP,
+		.is_vu = 1,
+	},
+	{
+		.drm = DRM_FORMAT_P030,
+		.vc_image = VC_IMAGE_YUV10COL,
+	},
+};
+
+static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) {
+		if (vc_image_formats[i].drm == drm_format)
+			return &vc_image_formats[i];
+	}
+
+	return NULL;
+}
+
+/* The firmware delivers a vblank interrupt to us through the SMI
+ * hardware, which has only this one register.
+ */
+#define SMICS 0x0
+#define SMIDSW0 0x14
+#define SMIDSW1 0x1C
+#define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
+
+/* Flag to denote that the firmware is giving multiple display callbacks */
+#define SMI_NEW 0xabcd0000
+
+#define vc4_crtc vc4_kms_crtc
+#define to_vc4_crtc to_vc4_kms_crtc
+struct vc4_crtc {
+	struct drm_crtc base;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	void __iomem *regs;
+
+	struct drm_pending_vblank_event *event;
+	bool vblank_enabled;
+	u32 display_number;
+	u32 display_type;
+};
+
+static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct vc4_crtc, base);
+}
+
+struct vc4_fkms_encoder {
+	struct drm_encoder base;
+	bool hdmi_monitor;
+	bool rgb_range_selectable;
+	int display_num;
+};
+
+static inline struct vc4_fkms_encoder *
+to_vc4_fkms_encoder(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct vc4_fkms_encoder, base);
+}
+
+/* "Broadcast RGB" property.
+ * Allows overriding of HDMI full or limited range RGB
+ */
+#define VC4_BROADCAST_RGB_AUTO 0
+#define VC4_BROADCAST_RGB_FULL 1
+#define VC4_BROADCAST_RGB_LIMITED 2
+
+/* VC4 FKMS connector KMS struct */
+struct vc4_fkms_connector {
+	struct drm_connector base;
+
+	/* Since the connector is attached to just the one encoder,
+	 * this is the reference to it so we can do the best_encoder()
+	 * hook.
+	 */
+	struct drm_encoder *encoder;
+	struct vc4_dev *vc4_dev;
+	u32 display_number;
+	u32 display_type;
+
+	struct drm_property *broadcast_rgb_property;
+};
+
+static inline struct vc4_fkms_connector *
+to_vc4_fkms_connector(struct drm_connector *connector)
+{
+	return container_of(connector, struct vc4_fkms_connector, base);
+}
+
+/* VC4 FKMS connector state */
+struct vc4_fkms_connector_state {
+	struct drm_connector_state base;
+
+	int broadcast_rgb;
+};
+
+#define to_vc4_fkms_connector_state(x) \
+			container_of(x, struct vc4_fkms_connector_state, base)
+
+static u32 vc4_get_display_type(u32 display_number)
+{
+	const u32 display_types[] = {
+		/* The firmware display (DispmanX) IDs map to specific types in
+		 * a fixed manner.
+		 */
+		DRM_MODE_ENCODER_DSI,	/* MAIN_LCD - DSI or DPI */
+		DRM_MODE_ENCODER_DSI,	/* AUX_LCD */
+		DRM_MODE_ENCODER_TMDS,	/* HDMI0 */
+		DRM_MODE_ENCODER_TVDAC,	/* VEC */
+		DRM_MODE_ENCODER_NONE,	/* FORCE_LCD */
+		DRM_MODE_ENCODER_NONE,	/* FORCE_TV */
+		DRM_MODE_ENCODER_NONE,	/* FORCE_OTHER */
+		DRM_MODE_ENCODER_TMDS,	/* HDMI1 */
+		DRM_MODE_ENCODER_NONE,	/* FORCE_TV2 */
+	};
+	return display_number > ARRAY_SIZE(display_types) - 1 ?
+			DRM_MODE_ENCODER_NONE : display_types[display_number];
+}
+
+/* Firmware's structure for making an FB mbox call. */
+struct fbinfo_s {
+	u32 xres, yres, xres_virtual, yres_virtual;
+	u32 pitch, bpp;
+	u32 xoffset, yoffset;
+	u32 base;
+	u32 screen_size;
+	u16 cmap[256];
+};
+
+struct vc4_fkms_plane {
+	struct drm_plane base;
+	struct fbinfo_s *fbinfo;
+	dma_addr_t fbinfo_bus_addr;
+	u32 pitch;
+	struct mailbox_set_plane mb;
+};
+
+static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
+{
+	return (struct vc4_fkms_plane *)plane;
+}
+
+static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
+{
+	struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+	struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+	struct mailbox_set_plane blank_mb = {
+		.tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 },
+		.plane = {
+			.display = vc4_plane->mb.plane.display,
+			.plane_id = vc4_plane->mb.plane.plane_id,
+		}
+	};
+	static const char * const plane_types[] = {
+							"overlay",
+							"primary",
+							"cursor"
+						  };
+	int ret;
+
+	DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s",
+			 plane->base.id, plane->name, plane_types[plane->type],
+			 blank ? "blank" : "unblank");
+
+	if (blank)
+		ret = rpi_firmware_property_list(vc4->firmware, &blank_mb,
+						 sizeof(blank_mb));
+	else
+		ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb,
+						 sizeof(vc4_plane->mb));
+
+	WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware",
+		  __func__);
+	return ret;
+}
+
+static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state,
+				      unsigned int *left, unsigned int *right,
+				      unsigned int *top, unsigned int *bottom)
+{
+	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
+	struct drm_connector_state *conn_state;
+	struct drm_connector *conn;
+	int i;
+
+	*left = vc4_state->margins.left;
+	*right = vc4_state->margins.right;
+	*top = vc4_state->margins.top;
+	*bottom = vc4_state->margins.bottom;
+
+	/* We have to interate over all new connector states because
+	 * vc4_fkms_crtc_get_margins() might be called before
+	 * vc4_fkms_crtc_atomic_check() which means margins info in
+	 * vc4_crtc_state might be outdated.
+	 */
+	for_each_new_connector_in_state(state->state, conn, conn_state, i) {
+		if (conn_state->crtc != state->crtc)
+			continue;
+
+		*left = conn_state->tv.margins.left;
+		*right = conn_state->tv.margins.right;
+		*top = conn_state->tv.margins.top;
+		*bottom = conn_state->tv.margins.bottom;
+		break;
+	}
+}
+
+static int vc4_fkms_margins_adj(struct drm_plane_state *pstate,
+				struct set_plane *plane)
+{
+	unsigned int left, right, top, bottom;
+	int adjhdisplay, adjvdisplay;
+	struct drm_crtc_state *crtc_state;
+
+	crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
+						   pstate->crtc);
+
+	vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
+
+	if (!left && !right && !top && !bottom)
+		return 0;
+
+	if (left + right >= crtc_state->mode.hdisplay ||
+	    top + bottom >= crtc_state->mode.vdisplay)
+		return -EINVAL;
+
+	adjhdisplay = crtc_state->mode.hdisplay - (left + right);
+	plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay,
+					 (int)crtc_state->mode.hdisplay);
+	plane->dst_x += left;
+	if (plane->dst_x > (int)(crtc_state->mode.hdisplay - right))
+		plane->dst_x = crtc_state->mode.hdisplay - right;
+
+	adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
+	plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay,
+					 (int)crtc_state->mode.vdisplay);
+	plane->dst_y += top;
+	if (plane->dst_y > (int)(crtc_state->mode.vdisplay - bottom))
+		plane->dst_y = crtc_state->mode.vdisplay - bottom;
+
+	plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay,
+					 crtc_state->mode.hdisplay);
+	plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay,
+					 crtc_state->mode.vdisplay);
+
+	if (!plane->dst_w || !plane->dst_h)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void vc4_plane_atomic_update(struct drm_plane *plane,
+				    struct drm_plane_state *old_state)
+{
+	struct drm_plane_state *state = plane->state;
+
+	/*
+	 * Do NOT set now, as we haven't checked if the crtc is active or not.
+	 * Set from vc4_plane_set_blank instead.
+	 *
+	 * If the CRTC is on (or going to be on) and we're enabled,
+	 * then unblank.  Otherwise, stay blank until CRTC enable.
+	 */
+	if (state->crtc->state->active)
+		vc4_plane_set_blank(plane, false);
+}
+
+static void vc4_plane_atomic_disable(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct drm_plane_state *state = plane->state;
+	struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+
+	DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
+			 plane->base.id, plane->name,
+			 state->crtc_w,
+			 state->crtc_h,
+			 vc4_plane->mb.plane.vc_image_type,
+			 state->crtc_x,
+			 state->crtc_y);
+	vc4_plane_set_blank(plane, true);
+}
+
+static bool plane_enabled(struct drm_plane_state *state)
+{
+	return state->fb && state->crtc;
+}
+
+static int vc4_plane_to_mb(struct drm_plane *plane,
+			   struct mailbox_set_plane *mb,
+			   struct drm_plane_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+	const struct drm_format_info *drm_fmt = fb->format;
+	const struct vc_image_format *vc_fmt =
+					vc4_get_vc_image_fmt(drm_fmt->format);
+	int num_planes = fb->format->num_planes;
+	unsigned int rotation;
+
+	mb->plane.vc_image_type = vc_fmt->vc_image;
+	mb->plane.width = fb->width;
+	mb->plane.height = fb->height;
+	mb->plane.pitch = fb->pitches[0];
+	mb->plane.src_w = state->src_w;
+	mb->plane.src_h = state->src_h;
+	mb->plane.src_x = state->src_x;
+	mb->plane.src_y = state->src_y;
+	mb->plane.dst_w = state->crtc_w;
+	mb->plane.dst_h = state->crtc_h;
+	mb->plane.dst_x = state->crtc_x;
+	mb->plane.dst_y = state->crtc_y;
+	mb->plane.alpha = state->alpha >> 8;
+	mb->plane.layer = state->normalized_zpos ?
+					state->normalized_zpos : -127;
+	mb->plane.num_planes = num_planes;
+	mb->plane.is_vu = vc_fmt->is_vu;
+	mb->plane.planes[0] = bo->paddr + fb->offsets[0];
+
+	rotation = drm_rotation_simplify(state->rotation,
+					 DRM_MODE_ROTATE_0 |
+					 DRM_MODE_REFLECT_X |
+					 DRM_MODE_REFLECT_Y);
+
+	mb->plane.transform = TRANSFORM_NO_ROTATE;
+	if (rotation & DRM_MODE_REFLECT_X)
+		mb->plane.transform |= TRANSFORM_FLIP_HRIZ;
+	if (rotation & DRM_MODE_REFLECT_Y)
+		mb->plane.transform |= TRANSFORM_FLIP_VERT;
+
+	vc4_fkms_margins_adj(state, &mb->plane);
+
+	if (num_planes > 1) {
+		/* Assume this must be YUV */
+		/* Makes assumptions on the stride for the chroma planes as we
+		 * can't easily plumb in non-standard pitches.
+		 */
+		mb->plane.planes[1] = bo->paddr + fb->offsets[1];
+		if (num_planes > 2)
+			mb->plane.planes[2] = bo->paddr + fb->offsets[2];
+		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.
+		 */
+		if (num_planes == 3 &&
+		    (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
+			mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
+
+		switch (state->color_encoding) {
+		default:
+		case DRM_COLOR_YCBCR_BT601:
+			if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE)
+				mb->plane.color_encoding =
+						VC_IMAGE_YUVINFO_CSC_ITUR_BT601;
+			else
+				mb->plane.color_encoding =
+						VC_IMAGE_YUVINFO_CSC_JPEG_JFIF;
+			break;
+		case DRM_COLOR_YCBCR_BT709:
+			/* Currently no support for a full range BT709 */
+			mb->plane.color_encoding =
+						VC_IMAGE_YUVINFO_CSC_ITUR_BT709;
+			break;
+		case DRM_COLOR_YCBCR_BT2020:
+			/* Currently no support for a full range BT2020 */
+			mb->plane.color_encoding =
+					VC_IMAGE_YUVINFO_CSC_REC_2020;
+			break;
+		}
+	} else {
+		mb->plane.planes[1] = 0;
+		mb->plane.planes[2] = 0;
+	}
+	mb->plane.planes[3] = 0;
+
+	switch (fourcc_mod_broadcom_mod(fb->modifier)) {
+	case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+		switch (mb->plane.vc_image_type) {
+		case VC_IMAGE_XRGB8888:
+			mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
+			break;
+		case VC_IMAGE_ARGB8888:
+			mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
+			break;
+		case VC_IMAGE_RGB565:
+			mb->plane.vc_image_type = VC_IMAGE_TF_RGB565;
+			break;
+		}
+		break;
+	case DRM_FORMAT_MOD_BROADCOM_SAND128:
+		switch (mb->plane.vc_image_type) {
+		case VC_IMAGE_YUV420SP:
+			mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
+			break;
+		/* VC_IMAGE_YUV10COL could be included in here, but it is only
+		 * valid as a SAND128 format, so the table at the top will have
+		 * already set the correct format.
+		 */
+		}
+		/* Note that the column pitch is passed across in lines, not
+		 * bytes.
+		 */
+		mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
+		break;
+	}
+
+	DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
+			 plane->base.id, plane->name,
+			 mb->plane.width,
+			 mb->plane.height,
+			 mb->plane.vc_image_type,
+			 state->crtc_x,
+			 state->crtc_y,
+			 state->crtc_w,
+			 state->crtc_h,
+			 mb->plane.src_x,
+			 mb->plane.src_y,
+			 mb->plane.src_w,
+			 mb->plane.src_h,
+			 mb->plane.planes[0],
+			 mb->plane.planes[1],
+			 mb->plane.planes[2],
+			 fb->pitches[0],
+			 state->alpha,
+			 state->normalized_zpos);
+
+	return 0;
+}
+
+static int vc4_plane_atomic_check(struct drm_plane *plane,
+				  struct drm_plane_state *state)
+{
+	struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+
+	if (!plane_enabled(state))
+		return 0;
+
+	return vc4_plane_to_mb(plane, &vc4_plane->mb, state);
+}
+
+/* Called during init to allocate the plane's atomic state. */
+static void vc4_plane_reset(struct drm_plane *plane)
+{
+	struct vc4_plane_state *vc4_state;
+
+	WARN_ON(plane->state);
+
+	vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
+	if (!vc4_state)
+		return;
+
+	__drm_atomic_helper_plane_reset(plane, &vc4_state->base);
+}
+
+static void vc4_plane_destroy(struct drm_plane *plane)
+{
+	drm_plane_cleanup(plane);
+}
+
+static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
+					  uint32_t format,
+					  uint64_t modifier)
+{
+	/* Support T_TILING for RGB formats only. */
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_RGB565:
+		switch (modifier) {
+		case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+		case DRM_FORMAT_MOD_LINEAR:
+			return true;
+		default:
+			return false;
+		}
+	case DRM_FORMAT_NV12:
+		switch (fourcc_mod_broadcom_mod(modifier)) {
+		case DRM_FORMAT_MOD_LINEAR:
+		case DRM_FORMAT_MOD_BROADCOM_SAND128:
+			return true;
+		default:
+			return false;
+		}
+	case DRM_FORMAT_P030:
+		switch (fourcc_mod_broadcom_mod(modifier)) {
+		case DRM_FORMAT_MOD_BROADCOM_SAND128:
+			return true;
+		default:
+			return false;
+		}
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+	case DRM_FORMAT_YUV422:
+	case DRM_FORMAT_YUV420:
+	case DRM_FORMAT_YVU420:
+	default:
+		return (modifier == DRM_FORMAT_MOD_LINEAR);
+	}
+}
+
+static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
+{
+	struct vc4_plane_state *vc4_state;
+
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
+	if (!vc4_state)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
+
+	return &vc4_state->base;
+}
+
+static const struct drm_plane_funcs vc4_plane_funcs = {
+	.update_plane = drm_atomic_helper_update_plane,
+	.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,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.format_mod_supported = vc4_fkms_format_mod_supported,
+};
+
+static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
+	.prepare_fb = drm_gem_fb_prepare_fb,
+	.cleanup_fb = NULL,
+	.atomic_check = vc4_plane_atomic_check,
+	.atomic_update = vc4_plane_atomic_update,
+	.atomic_disable = vc4_plane_atomic_disable,
+};
+
+static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
+					     enum drm_plane_type type,
+					     u8 display_num,
+					     u8 plane_id)
+{
+	struct drm_plane *plane = NULL;
+	struct vc4_fkms_plane *vc4_plane;
+	u32 formats[ARRAY_SIZE(vc_image_formats)];
+	unsigned int default_zpos = 0;
+	u32 num_formats = 0;
+	int ret = 0;
+	static const uint64_t modifiers[] = {
+		DRM_FORMAT_MOD_LINEAR,
+		/* VC4_T_TILED should come after linear, because we
+		 * would prefer to scan out linear (less bus traffic).
+		 */
+		DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
+		DRM_FORMAT_MOD_BROADCOM_SAND128,
+		DRM_FORMAT_MOD_INVALID,
+	};
+	int i;
+
+	vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
+				 GFP_KERNEL);
+	if (!vc4_plane) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++)
+		formats[num_formats++] = vc_image_formats[i].drm;
+
+	plane = &vc4_plane->base;
+	ret = drm_universal_plane_init(dev, plane, 0,
+				       &vc4_plane_funcs,
+				       formats, num_formats, modifiers,
+				       type, NULL);
+
+	/* FIXME: Do we need to be checking return values from all these calls?
+	 */
+	drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
+
+	drm_plane_create_alpha_property(plane);
+	drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
+					   DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y);
+	drm_plane_create_color_properties(plane,
+					  BIT(DRM_COLOR_YCBCR_BT601) |
+					  BIT(DRM_COLOR_YCBCR_BT709) |
+					  BIT(DRM_COLOR_YCBCR_BT2020),
+					  BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+					  BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+					  DRM_COLOR_YCBCR_BT709,
+					  DRM_COLOR_YCBCR_LIMITED_RANGE);
+
+	/*
+	 * Default frame buffer setup is with FB on -127, and raspistill etc
+	 * tend to drop overlays on layer 2. Cursor plane was on layer +127.
+	 *
+	 * For F-KMS the mailbox call allows for a s8.
+	 * Remap zpos 0 to -127 for the background layer, but leave all the
+	 * other layers as requested by KMS.
+	 */
+	switch (type) {
+	default:
+	case DRM_PLANE_TYPE_PRIMARY:
+		default_zpos = 0;
+		break;
+	case DRM_PLANE_TYPE_OVERLAY:
+		default_zpos = 1;
+		break;
+	case DRM_PLANE_TYPE_CURSOR:
+		default_zpos = 2;
+		break;
+	}
+	drm_plane_create_zpos_property(plane, default_zpos, 0, 127);
+
+	/* Prepare the static elements of the mailbox structure */
+	vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
+	vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
+	vc4_plane->mb.tag.req_resp_size = 0;
+	vc4_plane->mb.plane.display = display_num;
+	vc4_plane->mb.plane.plane_id = plane_id;
+	vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
+
+	return plane;
+fail:
+	if (plane)
+		vc4_plane_destroy(plane);
+
+	return ERR_PTR(ret);
+}
+
+static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct vc4_dev *vc4 = to_vc4_dev(dev);
+	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct vc4_fkms_encoder *vc4_encoder =
+					to_vc4_fkms_encoder(vc4_crtc->encoder);
+	struct mailbox_set_mode mb = {
+		.tag1 = { RPI_FIRMWARE_SET_TIMING,
+			  sizeof(struct set_timings), 0},
+	};
+	union hdmi_infoframe frame;
+	int ret;
+
+	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_crtc->connector, mode);
+	if (ret < 0) {
+		DRM_ERROR("couldn't fill AVI infoframe\n");
+		return;
+	}
+
+	DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u, flags 0x%04x\n",
+		      vc4_crtc->display_number, mode->name, mode->clock,
+		      mode->hdisplay, mode->hsync_start, mode->hsync_end,
+		      mode->htotal, mode->hskew, mode->vdisplay,
+		      mode->vsync_start, mode->vsync_end, mode->vtotal,
+		      mode->vscan, drm_mode_vrefresh(mode),
+		      mode->picture_aspect_ratio, mode->flags);
+	mb.timings.display = vc4_crtc->display_number;
+
+	mb.timings.clock = mode->clock;
+	mb.timings.hdisplay = mode->hdisplay;
+	mb.timings.hsync_start = mode->hsync_start;
+	mb.timings.hsync_end = mode->hsync_end;
+	mb.timings.htotal = mode->htotal;
+	mb.timings.hskew = mode->hskew;
+	mb.timings.vdisplay = mode->vdisplay;
+	mb.timings.vsync_start = mode->vsync_start;
+	mb.timings.vsync_end = mode->vsync_end;
+	mb.timings.vtotal = mode->vtotal;
+	mb.timings.vscan = mode->vscan;
+	mb.timings.vrefresh = drm_mode_vrefresh(mode);
+	mb.timings.flags = 0;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		mb.timings.flags |= TIMINGS_FLAGS_V_SYNC_POS;
+
+	switch (frame.avi.picture_aspect) {
+	default:
+	case HDMI_PICTURE_ASPECT_NONE:
+		mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE;
+		break;
+	case HDMI_PICTURE_ASPECT_4_3:
+		mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3;
+		break;
+	case HDMI_PICTURE_ASPECT_16_9:
+		mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9;
+		break;
+	case HDMI_PICTURE_ASPECT_64_27:
+		mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27;
+		break;
+	case HDMI_PICTURE_ASPECT_256_135:
+		mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135;
+		break;
+	}
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		mb.timings.flags |= TIMINGS_FLAGS_INTERLACE;
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		mb.timings.flags |= TIMINGS_FLAGS_DBL_CLK;
+
+	mb.timings.video_id_code = frame.avi.video_code;
+
+	if (!vc4_encoder->hdmi_monitor) {
+		mb.timings.flags |= TIMINGS_FLAGS_DVI;
+	} else {
+		struct vc4_fkms_connector_state *conn_state =
+			to_vc4_fkms_connector_state(vc4_crtc->connector->state);
+
+		if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) {
+			/* See CEA-861-E - 5.1 Default Encoding Parameters */
+			if (drm_default_rgb_quant_range(mode) ==
+					HDMI_QUANTIZATION_RANGE_LIMITED)
+				mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
+		} else {
+			if (conn_state->broadcast_rgb ==
+						VC4_BROADCAST_RGB_LIMITED)
+				mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
+
+			/* If not using the default range, then do not provide
+			 * a VIC as the HDMI spec requires that we do not
+			 * signal the opposite of the defined range in the AVI
+			 * infoframe.
+			 */
+			if (!!(mb.timings.flags & TIMINGS_FLAGS_RGB_LIMITED) !=
+			    (drm_default_rgb_quant_range(mode) ==
+					HDMI_QUANTIZATION_RANGE_LIMITED))
+				mb.timings.video_id_code = 0;
+		}
+	}
+
+	/*
+	 * FIXME: To implement
+	 * switch(mode->flag & DRM_MODE_FLAG_3D_MASK) {
+	 * case DRM_MODE_FLAG_3D_NONE:
+	 * case DRM_MODE_FLAG_3D_FRAME_PACKING:
+	 * case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
+	 * case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
+	 * case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
+	 * case DRM_MODE_FLAG_3D_L_DEPTH:
+	 * case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
+	 * case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
+	 * case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
+	 * }
+	 */
+
+	ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
+}
+
+static void vc4_crtc_disable(struct drm_crtc *crtc,
+			     struct drm_atomic_state *state)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_plane *plane;
+
+	DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
+		      crtc->base.id);
+	drm_crtc_vblank_off(crtc);
+
+	/* Always turn the planes off on CRTC disable. In DRM, planes
+	 * are enabled/disabled through the update/disable hooks
+	 * above, and the CRTC enable/disable independently controls
+	 * whether anything scans out at all, but the firmware doesn't
+	 * give us a CRTC-level control for that.
+	 */
+
+	drm_atomic_crtc_for_each_plane(plane, crtc)
+		vc4_plane_atomic_disable(plane, plane->state);
+
+	/*
+	 * Make sure we issue a vblank event after disabling the CRTC if
+	 * someone was waiting it.
+	 */
+	if (crtc->state->event) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&dev->event_lock, flags);
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+	}
+}
+
+static void vc4_crtc_consume_event(struct drm_crtc *crtc)
+{
+	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	unsigned long flags;
+
+	if (!crtc->state->event)
+		return;
+
+	crtc->state->event->pipe = drm_crtc_index(crtc);
+
+	WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	vc4_crtc->event = crtc->state->event;
+	crtc->state->event = NULL;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static void vc4_crtc_enable(struct drm_crtc *crtc,
+			    struct drm_atomic_state *state)
+{
+	struct drm_plane *plane;
+
+	DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
+		      crtc->base.id);
+	drm_crtc_vblank_on(crtc);
+	vc4_crtc_consume_event(crtc);
+
+	/* Unblank the planes (if they're supposed to be displayed). */
+	drm_atomic_crtc_for_each_plane(plane, crtc)
+		if (plane->state->fb)
+			vc4_plane_set_blank(plane, plane->state->visible);
+}
+
+static enum drm_mode_status
+vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
+{
+	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct vc4_dev *vc4 = to_vc4_dev(dev);
+	struct vc4_fkms *fkms = vc4->fkms;
+
+	/* Do not allow doublescan modes from user space */
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
+		DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
+			      crtc->base.id);
+		return MODE_NO_DBLESCAN;
+	}
+
+	/* Disable refresh rates > defined threshold (default 85Hz) as limited
+	 * gain from them
+	 */
+	if (drm_mode_vrefresh(mode) > fkms_max_refresh_rate)
+		return MODE_BAD_VVALUE;
+
+	/* Limit the pixel clock based on the HDMI clock limits from the
+	 * firmware
+	 */
+	switch (vc4_crtc->display_number) {
+	case 2:	/* HDMI0 */
+		if (fkms->cfg.max_pixel_clock[0] &&
+		    mode->clock > fkms->cfg.max_pixel_clock[0])
+			return MODE_CLOCK_HIGH;
+		break;
+	case 7:	/* HDMI1 */
+		if (fkms->cfg.max_pixel_clock[1] &&
+		    mode->clock > fkms->cfg.max_pixel_clock[1])
+			return MODE_CLOCK_HIGH;
+		break;
+	}
+
+	/* Pi4 can't generate odd horizontal timings on HDMI, so reject modes
+	 * that would set them.
+	 */
+	if (fkms->bcm2711 &&
+	    (vc4_crtc->display_number == 2 || vc4_crtc->display_number == 7) &&
+	    !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
+	    ((mode->hdisplay |				/* active */
+	      (mode->hsync_start - mode->hdisplay) |	/* front porch */
+	      (mode->hsync_end - mode->hsync_start) |	/* sync pulse */
+	      (mode->htotal - mode->hsync_end)) & 1))	/* back porch */ {
+		DRM_DEBUG_KMS("[CRTC:%d] Odd timing rejected %u %u %u %u.\n",
+			      crtc->base.id, mode->hdisplay, mode->hsync_start,
+			      mode->hsync_end, mode->htotal);
+		return MODE_H_ILLEGAL;
+	}
+
+	return MODE_OK;
+}
+
+static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+				 struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
+	struct drm_connector *conn;
+	struct drm_connector_state *conn_state;
+	int i;
+
+	DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id);
+
+	for_each_new_connector_in_state(crtc_state->state, conn, conn_state, i) {
+		if (conn_state->crtc != crtc)
+			continue;
+
+		vc4_state->margins.left = conn_state->tv.margins.left;
+		vc4_state->margins.right = conn_state->tv.margins.right;
+		vc4_state->margins.top = conn_state->tv.margins.top;
+		vc4_state->margins.bottom = conn_state->tv.margins.bottom;
+		break;
+	}
+	return 0;
+}
+
+static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
+				  struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
+
+	DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
+		      crtc->base.id);
+	if (crtc->state->active && old_state->active && crtc->state->event)
+		vc4_crtc_consume_event(crtc);
+}
+
+static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
+{
+	struct drm_crtc *crtc = &vc4_crtc->base;
+	struct drm_device *dev = crtc->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	if (vc4_crtc->event) {
+		drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
+		vc4_crtc->event = NULL;
+		drm_crtc_vblank_put(crtc);
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
+{
+	struct vc4_crtc **crtc_list = data;
+	int i;
+	u32 stat = readl(crtc_list[0]->regs + SMICS);
+	irqreturn_t ret = IRQ_NONE;
+	u32 chan;
+
+	if (stat & SMICS_INTERRUPTS) {
+		writel(0, crtc_list[0]->regs + SMICS);
+
+		chan = readl(crtc_list[0]->regs + SMIDSW0);
+
+		if ((chan & 0xFFFF0000) != SMI_NEW) {
+			/* Older firmware. Treat the one interrupt as vblank/
+			 * complete for all crtcs.
+			 */
+			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]);
+			}
+		} else {
+			if (chan & 1) {
+				writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0);
+				if (crtc_list[0]->vblank_enabled)
+					drm_crtc_handle_vblank(&crtc_list[0]->base);
+				vc4_crtc_handle_page_flip(crtc_list[0]);
+			}
+
+			if (crtc_list[1]) {
+				/* Check for the secondary display too */
+				chan = readl(crtc_list[0]->regs + SMIDSW1);
+
+				if (chan & 1) {
+					writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
+
+					if (crtc_list[1]->vblank_enabled)
+						drm_crtc_handle_vblank(&crtc_list[1]->base);
+					vc4_crtc_handle_page_flip(crtc_list[1]);
+				}
+			}
+		}
+
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static int vc4_fkms_page_flip(struct drm_crtc *crtc,
+			      struct drm_framebuffer *fb,
+			      struct drm_pending_vblank_event *event,
+			      uint32_t flags,
+			      struct drm_modeset_acquire_ctx *ctx)
+{
+	if (flags & DRM_MODE_PAGE_FLIP_ASYNC) {
+		DRM_ERROR("Async flips aren't allowed\n");
+		return -EINVAL;
+	}
+
+	return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
+}
+
+static struct drm_crtc_state *
+vc4_fkms_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct vc4_crtc_state *vc4_state, *old_vc4_state;
+
+	vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
+	if (!vc4_state)
+		return NULL;
+
+	old_vc4_state = to_vc4_crtc_state(crtc->state);
+	vc4_state->margins = old_vc4_state->margins;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
+	return &vc4_state->base;
+}
+
+static void
+vc4_fkms_crtc_reset(struct drm_crtc *crtc)
+{
+	if (crtc->state)
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
+	if (crtc->state)
+		crtc->state->crtc = crtc;
+}
+
+static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
+{
+	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
+	DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n",
+		      crtc->base.id);
+	vc4_crtc->vblank_enabled = true;
+
+	return 0;
+}
+
+static void vc4_fkms_disable_vblank(struct drm_crtc *crtc)
+{
+	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
+	DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n",
+		      crtc->base.id);
+	vc4_crtc->vblank_enabled = false;
+}
+
+static const struct drm_crtc_funcs vc4_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.page_flip = vc4_fkms_page_flip,
+	.set_property = NULL,
+	.cursor_set = NULL, /* handled by drm_mode_cursor_universal */
+	.cursor_move = NULL, /* handled by drm_mode_cursor_universal */
+	.reset = vc4_fkms_crtc_reset,
+	.atomic_duplicate_state = vc4_fkms_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+	.enable_vblank = vc4_fkms_enable_vblank,
+	.disable_vblank = vc4_fkms_disable_vblank,
+};
+
+static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
+	.mode_set_nofb = vc4_crtc_mode_set_nofb,
+	.mode_valid = vc4_crtc_mode_valid,
+	.atomic_check = vc4_crtc_atomic_check,
+	.atomic_flush = vc4_crtc_atomic_flush,
+	.atomic_enable = vc4_crtc_enable,
+	.atomic_disable = vc4_crtc_disable,
+};
+
+static const struct of_device_id vc4_firmware_kms_dt_match[] = {
+	{ .compatible = "raspberrypi,rpi-firmware-kms" },
+	{ .compatible = "raspberrypi,rpi-firmware-kms-2711",
+	  .data = (void *)1 },
+	{}
+};
+
+static enum drm_connector_status
+vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
+{
+	DRM_DEBUG_KMS("connector detect.\n");
+	return connector_status_connected;
+}
+
+/* Queries the firmware to populate a drm_mode structure for this display */
+static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector,
+				struct drm_display_mode *mode)
+{
+	struct vc4_dev *vc4 = fkms_connector->vc4_dev;
+	struct set_timings timings = { 0 };
+	int ret;
+
+	timings.display = fkms_connector->display_number;
+
+	ret = rpi_firmware_property(vc4->firmware,
+				    RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings,
+				    sizeof(timings));
+	if (ret || !timings.clock)
+		/* No mode returned - abort */
+		return -1;
+
+	/* Equivalent to DRM_MODE macro. */
+	memset(mode, 0, sizeof(*mode));
+	strncpy(mode->name, "FIXED_MODE", sizeof(mode->name));
+	mode->status = 0;
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	mode->clock = timings.clock;
+	mode->hdisplay = timings.hdisplay;
+	mode->hsync_start = timings.hsync_start;
+	mode->hsync_end = timings.hsync_end;
+	mode->htotal = timings.htotal;
+	mode->hskew = 0;
+	mode->vdisplay = timings.vdisplay;
+	mode->vsync_start = timings.vsync_start;
+	mode->vsync_end = timings.vsync_end;
+	mode->vtotal = timings.vtotal;
+	mode->vscan = timings.vscan;
+
+	if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
+		mode->flags |= DRM_MODE_FLAG_PHSYNC;
+	else
+		mode->flags |= DRM_MODE_FLAG_NHSYNC;
+
+	if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
+		mode->flags |= DRM_MODE_FLAG_PVSYNC;
+	else
+		mode->flags |= DRM_MODE_FLAG_NVSYNC;
+
+	if (timings.flags & TIMINGS_FLAGS_INTERLACE)
+		mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+	return 0;
+}
+
+static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
+				   size_t len)
+{
+	struct vc4_fkms_connector *fkms_connector =
+					(struct vc4_fkms_connector *)data;
+	struct vc4_dev *vc4 = fkms_connector->vc4_dev;
+	struct mailbox_get_edid mb = {
+		.tag1 = { RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY,
+			  128 + 8, 0 },
+		.block = block,
+		.display_number = fkms_connector->display_number,
+	};
+	int ret = 0;
+
+	ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
+
+	if (!ret)
+		memcpy(buf, mb.edid, len);
+
+	return ret;
+}
+
+static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
+{
+	struct vc4_fkms_connector *fkms_connector =
+					to_vc4_fkms_connector(connector);
+	struct drm_encoder *encoder = fkms_connector->encoder;
+	struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
+	struct drm_display_mode fw_mode;
+	struct drm_display_mode *mode;
+	struct edid *edid;
+	int num_modes;
+
+	if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) {
+		drm_mode_debug_printmodeline(&fw_mode);
+		mode = drm_mode_duplicate(connector->dev,
+					  &fw_mode);
+		drm_mode_probed_add(connector, mode);
+		num_modes = 1;	/* 1 mode */
+	} else {
+		edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
+				       fkms_connector);
+
+		/* FIXME: Can we do CEC?
+		 * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
+		 * if (!edid)
+		 *	return -ENODEV;
+		 */
+
+		vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+
+		drm_connector_update_edid_property(connector, edid);
+		num_modes = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	}
+
+	return num_modes;
+}
+
+/* This is the DSI panel resolution. Use this as a default should the firmware
+ * not respond to our request for the timings.
+ */
+static const struct drm_display_mode lcd_mode = {
+	DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+		 25979400 / 1000,
+		 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
+		 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
+		 0)
+};
+
+static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
+{
+	struct vc4_fkms_connector *fkms_connector =
+					to_vc4_fkms_connector(connector);
+	struct drm_display_mode *mode;
+	struct drm_display_mode fw_mode;
+
+	if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
+		mode = drm_mode_duplicate(connector->dev,
+					  &fw_mode);
+	else
+		mode = drm_mode_duplicate(connector->dev,
+					  &lcd_mode);
+
+	if (!mode) {
+		DRM_ERROR("Failed to create a new display mode\n");
+		return -ENOMEM;
+	}
+
+	drm_mode_probed_add(connector, mode);
+
+	/* We have one mode */
+	return 1;
+}
+
+static struct drm_encoder *
+vc4_fkms_connector_best_encoder(struct drm_connector *connector)
+{
+	struct vc4_fkms_connector *fkms_connector =
+		to_vc4_fkms_connector(connector);
+	DRM_DEBUG_KMS("best_connector.\n");
+	return fkms_connector->encoder;
+}
+
+static void vc4_fkms_connector_destroy(struct drm_connector *connector)
+{
+	DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n",
+		      connector->base.id);
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+/**
+ * vc4_connector_duplicate_state - duplicate connector state
+ * @connector: digital connector
+ *
+ * Allocates and returns a copy of the connector state (both common and
+ * digital connector specific) for the specified connector.
+ *
+ * Returns: The newly allocated connector state, or NULL on failure.
+ */
+struct drm_connector_state *
+vc4_connector_duplicate_state(struct drm_connector *connector)
+{
+	struct vc4_fkms_connector_state *state;
+
+	state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_connector_duplicate_state(connector, &state->base);
+	return &state->base;
+}
+
+/**
+ * vc4_connector_atomic_get_property - hook for connector->atomic_get_property.
+ * @connector: Connector to get the property for.
+ * @state: Connector state to retrieve the property from.
+ * @property: Property to retrieve.
+ * @val: Return value for the property.
+ *
+ * Returns the atomic property value for a digital connector.
+ */
+int vc4_connector_atomic_get_property(struct drm_connector *connector,
+				      const struct drm_connector_state *state,
+				      struct drm_property *property,
+				      uint64_t *val)
+{
+	struct vc4_fkms_connector *fkms_connector =
+					to_vc4_fkms_connector(connector);
+	struct vc4_fkms_connector_state *vc4_conn_state =
+					to_vc4_fkms_connector_state(state);
+
+	if (property == fkms_connector->broadcast_rgb_property) {
+		*val = vc4_conn_state->broadcast_rgb;
+	} else {
+		DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
+				 property->base.id, property->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * vc4_connector_atomic_set_property - hook for connector->atomic_set_property.
+ * @connector: Connector to set the property for.
+ * @state: Connector state to set the property on.
+ * @property: Property to set.
+ * @val: New value for the property.
+ *
+ * Sets the atomic property value for a digital connector.
+ */
+int vc4_connector_atomic_set_property(struct drm_connector *connector,
+				      struct drm_connector_state *state,
+				      struct drm_property *property,
+				      uint64_t val)
+{
+	struct vc4_fkms_connector *fkms_connector =
+					to_vc4_fkms_connector(connector);
+	struct vc4_fkms_connector_state *vc4_conn_state =
+					to_vc4_fkms_connector_state(state);
+
+	if (property == fkms_connector->broadcast_rgb_property) {
+		vc4_conn_state->broadcast_rgb = val;
+		return 0;
+	}
+
+	DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
+			 property->base.id, property->name);
+	return -EINVAL;
+}
+
+int vc4_connector_atomic_check(struct drm_connector *connector,
+			       struct drm_atomic_state *state)
+{
+	struct drm_connector_state *old_state =
+		drm_atomic_get_old_connector_state(state, connector);
+	struct vc4_fkms_connector_state *vc4_old_state =
+					to_vc4_fkms_connector_state(old_state);
+	struct drm_connector_state *new_state =
+		drm_atomic_get_new_connector_state(state, connector);
+	struct vc4_fkms_connector_state *vc4_new_state =
+					to_vc4_fkms_connector_state(new_state);
+	struct drm_crtc *crtc = new_state->crtc;
+
+	if (!crtc)
+		return 0;
+
+	if (vc4_old_state->broadcast_rgb != vc4_new_state->broadcast_rgb) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state, crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+
+		crtc_state->mode_changed = true;
+	}
+	return 0;
+}
+
+static void vc4_hdmi_connector_reset(struct drm_connector *connector)
+{
+	drm_atomic_helper_connector_reset(connector);
+	drm_atomic_helper_connector_tv_reset(connector);
+}
+
+static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
+	.detect = vc4_fkms_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = vc4_fkms_connector_destroy,
+	.reset = vc4_hdmi_connector_reset,
+	.atomic_duplicate_state = vc4_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+	.atomic_get_property = vc4_connector_atomic_get_property,
+	.atomic_set_property = vc4_connector_atomic_set_property,
+};
+
+static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
+	.get_modes = vc4_fkms_connector_get_modes,
+	.best_encoder = vc4_fkms_connector_best_encoder,
+	.atomic_check = vc4_connector_atomic_check,
+};
+
+static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs = {
+	.get_modes = vc4_fkms_lcd_connector_get_modes,
+	.best_encoder = vc4_fkms_connector_best_encoder,
+};
+
+static const struct drm_prop_enum_list broadcast_rgb_names[] = {
+	{ VC4_BROADCAST_RGB_AUTO, "Automatic" },
+	{ VC4_BROADCAST_RGB_FULL, "Full" },
+	{ VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" },
+};
+
+static void
+vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector)
+{
+	struct drm_device *dev = fkms_connector->base.dev;
+	struct drm_property *prop;
+
+	prop = fkms_connector->broadcast_rgb_property;
+	if (!prop) {
+		prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
+						"Broadcast RGB",
+						broadcast_rgb_names,
+						ARRAY_SIZE(broadcast_rgb_names));
+		if (!prop)
+			return;
+
+		fkms_connector->broadcast_rgb_property = prop;
+	}
+
+	drm_object_attach_property(&fkms_connector->base.base, prop, 0);
+}
+
+static struct drm_connector *
+vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
+			u32 display_num)
+{
+	struct drm_connector *connector = NULL;
+	struct vc4_fkms_connector *fkms_connector;
+	struct vc4_fkms_connector_state *conn_state = NULL;
+	struct vc4_dev *vc4_dev = to_vc4_dev(dev);
+	int ret = 0;
+
+	DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num);
+
+	fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
+				      GFP_KERNEL);
+	if (!fkms_connector)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * Allocate enough memory to hold vc4_fkms_connector_state,
+	 */
+	conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
+	if (!conn_state) {
+		kfree(fkms_connector);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	connector = &fkms_connector->base;
+
+	fkms_connector->encoder = encoder;
+	fkms_connector->display_number = display_num;
+	fkms_connector->display_type = vc4_get_display_type(display_num);
+	fkms_connector->vc4_dev = vc4_dev;
+
+	__drm_atomic_helper_connector_reset(connector,
+					    &conn_state->base);
+
+	if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
+		drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+				   DRM_MODE_CONNECTOR_DSI);
+		drm_connector_helper_add(connector,
+					 &vc4_fkms_lcd_conn_helper_funcs);
+		connector->interlace_allowed = 0;
+	} else if (fkms_connector->display_type == DRM_MODE_ENCODER_TVDAC) {
+		drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+				   DRM_MODE_CONNECTOR_Composite);
+		drm_connector_helper_add(connector,
+					 &vc4_fkms_lcd_conn_helper_funcs);
+		connector->interlace_allowed = 1;
+	} else {
+		drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+				   DRM_MODE_CONNECTOR_HDMIA);
+		drm_connector_helper_add(connector,
+					 &vc4_fkms_connector_helper_funcs);
+		connector->interlace_allowed = 1;
+	}
+
+	ret = drm_mode_create_tv_margin_properties(dev);
+	if (ret)
+		goto fail;
+
+	drm_connector_attach_tv_margin_properties(connector);
+
+	connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+			     DRM_CONNECTOR_POLL_DISCONNECT);
+
+	connector->doublescan_allowed = 0;
+
+	vc4_attach_broadcast_rgb_property(fkms_connector);
+
+	drm_connector_attach_encoder(connector, encoder);
+
+	return connector;
+
+ fail:
+	if (connector)
+		vc4_fkms_connector_destroy(connector);
+
+	return ERR_PTR(ret);
+}
+
+static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
+{
+	DRM_DEBUG_KMS("Encoder_destroy\n");
+	drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs vc4_fkms_encoder_funcs = {
+	.destroy = vc4_fkms_encoder_destroy,
+};
+
+static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power)
+{
+	struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
+	struct vc4_dev *vc4 = to_vc4_dev(encoder->dev);
+
+	struct mailbox_display_pwr pwr = {
+		.tag1 = {RPI_FIRMWARE_SET_DISPLAY_POWER, 8, 0, },
+		.display = vc4_encoder->display_num,
+		.state = power ? 1 : 0,
+	};
+
+	rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr));
+}
+
+static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
+{
+	vc4_fkms_display_power(encoder, true);
+	DRM_DEBUG_KMS("Encoder_enable\n");
+}
+
+static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
+{
+	vc4_fkms_display_power(encoder, false);
+	DRM_DEBUG_KMS("Encoder_disable\n");
+}
+
+static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
+	.enable = vc4_fkms_encoder_enable,
+	.disable = vc4_fkms_encoder_disable,
+};
+
+static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
+				  int display_idx, int display_ref,
+				  struct vc4_crtc **ret_crtc)
+{
+	struct vc4_dev *vc4 = to_vc4_dev(drm);
+	struct vc4_crtc *vc4_crtc;
+	struct vc4_fkms_encoder *vc4_encoder;
+	struct drm_crtc *crtc;
+	struct drm_plane *destroy_plane, *temp;
+	struct mailbox_blank_display blank = {
+		.tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
+		.display = display_idx,
+		.tag2 = { RPI_FIRMWARE_FRAMEBUFFER_BLANK, 4, 0, },
+		.blank = 1,
+	};
+	struct drm_plane *planes[PLANES_PER_CRTC];
+	int ret, i;
+
+	vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
+	if (!vc4_crtc)
+		return -ENOMEM;
+	crtc = &vc4_crtc->base;
+
+	vc4_crtc->display_number = display_ref;
+	vc4_crtc->display_type = vc4_get_display_type(display_ref);
+
+	/* Blank the firmware provided framebuffer */
+	rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
+
+	for (i = 0; i < PLANES_PER_CRTC; i++) {
+		planes[i] = vc4_fkms_plane_init(drm,
+						(i == 0) ?
+						  DRM_PLANE_TYPE_PRIMARY :
+						  (i == PLANES_PER_CRTC - 1) ?
+							DRM_PLANE_TYPE_CURSOR :
+							DRM_PLANE_TYPE_OVERLAY,
+						display_ref,
+						i + (display_idx * PLANES_PER_CRTC)
+					       );
+		if (IS_ERR(planes[i])) {
+			dev_err(dev, "failed to construct plane %u\n", i);
+			ret = PTR_ERR(planes[i]);
+			goto err;
+		}
+	}
+
+	drm_crtc_init_with_planes(drm, crtc, planes[0],
+				  planes[PLANES_PER_CRTC - 1], &vc4_crtc_funcs,
+				  NULL);
+	drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
+
+	/* Update the possible_crtcs mask for the overlay plane(s) */
+	for (i = 1; i < (PLANES_PER_CRTC - 1); i++)
+		planes[i]->possible_crtcs = drm_crtc_mask(crtc);
+
+	vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL);
+	if (!vc4_encoder)
+		return -ENOMEM;
+	vc4_crtc->encoder = &vc4_encoder->base;
+
+	vc4_encoder->display_num = display_ref;
+	vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc);
+
+	drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
+			 vc4_crtc->display_type, NULL);
+	drm_encoder_helper_add(&vc4_encoder->base,
+			       &vc4_fkms_encoder_helper_funcs);
+
+	vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
+						      display_ref);
+	if (IS_ERR(vc4_crtc->connector)) {
+		ret = PTR_ERR(vc4_crtc->connector);
+		goto err_destroy_encoder;
+	}
+
+	*ret_crtc = vc4_crtc;
+
+	return 0;
+
+err_destroy_encoder:
+	vc4_fkms_encoder_destroy(vc4_crtc->encoder);
+	list_for_each_entry_safe(destroy_plane, temp,
+				 &drm->mode_config.plane_list, head) {
+		if (destroy_plane->possible_crtcs == 1 << drm_crtc_index(crtc))
+			destroy_plane->funcs->destroy(destroy_plane);
+	}
+err:
+	return ret;
+}
+
+static int vc4_fkms_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 device_node *firmware_node;
+	const struct of_device_id *match;
+	struct vc4_crtc **crtc_list;
+	u32 num_displays, display_num;
+	struct vc4_fkms *fkms;
+	int ret;
+	u32 display_id;
+
+	vc4->firmware_kms = true;
+
+	fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL);
+	if (!fkms)
+		return -ENOMEM;
+
+	match = of_match_device(vc4_firmware_kms_dt_match, dev);
+	if (!match)
+		return -ENODEV;
+	if (match->data)
+		fkms->bcm2711 = true;
+
+	firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
+	vc4->firmware = rpi_firmware_get(firmware_node);
+	if (!vc4->firmware) {
+		DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
+		return -EPROBE_DEFER;
+	}
+	of_node_put(firmware_node);
+
+	ret = rpi_firmware_property(vc4->firmware,
+				    RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
+				    &num_displays, sizeof(u32));
+
+	/* If we fail to get the number of displays, then
+	 * assume old firmware that doesn't have the mailbox call, so just
+	 * set one display
+	 */
+	if (ret) {
+		num_displays = 1;
+		DRM_WARN("Unable to determine number of displays - assuming 1\n");
+		ret = 0;
+	}
+
+	ret = rpi_firmware_property(vc4->firmware,
+				    RPI_FIRMWARE_GET_DISPLAY_CFG,
+				    &fkms->cfg, sizeof(fkms->cfg));
+
+	if (ret)
+		return -EINVAL;
+	/* The firmware works in Hz. This will be compared against kHz, so div
+	 * 1000 now rather than multiple times later.
+	 */
+	fkms->cfg.max_pixel_clock[0] /= 1000;
+	fkms->cfg.max_pixel_clock[1] /= 1000;
+
+	/* Allocate a list, with space for a NULL on the end */
+	crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
+				 GFP_KERNEL);
+	if (!crtc_list)
+		return -ENOMEM;
+
+	for (display_num = 0; display_num < num_displays; display_num++) {
+		display_id = display_num;
+		ret = rpi_firmware_property(vc4->firmware,
+					    RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
+					    &display_id, sizeof(display_id));
+		/* FIXME: Determine the correct error handling here.
+		 * Should we fail to create the one "screen" but keep the
+		 * others, or fail the whole thing?
+		 */
+		if (ret)
+			DRM_ERROR("Failed to get display id %u\n", display_num);
+
+		ret = vc4_fkms_create_screen(dev, drm, display_num, display_id,
+					     &crtc_list[display_num]);
+		if (ret)
+			DRM_ERROR("Oh dear, failed to create display %u\n",
+				  display_num);
+	}
+
+	if (num_displays > 0) {
+		/* Map the SMI interrupt reg */
+		crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
+		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 (ret)
+			DRM_ERROR("Oh dear, failed to register IRQ\n");
+	} else {
+		DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
+	}
+
+	vc4->fkms = fkms;
+
+	platform_set_drvdata(pdev, crtc_list);
+
+	return 0;
+}
+
+static void vc4_fkms_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; crtc_list[i]; i++) {
+		vc4_fkms_connector_destroy(crtc_list[i]->connector);
+		vc4_fkms_encoder_destroy(crtc_list[i]->encoder);
+		drm_crtc_cleanup(&crtc_list[i]->base);
+	}
+
+	platform_set_drvdata(pdev, NULL);
+}
+
+static const struct component_ops vc4_fkms_ops = {
+	.bind   = vc4_fkms_bind,
+	.unbind = vc4_fkms_unbind,
+};
+
+static int vc4_fkms_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &vc4_fkms_ops);
+}
+
+static int vc4_fkms_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &vc4_fkms_ops);
+	return 0;
+}
+
+struct platform_driver vc4_firmware_kms_driver = {
+	.probe = vc4_fkms_probe,
+	.remove = vc4_fkms_remove,
+	.driver = {
+		.name = "vc4_firmware_kms",
+		.of_match_table = vc4_firmware_kms_dt_match,
+	},
+};
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_gem.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_gem.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_gem.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_gem.c	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1029 @
 		       void (*func)(struct vc4_seqno_cb *cb))
 {
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
-	int ret = 0;
 	unsigned long irqflags;
 
 	cb->func = func;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1043 @
 	}
 	spin_unlock_irqrestore(&vc4->job_lock, irqflags);
 
-	return ret;
+	return 0;
 }
 
 /* Scheduled when any job has been completed, this walks the list of
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hdmi.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hdmi.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hdmi.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hdmi.c	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:38 @
 #include <drm/drm_edid.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
+#include <drm/drm_scdc_helper.h>
 #include <linux/clk.h>
 #include <linux/component.h>
 #include <linux/i2c.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:48 @
 #include <linux/pm_runtime.h>
 #include <linux/rational.h>
 #include <linux/reset.h>
+#include <sound/asoundef.h>
 #include <sound/dmaengine_pcm.h>
+#include <sound/hdmi-codec.h>
 #include <sound/pcm_drm_eld.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/tlv.h>
 #include "media/cec.h"
 #include "vc4_drv.h"
 #include "vc4_hdmi.h"
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:83 @
 #define VC5_HDMI_VERTB_VSPO_SHIFT		16
 #define VC5_HDMI_VERTB_VSPO_MASK		VC4_MASK(29, 16)
 
+#define VC5_HDMI_SCRAMBLER_CTL_ENABLE		BIT(0)
+
+#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT	8
+#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK	VC4_MASK(10, 8)
+
+#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_SHIFT		0
+#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK		VC4_MASK(3, 0)
+
+#define VC5_HDMI_GCP_CONFIG_GCP_ENABLE		BIT(31)
+
+#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_SHIFT	8
+#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK	VC4_MASK(15, 8)
+
 # define VC4_HD_M_SW_RST			BIT(2)
 # define VC4_HD_M_ENABLE			BIT(0)
 
 #define CEC_CLOCK_FREQ 40000
-#define VC4_HSM_MID_CLOCK 149985000
+#define HDMI_14_MAX_TMDS_CLK   (340 * 1000 * 1000)
+
+static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode)
+{
+	return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK;
+}
 
 static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:115 @
 
 	drm_print_regset32(&p, &vc4_hdmi->hdmi_regset);
 	drm_print_regset32(&p, &vc4_hdmi->hd_regset);
+	drm_print_regset32(&p, &vc4_hdmi->cec_regset);
+	drm_print_regset32(&p, &vc4_hdmi->csc_regset);
+	drm_print_regset32(&p, &vc4_hdmi->dvp_regset);
+	drm_print_regset32(&p, &vc4_hdmi->phy_regset);
+	drm_print_regset32(&p, &vc4_hdmi->ram_regset);
+	drm_print_regset32(&p, &vc4_hdmi->rm_regset);
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:163 @
 	 * Set the clock divider: the hsm_clock rate and this divider
 	 * setting will give a 40 kHz CEC clock.
 	 */
-	clk_cnt = clk_get_rate(vc4_hdmi->hsm_clock) / CEC_CLOCK_FREQ;
+	clk_cnt = clk_get_rate(vc4_hdmi->cec_clock) / CEC_CLOCK_FREQ;
 	value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT;
 	HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:171 @
 static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
 #endif
 
+static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder);
+
 static enum drm_connector_status
 vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
 {
 	struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
+	enum drm_connector_status ret = connector_status_disconnected;
 	bool connected = false;
 
 	WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
+	WARN_ON(clk_prepare_enable(vc4_hdmi->hsm_clock));
 
 	if (vc4_hdmi->hpd_gpio) {
 		if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:204 @
 			}
 		}
 
-		pm_runtime_put(&vc4_hdmi->pdev->dev);
-		return connector_status_connected;
+		vc4_hdmi_enable_scrambling(&vc4_hdmi->encoder.base.base);
+
+		ret = connector_status_connected;
+		goto out;
 	}
 
 	cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
+
+out:
+	clk_disable_unprepare(vc4_hdmi->hsm_clock);
 	pm_runtime_put(&vc4_hdmi->pdev->dev);
-	return connector_status_disconnected;
+	return ret;
 }
 
 static void vc4_hdmi_connector_destroy(struct drm_connector *connector)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:242 @
 	ret = drm_add_edid_modes(connector, edid);
 	kfree(edid);
 
+	if (vc4_hdmi->disable_4kp60) {
+		struct drm_device *drm = connector->dev;
+		struct drm_display_mode *mode;
+
+		list_for_each_entry(mode, &connector->probed_modes, head) {
+			if (vc4_hdmi_mode_needs_scrambling(mode)) {
+				drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
+				drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
+			}
+		}
+	}
+
 	return ret;
 }
 
+static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector,
+					  struct drm_atomic_state *state)
+{
+	struct drm_connector_state *old_state =
+		drm_atomic_get_old_connector_state(state, connector);
+	struct drm_connector_state *new_state =
+		drm_atomic_get_new_connector_state(state, connector);
+	struct drm_crtc *crtc = new_state->crtc;
+
+	if (!crtc)
+		return 0;
+
+	if (old_state->colorspace != new_state->colorspace ||
+	    !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state, crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+
+		crtc_state->mode_changed = true;
+	}
+
+	return 0;
+}
+
 static void vc4_hdmi_connector_reset(struct drm_connector *connector)
 {
-	drm_atomic_helper_connector_reset(connector);
+	struct vc4_hdmi_connector_state *old_state =
+		conn_state_to_vc4_hdmi_conn_state(connector->state);
+	struct vc4_hdmi_connector_state *new_state =
+		kzalloc(sizeof(*new_state), GFP_KERNEL);
+
+	if (connector->state)
+		__drm_atomic_helper_connector_destroy_state(connector->state);
+
+	kfree(old_state);
+	__drm_atomic_helper_connector_reset(connector, &new_state->base);
+
+	if (!new_state)
+		return;
+
+	new_state->base.max_bpc = 8;
+	new_state->base.max_requested_bpc = 8;
 	drm_atomic_helper_connector_tv_reset(connector);
 }
 
+static struct drm_connector_state *
+vc4_hdmi_connector_duplicate_state(struct drm_connector *connector)
+{
+	struct drm_connector_state *conn_state = connector->state;
+	struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(conn_state);
+	struct vc4_hdmi_connector_state *new_state;
+
+	new_state = kzalloc(sizeof(*new_state), GFP_KERNEL);
+	if (!new_state)
+		return NULL;
+
+	new_state->pixel_rate = vc4_state->pixel_rate;
+	__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
+
+	return &new_state->base;
+}
+
 static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
 	.detect = vc4_hdmi_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.destroy = vc4_hdmi_connector_destroy,
 	.reset = vc4_hdmi_connector_reset,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_duplicate_state = vc4_hdmi_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
 	.get_modes = vc4_hdmi_connector_get_modes,
+	.atomic_check = vc4_hdmi_connector_atomic_check,
 };
 
 static int vc4_hdmi_connector_init(struct drm_device *dev,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:348 @
 				    vc4_hdmi->ddc);
 	drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
 
+	/*
+	 * Some of the properties below require access to state, like bpc.
+	 * Allocate some default initial connector state with our reset helper.
+	 */
+	if (connector->funcs->reset)
+		connector->funcs->reset(connector);
+
 	/* Create and attach TV margin props to this connector. */
 	ret = drm_mode_create_tv_margin_properties(dev);
 	if (ret)
 		return ret;
 
+	ret = drm_mode_create_hdmi_colorspace_property(connector);
+	if (ret)
+		return ret;
+
+	drm_connector_attach_colorspace_property(connector);
 	drm_connector_attach_tv_margin_properties(connector);
+	drm_connector_attach_max_bpc_property(connector, 8, 12);
 
 	connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
 			     DRM_CONNECTOR_POLL_DISCONNECT);
 
 	connector->interlace_allowed = 1;
 	connector->doublescan_allowed = 0;
+	connector->stereo_allowed = 1;
+
+	if (vc4_hdmi->variant->supports_hdr)
+		drm_connector_attach_hdr_output_metadata_property(connector);
 
 	drm_connector_attach_encoder(connector, encoder);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:384 @
 }
 
 static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
-				enum hdmi_infoframe_type type)
+				enum hdmi_infoframe_type type,
+				bool poll)
 {
 	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
 	u32 packet_id = type - 0x80;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:393 @
 	HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
 		   HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
 
+	if (!poll)
+		return 0;
+
 	return wait_for(!(HDMI_READ(HDMI_RAM_PACKET_STATUS) &
 			  BIT(packet_id)), 100);
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:408 @
 	const struct vc4_hdmi_register *ram_packet_start =
 		&vc4_hdmi->variant->registers[HDMI_RAM_PACKET_START];
 	u32 packet_reg = ram_packet_start->offset + VC4_HDMI_PACKET_STRIDE * packet_id;
+	u32 packet_reg_next = ram_packet_start->offset +
+		VC4_HDMI_PACKET_STRIDE * (packet_id + 1);
 	void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi,
 						       ram_packet_start->reg);
-	uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
+	uint8_t buffer[VC4_HDMI_PACKET_STRIDE] = {};
 	ssize_t len, i;
 	int ret;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:424 @
 	if (len < 0)
 		return;
 
-	ret = vc4_hdmi_stop_packet(encoder, frame->any.type);
+	ret = vc4_hdmi_stop_packet(encoder, frame->any.type, true);
 	if (ret) {
 		DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
 		return;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:445 @
 		packet_reg += 4;
 	}
 
+	/*
+	 * clear remainder of packet ram as it's included in the
+	 * infoframe and triggers a checksum error on hdmi analyser
+	 */
+	for (; packet_reg < packet_reg_next; packet_reg += 4)
+		writel(0, base + packet_reg);
+
 	HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
 		   HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
 	ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) &
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:483 @
 					   vc4_encoder->limited_rgb_range ?
 					   HDMI_QUANTIZATION_RANGE_LIMITED :
 					   HDMI_QUANTIZATION_RANGE_FULL);
-
+	drm_hdmi_avi_infoframe_colorspace(&frame.avi, cstate);
 	drm_hdmi_avi_infoframe_bars(&frame.avi, cstate);
 
 	vc4_hdmi_write_infoframe(encoder, &frame);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:508 @
 static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder)
 {
 	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+	struct hdmi_audio_infoframe *audio = &vc4_hdmi->audio.infoframe;
 	union hdmi_infoframe frame;
-	int ret;
 
-	ret = hdmi_audio_infoframe_init(&frame.audio);
+	memcpy(&frame.audio, audio, sizeof(*audio));
+	vc4_hdmi_write_infoframe(encoder, &frame);
+}
 
-	frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
-	frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
-	frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
-	frame.audio.channels = vc4_hdmi->audio.channels;
+static void vc4_hdmi_set_hdr_infoframe(struct drm_encoder *encoder)
+{
+	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+	struct drm_connector *connector = &vc4_hdmi->connector;
+	struct drm_connector_state *conn_state = connector->state;
+	union hdmi_infoframe frame;
+
+	if (!vc4_hdmi->variant->supports_hdr)
+		return;
+
+	if (!conn_state->hdr_output_metadata)
+		return;
+
+	if (drm_hdmi_infoframe_set_hdr_metadata(&frame.drm, conn_state))
+		return;
 
 	vc4_hdmi_write_infoframe(encoder, &frame);
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:546 @
 	 */
 	if (vc4_hdmi->audio.streaming)
 		vc4_hdmi_set_audio_infoframe(encoder);
+
+	vc4_hdmi_set_hdr_infoframe(encoder);
 }
 
-static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder)
+static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
+					 struct drm_display_mode *mode)
+{
+	struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
+	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+	struct drm_display_info *display = &vc4_hdmi->connector.display_info;
+
+	if (!vc4_encoder->hdmi_monitor)
+		return false;
+
+	if (!display->hdmi.scdc.supported ||
+	    !display->hdmi.scdc.scrambling.supported)
+		return false;
+
+	return true;
+}
+
+#define SCRAMBLING_POLLING_DELAY_MS	1000
+
+static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
+{
+	struct drm_display_mode *mode;
+	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+
+	if (!encoder->crtc || !encoder->crtc->state)
+		return;
+
+	mode = &encoder->crtc->state->adjusted_mode;
+	if (!vc4_hdmi_supports_scrambling(encoder, mode))
+		return;
+
+	if (!vc4_hdmi_mode_needs_scrambling(mode))
+		return;
+
+	drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
+	drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
+
+	HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
+		   VC5_HDMI_SCRAMBLER_CTL_ENABLE);
+
+	queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
+			   msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+}
+
+static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
+{
+	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+	struct drm_crtc *crtc = encoder->crtc;
+
+	/*
+	 * At boot, encoder->crtc will be NULL. Since we don't know the
+	 * state of the scrambler and in order to avoid any
+	 * inconsistency, let's disable it all the time.
+	 */
+	if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode))
+		return;
+
+	if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode))
+		return;
+
+	if (delayed_work_pending(&vc4_hdmi->scrambling_work))
+		cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
+
+	HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
+		   ~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
+
+	drm_scdc_set_scrambling(vc4_hdmi->ddc, false);
+	drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false);
+}
+
+static void vc4_hdmi_scrambling_wq(struct work_struct *work)
+{
+	struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
+						 struct vc4_hdmi,
+						 scrambling_work);
+
+	if (drm_scdc_get_scrambling_status(vc4_hdmi->ddc))
+		return;
+
+	drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
+	drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
+
+	queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
+			   msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+}
+
+static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
+					       struct drm_atomic_state *state)
 {
 	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
 
 	HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
 
-	HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) |
-		   VC4_HD_VID_CTL_CLRRGB | VC4_HD_VID_CTL_CLRSYNC);
+	HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB);
+
+	mdelay(1);
 
 	HDMI_WRITE(HDMI_VID_CTL,
-		   HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
+		   HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
+	vc4_hdmi_disable_scrambling(encoder);
 }
 
-static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder)
+static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
+						 struct drm_atomic_state *state)
 {
 	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
 	int ret;
 
+	HDMI_WRITE(HDMI_VID_CTL,
+		   HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
+
 	if (vc4_hdmi->variant->phy_disable)
 		vc4_hdmi->variant->phy_disable(vc4_hdmi);
 
-	HDMI_WRITE(HDMI_VID_CTL,
-		   HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
-
 	clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
+	if (vc4_hdmi->bvb_req)
+		clk_request_done(vc4_hdmi->bvb_req);
+	clk_request_done(vc4_hdmi->hsm_req);
 	clk_disable_unprepare(vc4_hdmi->pixel_clock);
 
 	ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:754 @
 }
 
 static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
+				 struct drm_connector_state *state,
 				 struct drm_display_mode *mode)
 {
 	bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:767 @
 				   VC4_HDMI_VERTA_VFP) |
 		     VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL));
 	u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
-		     VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
+		     VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
+				   interlaced,
 				   VC4_HDMI_VERTB_VBP));
 	u32 vertb_even = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
 			  VC4_SET_FIELD(mode->crtc_vtotal -
-					mode->crtc_vsync_end -
-					interlaced,
+					mode->crtc_vsync_end,
 					VC4_HDMI_VERTB_VBP));
 
 	HDMI_WRITE(HDMI_HORZA,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:798 @
 	HDMI_WRITE(HDMI_VERTB0, vertb_even);
 	HDMI_WRITE(HDMI_VERTB1, vertb);
 }
+
 static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
+				 struct drm_connector_state *state,
 				 struct drm_display_mode *mode)
 {
 	bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:813 @
 				   VC5_HDMI_VERTA_VFP) |
 		     VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL));
 	u32 vertb = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
-		     VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
+		     VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
+				   interlaced,
 				   VC4_HDMI_VERTB_VBP));
 	u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
 			  VC4_SET_FIELD(mode->crtc_vtotal -
-					mode->crtc_vsync_end -
-					interlaced,
+					mode->crtc_vsync_end,
 					VC4_HDMI_VERTB_VBP));
+	unsigned char gcp;
+	bool gcp_en;
+	u32 reg;
 
 	HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
 	HDMI_WRITE(HDMI_HORZA,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:848 @
 	HDMI_WRITE(HDMI_VERTB0, vertb_even);
 	HDMI_WRITE(HDMI_VERTB1, vertb);
 
+	switch (state->max_bpc) {
+	case 12:
+		gcp = 6;
+		gcp_en = true;
+		break;
+	case 10:
+		gcp = 5;
+		gcp_en = true;
+		break;
+	case 8:
+	default:
+		gcp = 4;
+		gcp_en = false;
+		break;
+	}
+
+	reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1);
+	reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK |
+		 VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK);
+	reg |= VC4_SET_FIELD(2, VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE) |
+	       VC4_SET_FIELD(gcp, VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH);
+	HDMI_WRITE(HDMI_DEEP_COLOR_CONFIG_1, reg);
+
+	reg = HDMI_READ(HDMI_GCP_WORD_1);
+	reg &= ~VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK;
+	reg |= VC4_SET_FIELD(gcp, VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1);
+	HDMI_WRITE(HDMI_GCP_WORD_1, reg);
+
+	reg = HDMI_READ(HDMI_GCP_CONFIG);
+	reg &= ~VC5_HDMI_GCP_CONFIG_GCP_ENABLE;
+	reg |= gcp_en ? VC5_HDMI_GCP_CONFIG_GCP_ENABLE : 0;
+	HDMI_WRITE(HDMI_GCP_CONFIG, reg);
+
 	HDMI_WRITE(HDMI_CLOCK_STOP, 0);
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:908 @
 		  "VC4_HDMI_FIFO_CTL_RECENTER_DONE");
 }
 
-static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder)
+static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
+						struct drm_atomic_state *state)
 {
-	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
 	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
-	unsigned long pixel_rate, hsm_rate;
+	struct drm_connector *connector = &vc4_hdmi->connector;
+	struct drm_connector_state *conn_state =
+		drm_atomic_get_new_connector_state(state, connector);
+	struct vc4_hdmi_connector_state *vc4_conn_state =
+		conn_state_to_vc4_hdmi_conn_state(conn_state);
+	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
+	unsigned long bvb_rate, pixel_rate, hsm_rate;
 	int ret;
 
 	ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
 	if (ret < 0) {
 		DRM_ERROR("Failed to retain power domain: %d\n", ret);
+		pm_runtime_put(&vc4_hdmi->pdev->dev);
 		return;
 	}
 
-	pixel_rate = mode->clock * 1000 * ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1);
+	pixel_rate = vc4_conn_state->pixel_rate;
 	ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
 	if (ret) {
 		DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
+		pm_runtime_put(&vc4_hdmi->pdev->dev);
 		return;
 	}
 
 	ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
 	if (ret) {
 		DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
+		pm_runtime_put(&vc4_hdmi->pdev->dev);
 		return;
 	}
 
-	/*
-	 * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
-	 * be faster than pixel clock, infinitesimally faster, tested in
-	 * simulation. Otherwise, exact value is unimportant for HDMI
-	 * operation." This conflicts with bcm2835's vc4 documentation, which
-	 * states HSM's clock has to be at least 108% of the pixel clock.
-	 *
-	 * Real life tests reveal that vc4's firmware statement holds up, and
-	 * users are able to use pixel clocks closer to HSM's, namely for
-	 * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
-	 * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
-	 * 162MHz.
-	 *
-	 * Additionally, the AXI clock needs to be at least 25% of
-	 * pixel clock, but HSM ends up being the limiting factor.
-	 */
-	hsm_rate = max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
-	ret = clk_set_min_rate(vc4_hdmi->hsm_clock, hsm_rate);
-	if (ret) {
-		DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
+	hsm_rate = vc4_hdmi->variant->calc_hsm_clock(vc4_hdmi, pixel_rate);
+	vc4_hdmi->hsm_req = clk_request_start(vc4_hdmi->hsm_clock, hsm_rate);
+	if (IS_ERR(vc4_hdmi->hsm_req)) {
+		DRM_ERROR("Failed to set HSM clock rate: %ld\n", PTR_ERR(vc4_hdmi->hsm_req));
+		clk_disable_unprepare(vc4_hdmi->pixel_clock);
+		pm_runtime_put(&vc4_hdmi->pdev->dev);
 		return;
 	}
 
 	vc4_hdmi_cec_update_clk_div(vc4_hdmi);
 
-	/*
-	 * FIXME: When the pixel freq is 594MHz (4k60), this needs to be setup
-	 * at 300MHz.
-	 */
-	ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock,
-			       (hsm_rate > VC4_HSM_MID_CLOCK ? 150000000 : 75000000));
-	if (ret) {
-		DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
+	if (pixel_rate > 297000000)
+		bvb_rate = 300000000;
+	else if (pixel_rate > 148500000)
+		bvb_rate = 150000000;
+	else
+		bvb_rate = 75000000;
+
+	if (vc4_hdmi->pixel_bvb_clock)
+		vc4_hdmi->bvb_req = clk_request_start(vc4_hdmi->pixel_bvb_clock, bvb_rate);
+	if (IS_ERR(vc4_hdmi->bvb_req)) {
+		DRM_ERROR("Failed to set pixel bvb clock rate: %ld\n", PTR_ERR(vc4_hdmi->bvb_req));
+		clk_request_done(vc4_hdmi->hsm_req);
 		clk_disable_unprepare(vc4_hdmi->pixel_clock);
+		pm_runtime_put(&vc4_hdmi->pdev->dev);
 		return;
 	}
 
 	ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
 	if (ret) {
 		DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
+		if (vc4_hdmi->bvb_req)
+			clk_request_done(vc4_hdmi->bvb_req);
+		clk_request_done(vc4_hdmi->hsm_req);
 		clk_disable_unprepare(vc4_hdmi->pixel_clock);
+		pm_runtime_put(&vc4_hdmi->pdev->dev);
 		return;
 	}
 
 	if (vc4_hdmi->variant->phy_init)
-		vc4_hdmi->variant->phy_init(vc4_hdmi, mode);
+		vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state);
 
 	HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
 		   HDMI_READ(HDMI_SCHEDULER_CONTROL) |
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:991 @
 		   VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS);
 
 	if (vc4_hdmi->variant->set_timings)
-		vc4_hdmi->variant->set_timings(vc4_hdmi, mode);
+		vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
 }
 
-static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder)
+static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
+					     struct drm_atomic_state *state)
 {
 	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
 	struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1017 @
 	HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
 }
 
-static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder)
+static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
+					      struct drm_atomic_state *state)
 {
 	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
 	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1029 @
 
 	HDMI_WRITE(HDMI_VID_CTL,
 		   VC4_HD_VID_CTL_ENABLE |
+		   VC4_HD_VID_CTL_CLRRGB |
 		   VC4_HD_VID_CTL_UNDERFLOW_ENABLE |
 		   VC4_HD_VID_CTL_FRAME_COUNTER_RESET |
 		   (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1075 @
 	}
 
 	vc4_hdmi_recenter_fifo(vc4_hdmi);
+	vc4_hdmi_enable_scrambling(encoder);
 }
 
 static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1089 @
 					 struct drm_crtc_state *crtc_state,
 					 struct drm_connector_state *conn_state)
 {
+	struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(conn_state);
 	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
 	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
 	unsigned long long pixel_rate = mode->clock * 1000;
 	unsigned long long tmds_rate;
 
 	if (vc4_hdmi->variant->unsupported_odd_h_timings &&
+	    !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
 	    ((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
 	     (mode->hsync_end % 2) || (mode->htotal % 2)))
 		return -EINVAL;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1115 @
 		pixel_rate = mode->clock * 1000;
 	}
 
+	if (conn_state->max_bpc == 12) {
+		pixel_rate = pixel_rate * 150;
+		do_div(pixel_rate, 100);
+	} else if (conn_state->max_bpc == 10) {
+		pixel_rate = pixel_rate * 125;
+		do_div(pixel_rate, 100);
+	}
+
 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
 		pixel_rate = pixel_rate * 2;
 
 	if (pixel_rate > vc4_hdmi->variant->max_pixel_clock)
 		return -EINVAL;
 
+	if (vc4_hdmi->disable_4kp60 && (pixel_rate > HDMI_14_MAX_TMDS_CLK))
+		return -EINVAL;
+
+	vc4_state->pixel_rate = pixel_rate;
+
 	return 0;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1144 @
 	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
 
 	if (vc4_hdmi->variant->unsupported_odd_h_timings &&
+	    !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
 	    ((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
 	     (mode->hsync_end % 2) || (mode->htotal % 2)))
 		return MODE_H_ILLEGAL;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1152 @
 	if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock)
 		return MODE_CLOCK_HIGH;
 
+	if (vc4_hdmi->disable_4kp60 && vc4_hdmi_mode_needs_scrambling(mode))
+		return MODE_CLOCK_HIGH;
+
 	return MODE_OK;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1165 @
 	.enable = vc4_hdmi_encoder_enable,
 };
 
+static u32 vc4_hdmi_calc_hsm_clock(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate)
+{
+	/*
+	 * Whilst this can vary, all the CEC timings are derived from this
+	 * clock, so make it constant to avoid having to reconfigure CEC on
+	 * every mode change.
+	 */
+
+	return 163682864;
+}
+
+static u32 vc5_hdmi_calc_hsm_clock(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate)
+{
+	/*
+	 * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
+	 * be faster than pixel clock, infinitesimally faster, tested in
+	 * simulation. Otherwise, exact value is unimportant for HDMI
+	 * operation." This conflicts with bcm2835's vc4 documentation, which
+	 * states HSM's clock has to be at least 108% of the pixel clock.
+	 *
+	 * Real life tests reveal that vc4's firmware statement holds up, and
+	 * users are able to use pixel clocks closer to HSM's, namely for
+	 * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
+	 * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
+	 * 162MHz.
+	 *
+	 * Additionally, the AXI clock needs to be at least 25% of
+	 * pixel clock, but HSM ends up being the limiting factor.
+	 */
+
+	return max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
+}
+
 static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
 {
 	int i;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1223 @
 }
 
 /* HDMI audio codec callbacks */
-static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi)
+static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
+					 unsigned int samplerate)
 {
 	u32 hsm_clock = clk_get_rate(vc4_hdmi->audio_clock);
 	unsigned long n, m;
 
-	rational_best_approximation(hsm_clock, vc4_hdmi->audio.samplerate,
+	rational_best_approximation(hsm_clock, samplerate,
 				    VC4_HD_MAI_SMP_N_MASK >>
 				    VC4_HD_MAI_SMP_N_SHIFT,
 				    (VC4_HD_MAI_SMP_M_MASK >>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1241 @
 		   VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
 }
 
-static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi)
+static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate)
 {
 	struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
 	struct drm_crtc *crtc = encoder->crtc;
 	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
-	u32 samplerate = vc4_hdmi->audio.samplerate;
 	u32 n, cts;
 	u64 tmp;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1274 @
 	return snd_soc_card_get_drvdata(card);
 }
 
-static int vc4_hdmi_audio_startup(struct snd_pcm_substream *substream,
-				  struct snd_soc_dai *dai)
+static int vc4_hdmi_audio_startup(struct device *dev, void *data)
 {
-	struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
+	struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
 	struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
-	struct drm_connector *connector = &vc4_hdmi->connector;
-	int ret;
-
-	if (vc4_hdmi->audio.substream && vc4_hdmi->audio.substream != substream)
-		return -EINVAL;
-
-	vc4_hdmi->audio.substream = substream;
 
 	/*
 	 * If the HDMI encoder hasn't probed, or the encoder is
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1287 @
 				VC4_HDMI_RAM_PACKET_ENABLE))
 		return -ENODEV;
 
-	ret = snd_pcm_hw_constraint_eld(substream->runtime, connector->eld);
-	if (ret)
-		return ret;
+	vc4_hdmi->audio.streaming = true;
 
-	return 0;
-}
+	HDMI_WRITE(HDMI_MAI_CTL,
+		   VC4_HD_MAI_CTL_RESET |
+		   VC4_HD_MAI_CTL_FLUSH |
+		   VC4_HD_MAI_CTL_DLATE |
+		   VC4_HD_MAI_CTL_ERRORE |
+		   VC4_HD_MAI_CTL_ERRORF);
+
+	if (vc4_hdmi->variant->phy_rng_enable)
+		vc4_hdmi->variant->phy_rng_enable(vc4_hdmi);
 
-static int vc4_hdmi_audio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
 	return 0;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1309 @
 	int ret;
 
 	vc4_hdmi->audio.streaming = false;
-	ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO);
+	ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO, false);
 	if (ret)
 		dev_err(dev, "Failed to stop audio infoframe: %d\n", ret);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1318 @
 	HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
 }
 
-static void vc4_hdmi_audio_shutdown(struct snd_pcm_substream *substream,
-				    struct snd_soc_dai *dai)
+static void vc4_hdmi_audio_shutdown(struct device *dev, void *data)
 {
-	struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
+	struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
 
-	if (substream != vc4_hdmi->audio.substream)
-		return;
+	HDMI_WRITE(HDMI_MAI_CTL,
+		   VC4_HD_MAI_CTL_DLATE |
+		   VC4_HD_MAI_CTL_ERRORE |
+		   VC4_HD_MAI_CTL_ERRORF);
 
+	if (vc4_hdmi->variant->phy_rng_disable)
+		vc4_hdmi->variant->phy_rng_disable(vc4_hdmi);
+
+	vc4_hdmi->audio.streaming = false;
 	vc4_hdmi_audio_reset(vc4_hdmi);
+}
 
-	vc4_hdmi->audio.substream = NULL;
+static int sample_rate_to_mai_fmt(int samplerate)
+{
+	switch (samplerate) {
+	case 8000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_8000;
+	case 11025:
+		return VC4_HDMI_MAI_SAMPLE_RATE_11025;
+	case 12000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_12000;
+	case 16000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_16000;
+	case 22050:
+		return VC4_HDMI_MAI_SAMPLE_RATE_22050;
+	case 24000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_24000;
+	case 32000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_32000;
+	case 44100:
+		return VC4_HDMI_MAI_SAMPLE_RATE_44100;
+	case 48000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_48000;
+	case 64000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_64000;
+	case 88200:
+		return VC4_HDMI_MAI_SAMPLE_RATE_88200;
+	case 96000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_96000;
+	case 128000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_128000;
+	case 176400:
+		return VC4_HDMI_MAI_SAMPLE_RATE_176400;
+	case 192000:
+		return VC4_HDMI_MAI_SAMPLE_RATE_192000;
+	default:
+		return VC4_HDMI_MAI_SAMPLE_RATE_NOT_INDICATED;
+	}
 }
 
 /* HDMI audio codec callbacks */
-static int vc4_hdmi_audio_hw_params(struct snd_pcm_substream *substream,
-				    struct snd_pcm_hw_params *params,
-				    struct snd_soc_dai *dai)
+static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
+				  struct hdmi_codec_daifmt *daifmt,
+				  struct hdmi_codec_params *params)
 {
-	struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
+	struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
 	struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
-	struct device *dev = &vc4_hdmi->pdev->dev;
+	unsigned int sample_rate = params->sample_rate;
+	unsigned int channels = params->channels;
 	u32 audio_packet_config, channel_mask;
 	u32 channel_map;
-
-	if (substream != vc4_hdmi->audio.substream)
-		return -EINVAL;
+	u32 mai_audio_format;
+	u32 mai_sample_rate;
 
 	dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
-		params_rate(params), params_width(params),
-		params_channels(params));
-
-	vc4_hdmi->audio.channels = params_channels(params);
-	vc4_hdmi->audio.samplerate = params_rate(params);
+		sample_rate, params->sample_width, channels);
 
 	HDMI_WRITE(HDMI_MAI_CTL,
-		   VC4_HD_MAI_CTL_RESET |
-		   VC4_HD_MAI_CTL_FLUSH |
-		   VC4_HD_MAI_CTL_DLATE |
-		   VC4_HD_MAI_CTL_ERRORE |
-		   VC4_HD_MAI_CTL_ERRORF);
-
-	vc4_hdmi_audio_set_mai_clock(vc4_hdmi);
+		   VC4_SET_FIELD(channels, VC4_HD_MAI_CTL_CHNUM) |
+		   VC4_HD_MAI_CTL_WHOLSMP |
+		   VC4_HD_MAI_CTL_CHALIGN |
+		   VC4_HD_MAI_CTL_ENABLE);
+
+	vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
+
+	mai_sample_rate = sample_rate_to_mai_fmt(sample_rate);
+	if (params->iec.status[0] & IEC958_AES0_NONAUDIO &&
+	    params->channels == 8)
+		mai_audio_format = VC4_HDMI_MAI_FORMAT_HBR;
+	else
+		mai_audio_format = VC4_HDMI_MAI_FORMAT_PCM;
+	HDMI_WRITE(HDMI_MAI_FMT,
+		   VC4_SET_FIELD(mai_sample_rate,
+				 VC4_HDMI_MAI_FORMAT_SAMPLE_RATE) |
+		   VC4_SET_FIELD(mai_audio_format,
+				 VC4_HDMI_MAI_FORMAT_AUDIO_FORMAT));
 
 	/* The B frame identifier should match the value used by alsa-lib (8) */
 	audio_packet_config =
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1415 @
 		VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS |
 		VC4_SET_FIELD(0x8, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER);
 
-	channel_mask = GENMASK(vc4_hdmi->audio.channels - 1, 0);
+	channel_mask = GENMASK(channels - 1, 0);
 	audio_packet_config |= VC4_SET_FIELD(channel_mask,
 					     VC4_HDMI_AUDIO_PACKET_CEA_MASK);
 
-	/* Set the MAI threshold.  This logic mimics the firmware's. */
-	if (vc4_hdmi->audio.samplerate > 96000) {
-		HDMI_WRITE(HDMI_MAI_THR,
-			   VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) |
-			   VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
-	} else if (vc4_hdmi->audio.samplerate > 48000) {
-		HDMI_WRITE(HDMI_MAI_THR,
-			   VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) |
-			   VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
-	} else {
-		HDMI_WRITE(HDMI_MAI_THR,
-			   VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) |
-			   VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) |
-			   VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) |
-			   VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW));
-	}
+	/* Set the MAI threshold */
+	HDMI_WRITE(HDMI_MAI_THR,
+		   VC4_SET_FIELD(0x08, VC4_HD_MAI_THR_PANICHIGH) |
+		   VC4_SET_FIELD(0x08, VC4_HD_MAI_THR_PANICLOW) |
+		   VC4_SET_FIELD(0x06, VC4_HD_MAI_THR_DREQHIGH) |
+		   VC4_SET_FIELD(0x08, VC4_HD_MAI_THR_DREQLOW));
 
 	HDMI_WRITE(HDMI_MAI_CONFIG,
 		   VC4_HDMI_MAI_CONFIG_BIT_REVERSE |
+		   VC4_HDMI_MAI_CONFIG_FORMAT_REVERSE |
 		   VC4_SET_FIELD(channel_mask, VC4_HDMI_MAI_CHANNEL_MASK));
 
 	channel_map = vc4_hdmi->variant->channel_map(vc4_hdmi, channel_mask);
 	HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map);
 	HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config);
-	vc4_hdmi_set_n_cts(vc4_hdmi);
+	vc4_hdmi_set_n_cts(vc4_hdmi, sample_rate);
 
+	memcpy(&vc4_hdmi->audio.infoframe, &params->cea, sizeof(params->cea));
 	vc4_hdmi_set_audio_infoframe(encoder);
 
 	return 0;
 }
 
-static int vc4_hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
-				  struct snd_soc_dai *dai)
-{
-	struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		vc4_hdmi->audio.streaming = true;
-
-		if (vc4_hdmi->variant->phy_rng_enable)
-			vc4_hdmi->variant->phy_rng_enable(vc4_hdmi);
-
-		HDMI_WRITE(HDMI_MAI_CTL,
-			   VC4_SET_FIELD(vc4_hdmi->audio.channels,
-					 VC4_HD_MAI_CTL_CHNUM) |
-			   VC4_HD_MAI_CTL_ENABLE);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		HDMI_WRITE(HDMI_MAI_CTL,
-			   VC4_HD_MAI_CTL_DLATE |
-			   VC4_HD_MAI_CTL_ERRORE |
-			   VC4_HD_MAI_CTL_ERRORF);
-
-		if (vc4_hdmi->variant->phy_rng_disable)
-			vc4_hdmi->variant->phy_rng_disable(vc4_hdmi);
-
-		vc4_hdmi->audio.streaming = false;
-
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static inline struct vc4_hdmi *
-snd_component_to_hdmi(struct snd_soc_component *component)
-{
-	struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
-
-	return snd_soc_card_get_drvdata(card);
-}
-
-static int vc4_hdmi_audio_eld_ctl_info(struct snd_kcontrol *kcontrol,
-				       struct snd_ctl_elem_info *uinfo)
-{
-	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
-	struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component);
-	struct drm_connector *connector = &vc4_hdmi->connector;
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
-	uinfo->count = sizeof(connector->eld);
-
-	return 0;
-}
-
-static int vc4_hdmi_audio_eld_ctl_get(struct snd_kcontrol *kcontrol,
-				      struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
-	struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component);
-	struct drm_connector *connector = &vc4_hdmi->connector;
-
-	memcpy(ucontrol->value.bytes.data, connector->eld,
-	       sizeof(connector->eld));
-
-	return 0;
-}
-
-static const struct snd_kcontrol_new vc4_hdmi_audio_controls[] = {
-	{
-		.access = SNDRV_CTL_ELEM_ACCESS_READ |
-			  SNDRV_CTL_ELEM_ACCESS_VOLATILE,
-		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-		.name = "ELD",
-		.info = vc4_hdmi_audio_eld_ctl_info,
-		.get = vc4_hdmi_audio_eld_ctl_get,
-	},
-};
-
 static const struct snd_soc_dapm_widget vc4_hdmi_audio_widgets[] = {
 	SND_SOC_DAPM_OUTPUT("TX"),
 };
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1452 @
 
 static const struct snd_soc_component_driver vc4_hdmi_audio_component_drv = {
 	.name			= "vc4-hdmi-codec-dai-component",
-	.controls		= vc4_hdmi_audio_controls,
-	.num_controls		= ARRAY_SIZE(vc4_hdmi_audio_controls),
 	.dapm_widgets		= vc4_hdmi_audio_widgets,
 	.num_dapm_widgets	= ARRAY_SIZE(vc4_hdmi_audio_widgets),
 	.dapm_routes		= vc4_hdmi_audio_routes,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1462 @
 	.non_legacy_dai_naming	= 1,
 };
 
-static const struct snd_soc_dai_ops vc4_hdmi_audio_dai_ops = {
-	.startup = vc4_hdmi_audio_startup,
-	.shutdown = vc4_hdmi_audio_shutdown,
-	.hw_params = vc4_hdmi_audio_hw_params,
-	.set_fmt = vc4_hdmi_audio_set_fmt,
-	.trigger = vc4_hdmi_audio_trigger,
-};
-
-static struct snd_soc_dai_driver vc4_hdmi_audio_codec_dai_drv = {
-	.name = "vc4-hdmi-hifi",
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 2,
-		.channels_max = 8,
-		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
-			 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
-			 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
-			 SNDRV_PCM_RATE_192000,
-		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
-	},
-};
-
 static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = {
 	.name = "vc4-hdmi-cpu-dai-component",
 };
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1488 @
 			 SNDRV_PCM_RATE_192000,
 		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
 	},
-	.ops = &vc4_hdmi_audio_dai_ops,
 };
 
 static const struct snd_dmaengine_pcm_config pcm_conf = {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1495 @
 	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
 };
 
+
+static int vc4_hdmi_audio_get_eld(struct device *dev, void *data,
+				  uint8_t *buf, size_t len)
+{
+	struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
+	struct drm_connector *connector = &vc4_hdmi->connector;
+
+	memcpy(buf, connector->eld, min(sizeof(connector->eld), len));
+
+	return 0;
+}
+
+static const struct hdmi_codec_ops vc4_hdmi_codec_ops = {
+	.get_eld = vc4_hdmi_audio_get_eld,
+	.prepare = vc4_hdmi_audio_prepare,
+	.audio_shutdown = vc4_hdmi_audio_shutdown,
+	.audio_startup = vc4_hdmi_audio_startup,
+};
+
+struct hdmi_codec_pdata vc4_hdmi_codec_pdata = {
+	.ops = &vc4_hdmi_codec_ops,
+	.max_i2s_channels = 8,
+	.i2s = 1,
+};
+
 static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
 {
 	const struct vc4_hdmi_register *mai_data =
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1527 @
 	struct snd_soc_dai_link *dai_link = &vc4_hdmi->audio.link;
 	struct snd_soc_card *card = &vc4_hdmi->audio.card;
 	struct device *dev = &vc4_hdmi->pdev->dev;
+	struct platform_device *codec_pdev;
 	const __be32 *addr;
 	int index;
 	int ret;
+	int len;
 
-	if (!of_find_property(dev->of_node, "dmas", NULL)) {
+	if (!of_find_property(dev->of_node, "dmas", &len) ||
+	    len == 0) {
 		dev_warn(dev,
-			 "'dmas' DT property is missing, no HDMI audio\n");
+			 "'dmas' DT property is missing or empty, no HDMI audio\n");
 		return 0;
 	}
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1576 @
 		return ret;
 	}
 
-	/* register component and codec dai */
-	ret = devm_snd_soc_register_component(dev, &vc4_hdmi_audio_component_drv,
-				     &vc4_hdmi_audio_codec_dai_drv, 1);
-	if (ret) {
-		dev_err(dev, "Could not register component: %d\n", ret);
-		return ret;
+	codec_pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+						   PLATFORM_DEVID_AUTO,
+						   &vc4_hdmi_codec_pdata,
+						   sizeof(vc4_hdmi_codec_pdata));
+	if (IS_ERR(codec_pdev)) {
+		dev_err(dev, "Couldn't register the HDMI codec: %ld\n", PTR_ERR(codec_pdev));
+		return PTR_ERR(codec_pdev);
 	}
 
 	dai_link->cpus		= &vc4_hdmi->audio.cpu;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1595 @
 
 	dai_link->name = "MAI";
 	dai_link->stream_name = "MAI PCM";
-	dai_link->codecs->dai_name = vc4_hdmi_audio_codec_dai_drv.name;
+	dai_link->codecs->dai_name = "i2s-hifi";
 	dai_link->cpus->dai_name = dev_name(dev);
-	dai_link->codecs->name = dev_name(dev);
+	dai_link->codecs->name = dev_name(&codec_pdev->dev);
 	dai_link->platforms->name = dev_name(dev);
 
 	card->dai_link = dai_link;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1623 @
 
 }
 
+static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
+{
+	struct vc4_hdmi *vc4_hdmi = priv;
+	struct drm_device *dev = vc4_hdmi->connector.dev;
+
+	if (dev && dev->registered)
+		drm_kms_helper_hotplug_event(dev);
+
+	return IRQ_HANDLED;
+}
+
+static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi)
+{
+	struct platform_device *pdev = vc4_hdmi->pdev;
+	struct drm_connector *connector = &vc4_hdmi->connector;
+	int ret;
+
+	if (vc4_hdmi->variant->external_irq_controller) {
+		unsigned int hpd_con = platform_get_irq_byname(pdev, "hpd-connected");
+		unsigned int hpd_rm = platform_get_irq_byname(pdev, "hpd-removed");
+
+		ret = request_threaded_irq(hpd_con,
+					   NULL,
+					   vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
+					   "vc4 hdmi hpd connected", vc4_hdmi);
+		if (ret)
+			return ret;
+
+		ret = request_threaded_irq(hpd_rm,
+					   NULL,
+					   vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
+					   "vc4 hdmi hpd disconnected", vc4_hdmi);
+		if (ret) {
+			free_irq(hpd_con, vc4_hdmi);
+			return ret;
+		}
+
+		connector->polled = DRM_CONNECTOR_POLL_HPD;
+	}
+
+	return 0;
+}
+
+static void vc4_hdmi_hotplug_exit(struct vc4_hdmi *vc4_hdmi)
+{
+	struct platform_device *pdev = vc4_hdmi->pdev;
+
+	if (vc4_hdmi->variant->external_irq_controller) {
+		free_irq(platform_get_irq_byname(pdev, "hpd-connected"), vc4_hdmi);
+		free_irq(platform_get_irq_byname(pdev, "hpd-removed"), vc4_hdmi);
+	}
+}
+
 #ifdef CONFIG_DRM_VC4_HDMI_CEC
-static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
+static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv)
+{
+	struct vc4_hdmi *vc4_hdmi = priv;
+
+	if (vc4_hdmi->cec_rx_msg.len)
+		cec_received_msg(vc4_hdmi->cec_adap,
+				 &vc4_hdmi->cec_rx_msg);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t vc4_cec_irq_handler_tx_thread(int irq, void *priv)
 {
 	struct vc4_hdmi *vc4_hdmi = priv;
 
-	if (vc4_hdmi->cec_irq_was_rx) {
-		if (vc4_hdmi->cec_rx_msg.len)
-			cec_received_msg(vc4_hdmi->cec_adap,
-					 &vc4_hdmi->cec_rx_msg);
-	} else if (vc4_hdmi->cec_tx_ok) {
+	if (vc4_hdmi->cec_tx_ok) {
 		cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_OK,
 				  0, 0, 0, 0);
 	} else {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1706 @
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
+{
+	struct vc4_hdmi *vc4_hdmi = priv;
+	irqreturn_t ret;
+
+	if (vc4_hdmi->cec_irq_was_rx)
+		ret = vc4_cec_irq_handler_rx_thread(irq, priv);
+	else
+		ret = vc4_cec_irq_handler_tx_thread(irq, priv);
+
+	return ret;
+}
+
 static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
 {
 	struct drm_device *dev = vc4_hdmi->connector.dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1743 @
 	}
 }
 
+static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
+{
+	struct vc4_hdmi *vc4_hdmi = priv;
+	u32 cntrl1;
+
+	cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
+	vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
+	cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
+	HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
+{
+	struct vc4_hdmi *vc4_hdmi = priv;
+	u32 cntrl1;
+
+	vc4_hdmi->cec_rx_msg.len = 0;
+	cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
+	vc4_cec_read_msg(vc4_hdmi, cntrl1);
+	cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
+	HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
+	cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
+
+	HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
+
+	return IRQ_WAKE_THREAD;
+}
+
 static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
 {
 	struct vc4_hdmi *vc4_hdmi = priv;
 	u32 stat = HDMI_READ(HDMI_CEC_CPU_STATUS);
-	u32 cntrl1, cntrl5;
+	irqreturn_t ret;
+	u32 cntrl5;
 
 	if (!(stat & VC4_HDMI_CPU_CEC))
 		return IRQ_NONE;
-	vc4_hdmi->cec_rx_msg.len = 0;
-	cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
+
 	cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5);
 	vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
-	if (vc4_hdmi->cec_irq_was_rx) {
-		vc4_cec_read_msg(vc4_hdmi, cntrl1);
-		cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
-		HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
-		cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
-	} else {
-		vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
-		cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
-	}
-	HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
-	HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
+	if (vc4_hdmi->cec_irq_was_rx)
+		ret = vc4_cec_irq_handler_rx_bare(irq, priv);
+	else
+		ret = vc4_cec_irq_handler_tx_bare(irq, priv);
 
-	return IRQ_WAKE_THREAD;
+	HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
+	return ret;
 }
 
-static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
+static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
 {
 	struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
 	/* clock period in microseconds */
 	const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
-	u32 val = HDMI_READ(HDMI_CEC_CNTRL_5);
+	u32 val;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
+	if (ret)
+		return ret;
 
+	val = HDMI_READ(HDMI_CEC_CNTRL_5);
 	val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
 		 VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
 		 VC4_HDMI_CEC_CNT_TO_4500_US_MASK);
 	val |= ((4700 / usecs) << VC4_HDMI_CEC_CNT_TO_4700_US_SHIFT) |
 	       ((4500 / usecs) << VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT);
 
-	if (enable) {
-		HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
-			   VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
-		HDMI_WRITE(HDMI_CEC_CNTRL_5, val);
-		HDMI_WRITE(HDMI_CEC_CNTRL_2,
-			   ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
-			   ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
-			   ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
-			   ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
-			   ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
-		HDMI_WRITE(HDMI_CEC_CNTRL_3,
-			   ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
-			   ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
-			   ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
-			   ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
-		HDMI_WRITE(HDMI_CEC_CNTRL_4,
-			   ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
-			   ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
-			   ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
-			   ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
+	HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
+		   VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
+	HDMI_WRITE(HDMI_CEC_CNTRL_5, val);
+	HDMI_WRITE(HDMI_CEC_CNTRL_2,
+		   ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
+		   ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
+		   ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
+		   ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
+		   ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
+	HDMI_WRITE(HDMI_CEC_CNTRL_3,
+		   ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
+		   ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
+		   ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
+		   ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
+	HDMI_WRITE(HDMI_CEC_CNTRL_4,
+		   ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
+		   ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
+		   ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
+		   ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
 
+	if (!vc4_hdmi->variant->external_irq_controller)
 		HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
-	} else {
+
+	return 0;
+}
+
+static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
+{
+	struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
+
+	if (!vc4_hdmi->variant->external_irq_controller)
 		HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
-		HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
-			   VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
-	}
+
+	HDMI_WRITE(HDMI_CEC_CNTRL_5, HDMI_READ(HDMI_CEC_CNTRL_5) |
+		   VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
+
+	pm_runtime_put(&vc4_hdmi->pdev->dev);
+
 	return 0;
 }
 
+static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+	if (enable)
+		return vc4_hdmi_cec_enable(adap);
+	else
+		return vc4_hdmi_cec_disable(adap);
+}
+
 static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
 {
 	struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1913 @
 {
 	struct cec_connector_info conn_info;
 	struct platform_device *pdev = vc4_hdmi->pdev;
+	struct device *dev = &pdev->dev;
 	u32 value;
 	int ret;
 
-	if (!vc4_hdmi->variant->cec_available)
+	if (!of_find_property(dev->of_node, "interrupts", NULL)) {
+		dev_warn(dev, "'interrupts' DT property is missing, no CEC\n");
 		return 0;
+	}
 
 	vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops,
 						  vc4_hdmi, "vc4",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1933 @
 	cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector);
 	cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info);
 
-	HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
-
 	value = HDMI_READ(HDMI_CEC_CNTRL_1);
 	/* Set the logical address to Unregistered */
 	value |= VC4_HDMI_CEC_ADDR_MASK;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1940 @
 
 	vc4_hdmi_cec_update_clk_div(vc4_hdmi);
 
-	ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0),
-					vc4_cec_irq_handler,
-					vc4_cec_irq_handler_thread, 0,
-					"vc4 hdmi cec", vc4_hdmi);
-	if (ret)
-		goto err_delete_cec_adap;
+	if (vc4_hdmi->variant->external_irq_controller) {
+		ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-rx"),
+					   vc4_cec_irq_handler_rx_bare,
+					   vc4_cec_irq_handler_rx_thread, 0,
+					   "vc4 hdmi cec rx", vc4_hdmi);
+		if (ret)
+			goto err_delete_cec_adap;
+
+		ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-tx"),
+					   vc4_cec_irq_handler_tx_bare,
+					   vc4_cec_irq_handler_tx_thread, 0,
+					   "vc4 hdmi cec tx", vc4_hdmi);
+		if (ret)
+			goto err_remove_cec_rx_handler;
+	} else {
+		HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
+
+		ret = request_threaded_irq(platform_get_irq(pdev, 0),
+					   vc4_cec_irq_handler,
+					   vc4_cec_irq_handler_thread, 0,
+					   "vc4 hdmi cec", vc4_hdmi);
+		if (ret)
+			goto err_delete_cec_adap;
+	}
 
 	ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev);
 	if (ret < 0)
-		goto err_delete_cec_adap;
+		goto err_remove_handlers;
 
 	return 0;
 
+err_remove_handlers:
+	if (vc4_hdmi->variant->external_irq_controller)
+		free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
+	else
+		free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
+
+err_remove_cec_rx_handler:
+	if (vc4_hdmi->variant->external_irq_controller)
+		free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
+
 err_delete_cec_adap:
 	cec_delete_adapter(vc4_hdmi->cec_adap);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1989 @
 
 static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi)
 {
+	struct platform_device *pdev = vc4_hdmi->pdev;
+
+	if (vc4_hdmi->variant->external_irq_controller) {
+		free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
+		free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
+	} else {
+		free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
+	}
+
 	cec_unregister_adapter(vc4_hdmi->cec_adap);
 }
 #else
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2082 @
 		return PTR_ERR(vc4_hdmi->hsm_clock);
 	}
 	vc4_hdmi->audio_clock = vc4_hdmi->hsm_clock;
+	vc4_hdmi->cec_clock = vc4_hdmi->hsm_clock;
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2092 @
 	struct platform_device *pdev = vc4_hdmi->pdev;
 	struct device *dev = &pdev->dev;
 	struct resource *res;
+	int ret;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi");
 	if (!res)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2177 @
 		return PTR_ERR(vc4_hdmi->audio_clock);
 	}
 
+	vc4_hdmi->cec_clock = devm_clk_get(dev, "cec");
+	if (IS_ERR(vc4_hdmi->cec_clock)) {
+		DRM_ERROR("Failed to get CEC clock\n");
+		return PTR_ERR(vc4_hdmi->cec_clock);
+	}
+
 	vc4_hdmi->reset = devm_reset_control_get(dev, NULL);
 	if (IS_ERR(vc4_hdmi->reset)) {
 		DRM_ERROR("Failed to get HDMI reset line\n");
 		return PTR_ERR(vc4_hdmi->reset);
 	}
 
+	ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI);
+	if (ret)
+		return ret;
+
+	ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD);
+	if (ret)
+		return ret;
+
+	ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->cec_regset, VC5_CEC);
+	if (ret)
+		return ret;
+
+	ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->csc_regset, VC5_CSC);
+	if (ret)
+		return ret;
+
+	ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->dvp_regset, VC5_DVP);
+	if (ret)
+		return ret;
+
+	ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->phy_regset, VC5_PHY);
+	if (ret)
+		return ret;
+
+	ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->ram_regset, VC5_RAM);
+	if (ret)
+		return ret;
+
+	ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->rm_regset, VC5_RM);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2261 @
 	vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
 	if (!vc4_hdmi)
 		return -ENOMEM;
+	INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
 
 	dev_set_drvdata(dev, vc4_hdmi);
 	encoder = &vc4_hdmi->encoder.base.base;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2311 @
 	vc4_hdmi->disable_wifi_frequencies =
 		of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence");
 
+	if (variant->max_pixel_clock == 600000000) {
+		struct vc4_dev *vc4 = to_vc4_dev(drm);
+		long max_rate = clk_round_rate(vc4->hvs->core_clk, 550000000);
+
+		if (max_rate < 550000000)
+			vc4_hdmi->disable_4kp60 = true;
+	}
+
+	/*
+	 * We need to have the device powered up at this point to call
+	 * our reset hook and for the CEC init.
+	 */
+	ret = vc4_hdmi_runtime_resume(dev);
+	if (ret)
+		goto err_put_ddc;
+
+	pm_runtime_get_noresume(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
 	if (vc4_hdmi->variant->reset)
 		vc4_hdmi->variant->reset(vc4_hdmi);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2342 @
 		clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
 	}
 
-	pm_runtime_enable(dev);
-
 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 	drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2349 @
 	if (ret)
 		goto err_destroy_encoder;
 
-	ret = vc4_hdmi_cec_init(vc4_hdmi);
+	ret = vc4_hdmi_hotplug_init(vc4_hdmi);
 	if (ret)
 		goto err_destroy_conn;
 
+	ret = vc4_hdmi_cec_init(vc4_hdmi);
+	if (ret)
+		goto err_free_hotplug;
+
 	ret = vc4_hdmi_audio_init(vc4_hdmi);
 	if (ret)
 		goto err_free_cec;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2365 @
 			     vc4_hdmi_debugfs_regs,
 			     vc4_hdmi);
 
+	pm_runtime_put_sync(dev);
+
 	return 0;
 
 err_free_cec:
 	vc4_hdmi_cec_exit(vc4_hdmi);
+err_free_hotplug:
+	vc4_hdmi_hotplug_exit(vc4_hdmi);
 err_destroy_conn:
 	vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
 err_destroy_encoder:
 	drm_encoder_cleanup(encoder);
+	pm_runtime_put_sync(dev);
 	pm_runtime_disable(dev);
 err_put_ddc:
 	put_device(&vc4_hdmi->ddc->dev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2415 @
 	kfree(vc4_hdmi->hd_regset.regs);
 
 	vc4_hdmi_cec_exit(vc4_hdmi);
+	vc4_hdmi_hotplug_exit(vc4_hdmi);
 	vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
 	drm_encoder_cleanup(&vc4_hdmi->encoder.base.base);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2445 @
 	.debugfs_name		= "hdmi_regs",
 	.card_name		= "vc4-hdmi",
 	.max_pixel_clock	= 162000000,
-	.cec_available		= true,
 	.registers		= vc4_hdmi_fields,
 	.num_registers		= ARRAY_SIZE(vc4_hdmi_fields),
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2456 @
 	.phy_disable		= vc4_hdmi_phy_disable,
 	.phy_rng_enable		= vc4_hdmi_phy_rng_enable,
 	.phy_rng_disable	= vc4_hdmi_phy_rng_disable,
+	.calc_hsm_clock		= vc4_hdmi_calc_hsm_clock,
 	.channel_map		= vc4_hdmi_channel_map,
+	.supports_hdr		= false,
 };
 
 static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
 	.encoder_type		= VC4_ENCODER_TYPE_HDMI0,
 	.debugfs_name		= "hdmi0_regs",
 	.card_name		= "vc4-hdmi-0",
-	.max_pixel_clock	= 297000000,
+	.max_pixel_clock	= 600000000,
 	.registers		= vc5_hdmi_hdmi0_fields,
 	.num_registers		= ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
 	.phy_lane_mapping	= {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2475 @
 		PHY_LANE_CK,
 	},
 	.unsupported_odd_h_timings	= true,
+	.external_irq_controller	= true,
 
 	.init_resources		= vc5_hdmi_init_resources,
 	.csc_setup		= vc5_hdmi_csc_setup,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2485 @
 	.phy_disable		= vc5_hdmi_phy_disable,
 	.phy_rng_enable		= vc5_hdmi_phy_rng_enable,
 	.phy_rng_disable	= vc5_hdmi_phy_rng_disable,
+	.calc_hsm_clock		= vc5_hdmi_calc_hsm_clock,
 	.channel_map		= vc5_hdmi_channel_map,
+	.supports_hdr		= true,
 };
 
 static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
 	.encoder_type		= VC4_ENCODER_TYPE_HDMI1,
 	.debugfs_name		= "hdmi1_regs",
 	.card_name		= "vc4-hdmi-1",
-	.max_pixel_clock	= 297000000,
+	.max_pixel_clock	= HDMI_14_MAX_TMDS_CLK,
 	.registers		= vc5_hdmi_hdmi1_fields,
 	.num_registers		= ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
 	.phy_lane_mapping	= {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2504 @
 		PHY_LANE_2,
 	},
 	.unsupported_odd_h_timings	= true,
+	.external_irq_controller	= true,
 
 	.init_resources		= vc5_hdmi_init_resources,
 	.csc_setup		= vc5_hdmi_csc_setup,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2514 @
 	.phy_disable		= vc5_hdmi_phy_disable,
 	.phy_rng_enable		= vc5_hdmi_phy_rng_enable,
 	.phy_rng_disable	= vc5_hdmi_phy_rng_disable,
+	.calc_hsm_clock		= vc5_hdmi_calc_hsm_clock,
 	.channel_map		= vc5_hdmi_channel_map,
+	.supports_hdr		= true,
 };
 
 static const struct of_device_id vc4_hdmi_dt_match[] = {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hdmi.h linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hdmi.h
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hdmi.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hdmi.h	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:24 @
 	return container_of(encoder, struct vc4_hdmi_encoder, base.base);
 }
 
-struct drm_display_mode;
-
 struct vc4_hdmi;
 struct vc4_hdmi_register;
+struct vc4_hdmi_connector_state;
 
 enum vc4_hdmi_phy_channel {
 	PHY_LANE_0 = 0,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:45 @
 	/* Filename to expose the registers in debugfs */
 	const char *debugfs_name;
 
-	/* Set to true when the CEC support is available */
-	bool cec_available;
-
 	/* Maximum pixel clock supported by the controller (in Hz) */
 	unsigned long long max_pixel_clock;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:64 @
 	/* The BCM2711 cannot deal with odd horizontal pixel timings */
 	bool unsupported_odd_h_timings;
 
+	/*
+	 * The BCM2711 CEC/hotplug IRQ controller is shared between the
+	 * two HDMI controllers, and we have a proper irqchip driver for
+	 * it.
+	 */
+	bool external_irq_controller;
+
 	/* Callback to get the resources (memory region, interrupts,
 	 * clocks, etc) for that variant.
 	 */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:84 @
 
 	/* Callback to configure the video timings in the HDMI block */
 	void (*set_timings)(struct vc4_hdmi *vc4_hdmi,
+			    struct drm_connector_state *state,
 			    struct drm_display_mode *mode);
 
-	/* Callback to initialize the PHY according to the mode */
+	/* Callback to initialize the PHY according to the connector state */
 	void (*phy_init)(struct vc4_hdmi *vc4_hdmi,
-			 struct drm_display_mode *mode);
+			 struct vc4_hdmi_connector_state *vc4_conn_state);
 
 	/* Callback to disable the PHY */
 	void (*phy_disable)(struct vc4_hdmi *vc4_hdmi);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:100 @
 	/* Callback to disable the RNG in the PHY */
 	void (*phy_rng_disable)(struct vc4_hdmi *vc4_hdmi);
 
+	/* Callback to calculate hsm clock */
+	u32 (*calc_hsm_clock)(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate);
+
 	/* Callback to get channel map */
 	u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask);
+
+	/* Enables HDR metadata */
+	bool supports_hdr;
 };
 
 /* HDMI audio information */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:117 @
 	struct snd_soc_dai_link_component cpu;
 	struct snd_soc_dai_link_component codec;
 	struct snd_soc_dai_link_component platform;
-	int samplerate;
-	int channels;
 	struct snd_dmaengine_dai_dma_data dma_data;
-	struct snd_pcm_substream *substream;
-
+	struct hdmi_audio_infoframe infoframe;
 	bool streaming;
 };
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:132 @
 	struct vc4_hdmi_encoder encoder;
 	struct drm_connector connector;
 
+	struct delayed_work scrambling_work;
+
 	struct i2c_adapter *ddc;
 	void __iomem *hdmicore_regs;
 	void __iomem *hd_regs;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:162 @
 	 */
 	bool disable_wifi_frequencies;
 
+	/*
+	 * Even if HDMI0 on the RPi4 can output modes requiring a pixel
+	 * rate higher than 297MHz, it needs some adjustments in the
+	 * config.txt file to be able to do so and thus won't always be
+	 * available.
+	 */
+	bool disable_4kp60;
+
 	struct cec_adapter *cec_adap;
 	struct cec_msg cec_rx_msg;
 	bool cec_tx_ok;
 	bool cec_irq_was_rx;
 
+	struct clk *cec_clock;
 	struct clk *pixel_clock;
 	struct clk *hsm_clock;
 	struct clk *audio_clock;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:183 @
 
 	struct reset_control *reset;
 
+	struct clk_request *bvb_req;
+	struct clk_request *hsm_req;
+
+	/* Common debugfs regset */
 	struct debugfs_regset32 hdmi_regset;
 	struct debugfs_regset32 hd_regset;
+	/* VC5 debugfs regset */
+	struct debugfs_regset32 cec_regset;
+	struct debugfs_regset32 csc_regset;
+	struct debugfs_regset32 dvp_regset;
+	struct debugfs_regset32 phy_regset;
+	struct debugfs_regset32 ram_regset;
+	struct debugfs_regset32 rm_regset;
 };
 
 static inline struct vc4_hdmi *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:212 @
 	return container_of(_encoder, struct vc4_hdmi, encoder);
 }
 
+struct vc4_hdmi_connector_state {
+	struct drm_connector_state	base;
+	unsigned long long		pixel_rate;
+};
+
+static inline struct vc4_hdmi_connector_state *
+conn_state_to_vc4_hdmi_conn_state(struct drm_connector_state *conn_state)
+{
+	return container_of(conn_state, struct vc4_hdmi_connector_state, base);
+}
+
 void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
-		       struct drm_display_mode *mode);
+		       struct vc4_hdmi_connector_state *vc4_conn_state);
 void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi);
 void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi);
 void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi);
 
 void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
-		       struct drm_display_mode *mode);
+		       struct vc4_hdmi_connector_state *vc4_conn_state);
 void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi);
 void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi);
 void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hdmi_phy.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hdmi_phy.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hdmi_phy.c	2021-07-25 16:46:01.698362435 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:130 @
 
 #define OSCILLATOR_FREQUENCY	54000000
 
-void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode)
+void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
+		       struct vc4_hdmi_connector_state *conn_state)
 {
 	/* PHY should be in reset, like
 	 * vc4_hdmi_encoder_disable() does.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:343 @
 	HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, BIT(10));
 }
 
-void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode)
+void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
+		       struct vc4_hdmi_connector_state *conn_state)
 {
 	const struct phy_lane_settings *chan0_settings, *chan1_settings, *chan2_settings, *clock_settings;
 	const struct vc4_hdmi_variant *variant = vc4_hdmi->variant;
-	unsigned long long pixel_freq = mode->clock * 1000;
+	unsigned long long pixel_freq = conn_state->pixel_rate;
 	unsigned long long vco_freq;
 	unsigned char word_sel;
 	u8 vco_sel, vco_div;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hdmi_regs.h linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hdmi_regs.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hdmi_regs.h	2021-07-25 16:46:01.708362267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
 #ifndef _VC4_HDMI_REGS_H_
 #define _VC4_HDMI_REGS_H_
 
+#include <linux/pm_runtime.h>
+
 #include "vc4_hdmi.h"
 
 #define VC4_HDMI_PACKET_STRIDE			0x24
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:65 @
 	 */
 	HDMI_CTS_0,
 	HDMI_CTS_1,
+	HDMI_DEEP_COLOR_CONFIG_1,
 	HDMI_DVP_CTL,
 	HDMI_FIFO_CTL,
 	HDMI_FRAME_COUNT,
+	HDMI_GCP_CONFIG,
+	HDMI_GCP_WORD_1,
 	HDMI_HORZA,
 	HDMI_HORZB,
 	HDMI_HOTPLUG,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:105 @
 	HDMI_RM_FORMAT,
 	HDMI_RM_OFFSET,
 	HDMI_SCHEDULER_CONTROL,
+	HDMI_SCRAMBLER_CTL,
 	HDMI_SW_RESET_CONTROL,
 	HDMI_TX_PHY_CHANNEL_SWAP,
 	HDMI_TX_PHY_CLK_DIV,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:152 @
 #define VC5_RAM_REG(reg, offset)	_VC4_REG(VC5_RAM, reg, offset)
 #define VC5_RM_REG(reg, offset)		_VC4_REG(VC5_RM, reg, offset)
 
-static const struct vc4_hdmi_register vc4_hdmi_fields[] = {
+static const struct vc4_hdmi_register __maybe_unused vc4_hdmi_fields[] = {
 	VC4_HD_REG(HDMI_M_CTL, 0x000c),
 	VC4_HD_REG(HDMI_MAI_CTL, 0x0014),
 	VC4_HD_REG(HDMI_MAI_THR, 0x0018),
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:214 @
 	VC4_HDMI_REG(HDMI_RAM_PACKET_START, 0x0400),
 };
 
-static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields[] = {
+static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi0_fields[] = {
 	VC4_HD_REG(HDMI_DVP_CTL, 0x0000),
 	VC4_HD_REG(HDMI_MAI_CTL, 0x0010),
 	VC4_HD_REG(HDMI_MAI_THR, 0x0014),
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:240 @
 	VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
 	VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
 	VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
+	VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170),
+	VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178),
+	VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c),
 	VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
+	VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
 
 	VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
 	VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:294 @
 	VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
 };
 
-static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields[] = {
+static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = {
 	VC4_HD_REG(HDMI_DVP_CTL, 0x0000),
 	VC4_HD_REG(HDMI_MAI_CTL, 0x0030),
 	VC4_HD_REG(HDMI_MAI_THR, 0x0034),
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:320 @
 	VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
 	VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
 	VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
+	VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170),
+	VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178),
+	VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c),
 	VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
+	VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
 
 	VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
 	VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:417 @
 	const struct vc4_hdmi_variant *variant = hdmi->variant;
 	void __iomem *base;
 
+	WARN_ON(!pm_runtime_active(&hdmi->pdev->dev));
+
 	if (reg >= variant->num_registers) {
 		dev_warn(&hdmi->pdev->dev,
 			 "Invalid register ID %u\n", reg);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:445 @
 	const struct vc4_hdmi_variant *variant = hdmi->variant;
 	void __iomem *base;
 
+	WARN_ON(!pm_runtime_active(&hdmi->pdev->dev));
+
 	if (reg >= variant->num_registers) {
 		dev_warn(&hdmi->pdev->dev,
 			 "Invalid register ID %u\n", reg);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hvs.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hvs.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_hvs.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_hvs.c	2021-07-25 16:46:01.708362267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:98 @
 	return 0;
 }
 
+static int vc4_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 drm_printer p = drm_seq_file_printer(m);
+	unsigned int next_entry_start = 0;
+	unsigned int i, j;
+	u32 dlist_word, dispstat;
+
+	for (i = 0; i < SCALER_CHANNELS_COUNT; i++) {
+		dispstat = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(i)),
+					 SCALER_DISPSTATX_MODE);
+		if (dispstat == SCALER_DISPSTATX_MODE_DISABLED ||
+		    dispstat == SCALER_DISPSTATX_MODE_EOF) {
+			drm_printf(&p, "HVS chan %u disabled\n", i);
+			continue;
+		}
+
+		drm_printf(&p, "HVS chan %u:\n", i);
+
+		for (j = HVS_READ(SCALER_DISPLISTX(i)); j < 256; j++) {
+			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;
+}
+
 /* The filter kernel is composed of dwords each containing 3 9-bit
  * signed integers packed next to each other.
  */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:368 @
 		     SCALER_DISPSTATX_EMPTY);
 }
 
-int vc4_hvs_atomic_check(struct drm_crtc *crtc,
-			 struct drm_crtc_state *state)
+int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
 {
-	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
 	struct drm_device *dev = crtc->dev;
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
 	struct drm_plane *plane;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:383 @
 	/* The pixelvalve can only feed one encoder (and encoders are
 	 * 1:1 with connectors.)
 	 */
-	if (hweight32(state->connector_mask) > 1)
+	if (hweight32(crtc_state->connector_mask) > 1)
 		return -EINVAL;
 
-	drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, state)
+	drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state)
 		dlist_count += vc4_plane_dlist_size(plane_state);
 
 	dlist_count++; /* Account for SCALER_CTL0_END. */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:433 @
 }
 
 void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
-			   struct drm_crtc_state *old_state)
+			   struct drm_atomic_state *state)
 {
 	struct drm_device *dev = crtc->dev;
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
-	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
+	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(new_crtc_state);
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
 	bool oneshot = vc4_state->feed_txp;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:447 @
 }
 
 void vc4_hvs_atomic_disable(struct drm_crtc *crtc,
-			    struct drm_crtc_state *old_state)
+			    struct drm_atomic_state *state)
 {
 	struct drm_device *dev = crtc->dev;
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc);
 	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(old_state);
 	unsigned int chan = vc4_state->assigned_channel;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:458 @
 }
 
 void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
-			  struct drm_crtc_state *old_state)
+			  struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
+									 crtc);
 	struct drm_device *dev = crtc->dev;
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
 	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:717 @
 	vc4_debugfs_add_regset32(drm, "hvs_regs", &hvs->regset);
 	vc4_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun,
 			     NULL);
+	vc4_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist,
+			     NULL);
 
 	return 0;
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_kms.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_kms.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_kms.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_kms.c	2021-07-25 16:46:01.708362267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:42 @
 
 struct vc4_hvs_state {
 	struct drm_private_state base;
-	unsigned int unassigned_channels;
+	unsigned long core_clock_rate;
+
+	struct {
+		unsigned in_use: 1;
+		unsigned long fifo_load;
+		struct drm_crtc_commit *pending_commit;
+	} fifo_state[HVS_NUM_CHANNELS];
 };
 
 static struct vc4_hvs_state *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:163 @
 	struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state);
 	struct drm_color_ctm *ctm = ctm_state->ctm;
 
+	if (vc4->firmware_kms)
+		return;
+
 	if (ctm_state->fifo) {
 		HVS_WRITE(SCALER_OLEDCOEF2,
 			  VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]),
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:195 @
 }
 
 static struct vc4_hvs_state *
+vc4_hvs_get_new_global_state(struct drm_atomic_state *state)
+{
+	struct vc4_dev *vc4 = to_vc4_dev(state->dev);
+	struct drm_private_state *priv_state;
+
+	priv_state = drm_atomic_get_new_private_obj_state(state, &vc4->hvs_channels);
+	if (IS_ERR(priv_state))
+		return ERR_CAST(priv_state);
+
+	return to_vc4_hvs_state(priv_state);
+}
+
+static struct vc4_hvs_state *
+vc4_hvs_get_old_global_state(struct drm_atomic_state *state)
+{
+	struct vc4_dev *vc4 = to_vc4_dev(state->dev);
+	struct drm_private_state *priv_state;
+
+	priv_state = drm_atomic_get_old_private_obj_state(state, &vc4->hvs_channels);
+	if (IS_ERR(priv_state))
+		return ERR_CAST(priv_state);
+
+	return to_vc4_hvs_state(priv_state);
+}
+
+static struct vc4_hvs_state *
 vc4_hvs_get_global_state(struct drm_atomic_state *state)
 {
 	struct vc4_dev *vc4 = to_vc4_dev(state->dev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:340 @
 	}
 }
 
-static void
-vc4_atomic_complete_commit(struct drm_atomic_state *state)
+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 *old_crtc_state;
 	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;
+	struct clk_request *core_req;
 	int i;
 
+	old_hvs_state = vc4_hvs_get_old_global_state(state);
+	if (WARN_ON(!old_hvs_state))
+		return;
+
+	new_hvs_state = vc4_hvs_get_new_global_state(state);
+	if (WARN_ON(!new_hvs_state))
+		return;
+
 	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
 		struct vc4_crtc_state *vc4_crtc_state;
 
-		if (!new_crtc_state->commit)
+		if (!new_crtc_state->commit || vc4->firmware_kms)
 			continue;
 
 		vc4_crtc_state = to_vc4_crtc_state(new_crtc_state);
 		vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
 	}
 
-	if (vc4->hvs->hvs5)
-		clk_set_min_rate(hvs->core_clk, 500000000);
+	if (vc4->hvs && vc4->hvs->hvs5) {
+		unsigned long core_rate = max_t(unsigned long,
+						500000000,
+						new_hvs_state->core_clock_rate);
 
-	drm_atomic_helper_wait_for_fences(dev, state, false);
+		drm_dbg(dev, "Raising the core clock at %lu Hz\n", core_rate);
 
-	drm_atomic_helper_wait_for_dependencies(state);
+		/*
+		 * Do a temporary request on the core clock during the
+		 * modeset.
+		 */
+		core_req = clk_request_start(hvs->core_clk, core_rate);
+
+		/*
+		 * And remove the previous one based on the HVS
+		 * requirements if any.
+		 */
+		clk_request_done(hvs->core_req);
+	}
+
+	for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
+		struct vc4_crtc_state *vc4_crtc_state =
+			to_vc4_crtc_state(old_crtc_state);
+		struct drm_crtc_commit *commit;
+		unsigned int channel = vc4_crtc_state->assigned_channel;
+		unsigned long done;
+
+		if (channel == VC4_HVS_CHANNEL_DISABLED)
+			continue;
+
+		if (!old_hvs_state->fifo_state[channel].in_use)
+			continue;
+
+		commit = old_hvs_state->fifo_state[i].pending_commit;
+		if (!commit)
+			continue;
+
+		done = wait_for_completion_timeout(&commit->hw_done, 10 * HZ);
+		if (!done)
+			drm_err(dev, "Timed out waiting for hw_done\n");
+
+		done = wait_for_completion_timeout(&commit->flip_done, 10 * HZ);
+		if (!done)
+			drm_err(dev, "Timed out waiting for flip_done\n");
+	}
 
 	drm_atomic_helper_commit_modeset_disables(dev, state);
 
 	vc4_ctm_commit(vc4, state);
 
-	if (vc4->hvs->hvs5)
-		vc5_hvs_pv_muxing_commit(vc4, state);
-	else
-		vc4_hvs_pv_muxing_commit(vc4, state);
+	if (!vc4->firmware_kms) {
+		if (vc4->hvs->hvs5)
+			vc5_hvs_pv_muxing_commit(vc4, state);
+		else
+			vc4_hvs_pv_muxing_commit(vc4, state);
+	}
 
 	drm_atomic_helper_commit_planes(dev, state, 0);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:440 @
 
 	drm_atomic_helper_cleanup_planes(dev, state);
 
-	drm_atomic_helper_commit_cleanup_done(state);
+	if (vc4->hvs && vc4->hvs->hvs5) {
+		drm_dbg(dev, "Running the core clock at %lu Hz\n",
+			new_hvs_state->core_clock_rate);
 
-	if (vc4->hvs->hvs5)
-		clk_set_min_rate(hvs->core_clk, 0);
-
-	drm_atomic_state_put(state);
-
-	up(&vc4->async_modeset);
-}
+		/*
+		 * Request a clock rate based on the current HVS
+		 * requirements.
+		 */
+		hvs->core_req = clk_request_start(hvs->core_clk,
+						  new_hvs_state->core_clock_rate);
 
-static void commit_work(struct work_struct *work)
-{
-	struct drm_atomic_state *state = container_of(work,
-						      struct drm_atomic_state,
-						      commit_work);
-	vc4_atomic_complete_commit(state);
+		/* And drop the temporary request */
+		clk_request_done(core_req);
+	}
 }
 
-/**
- * vc4_atomic_commit - commit validated state object
- * @dev: DRM device
- * @state: the driver state object
- * @nonblock: nonblocking commit
- *
- * This function commits a with drm_atomic_helper_check() pre-validated state
- * object. This can still fail when e.g. the framebuffer reservation fails. For
- * now this doesn't implement asynchronous commits.
- *
- * RETURNS
- * Zero for success or -errno.
- */
-static int vc4_atomic_commit(struct drm_device *dev,
-			     struct drm_atomic_state *state,
-			     bool nonblock)
+static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
 {
+	struct drm_device *dev = state->dev;
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
-	int ret;
-
-	if (state->async_update) {
-		ret = down_interruptible(&vc4->async_modeset);
-		if (ret)
-			return ret;
-
-		ret = drm_atomic_helper_prepare_planes(dev, state);
-		if (ret) {
-			up(&vc4->async_modeset);
-			return ret;
-		}
-
-		drm_atomic_helper_async_commit(dev, state);
-
-		drm_atomic_helper_cleanup_planes(dev, state);
-
-		up(&vc4->async_modeset);
-
-		return 0;
-	}
+	struct drm_crtc_state *crtc_state;
+	struct vc4_hvs_state *hvs_state;
+	struct drm_crtc *crtc;
+	unsigned int i;
 
 	/* We know for sure we don't want an async update here. Set
 	 * state->legacy_cursor_update to false to prevent
 	 * drm_atomic_helper_setup_commit() from auto-completing
 	 * commit->flip_done.
 	 */
-	state->legacy_cursor_update = false;
-	ret = drm_atomic_helper_setup_commit(state, nonblock);
-	if (ret)
-		return ret;
-
-	INIT_WORK(&state->commit_work, commit_work);
-
-	ret = down_interruptible(&vc4->async_modeset);
-	if (ret)
-		return ret;
+	if (!vc4->firmware_kms)
+		state->legacy_cursor_update = false;
 
-	ret = drm_atomic_helper_prepare_planes(dev, state);
-	if (ret) {
-		up(&vc4->async_modeset);
-		return ret;
-	}
-
-	if (!nonblock) {
-		ret = drm_atomic_helper_wait_for_fences(dev, state, true);
-		if (ret) {
-			drm_atomic_helper_cleanup_planes(dev, state);
-			up(&vc4->async_modeset);
-			return ret;
-		}
-	}
+	hvs_state = vc4_hvs_get_new_global_state(state);
+	if (!hvs_state)
+		return -EINVAL;
 
-	/*
-	 * This is the point of no return - everything below never fails except
-	 * when the hw goes bonghits. Which means we can commit the new state on
-	 * the software side now.
-	 */
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+		struct vc4_crtc_state *vc4_crtc_state =
+			to_vc4_crtc_state(crtc_state);
+		unsigned int channel =
+			vc4_crtc_state->assigned_channel;
 
-	BUG_ON(drm_atomic_helper_swap_state(state, false) < 0);
+		if (channel == VC4_HVS_CHANNEL_DISABLED)
+			continue;
 
-	/*
-	 * Everything below can be run asynchronously without the need to grab
-	 * any modeset locks at all under one condition: It must be guaranteed
-	 * that the asynchronous work has either been cancelled (if the driver
-	 * supports it, which at least requires that the framebuffers get
-	 * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
-	 * before the new state gets committed on the software side with
-	 * drm_atomic_helper_swap_state().
-	 *
-	 * This scheme allows new atomic state updates to be prepared and
-	 * checked in parallel to the asynchronous completion of the previous
-	 * update. Which is important since compositors need to figure out the
-	 * composition of the next frame right after having submitted the
-	 * current layout.
-	 */
+		if (!hvs_state->fifo_state[channel].in_use)
+			continue;
 
-	drm_atomic_state_get(state);
-	if (nonblock)
-		queue_work(system_unbound_wq, &state->commit_work);
-	else
-		vc4_atomic_complete_commit(state);
+		hvs_state->fifo_state[channel].pending_commit =
+			drm_crtc_commit_get(crtc_state->commit);
+	}
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:615 @
 	struct drm_plane *plane;
 	int i;
 
-	if (!vc4->load_tracker_available)
-		return 0;
-
 	priv_state = drm_atomic_get_private_obj_state(state,
 						      &vc4->load_tracker);
 	if (IS_ERR(priv_state))
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:689 @
 {
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
 
-	if (!vc4->load_tracker_available)
-		return;
-
 	drm_atomic_private_obj_fini(&vc4->load_tracker);
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:696 @
 {
 	struct vc4_load_tracker_state *load_state;
 
-	if (!vc4->load_tracker_available)
-		return 0;
-
 	load_state = kzalloc(sizeof(*load_state), GFP_KERNEL);
 	if (!load_state)
 		return -ENOMEM;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:712 @
 {
 	struct vc4_hvs_state *old_state = to_vc4_hvs_state(obj->state);
 	struct vc4_hvs_state *state;
+	unsigned int i;
 
 	state = kzalloc(sizeof(*state), GFP_KERNEL);
 	if (!state)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:720 @
 
 	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
 
-	state->unassigned_channels = old_state->unassigned_channels;
+	for (i = 0; i < HVS_NUM_CHANNELS; i++) {
+		state->fifo_state[i].in_use = old_state->fifo_state[i].in_use;
+		state->fifo_state[i].fifo_load = old_state->fifo_state[i].fifo_load;
+
+		if (!old_state->fifo_state[i].pending_commit)
+			continue;
+
+		state->fifo_state[i].pending_commit =
+			drm_crtc_commit_get(old_state->fifo_state[i].pending_commit);
+	}
+
+	state->core_clock_rate = old_state->core_clock_rate;
+
 
 	return &state->base;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:741 @
 					   struct drm_private_state *state)
 {
 	struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state);
+	unsigned int i;
+
+	for (i = 0; i < HVS_NUM_CHANNELS; i++) {
+		if (!hvs_state->fifo_state[i].pending_commit)
+			continue;
+
+		drm_crtc_commit_put(hvs_state->fifo_state[i].pending_commit);
+	}
 
 	kfree(hvs_state);
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:773 @
 	if (!state)
 		return -ENOMEM;
 
-	state->unassigned_channels = GENMASK(HVS_NUM_CHANNELS - 1, 0);
 	drm_atomic_private_obj_init(&vc4->base, &vc4->hvs_channels,
 				    &state->base,
 				    &vc4_hvs_state_funcs);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:813 @
 static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
 				      struct drm_atomic_state *state)
 {
+	struct vc4_dev *vc4 = to_vc4_dev(state->dev);
 	struct vc4_hvs_state *hvs_new_state;
 	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
 	struct drm_crtc *crtc;
+	unsigned int unassigned_channels = 0;
 	unsigned int i;
 
 	hvs_new_state = vc4_hvs_get_global_state(state);
 	if (!hvs_new_state)
 		return -EINVAL;
 
+	for (i = 0; i < ARRAY_SIZE(hvs_new_state->fifo_state); i++)
+		if (!hvs_new_state->fifo_state[i].in_use)
+			unassigned_channels |= BIT(i);
+
 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
 		struct vc4_crtc_state *old_vc4_crtc_state =
 			to_vc4_crtc_state(old_crtc_state);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:835 @
 			to_vc4_crtc_state(new_crtc_state);
 		struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
 		unsigned int matching_channels;
+		unsigned int channel;
+
+		if (vc4->firmware_kms)
+			continue;
 
 		/* Nothing to do here, let's skip it */
 		if (old_crtc_state->enable == new_crtc_state->enable)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:849 @
 
 		/* If we're disabling our CRTC, we put back our channel */
 		if (!new_crtc_state->enable) {
-			hvs_new_state->unassigned_channels |= BIT(old_vc4_crtc_state->assigned_channel);
+			channel = old_vc4_crtc_state->assigned_channel;
+			hvs_new_state->fifo_state[channel].in_use = false;
 			new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED;
 			continue;
 		}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:879 @
 		 * the future, we will need to have something smarter,
 		 * but it works so far.
 		 */
-		matching_channels = hvs_new_state->unassigned_channels & vc4_crtc->data->hvs_available_channels;
-		if (matching_channels) {
-			unsigned int channel = ffs(matching_channels) - 1;
-
-			new_vc4_crtc_state->assigned_channel = channel;
-			hvs_new_state->unassigned_channels &= ~BIT(channel);
-		} else {
+		matching_channels = unassigned_channels & vc4_crtc->data->hvs_available_channels;
+		if (!matching_channels)
 			return -EINVAL;
+
+		channel = ffs(matching_channels) - 1;
+		new_vc4_crtc_state->assigned_channel = channel;
+		unassigned_channels &= ~BIT(channel);
+		hvs_new_state->fifo_state[channel].in_use = true;
+	}
+
+	return 0;
+}
+
+static int
+vc4_core_clock_atomic_check(struct drm_atomic_state *state)
+{
+	struct vc4_dev *vc4 = to_vc4_dev(state->dev);
+	struct drm_private_state *priv_state;
+	struct vc4_hvs_state *hvs_new_state;
+	struct vc4_load_tracker_state *load_state;
+	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+	struct drm_crtc *crtc;
+	unsigned int num_outputs;
+	unsigned long pixel_rate;
+	unsigned long cob_rate;
+	unsigned int i;
+
+	priv_state = drm_atomic_get_private_obj_state(state,
+						      &vc4->load_tracker);
+	if (IS_ERR(priv_state))
+		return PTR_ERR(priv_state);
+
+	load_state = to_vc4_load_tracker_state(priv_state);
+
+	hvs_new_state = vc4_hvs_get_global_state(state);
+	if (!hvs_new_state)
+		return -EINVAL;
+
+	for_each_oldnew_crtc_in_state(state, crtc,
+				      old_crtc_state,
+				      new_crtc_state,
+				      i) {
+		if (old_crtc_state->active) {
+			struct vc4_crtc_state *old_vc4_state =
+				to_vc4_crtc_state(old_crtc_state);
+			unsigned int channel = old_vc4_state->assigned_channel;
+
+			hvs_new_state->fifo_state[channel].fifo_load = 0;
 		}
+
+		if (new_crtc_state->active) {
+			struct vc4_crtc_state *new_vc4_state =
+				to_vc4_crtc_state(new_crtc_state);
+			unsigned int channel = new_vc4_state->assigned_channel;
+
+			hvs_new_state->fifo_state[channel].fifo_load =
+				new_vc4_state->hvs_load;
+		}
+	}
+
+	cob_rate = 0;
+	num_outputs = 0;
+	for (i = 0; i < HVS_NUM_CHANNELS; i++) {
+		if (!hvs_new_state->fifo_state[i].in_use)
+			continue;
+
+		num_outputs++;
+		cob_rate += hvs_new_state->fifo_state[i].fifo_load;
 	}
 
+	pixel_rate = load_state->hvs_load;
+	if (num_outputs > 1) {
+		pixel_rate = (pixel_rate * 40) / 100;
+	} else {
+		pixel_rate = (pixel_rate * 60) / 100;
+	}
+
+	hvs_new_state->core_clock_rate = max(cob_rate, pixel_rate);
+
 	return 0;
 }
 
+
 static int
 vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:979 @
 	if (ret)
 		return ret;
 
-	return vc4_load_tracker_atomic_check(state);
+	ret = vc4_load_tracker_atomic_check(state);
+	if (ret)
+		return ret;
+
+	return vc4_core_clock_atomic_check(state);
 }
 
+static struct drm_mode_config_helper_funcs vc4_mode_config_helpers = {
+	.atomic_commit_setup	= vc4_atomic_commit_setup,
+	.atomic_commit_tail	= vc4_atomic_commit_tail,
+};
+
 static const struct drm_mode_config_funcs vc4_mode_funcs = {
 	.atomic_check = vc4_atomic_check,
-	.atomic_commit = vc4_atomic_commit,
+	.atomic_commit = drm_atomic_helper_commit,
 	.fb_create = vc4_fb_create,
 };
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1004 @
 					      "brcm,bcm2711-vc5");
 	int ret;
 
+	/*
+	 * The limits enforced by the load tracker aren't relevant for
+	 * the BCM2711, but the load tracker computations are used for
+	 * the core clock rate calculation.
+	 */
 	if (!is_vc5) {
-		vc4->load_tracker_available = true;
-
 		/* Start with the load tracker enabled. Can be
 		 * disabled through the debugfs load_tracker file.
 		 */
 		vc4->load_tracker_enabled = true;
 	}
 
-	sema_init(&vc4->async_modeset, 1);
-
 	/* Set support for vblank irq fast disable, before drm_vblank_init() */
 	dev->vblank_disable_immediate = true;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1035 @
 	}
 
 	dev->mode_config.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;
 	dev->mode_config.allow_fb_modifiers = true;
+	if (vc4->firmware_kms)
+		dev->mode_config.normalize_zpos = true;
 
 	ret = vc4_ctm_obj_init(vc4);
 	if (ret)
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_perfmon.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_perfmon.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_perfmon.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_perfmon.c	2021-07-25 16:46:01.708362267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:80 @
 void vc4_perfmon_open_file(struct vc4_file *vc4file)
 {
 	mutex_init(&vc4file->perfmon.lock);
-	idr_init(&vc4file->perfmon.idr);
+	idr_init_base(&vc4file->perfmon.idr, VC4_PERFMONID_MIN);
 }
 
 static int vc4_perfmon_idr_del(int id, void *elem, void *data)
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_plane.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_plane.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_plane.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_plane.c	2021-07-25 16:46:01.708362267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:36 @
 	u32 hvs; /* HVS_FORMAT_* */
 	u32 pixel_order;
 	u32 pixel_order_hvs5;
+	bool hvs5_only;
 } hvs_formats[] = {
 	{
 		.drm = DRM_FORMAT_XRGB8888,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:132 @
 		.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
 		.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
 	},
+	{
+		.drm = DRM_FORMAT_P030,
+		.hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,
+		.pixel_order = HVS_PIXEL_ORDER_XYCBCR,
+		.hvs5_only = true,
+	},
 };
 
 static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:313 @
 					       adjhdisplay,
 					       crtc_state->mode.hdisplay);
 	vc4_pstate->crtc_x += left;
-	if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - left)
-		vc4_pstate->crtc_x = crtc_state->mode.hdisplay - left;
+	if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - right)
+		vc4_pstate->crtc_x = crtc_state->mode.hdisplay - right;
 
 	adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
 	vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
 					       adjvdisplay,
 					       crtc_state->mode.vdisplay);
 	vc4_pstate->crtc_y += top;
-	if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - top)
-		vc4_pstate->crtc_y = crtc_state->mode.vdisplay - top;
+	if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - bottom)
+		vc4_pstate->crtc_y = crtc_state->mode.vdisplay - bottom;
 
 	vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
 					       adjhdisplay,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:342 @
 	struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 	struct drm_framebuffer *fb = state->fb;
 	struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-	u32 subpixel_src_mask = (1 << 16) - 1;
 	int num_planes = fb->format->num_planes;
 	struct drm_crtc_state *crtc_state;
 	u32 h_subsample = fb->format->hsub;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:363 @
 	for (i = 0; i < num_planes; i++)
 		vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
 
-	/* We don't support subpixel source positioning for scaling. */
-	if ((state->src.x1 & subpixel_src_mask) ||
-	    (state->src.x2 & subpixel_src_mask) ||
-	    (state->src.y1 & subpixel_src_mask) ||
-	    (state->src.y2 & subpixel_src_mask)) {
-		return -EINVAL;
-	}
-
-	vc4_state->src_x = state->src.x1 >> 16;
-	vc4_state->src_y = state->src.y1 >> 16;
-	vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
-	vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
+	/* We don't support subpixel source positioning for scaling,
+	 * but fractional coordinates can be generated by clipping
+	 * so just round for now
+	 */
+	vc4_state->src_x = DIV_ROUND_CLOSEST(state->src.x1, 1<<16);
+	vc4_state->src_y = DIV_ROUND_CLOSEST(state->src.y1, 1<<16);
+	vc4_state->src_w[0] = DIV_ROUND_CLOSEST(state->src.x2, 1<<16) - vc4_state->src_x;
+	vc4_state->src_h[0] = DIV_ROUND_CLOSEST(state->src.y2, 1<<16) - vc4_state->src_y;
 
 	vc4_state->crtc_x = state->dst.x1;
 	vc4_state->crtc_y = state->dst.y1;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:537 @
 	struct vc4_dev *vc4;
 
 	vc4 = to_vc4_dev(state->plane->dev);
-	if (!vc4->load_tracker_available)
-		return;
-
 	vc4_state = to_vc4_plane_state(state);
 	crtc_state = drm_atomic_get_existing_crtc_state(state->state,
 							state->crtc);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:623 @
 	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
+ * each supported colorspace.
+ */
+#define VC4_LIMITED_RANGE	0
+#define VC4_FULL_RANGE		1
+
+static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
+	{
+		/* Limited range */
+		{
+			/* BT601 */
+			SCALER_CSC0_ITR_R_601_5,
+			SCALER_CSC1_ITR_R_601_5,
+			SCALER_CSC2_ITR_R_601_5,
+		}, {
+			/* BT709 */
+			SCALER_CSC0_ITR_R_709_3,
+			SCALER_CSC1_ITR_R_709_3,
+			SCALER_CSC2_ITR_R_709_3,
+		}, {
+			/* BT2020 */
+			SCALER_CSC0_ITR_R_2020,
+			SCALER_CSC1_ITR_R_2020,
+			SCALER_CSC2_ITR_R_2020,
+		}
+	}, {
+		/* Full range */
+		{
+			/* JFIF */
+			SCALER_CSC0_JPEG_JFIF,
+			SCALER_CSC1_JPEG_JFIF,
+			SCALER_CSC2_JPEG_JFIF,
+		}, {
+			/* BT709 */
+			SCALER_CSC0_ITR_R_709_3_FR,
+			SCALER_CSC1_ITR_R_709_3_FR,
+			SCALER_CSC2_ITR_R_709_3_FR,
+		}, {
+			/* BT2020 */
+			SCALER_CSC0_ITR_R_2020_FR,
+			SCALER_CSC1_ITR_R_2020_FR,
+			SCALER_CSC2_ITR_R_2020_FR,
+		}
+	}
+};
+
 /* Writes out a full display list for an active plane to the plane's
  * private dlist state.
  */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:818 @
 		uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
 		u32 tile_w, tile, x_off, pix_per_tile;
 
-		hvs_format = HVS_PIXEL_FORMAT_H264;
+		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 = vc4_state->src_x % 96;
+			u32 aligned = remaining_pixels / 12;
+			u32 last_bits = remaining_pixels % 12;
 
-		switch (base_format_mod) {
-		case DRM_FORMAT_MOD_BROADCOM_SAND64:
-			tiling = SCALER_CTL0_TILING_64B;
-			tile_w = 64;
-			break;
-		case DRM_FORMAT_MOD_BROADCOM_SAND128:
+			x_off = aligned * 16 + last_bits;
+			hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
 			tiling = SCALER_CTL0_TILING_128B;
 			tile_w = 128;
-			break;
-		case DRM_FORMAT_MOD_BROADCOM_SAND256:
-			tiling = SCALER_CTL0_TILING_256B_OR_T;
-			tile_w = 256;
-			break;
-		default:
-			break;
-		}
+			pix_per_tile = 96;
+		} else {
+			hvs_format = HVS_PIXEL_FORMAT_H264;
 
+			switch (base_format_mod) {
+			case DRM_FORMAT_MOD_BROADCOM_SAND64:
+				tiling = SCALER_CTL0_TILING_64B;
+				tile_w = 64;
+				break;
+			case DRM_FORMAT_MOD_BROADCOM_SAND128:
+				tiling = SCALER_CTL0_TILING_128B;
+				tile_w = 128;
+				break;
+			case DRM_FORMAT_MOD_BROADCOM_SAND256:
+				tiling = SCALER_CTL0_TILING_256B_OR_T;
+				tile_w = 256;
+				break;
+			default:
+				break;
+			}
+			pix_per_tile = tile_w / fb->format->cpp[0];
+			x_off = (vc4_state->src_x % pix_per_tile) /
+				(i ? h_subsample : 1) * fb->format->cpp[i];
+		}
 		if (param > SCALER_TILE_HEIGHT_MASK) {
-			DRM_DEBUG_KMS("SAND height too large (%d)\n", param);
+			DRM_DEBUG_KMS("SAND height too large (%d)\n",
+				      param);
 			return -EINVAL;
 		}
-
-		pix_per_tile = tile_w / fb->format->cpp[0];
 		tile = vc4_state->src_x / pix_per_tile;
-		x_off = vc4_state->src_x % pix_per_tile;
-
 		/* 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++) {
 			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 ? h_subsample : 1) *
-						 fb->format->cpp[i];
+			vc4_state->offsets[i] += x_off & ~(i ? 1 : 0);
 		}
 
 		pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1031 @
 
 	/* Pitch word 1/2 */
 	for (i = 1; i < num_planes; i++) {
-		if (hvs_format != HVS_PIXEL_FORMAT_H264) {
+		if (hvs_format != HVS_PIXEL_FORMAT_H264 &&
+		    hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT) {
 			vc4_dlist_write(vc4_state,
 					VC4_SET_FIELD(fb->pitches[i],
 						      SCALER_SRC_PITCH));
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1043 @
 
 	/* Colorspace conversion words */
 	if (vc4_state->is_yuv) {
-		vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
-		vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
-		vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
+		enum drm_color_encoding color_encoding = state->color_encoding;
+		enum drm_color_range color_range = state->color_range;
+		const u32 *ccm;
+
+		if (color_encoding >= DRM_COLOR_ENCODING_MAX)
+			color_encoding = DRM_COLOR_YCBCR_BT601;
+		if (color_range >= DRM_COLOR_RANGE_MAX)
+			color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
+
+		ccm = colorspace_coeffs[color_range][color_encoding];
+
+		vc4_dlist_write(vc4_state, ccm[0]);
+		vc4_dlist_write(vc4_state, ccm[1]);
+		vc4_dlist_write(vc4_state, ccm[2]);
 	}
 
 	vc4_state->lbm_offset = 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1229 @
 	plane->state->src_y = state->src_y;
 	plane->state->src_w = state->src_w;
 	plane->state->src_h = state->src_h;
-	plane->state->src_h = state->src_h;
 	plane->state->alpha = state->alpha;
 	plane->state->pixel_blend_mode = state->pixel_blend_mode;
 	plane->state->rotation = state->rotation;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1365 @
 	.atomic_async_update = vc4_plane_atomic_async_update,
 };
 
-static void vc4_plane_destroy(struct drm_plane *plane)
-{
-	drm_plane_cleanup(plane);
-}
-
 static bool vc4_format_mod_supported(struct drm_plane *plane,
 				     uint32_t format,
 				     uint64_t modifier)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1397 @
 		default:
 			return false;
 		}
+	case DRM_FORMAT_P030:
+		switch (fourcc_mod_broadcom_mod(modifier)) {
+		case DRM_FORMAT_MOD_BROADCOM_SAND128:
+			return true;
+		default:
+			return false;
+		}
 	case DRM_FORMAT_RGBX1010102:
 	case DRM_FORMAT_BGRX1010102:
 	case DRM_FORMAT_RGBA1010102:
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1422 @
 static const struct drm_plane_funcs vc4_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = vc4_plane_destroy,
+	.destroy = drm_plane_cleanup,
 	.set_property = NULL,
 	.reset = vc4_plane_reset,
 	.atomic_duplicate_state = vc4_plane_duplicate_state,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1436 @
 	struct drm_plane *plane = NULL;
 	struct vc4_plane *vc4_plane;
 	u32 formats[ARRAY_SIZE(hvs_formats)];
+	int num_formats = 0;
 	int ret = 0;
 	unsigned i;
+	bool hvs5 = of_device_is_compatible(dev->dev->of_node,
+					    "brcm,bcm2711-vc5");
 	static const uint64_t modifiers[] = {
 		DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
 		DRM_FORMAT_MOD_BROADCOM_SAND128,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1455 @
 	if (!vc4_plane)
 		return ERR_PTR(-ENOMEM);
 
-	for (i = 0; i < ARRAY_SIZE(hvs_formats); i++)
-		formats[i] = hvs_formats[i].drm;
+	for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
+		if (!hvs_formats[i].hvs5_only || hvs5) {
+			formats[num_formats] = hvs_formats[i].drm;
+			num_formats++;
+		}
+	}
 
 	plane = &vc4_plane->base;
 	ret = drm_universal_plane_init(dev, plane, 0,
 				       &vc4_plane_funcs,
-				       formats, ARRAY_SIZE(formats),
+				       formats, num_formats,
 				       modifiers, type, NULL);
 	if (ret)
 		return ERR_PTR(ret);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1479 @
 					   DRM_MODE_REFLECT_X |
 					   DRM_MODE_REFLECT_Y);
 
+	drm_plane_create_color_properties(plane,
+					  BIT(DRM_COLOR_YCBCR_BT601) |
+					  BIT(DRM_COLOR_YCBCR_BT709) |
+					  BIT(DRM_COLOR_YCBCR_BT2020),
+					  BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+					  BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+					  DRM_COLOR_YCBCR_BT709,
+					  DRM_COLOR_YCBCR_LIMITED_RANGE);
+
 	return plane;
 }
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_regs.h linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_regs.h
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_regs.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_regs.h	2021-07-25 16:46:01.708362267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:519 @
 # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_MASK			VC4_MASK(7, 0)
 # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_SHIFT			0
 
+# define VC4_HDMI_MAI_FORMAT_AUDIO_FORMAT_MASK		VC4_MASK(23, 16)
+# define VC4_HDMI_MAI_FORMAT_AUDIO_FORMAT_SHIFT		16
+
+enum {
+	VC4_HDMI_MAI_FORMAT_PCM = 2,
+	VC4_HDMI_MAI_FORMAT_HBR = 200,
+};
+
+# define VC4_HDMI_MAI_FORMAT_SAMPLE_RATE_MASK		VC4_MASK(15, 8)
+# define VC4_HDMI_MAI_FORMAT_SAMPLE_RATE_SHIFT		8
+
+enum {
+	VC4_HDMI_MAI_SAMPLE_RATE_NOT_INDICATED = 0,
+	VC4_HDMI_MAI_SAMPLE_RATE_8000 = 1,
+	VC4_HDMI_MAI_SAMPLE_RATE_11025 = 2,
+	VC4_HDMI_MAI_SAMPLE_RATE_12000 = 3,
+	VC4_HDMI_MAI_SAMPLE_RATE_16000 = 4,
+	VC4_HDMI_MAI_SAMPLE_RATE_22050 = 5,
+	VC4_HDMI_MAI_SAMPLE_RATE_24000 = 6,
+	VC4_HDMI_MAI_SAMPLE_RATE_32000 = 7,
+	VC4_HDMI_MAI_SAMPLE_RATE_44100 = 8,
+	VC4_HDMI_MAI_SAMPLE_RATE_48000 = 9,
+	VC4_HDMI_MAI_SAMPLE_RATE_64000 = 10,
+	VC4_HDMI_MAI_SAMPLE_RATE_88200 = 11,
+	VC4_HDMI_MAI_SAMPLE_RATE_96000 = 12,
+	VC4_HDMI_MAI_SAMPLE_RATE_128000 = 13,
+	VC4_HDMI_MAI_SAMPLE_RATE_176400 = 14,
+	VC4_HDMI_MAI_SAMPLE_RATE_192000 = 15,
+};
+
 # define VC4_HDMI_RAM_PACKET_ENABLE		BIT(16)
 
 /* When set, the CTS_PERIOD counts based on MAI bus sync pulse instead
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:978 @
 #define SCALER_CSC0_COEF_CR_OFS_SHIFT		0
 #define SCALER_CSC0_ITR_R_601_5			0x00f00000
 #define SCALER_CSC0_ITR_R_709_3			0x00f00000
+#define SCALER_CSC0_ITR_R_2020			0x00f00000
 #define SCALER_CSC0_JPEG_JFIF			0x00000000
+#define SCALER_CSC0_ITR_R_709_3_FR		0x00000000
+#define SCALER_CSC0_ITR_R_2020_FR		0x00000000
 
 /* S2.8 contribution of Cb to Green */
 #define SCALER_CSC1_COEF_CB_GRN_MASK		VC4_MASK(31, 22)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:996 @
 #define SCALER_CSC1_COEF_CR_BLU_MASK		VC4_MASK(1, 0)
 #define SCALER_CSC1_COEF_CR_BLU_SHIFT		0
 #define SCALER_CSC1_ITR_R_601_5			0xe73304a8
-#define SCALER_CSC1_ITR_R_709_3			0xf2b784a8
-#define SCALER_CSC1_JPEG_JFIF			0xea34a400
+#define SCALER_CSC1_ITR_R_709_3			0xf27784a8
+#define SCALER_CSC1_ITR_R_2020			0xf43594a8
+#define SCALER_CSC1_JPEG_JFIF			0xea349400
+#define SCALER_CSC1_ITR_R_709_3_FR		0xf4388400
+#define SCALER_CSC1_ITR_R_2020_FR		0xf5b6d400
 
 /* S2.8 contribution of Cb to Red */
 #define SCALER_CSC2_COEF_CB_RED_MASK		VC4_MASK(29, 20)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1011 @
 /* S2.8 contribution of Cb to Blue */
 #define SCALER_CSC2_COEF_CB_BLU_MASK		VC4_MASK(19, 10)
 #define SCALER_CSC2_COEF_CB_BLU_SHIFT		10
-#define SCALER_CSC2_ITR_R_601_5			0x00066204
-#define SCALER_CSC2_ITR_R_709_3			0x00072a1c
-#define SCALER_CSC2_JPEG_JFIF			0x000599c5
+#define SCALER_CSC2_ITR_R_601_5			0x00066604
+#define SCALER_CSC2_ITR_R_709_3			0x00072e1d
+#define SCALER_CSC2_ITR_R_2020			0x0006b624
+#define SCALER_CSC2_JPEG_JFIF			0x00059dc6
+#define SCALER_CSC2_ITR_R_709_3_FR		0x00064ddb
+#define SCALER_CSC2_ITR_R_2020_FR		0x0005e5e2
 
 #define SCALER_TPZ0_VERT_RECALC			BIT(31)
 #define SCALER_TPZ0_SCALE_MASK			VC4_MASK(28, 8)
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_txp.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_txp.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_txp.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_txp.c	2021-07-25 16:46:01.708362267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:16 @
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_fb_cma_helper.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:276 @
 }
 
 static void vc4_txp_connector_atomic_commit(struct drm_connector *conn,
-					struct drm_connector_state *conn_state)
+					struct drm_atomic_state *state)
 {
+	struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state,
+										    conn);
 	struct vc4_txp *txp = connector_to_vc4_txp(conn);
 	struct drm_gem_cma_object *gem;
 	struct drm_display_mode *mode;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:385 @
 	.reset			= vc4_crtc_reset,
 	.atomic_duplicate_state	= vc4_crtc_duplicate_state,
 	.atomic_destroy_state	= vc4_crtc_destroy_state,
-	.gamma_set		= drm_atomic_helper_legacy_gamma_set,
 	.enable_vblank		= vc4_txp_enable_vblank,
 	.disable_vblank		= vc4_txp_disable_vblank,
 };
 
 static int vc4_txp_atomic_check(struct drm_crtc *crtc,
-				struct drm_crtc_state *state)
+				struct drm_atomic_state *state)
 {
-	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+	struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
 	int ret;
 
 	ret = vc4_hvs_atomic_check(crtc, state);
 	if (ret)
 		return ret;
 
-	state->no_vblank = true;
+	crtc_state->no_vblank = true;
 	vc4_state->feed_txp = true;
 
 	return 0;
 }
 
 static void vc4_txp_atomic_enable(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_state)
+				  struct drm_atomic_state *state)
 {
 	drm_crtc_vblank_on(crtc);
-	vc4_hvs_atomic_enable(crtc, old_state);
+	vc4_hvs_atomic_enable(crtc, state);
 }
 
 static void vc4_txp_atomic_disable(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_state)
+				   struct drm_atomic_state *state)
 {
 	struct drm_device *dev = crtc->dev;
 
 	/* Disable vblank irq handling before crtc is disabled. */
 	drm_crtc_vblank_off(crtc);
 
-	vc4_hvs_atomic_disable(crtc, old_state);
+	vc4_hvs_atomic_disable(crtc, state);
 
 	/*
 	 * Make sure we issue a vblank event after disabling the CRTC if
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_vec.c linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_vec.c
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc4_vec.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc4_vec.c	2021-07-25 16:46:01.708362267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:48 @
 #define VEC_CONFIG0_YDEL(x)		((x) << 26)
 #define VEC_CONFIG0_CDEL_MASK		GENMASK(25, 24)
 #define VEC_CONFIG0_CDEL(x)		((x) << 24)
+#define VEC_CONFIG0_SECAM_STD		BIT(21)
 #define VEC_CONFIG0_PBPR_FIL		BIT(18)
 #define VEC_CONFIG0_CHROMA_GAIN_MASK	GENMASK(17, 16)
 #define VEC_CONFIG0_CHROMA_GAIN_UNITY	(0 << 16)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:69 @
 #define VEC_CONFIG0_YCDELAY		BIT(4)
 #define VEC_CONFIG0_RAMPEN		BIT(2)
 #define VEC_CONFIG0_YCDIS		BIT(2)
-#define VEC_CONFIG0_STD_MASK		GENMASK(1, 0)
+#define VEC_CONFIG0_STD_MASK		(VEC_CONFIG0_SECAM_STD | GENMASK(1, 0))
 #define VEC_CONFIG0_NTSC_STD		0
 #define VEC_CONFIG0_PAL_BDGHI_STD	1
+#define VEC_CONFIG0_PAL_M_STD		2
 #define VEC_CONFIG0_PAL_N_STD		3
 
 #define VEC_SCHPH			0x108
 #define VEC_SOFT_RESET			0x10c
 #define VEC_CLMP0_START			0x144
 #define VEC_CLMP0_END			0x148
+
+/*
+ * These set the color subcarrier frequency
+ * if VEC_CONFIG1_CUSTOM_FREQ is enabled.
+ *
+ * VEC_FREQ1_0 contains the most significant 16-bit half-word,
+ * VEC_FREQ3_2 contains the least significant 16-bit half-word.
+ * 0x80000000 seems to be equivalent to the pixel clock
+ * (which itself is the VEC clock divided by 8).
+ *
+ * Reference values (with the default pixel clock of 13.5 MHz):
+ *
+ * NTSC  (3579545.[45] Hz)     - 0x21F07C1F
+ * PAL   (4433618.75 Hz)       - 0x2A098ACB
+ * PAL-M (3575611.[888111] Hz) - 0x21E6EFE3
+ * PAL-N (3582056.25 Hz)       - 0x21F69446
+ *
+ * NOTE: For SECAM, it is used as the Dr center frequency,
+ * regardless of whether VEC_CONFIG1_CUSTOM_FREQ is enabled or not;
+ * that is specified as 4406250 Hz, which corresponds to 0x29C71C72.
+ */
 #define VEC_FREQ3_2			0x180
 #define VEC_FREQ1_0			0x184
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:142 @
 
 #define VEC_INTERRUPT_CONTROL		0x190
 #define VEC_INTERRUPT_STATUS		0x194
+
+/*
+ * Db center frequency for SECAM; the clock for this is the same as for
+ * VEC_FREQ3_2/VEC_FREQ1_0, which is used for Dr center frequency.
+ *
+ * This is specified as 4250000 Hz, which corresponds to 0x284BDA13.
+ * That is also the default value, so no need to set it explicitly.
+ */
 #define VEC_FCW_SECAM_B			0x198
 #define VEC_SECAM_GAIN_VAL		0x19c
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:188 @
 #define VEC_DAC_MISC_DAC_RST_N		BIT(0)
 
 
+static char *vc4_vec_tv_norm;
+
+struct vc4_vec_variant {
+	u32 dac_config;
+};
+
 /* General VEC hardware state. */
 struct vc4_vec {
 	struct platform_device *pdev;
+	const struct vc4_vec_variant *variant;
 
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:206 @
 
 	struct clk *clock;
 
-	const struct vc4_vec_tv_mode *tv_mode;
-
 	struct debugfs_regset32 regset;
 };
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:245 @
 enum vc4_vec_tv_mode_id {
 	VC4_VEC_TV_MODE_NTSC,
 	VC4_VEC_TV_MODE_NTSC_J,
+	VC4_VEC_TV_MODE_NTSC_443,
 	VC4_VEC_TV_MODE_PAL,
 	VC4_VEC_TV_MODE_PAL_M,
+	VC4_VEC_TV_MODE_PAL_N,
+	VC4_VEC_TV_MODE_PAL60,
+	VC4_VEC_TV_MODE_SECAM,
 };
 
 struct vc4_vec_tv_mode {
 	const struct drm_display_mode *mode;
-	void (*mode_set)(struct vc4_vec *vec);
+	u32 config0;
+	u32 config1;
+	u32 custom_freq;
 };
 
 static const struct debugfs_reg32 vec_regs[] = {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:287 @
 	VC4_REG32(VEC_DAC_MISC),
 };
 
-static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
-{
-	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
-	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
-}
-
-static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
-{
-	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
-	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
-}
-
-static const struct drm_display_mode ntsc_mode = {
+static const struct drm_display_mode drm_mode_480i = {
 	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
 		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
-		 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
+		 480, 480 + 7, 480 + 7 + 6, 525, 0,
 		 DRM_MODE_FLAG_INTERLACE)
 };
 
-static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
-{
-	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
-	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
-}
-
-static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
-{
-	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
-	VEC_WRITE(VEC_CONFIG1,
-		  VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
-	VEC_WRITE(VEC_FREQ3_2, 0x223b);
-	VEC_WRITE(VEC_FREQ1_0, 0x61d1);
-}
-
-static const struct drm_display_mode pal_mode = {
+static const struct drm_display_mode drm_mode_576i = {
 	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
 		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
-		 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
+		 576, 576 + 4, 576 + 4 + 6, 625, 0,
 		 DRM_MODE_FLAG_INTERLACE)
 };
 
 static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
 	[VC4_VEC_TV_MODE_NTSC] = {
-		.mode = &ntsc_mode,
-		.mode_set = vc4_vec_ntsc_mode_set,
+		.mode = &drm_mode_480i,
+		.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 	[VC4_VEC_TV_MODE_NTSC_J] = {
-		.mode = &ntsc_mode,
-		.mode_set = vc4_vec_ntsc_j_mode_set,
+		.mode = &drm_mode_480i,
+		.config0 = VEC_CONFIG0_NTSC_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
+	},
+	[VC4_VEC_TV_MODE_NTSC_443] = {
+		/* NTSC with PAL chroma frequency */
+		.mode = &drm_mode_480i,
+		.config0 = VEC_CONFIG0_NTSC_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
+		.custom_freq = 0x2a098acb,
 	},
 	[VC4_VEC_TV_MODE_PAL] = {
-		.mode = &pal_mode,
-		.mode_set = vc4_vec_pal_mode_set,
+		.mode = &drm_mode_576i,
+		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 	[VC4_VEC_TV_MODE_PAL_M] = {
-		.mode = &pal_mode,
-		.mode_set = vc4_vec_pal_m_mode_set,
+		.mode = &drm_mode_480i,
+		.config0 = VEC_CONFIG0_PAL_M_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
+	},
+	[VC4_VEC_TV_MODE_PAL_N] = {
+		.mode = &drm_mode_576i,
+		.config0 = VEC_CONFIG0_PAL_N_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
+	},
+	[VC4_VEC_TV_MODE_PAL60] = {
+		/* PAL-M with chroma frequency of regular PAL */
+		.mode = &drm_mode_480i,
+		.config0 = VEC_CONFIG0_PAL_M_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
+		.custom_freq = 0x2a098acb,
+	},
+	[VC4_VEC_TV_MODE_SECAM] = {
+		.mode = &drm_mode_576i,
+		.config0 = VEC_CONFIG0_SECAM_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
+		.custom_freq = 0x29c71c72,
 	},
 };
 
+static const char * const tv_mode_names[] = {
+	[VC4_VEC_TV_MODE_NTSC] = "NTSC",
+	[VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
+	[VC4_VEC_TV_MODE_NTSC_443] = "NTSC-443",
+	[VC4_VEC_TV_MODE_PAL] = "PAL",
+	[VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
+	[VC4_VEC_TV_MODE_PAL_N] = "PAL-N",
+	[VC4_VEC_TV_MODE_PAL60] = "PAL60",
+	[VC4_VEC_TV_MODE_SECAM] = "SECAM",
+};
+
+enum vc4_vec_tv_mode_id
+vc4_vec_get_default_mode(struct drm_connector *connector)
+{
+	int i;
+
+	if (vc4_vec_tv_norm) {
+		for (i = 0; i < ARRAY_SIZE(tv_mode_names); i++)
+			if (strcmp(vc4_vec_tv_norm, tv_mode_names[i]) == 0)
+				return (enum vc4_vec_tv_mode_id) i;
+	} else if (connector->cmdline_mode.specified &&
+		   ((connector->cmdline_mode.refresh_specified &&
+		     (connector->cmdline_mode.refresh == 25 ||
+		      connector->cmdline_mode.refresh == 50)) ||
+		    (!connector->cmdline_mode.refresh_specified &&
+		     (connector->cmdline_mode.yres == 288 ||
+		      connector->cmdline_mode.yres == 576)))) {
+		/*
+		 * no explicitly specified TV norm; use PAL if a mode that
+		 * looks like PAL has been specified on the command line
+		 */
+		return VC4_VEC_TV_MODE_PAL;
+	}
+
+	/* in all other cases, default to NTSC */
+	return VC4_VEC_TV_MODE_NTSC;
+}
+
 static enum drm_connector_status
 vc4_vec_connector_detect(struct drm_connector *connector, bool force)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:416 @
 	return 1;
 }
 
+static void vc4_vec_connector_reset(struct drm_connector *connector)
+{
+	drm_atomic_helper_connector_reset(connector);
+	/* preserve TV standard */
+	if (connector->state)
+		connector->state->tv.mode = vc4_vec_get_default_mode(connector);
+}
+
+static int vc4_vec_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);
+
+	const struct vc4_vec_tv_mode *vec_mode =
+		&vc4_vec_tv_modes[new_state->tv.mode];
+
+	if (new_state->crtc) {
+		struct drm_crtc_state *crtc_state =
+			drm_atomic_get_new_crtc_state(state, new_state->crtc);
+
+		if (!drm_mode_equal(vec_mode->mode, &crtc_state->mode))
+			return -EINVAL;
+
+		if (old_state->tv.mode != new_state->tv.mode)
+			crtc_state->mode_changed = true;
+	}
+
+	return 0;
+}
+
 static const struct drm_connector_funcs vc4_vec_connector_funcs = {
 	.detect = vc4_vec_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.destroy = vc4_vec_connector_destroy,
-	.reset = drm_atomic_helper_connector_reset,
+	.reset = vc4_vec_connector_reset,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
 	.get_modes = vc4_vec_connector_get_modes,
+	.atomic_check = vc4_vec_connector_atomic_check,
 };
 
 static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:486 @
 
 	drm_object_attach_property(&connector->base,
 				   dev->mode_config.tv_mode_property,
-				   VC4_VEC_TV_MODE_NTSC);
-	vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
+				   vc4_vec_get_default_mode(connector));
 
 	drm_connector_attach_encoder(connector, vec->encoder);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:519 @
 {
 	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
 	struct vc4_vec *vec = vc4_vec_encoder->vec;
+	unsigned int tv_mode = vec->connector->state->tv.mode;
 	int ret;
 
 	ret = pm_runtime_get_sync(&vec->pdev->dev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:570 @
 	VEC_WRITE(VEC_CONFIG2,
 		  VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
 	VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
-	VEC_WRITE(VEC_DAC_CONFIG,
-		  VEC_DAC_CONFIG_DAC_CTRL(0xc) |
-		  VEC_DAC_CONFIG_DRIVER_CTRL(0xc) |
-		  VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46));
+	VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);
 
 	/* Mask all interrupts. */
 	VEC_WRITE(VEC_MASK0, 0);
 
-	vec->tv_mode->mode_set(vec);
+	VEC_WRITE(VEC_CONFIG0, vc4_vec_tv_modes[tv_mode].config0);
+	VEC_WRITE(VEC_CONFIG1, vc4_vec_tv_modes[tv_mode].config1);
+	if (vc4_vec_tv_modes[tv_mode].custom_freq != 0) {
+		VEC_WRITE(VEC_FREQ3_2,
+			  (vc4_vec_tv_modes[tv_mode].custom_freq >> 16) &
+			  0xffff);
+		VEC_WRITE(VEC_FREQ1_0,
+			  vc4_vec_tv_modes[tv_mode].custom_freq & 0xffff);
+	}
 
 	VEC_WRITE(VEC_DAC_MISC,
 		  VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:598 @
 	return true;
 }
 
-static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
-					struct drm_crtc_state *crtc_state,
-					struct drm_connector_state *conn_state)
-{
-	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
-	struct vc4_vec *vec = vc4_vec_encoder->vec;
-
-	vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
-}
-
-static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
-					struct drm_crtc_state *crtc_state,
-					struct drm_connector_state *conn_state)
-{
-	const struct vc4_vec_tv_mode *vec_mode;
-
-	vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
-
-	if (conn_state->crtc &&
-	    !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
-		return -EINVAL;
-
-	return 0;
-}
-
 static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
 	.disable = vc4_vec_encoder_disable,
 	.enable = vc4_vec_encoder_enable,
 	.mode_fixup = vc4_vec_encoder_mode_fixup,
-	.atomic_check = vc4_vec_encoder_atomic_check,
-	.atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
 };
 
-static const struct of_device_id vc4_vec_dt_match[] = {
-	{ .compatible = "brcm,bcm2835-vec", .data = NULL },
-	{ /* sentinel */ },
+static const struct vc4_vec_variant bcm2835_vec_variant = {
+	.dac_config = VEC_DAC_CONFIG_DAC_CTRL(0xc) |
+		      VEC_DAC_CONFIG_DRIVER_CTRL(0xc) |
+		      VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46)
 };
 
-static const char * const tv_mode_names[] = {
-	[VC4_VEC_TV_MODE_NTSC] = "NTSC",
-	[VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
-	[VC4_VEC_TV_MODE_PAL] = "PAL",
-	[VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
+static const struct vc4_vec_variant bcm2711_vec_variant = {
+	.dac_config = VEC_DAC_CONFIG_DAC_CTRL(0x0) |
+		      VEC_DAC_CONFIG_DRIVER_CTRL(0x80) |
+		      VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x61)
+};
+
+static const struct of_device_id vc4_vec_dt_match[] = {
+	{ .compatible = "brcm,bcm2835-vec", .data = &bcm2835_vec_variant },
+	{ .compatible = "brcm,bcm2711-vec", .data = &bcm2711_vec_variant },
+	{ /* sentinel */ },
 };
 
 static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:649 @
 	vec->encoder = &vc4_vec_encoder->base.base;
 
 	vec->pdev = pdev;
+	vec->variant = (const struct vc4_vec_variant *)
+		of_device_get_match_data(dev);
 	vec->regs = vc4_ioremap_regs(pdev, 0);
 	if (IS_ERR(vec->regs))
 		return PTR_ERR(vec->regs);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:730 @
 		.of_match_table = vc4_vec_dt_match,
 	},
 };
+
+module_param_named(tv_norm, vc4_vec_tv_norm, 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, SECAM.\n"
+		 "\t\tDefault: PAL if a 50 Hz mode has been set via video=,\n"
+		 "\t\t\tNTSC otherwise");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vc4/vc_image_types.h linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc_image_types.h
--- linux-5.10.52-orig/drivers/gpu/drm/vc4/vc_image_types.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vc4/vc_image_types.h	2021-07-25 16:46:01.708362267 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+
+/*
+ * Copyright (c) 2012, Broadcom Europe Ltd
+ *
+ * Values taken from vc_image_types.h released by Broadcom at
+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
+ * and vc_image_structs.h at
+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_structs.h
+ *
+ * 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.
+ */
+
+enum {
+	VC_IMAGE_MIN = 0, //bounds for error checking
+
+	VC_IMAGE_RGB565 = 1,
+	VC_IMAGE_1BPP,
+	VC_IMAGE_YUV420,
+	VC_IMAGE_48BPP,
+	VC_IMAGE_RGB888,
+	VC_IMAGE_8BPP,
+	/* 4bpp palettised image */
+	VC_IMAGE_4BPP,
+	/* A separated format of 16 colour/light shorts followed by 16 z
+	 * values
+	 */
+	VC_IMAGE_3D32,
+	/* 16 colours followed by 16 z values */
+	VC_IMAGE_3D32B,
+	/* A separated format of 16 material/colour/light shorts followed by
+	 * 16 z values
+	 */
+	VC_IMAGE_3D32MAT,
+	/* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
+	VC_IMAGE_RGB2X9,
+	/* 32-bit format holding 18 bits of 6.6.6 RGB */
+	VC_IMAGE_RGB666,
+	/* 4bpp palettised image with embedded palette */
+	VC_IMAGE_PAL4_OBSOLETE,
+	/* 8bpp palettised image with embedded palette */
+	VC_IMAGE_PAL8_OBSOLETE,
+	/* RGB888 with an alpha byte after each pixel */
+	VC_IMAGE_RGBA32,
+	/* a line of Y (32-byte padded), a line of U (16-byte padded), and a
+	 * line of V (16-byte padded)
+	 */
+	VC_IMAGE_YUV422,
+	/* RGB565 with a transparent patch */
+	VC_IMAGE_RGBA565,
+	/* Compressed (4444) version of RGBA32 */
+	VC_IMAGE_RGBA16,
+	/* VCIII codec format */
+	VC_IMAGE_YUV_UV,
+	/* VCIII T-format RGBA8888 */
+	VC_IMAGE_TF_RGBA32,
+	/* VCIII T-format RGBx8888 */
+	VC_IMAGE_TF_RGBX32,
+	/* VCIII T-format float */
+	VC_IMAGE_TF_FLOAT,
+	/* VCIII T-format RGBA4444 */
+	VC_IMAGE_TF_RGBA16,
+	/* VCIII T-format RGB5551 */
+	VC_IMAGE_TF_RGBA5551,
+	/* VCIII T-format RGB565 */
+	VC_IMAGE_TF_RGB565,
+	/* VCIII T-format 8-bit luma and 8-bit alpha */
+	VC_IMAGE_TF_YA88,
+	/* VCIII T-format 8 bit generic sample */
+	VC_IMAGE_TF_BYTE,
+	/* VCIII T-format 8-bit palette */
+	VC_IMAGE_TF_PAL8,
+	/* VCIII T-format 4-bit palette */
+	VC_IMAGE_TF_PAL4,
+	/* VCIII T-format Ericsson Texture Compressed */
+	VC_IMAGE_TF_ETC1,
+	/* RGB888 with R & B swapped */
+	VC_IMAGE_BGR888,
+	/* RGB888 with R & B swapped, but with no pitch, i.e. no padding after
+	 * each row of pixels
+	 */
+	VC_IMAGE_BGR888_NP,
+	/* Bayer image, extra defines which variant is being used */
+	VC_IMAGE_BAYER,
+	/* General wrapper for codec images e.g. JPEG from camera */
+	VC_IMAGE_CODEC,
+	/* VCIII codec format */
+	VC_IMAGE_YUV_UV32,
+	/* VCIII T-format 8-bit luma */
+	VC_IMAGE_TF_Y8,
+	/* VCIII T-format 8-bit alpha */
+	VC_IMAGE_TF_A8,
+	/* VCIII T-format 16-bit generic sample */
+	VC_IMAGE_TF_SHORT,
+	/* VCIII T-format 1bpp black/white */
+	VC_IMAGE_TF_1BPP,
+	VC_IMAGE_OPENGL,
+	/* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
+	VC_IMAGE_YUV444I,
+	/* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on
+	 * a per line basis)
+	 */
+	VC_IMAGE_YUV422PLANAR,
+	/* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */
+	VC_IMAGE_ARGB8888,
+	/* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */
+	VC_IMAGE_XRGB8888,
+
+	/* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */
+	VC_IMAGE_YUV422YUYV,
+	VC_IMAGE_YUV422YVYU,
+	VC_IMAGE_YUV422UYVY,
+	VC_IMAGE_YUV422VYUY,
+
+	/* 32bpp like RGBA32 but with unused alpha */
+	VC_IMAGE_RGBX32,
+	/* 32bpp, corresponding to RGBA with unused alpha */
+	VC_IMAGE_RGBX8888,
+	/* 32bpp, corresponding to BGRA with unused alpha */
+	VC_IMAGE_BGRX8888,
+
+	/* Y as a plane, then UV byte interleaved in plane with same pitch,
+	 * half height
+	 */
+	VC_IMAGE_YUV420SP,
+
+	/* Y, U, & V planes separately 4:4:4 */
+	VC_IMAGE_YUV444PLANAR,
+
+	/* T-format 8-bit U - same as TF_Y8 buf from U plane */
+	VC_IMAGE_TF_U8,
+	/* T-format 8-bit U - same as TF_Y8 buf from V plane */
+	VC_IMAGE_TF_V8,
+
+	/* YUV4:2:0 planar, 16bit values */
+	VC_IMAGE_YUV420_16,
+	/* YUV4:2:0 codec format, 16bit values */
+	VC_IMAGE_YUV_UV_16,
+	/* YUV4:2:0 with U,V in side-by-side format */
+	VC_IMAGE_YUV420_S,
+	/* 10-bit YUV 420 column image format */
+	VC_IMAGE_YUV10COL,
+	/* 32-bpp, 10-bit R/G/B, 2-bit Alpha */
+	VC_IMAGE_RGBA1010102,
+
+	VC_IMAGE_MAX,     /* bounds for error checking */
+	VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
+};
+
+enum {
+	/* Unknown or unset - defaults to BT601 interstitial */
+	VC_IMAGE_YUVINFO_UNSPECIFIED    = 0,
+
+	/* colour-space conversions data [4 bits] */
+
+	/* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */
+	VC_IMAGE_YUVINFO_CSC_ITUR_BT601      = 1,
+	/* ITU-R BT.709-3 [HDTV] */
+	VC_IMAGE_YUVINFO_CSC_ITUR_BT709      = 2,
+	/* JPEG JFIF */
+	VC_IMAGE_YUVINFO_CSC_JPEG_JFIF       = 3,
+	/* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
+	VC_IMAGE_YUVINFO_CSC_FCC             = 4,
+	/* Society of Motion Picture and Television Engineers 240M (1999) */
+	VC_IMAGE_YUVINFO_CSC_SMPTE_240M      = 5,
+	/* ITU-R BT.470-2 System M */
+	VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M  = 6,
+	/* ITU-R BT.470-2 System B,G */
+	VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7,
+	/* JPEG JFIF, but with 16..255 luma */
+	VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8,
+	/* Rec 2020 */
+	VC_IMAGE_YUVINFO_CSC_REC_2020        = 9,
+};
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/virtio/virtgpu_display.c linux-5.10.52-v7l+/drivers/gpu/drm/virtio/virtgpu_display.c
--- linux-5.10.52-orig/drivers/gpu/drm/virtio/virtgpu_display.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/virtio/virtgpu_display.c	2021-07-25 16:46:01.718362100 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:98 @
 }
 
 static void virtio_gpu_crtc_atomic_enable(struct drm_crtc *crtc,
-					  struct drm_crtc_state *old_state)
+					  struct drm_atomic_state *state)
 {
 }
 
 static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc,
-					   struct drm_crtc_state *old_state)
+					   struct drm_atomic_state *state)
 {
 	struct drm_device *dev = crtc->dev;
 	struct virtio_gpu_device *vgdev = dev->dev_private;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:114 @
 }
 
 static int virtio_gpu_crtc_atomic_check(struct drm_crtc *crtc,
-					struct drm_crtc_state *state)
+					struct drm_atomic_state *state)
 {
 	return 0;
 }
 
 static void virtio_gpu_crtc_atomic_flush(struct drm_crtc *crtc,
-					 struct drm_crtc_state *old_state)
+					 struct drm_atomic_state *state)
 {
 	struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vkms/vkms_crtc.c linux-5.10.52-v7l+/drivers/gpu/drm/vkms/vkms_crtc.c
--- linux-5.10.52-orig/drivers/gpu/drm/vkms/vkms_crtc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vkms/vkms_crtc.c	2021-07-25 16:46:01.718362100 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:172 @
 };
 
 static int vkms_crtc_atomic_check(struct drm_crtc *crtc,
-				  struct drm_crtc_state *state)
+				  struct drm_atomic_state *state)
 {
-	struct vkms_crtc_state *vkms_state = to_vkms_crtc_state(state);
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+	struct vkms_crtc_state *vkms_state = to_vkms_crtc_state(crtc_state);
 	struct drm_plane *plane;
 	struct drm_plane_state *plane_state;
 	int i = 0, ret;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:184 @
 	if (vkms_state->active_planes)
 		return 0;
 
-	ret = drm_atomic_add_affected_planes(state->state, crtc);
+	ret = drm_atomic_add_affected_planes(crtc_state->state, crtc);
 	if (ret < 0)
 		return ret;
 
-	drm_for_each_plane_mask(plane, crtc->dev, state->plane_mask) {
-		plane_state = drm_atomic_get_existing_plane_state(state->state,
+	drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) {
+		plane_state = drm_atomic_get_existing_plane_state(crtc_state->state,
 								  plane);
 		WARN_ON(!plane_state);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:205 @
 	vkms_state->num_active_planes = i;
 
 	i = 0;
-	drm_for_each_plane_mask(plane, crtc->dev, state->plane_mask) {
-		plane_state = drm_atomic_get_existing_plane_state(state->state,
+	drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) {
+		plane_state = drm_atomic_get_existing_plane_state(crtc_state->state,
 								  plane);
 
 		if (!plane_state->visible)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:220 @
 }
 
 static void vkms_crtc_atomic_enable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
+				    struct drm_atomic_state *state)
 {
 	drm_crtc_vblank_on(crtc);
 }
 
 static void vkms_crtc_atomic_disable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
+				     struct drm_atomic_state *state)
 {
 	drm_crtc_vblank_off(crtc);
 }
 
 static void vkms_crtc_atomic_begin(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:243 @
 }
 
 static void vkms_crtc_atomic_flush(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
+				   struct drm_atomic_state *state)
 {
 	struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc);
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vkms/vkms_writeback.c linux-5.10.52-v7l+/drivers/gpu/drm/vkms/vkms_writeback.c
--- linux-5.10.52-orig/drivers/gpu/drm/vkms/vkms_writeback.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vkms/vkms_writeback.c	2021-07-25 16:46:01.718362100 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
 // SPDX-License-Identifier: GPL-2.0+
 
 #include "vkms_drv.h"
+
+#include <drm/drm_atomic.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_writeback.h>
 #include <drm/drm_probe_helper.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:105 @
 }
 
 static void vkms_wb_atomic_commit(struct drm_connector *conn,
-				  struct drm_connector_state *state)
+				  struct drm_atomic_state *state)
 {
+	struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state,
+											 conn);
 	struct vkms_device *vkmsdev = drm_device_to_vkms_device(conn->dev);
 	struct vkms_output *output = &vkmsdev->output;
 	struct drm_writeback_connector *wb_conn = &output->wb_connector;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:124 @
 	crtc_state->active_writeback = conn_state->writeback_job->priv;
 	crtc_state->wb_pending = true;
 	spin_unlock_irq(&output->composer_lock);
-	drm_writeback_queue_job(wb_conn, state);
+	drm_writeback_queue_job(wb_conn, connector_state);
 }
 
 static const struct drm_connector_helper_funcs vkms_wb_conn_helper_funcs = {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
--- linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c	2021-07-25 16:46:01.748361597 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:525 @
 
 
 int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
-			     struct drm_crtc_state *new_state)
+			     struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state,
+									 crtc);
 	struct vmw_display_unit *du = vmw_crtc_to_du(new_state->crtc);
 	int connector_mask = drm_connector_mask(&du->connector);
 	bool has_primary = new_state->plane_mask &
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:557 @
 
 
 void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
-			      struct drm_crtc_state *old_crtc_state)
+			      struct drm_atomic_state *state)
 {
 }
 
 
 void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
-			      struct drm_crtc_state *old_crtc_state)
+			      struct drm_atomic_state *state)
 {
 	struct drm_pending_vblank_event *event = crtc->state->event;
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
--- linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h	2021-07-25 16:46:01.748361597 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:476 @
 			     bool unreference);
 
 int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
-			     struct drm_crtc_state *state);
+			     struct drm_atomic_state *state);
 void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
-			      struct drm_crtc_state *old_crtc_state);
+			      struct drm_atomic_state *state);
 void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
-			      struct drm_crtc_state *old_crtc_state);
+			      struct drm_atomic_state *state);
 void vmw_du_crtc_reset(struct drm_crtc *crtc);
 struct drm_crtc_state *vmw_du_crtc_duplicate_state(struct drm_crtc *crtc);
 void vmw_du_crtc_destroy_state(struct drm_crtc *crtc,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
--- linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c	2021-07-25 16:46:01.748361597 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:217 @
  * CRTC, it makes more sense to do those at plane update time.
  */
 static void vmw_ldu_crtc_atomic_enable(struct drm_crtc *crtc,
-				       struct drm_crtc_state *old_state)
+				       struct drm_atomic_state *state)
 {
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:227 @
  * @crtc: CRTC to be turned off
  */
 static void vmw_ldu_crtc_atomic_disable(struct drm_crtc *crtc,
-					struct drm_crtc_state *old_state)
+					struct drm_atomic_state *state)
 {
 }
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
--- linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c	2021-07-25 16:46:01.748361597 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:282 @
  * This is called after a mode set has been completed.
  */
 static void vmw_sou_crtc_atomic_enable(struct drm_crtc *crtc,
-				       struct drm_crtc_state *old_state)
+				       struct drm_atomic_state *state)
 {
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:292 @
  * @crtc: CRTC to be turned off
  */
 static void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc,
-					struct drm_crtc_state *old_state)
+					struct drm_atomic_state *state)
 {
 	struct vmw_private *dev_priv;
 	struct vmw_screen_object_unit *sou;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
--- linux-5.10.52-orig/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c	2021-07-25 16:46:01.758361429 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:411 @
 }
 
 static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc,
-					struct drm_crtc_state *old_state)
+					struct drm_atomic_state *state)
 {
 }
 
 static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc,
-					 struct drm_crtc_state *old_state)
+					 struct drm_atomic_state *state)
 {
 	struct vmw_private *dev_priv;
 	struct vmw_screen_target_display_unit *stdu;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/xlnx/zynqmp_disp.c linux-5.10.52-v7l+/drivers/gpu/drm/xlnx/zynqmp_disp.c
--- linux-5.10.52-orig/drivers/gpu/drm/xlnx/zynqmp_disp.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/xlnx/zynqmp_disp.c	2021-07-25 16:46:01.758361429 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1444 @
 
 static void
 zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc,
-			       struct drm_crtc_state *old_crtc_state)
+			       struct drm_atomic_state *state)
 {
 	struct zynqmp_disp *disp = crtc_to_disp(crtc);
 	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1475 @
 
 static void
 zynqmp_disp_crtc_atomic_disable(struct drm_crtc *crtc,
-				struct drm_crtc_state *old_crtc_state)
+				struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
+									      crtc);
 	struct zynqmp_disp *disp = crtc_to_disp(crtc);
 	struct drm_plane_state *old_plane_state;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1508 @
 }
 
 static int zynqmp_disp_crtc_atomic_check(struct drm_crtc *crtc,
-					 struct drm_crtc_state *state)
+					 struct drm_atomic_state *state)
 {
-	return drm_atomic_add_affected_planes(state->state, crtc);
+	return drm_atomic_add_affected_planes(state, crtc);
 }
 
 static void
 zynqmp_disp_crtc_atomic_begin(struct drm_crtc *crtc,
-			      struct drm_crtc_state *old_crtc_state)
+			      struct drm_atomic_state *state)
 {
 	drm_crtc_vblank_on(crtc);
 }
 
 static void
 zynqmp_disp_crtc_atomic_flush(struct drm_crtc *crtc,
-			      struct drm_crtc_state *old_crtc_state)
+			      struct drm_atomic_state *state)
 {
 	if (crtc->state->event) {
 		struct drm_pending_vblank_event *event;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/gpu/drm/zte/zx_vou.c linux-5.10.52-v7l+/drivers/gpu/drm/zte/zx_vou.c
--- linux-5.10.52-orig/drivers/gpu/drm/zte/zx_vou.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/gpu/drm/zte/zx_vou.c	2021-07-25 16:46:01.768361261 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:353 @
 }
 
 static void zx_crtc_atomic_enable(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_state)
+				  struct drm_atomic_state *state)
 {
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
 	bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:458 @
 }
 
 static void zx_crtc_atomic_disable(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_state)
+				   struct drm_atomic_state *state)
 {
 	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
 	const struct zx_crtc_bits *bits = zcrtc->bits;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:476 @
 }
 
 static void zx_crtc_atomic_flush(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_state)
+				  struct drm_atomic_state *state)
 {
 	struct drm_pending_vblank_event *event = crtc->state->event;
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/hid/hid-ids.h linux-5.10.52-v7l+/drivers/hid/hid-ids.h
--- linux-5.10.52-orig/drivers/hid/hid-ids.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/hid/hid-ids.h	2021-07-25 16:46:01.808360591 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:224 @
 #define USB_VENDOR_ID_BAANTO		0x2453
 #define USB_DEVICE_ID_BAANTO_MT_190W2	0x0100
 
+#define USB_VENDOR_ID_BEKEN		0x25a7
+#define USB_DEVICE_ID_AIRMOUSE_T3	0x2402
+
 #define USB_VENDOR_ID_BELKIN		0x050d
 #define USB_DEVICE_ID_FLIP_KVM		0x3201
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1274 @
 #define USB_VENDOR_ID_XAT	0x2505
 #define USB_DEVICE_ID_XAT_CSR	0x0220
 
+#define USB_VENDOR_ID_XENTA			0x1d57
+#define USB_DEVICE_ID_AIRMOUSE_MX3		0xad03
+
 #define USB_VENDOR_ID_XIN_MO			0x16c0
 #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE	0x05e1
 #define USB_DEVICE_ID_THT_2P_ARCADE		0x75e1
diff -Nur --no-dereference linux-5.10.52-orig/drivers/hid/hid-quirks.c linux-5.10.52-v7l+/drivers/hid/hid-quirks.c
--- linux-5.10.52-orig/drivers/hid/hid-quirks.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/hid/hid-quirks.c	2021-07-25 16:46:01.818360423 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:44 @
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_BEKEN, USB_DEVICE_ID_AIRMOUSE_T3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:197 @
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_GROUP_AUDIO), HID_QUIRK_NOGET },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_XENTA, USB_DEVICE_ID_AIRMOUSE_MX3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
 
 	{ 0 }
 };
diff -Nur --no-dereference linux-5.10.52-orig/drivers/hid/usbhid/hid-core.c linux-5.10.52-v7l+/drivers/hid/usbhid/hid-core.c
--- linux-5.10.52-orig/drivers/hid/usbhid/hid-core.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/hid/usbhid/hid-core.c	2021-07-25 16:46:01.848359920 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:48 @
  * Module parameters.
  */
 
-static unsigned int hid_mousepoll_interval;
+static unsigned int hid_mousepoll_interval = ~0;
 module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
 MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1117 @
 		 */
 		switch (hid->collection->usage) {
 		case HID_GD_MOUSE:
-			if (hid_mousepoll_interval > 0)
+			if (hid_mousepoll_interval == ~0 && interval < 16)
+				interval = 16;
+			else if (hid_mousepoll_interval != ~0 && hid_mousepoll_interval != 0)
 				interval = hid_mousepoll_interval;
 			break;
 		case HID_GD_JOYSTICK:
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1131 @
 				interval = hid_kbpoll_interval;
 			break;
 		}
+		usb_fixup_endpoint(dev, endpoint->bEndpointAddress, interval);
 
 		ret = -ENOMEM;
 		if (usb_endpoint_dir_in(endpoint)) {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/hwmon/Kconfig linux-5.10.52-v7l+/drivers/hwmon/Kconfig
--- linux-5.10.52-orig/drivers/hwmon/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/hwmon/Kconfig	2021-07-25 16:46:01.868359585 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1492 @
 	  This driver can also be built as a module. If so, the module
 	  will be called raspberrypi-hwmon.
 
+config SENSORS_RPI_POE_FAN
+	tristate "Raspberry Pi PoE HAT fan"
+	depends on RASPBERRYPI_FIRMWARE
+	depends on THERMAL || THERMAL=n
+	help
+	  If you say yes here you get support for Raspberry Pi PoE (Power over
+	  Ethernet) HAT fan.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called rpi-poe-fan.
+
 config SENSORS_SL28CPLD
 	tristate "Kontron sl28cpld hardware monitoring driver"
 	depends on MFD_SL28CPLD || COMPILE_TEST
diff -Nur --no-dereference linux-5.10.52-orig/drivers/hwmon/Makefile linux-5.10.52-v7l+/drivers/hwmon/Makefile
--- linux-5.10.52-orig/drivers/hwmon/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/hwmon/Makefile	2021-07-25 16:46:01.868359585 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:160 @
 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_RPI_POE_FAN)	+= rpi-poe-fan.o
 obj-$(CONFIG_SENSORS_S3C)	+= s3c-hwmon.o
 obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
 obj-$(CONFIG_SENSORS_SCH5627)	+= sch5627.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/hwmon/raspberrypi-hwmon.c linux-5.10.52-v7l+/drivers/hwmon/raspberrypi-hwmon.c
--- linux-5.10.52-orig/drivers/hwmon/raspberrypi-hwmon.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/hwmon/raspberrypi-hwmon.c	2021-07-25 16:46:02.028356902 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:18 @
 #include <linux/workqueue.h>
 #include <soc/bcm2835/raspberrypi-firmware.h>
 
+/*
+ * This section defines some rate limited logging that prevent
+ * repeated messages at much lower Hz than the default kernel settings.
+ * It's usually 5s, this is 5 minutes.
+ * Burst 3 means you may get three messages 'quickly', before
+ * the ratelimiting kicks in.
+ */
+#define LOCAL_RATELIMIT_INTERVAL (5 * 60 * HZ)
+#define LOCAL_RATELIMIT_BURST 3
+
+#ifdef CONFIG_PRINTK
+#define printk_ratelimited_local(fmt, ...)	\
+({						\
+	static DEFINE_RATELIMIT_STATE(_rs,	\
+		LOCAL_RATELIMIT_INTERVAL,	\
+		LOCAL_RATELIMIT_BURST);		\
+						\
+	if (__ratelimit(&_rs))			\
+		printk(fmt, ##__VA_ARGS__);	\
+})
+#else
+#define printk_ratelimited_local(fmt, ...)	\
+	no_printk(fmt, ##__VA_ARGS__)
+#endif
+
+#define pr_crit_ratelimited_local(fmt, ...)              \
+	printk_ratelimited_local(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_info_ratelimited_local(fmt, ...)              \
+printk_ratelimited_local(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+
 #define UNDERVOLTAGE_STICKY_BIT	BIT(16)
 
 struct rpi_hwmon_data {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:80 @
 	if (new_uv == old_uv)
 		return;
 
-	if (new_uv)
-		dev_crit(data->hwmon_dev, "Undervoltage detected!\n");
-	else
-		dev_info(data->hwmon_dev, "Voltage normalised\n");
+	if (new_uv) {
+		pr_crit_ratelimited_local("Under-voltage detected! (0x%08x)\n",
+					  value);
+	} else {
+		pr_info_ratelimited_local("Voltage normalised (0x%08x)\n",
+					  value);
+	}
 
 	sysfs_notify(&data->hwmon_dev->kobj, NULL, "in0_lcrit_alarm");
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/hwmon/rpi-poe-fan.c linux-5.10.52-v7l+/drivers/hwmon/rpi-poe-fan.c
--- linux-5.10.52-orig/drivers/hwmon/rpi-poe-fan.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/hwmon/rpi-poe-fan.c	2021-07-25 16:46:02.028356902 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rpi-poe-fan.c - Hwmon driver for Raspberry Pi PoE HAT fan.
+ *
+ * Copyright (C) 2018 Raspberry Pi (Trading) Ltd.
+ * Based on pwm-fan.c by Kamil Debski <k.debski@samsung.com>
+ *
+ * Author: Serge Schneider <serge@raspberrypi.org>
+ */
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/sysfs.h>
+#include <linux/thermal.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define MAX_PWM 255
+
+#define POE_CUR_PWM 0x0
+#define POE_DEF_PWM 0x1
+
+struct rpi_poe_fan_ctx {
+	struct mutex lock;
+	struct rpi_firmware *fw;
+	u32 set_tag;
+	unsigned int pwm_value;
+	unsigned int def_pwm_value;
+	unsigned int rpi_poe_fan_state;
+	unsigned int rpi_poe_fan_max_state;
+	unsigned int *rpi_poe_fan_cooling_levels;
+	struct thermal_cooling_device *cdev;
+	struct notifier_block nb;
+};
+
+struct fw_tag_data_s{
+	u32 reg;
+	u32 val;
+	u32 ret;
+};
+
+static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val, u32 set_tag)
+{
+	struct fw_tag_data_s fw_tag_data = {
+		.reg = reg,
+		.val = *val
+	};
+	int ret;
+
+	ret = rpi_firmware_property(fw, set_tag,
+				    &fw_tag_data, sizeof(fw_tag_data));
+	if (ret) {
+		return ret;
+	} else if (fw_tag_data.ret) {
+		return -EIO;
+	}
+	return 0;
+}
+
+static int read_reg(struct rpi_firmware *fw, u32 reg, u32 *val){
+	struct fw_tag_data_s fw_tag_data = {
+		.reg = reg,
+	};
+	int ret;
+	ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_POE_HAT_VAL,
+				    &fw_tag_data, sizeof(fw_tag_data));
+	if (ret) {
+		return ret;
+	} else if (fw_tag_data.ret) {
+		return -EIO;
+	}
+	*val = fw_tag_data.val;
+	return 0;
+}
+
+static int rpi_poe_reboot(struct notifier_block *nb, unsigned long code,
+			  void *unused)
+{
+	struct rpi_poe_fan_ctx *ctx = container_of(nb, struct rpi_poe_fan_ctx,
+						   nb);
+
+	if (ctx->pwm_value != ctx->def_pwm_value)
+		write_reg(ctx->fw, POE_CUR_PWM, &ctx->def_pwm_value, ctx->set_tag);
+
+	return NOTIFY_DONE;
+}
+
+static int  __set_pwm(struct rpi_poe_fan_ctx *ctx, u32 pwm)
+{
+	int ret = 0;
+
+	mutex_lock(&ctx->lock);
+	if (ctx->pwm_value == pwm)
+		goto exit_set_pwm_err;
+
+	ret = write_reg(ctx->fw, POE_CUR_PWM, &pwm, ctx->set_tag);
+	if (!ret)
+		ctx->pwm_value = pwm;
+exit_set_pwm_err:
+	mutex_unlock(&ctx->lock);
+	return ret;
+}
+
+static int  __set_def_pwm(struct rpi_poe_fan_ctx *ctx, u32 def_pwm)
+{
+	int ret = 0;
+	mutex_lock(&ctx->lock);
+	if (ctx->def_pwm_value == def_pwm)
+		goto exit_set_def_pwm_err;
+
+	ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm, ctx->set_tag);
+	if (!ret)
+		ctx->def_pwm_value = def_pwm;
+exit_set_def_pwm_err:
+	mutex_unlock(&ctx->lock);
+	return ret;
+}
+
+static void rpi_poe_fan_update_state(struct rpi_poe_fan_ctx *ctx,
+				     unsigned long pwm)
+{
+	int i;
+
+	for (i = 0; i < ctx->rpi_poe_fan_max_state; ++i)
+		if (pwm < ctx->rpi_poe_fan_cooling_levels[i + 1])
+			break;
+
+	ctx->rpi_poe_fan_state = i;
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+	unsigned long pwm;
+	int ret;
+
+	if (kstrtoul(buf, 10, &pwm) || pwm > MAX_PWM)
+		return -EINVAL;
+
+	ret = __set_pwm(ctx, pwm);
+	if (ret)
+		return ret;
+
+	rpi_poe_fan_update_state(ctx, pwm);
+	return count;
+}
+
+static ssize_t set_def_pwm(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+	unsigned long def_pwm;
+	int ret;
+
+	if (kstrtoul(buf, 10, &def_pwm) || def_pwm > MAX_PWM)
+		return -EINVAL;
+
+	ret = __set_def_pwm(ctx, def_pwm);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ctx->pwm_value);
+}
+
+static ssize_t show_def_pwm(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ctx->def_pwm_value);
+}
+
+
+static SENSOR_DEVICE_ATTR(pwm1, 0644, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(def_pwm1, 0644, show_def_pwm, set_def_pwm, 1);
+
+static struct attribute *rpi_poe_fan_attrs[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_def_pwm1.dev_attr.attr,
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(rpi_poe_fan);
+
+/* thermal cooling device callbacks */
+static int rpi_poe_fan_get_max_state(struct thermal_cooling_device *cdev,
+				     unsigned long *state)
+{
+	struct rpi_poe_fan_ctx *ctx = cdev->devdata;
+
+	if (!ctx)
+		return -EINVAL;
+
+	*state = ctx->rpi_poe_fan_max_state;
+
+	return 0;
+}
+
+static int rpi_poe_fan_get_cur_state(struct thermal_cooling_device *cdev,
+				     unsigned long *state)
+{
+	struct rpi_poe_fan_ctx *ctx = cdev->devdata;
+
+	if (!ctx)
+		return -EINVAL;
+
+	*state = ctx->rpi_poe_fan_state;
+
+	return 0;
+}
+
+static int rpi_poe_fan_set_cur_state(struct thermal_cooling_device *cdev,
+				     unsigned long state)
+{
+	struct rpi_poe_fan_ctx *ctx = cdev->devdata;
+	int ret;
+
+	if (!ctx || (state > ctx->rpi_poe_fan_max_state))
+		return -EINVAL;
+
+	if (state == ctx->rpi_poe_fan_state)
+		return 0;
+
+	ret = __set_pwm(ctx, ctx->rpi_poe_fan_cooling_levels[state]);
+	if (ret) {
+		dev_err(&cdev->device, "Cannot set pwm!\n");
+		return ret;
+	}
+
+	ctx->rpi_poe_fan_state = state;
+
+	return ret;
+}
+
+static const struct thermal_cooling_device_ops rpi_poe_fan_cooling_ops = {
+	.get_max_state = rpi_poe_fan_get_max_state,
+	.get_cur_state = rpi_poe_fan_get_cur_state,
+	.set_cur_state = rpi_poe_fan_set_cur_state,
+};
+
+static int rpi_poe_fan_of_get_cooling_data(struct device *dev,
+				       struct rpi_poe_fan_ctx *ctx)
+{
+	struct device_node *np = dev->of_node;
+	int num, i, ret;
+
+	if (!of_find_property(np, "cooling-levels", NULL))
+		return 0;
+
+	ret = of_property_count_u32_elems(np, "cooling-levels");
+	if (ret <= 0) {
+		dev_err(dev, "cooling-levels property missing or invalid: %d\n",
+			ret);
+		return ret ? : -EINVAL;
+	}
+
+	num = ret;
+	ctx->rpi_poe_fan_cooling_levels = devm_kzalloc(dev, num * sizeof(u32),
+						   GFP_KERNEL);
+	if (!ctx->rpi_poe_fan_cooling_levels)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(np, "cooling-levels",
+					 ctx->rpi_poe_fan_cooling_levels, num);
+	if (ret) {
+		dev_err(dev, "Property 'cooling-levels' cannot be read!\n");
+		return ret;
+	}
+
+	for (i = 0; i < num; i++) {
+		if (ctx->rpi_poe_fan_cooling_levels[i] > MAX_PWM) {
+			dev_err(dev, "PWM fan state[%d]:%d > %d\n", i,
+				ctx->rpi_poe_fan_cooling_levels[i], MAX_PWM);
+			return -EINVAL;
+		}
+	}
+
+	ctx->rpi_poe_fan_max_state = num - 1;
+
+	return 0;
+}
+
+static int rpi_poe_fan_probe(struct platform_device *pdev)
+{
+	struct thermal_cooling_device *cdev;
+	struct rpi_poe_fan_ctx *ctx;
+	struct device *hwmon;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *fw_node;
+	u32 revision;
+	int ret;
+
+	fw_node = of_parse_phandle(np, "firmware", 0);
+	if (!fw_node) {
+		dev_err(&pdev->dev, "Missing firmware node\n");
+		return -ENOENT;
+	}
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	mutex_init(&ctx->lock);
+
+	ctx->fw = rpi_firmware_get(fw_node);
+	if (!ctx->fw)
+		return -EPROBE_DEFER;
+	ret = rpi_firmware_property(ctx->fw,
+		RPI_FIRMWARE_GET_FIRMWARE_REVISION,
+		&revision, sizeof(revision));
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to get firmware revision: %i\n", ret);
+		return ret;
+	}
+	if (revision < 0x60af72e8)
+		ctx->set_tag = RPI_FIRMWARE_SET_POE_HAT_VAL_OLD;
+	else
+		ctx->set_tag = RPI_FIRMWARE_SET_POE_HAT_VAL;
+
+	platform_set_drvdata(pdev, ctx);
+
+	ctx->nb.notifier_call = rpi_poe_reboot;
+	ret = register_reboot_notifier(&ctx->nb);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register reboot notifier: %i\n",
+			ret);
+		return ret;
+	}
+	ret = read_reg(ctx->fw, POE_DEF_PWM, &ctx->def_pwm_value);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to get default PWM value: %i\n",
+			ret);
+		goto err;
+	}
+	ret = read_reg(ctx->fw, POE_CUR_PWM, &ctx->pwm_value);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to get current PWM value: %i\n",
+			ret);
+		goto err;
+	}
+
+	hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "rpipoefan",
+						       ctx, rpi_poe_fan_groups);
+	if (IS_ERR(hwmon)) {
+		dev_err(&pdev->dev, "Failed to register hwmon device\n");
+		ret = PTR_ERR(hwmon);
+		goto err;
+	}
+
+	ret = rpi_poe_fan_of_get_cooling_data(&pdev->dev, ctx);
+	if (ret)
+		return ret;
+
+	rpi_poe_fan_update_state(ctx, ctx->pwm_value);
+	if (!IS_ENABLED(CONFIG_THERMAL))
+		return 0;
+
+	cdev = thermal_of_cooling_device_register(np,
+						  "rpi-poe-fan", ctx,
+						  &rpi_poe_fan_cooling_ops);
+	if (IS_ERR(cdev)) {
+		dev_err(&pdev->dev,
+			"Failed to register rpi-poe-fan as cooling device");
+		ret = PTR_ERR(cdev);
+		goto err;
+	}
+	ctx->cdev = cdev;
+	thermal_cdev_update(cdev);
+
+	return 0;
+err:
+	unregister_reboot_notifier(&ctx->nb);
+	return ret;
+}
+
+static int rpi_poe_fan_remove(struct platform_device *pdev)
+{
+	struct rpi_poe_fan_ctx *ctx = platform_get_drvdata(pdev);
+	u32 value = ctx->def_pwm_value;
+
+	unregister_reboot_notifier(&ctx->nb);
+	thermal_cooling_device_unregister(ctx->cdev);
+	if (ctx->pwm_value != value)
+		write_reg(ctx->fw, POE_CUR_PWM, &value, ctx->set_tag);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rpi_poe_fan_suspend(struct device *dev)
+{
+	struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+	u32 value = 0;
+	int ret = 0;
+
+	if (ctx->pwm_value != value)
+		ret = write_reg(ctx->fw, POE_CUR_PWM, &value, ctx->set_tag);
+	return ret;
+}
+
+static int rpi_poe_fan_resume(struct device *dev)
+{
+	struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+	u32 value = ctx->pwm_value;
+	int ret = 0;
+
+	if (value != 0)
+		ret = write_reg(ctx->fw, POE_CUR_PWM, &value, ctx->set_tag);
+
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rpi_poe_fan_pm, rpi_poe_fan_suspend,
+			 rpi_poe_fan_resume);
+
+static const struct of_device_id of_rpi_poe_fan_match[] = {
+	{ .compatible = "raspberrypi,rpi-poe-fan", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_rpi_poe_fan_match);
+
+static struct platform_driver rpi_poe_fan_driver = {
+	.probe		= rpi_poe_fan_probe,
+	.remove		= rpi_poe_fan_remove,
+	.driver	= {
+		.name		= "rpi-poe-fan",
+		.pm		= &rpi_poe_fan_pm,
+		.of_match_table	= of_rpi_poe_fan_match,
+	},
+};
+
+module_platform_driver(rpi_poe_fan_driver);
+
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
+MODULE_ALIAS("platform:rpi-poe-fan");
+MODULE_DESCRIPTION("Raspberry Pi PoE HAT fan driver");
+MODULE_LICENSE("GPL");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/i2c/busses/i2c-bcm2708.c linux-5.10.52-v7l+/drivers/i2c/busses/i2c-bcm2708.c
--- linux-5.10.52-orig/drivers/i2c/busses/i2c-bcm2708.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/i2c/busses/i2c-bcm2708.c	2021-07-25 16:46:02.118355394 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Driver for Broadcom BCM2708 BSC Controllers
+ *
+ * Copyright (C) 2012 Chris Boot & Frank Buss
+ *
+ * This driver is inspired by:
+ * i2c-ocores.c, by Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+/* BSC register offsets */
+#define BSC_C			0x00
+#define BSC_S			0x04
+#define BSC_DLEN		0x08
+#define BSC_A			0x0c
+#define BSC_FIFO		0x10
+#define BSC_DIV			0x14
+#define BSC_DEL			0x18
+#define BSC_CLKT		0x1c
+
+/* Bitfields in BSC_C */
+#define BSC_C_I2CEN		0x00008000
+#define BSC_C_INTR		0x00000400
+#define BSC_C_INTT		0x00000200
+#define BSC_C_INTD		0x00000100
+#define BSC_C_ST		0x00000080
+#define BSC_C_CLEAR_1		0x00000020
+#define BSC_C_CLEAR_2		0x00000010
+#define BSC_C_READ		0x00000001
+
+/* Bitfields in BSC_S */
+#define BSC_S_CLKT		0x00000200
+#define BSC_S_ERR		0x00000100
+#define BSC_S_RXF		0x00000080
+#define BSC_S_TXE		0x00000040
+#define BSC_S_RXD		0x00000020
+#define BSC_S_TXD		0x00000010
+#define BSC_S_RXR		0x00000008
+#define BSC_S_TXW		0x00000004
+#define BSC_S_DONE		0x00000002
+#define BSC_S_TA		0x00000001
+
+#define I2C_WAIT_LOOP_COUNT	200
+
+#define DRV_NAME		"bcm2708_i2c"
+
+static unsigned int baudrate;
+module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+MODULE_PARM_DESC(baudrate, "The I2C baudrate");
+
+static bool combined = false;
+module_param(combined, bool, 0644);
+MODULE_PARM_DESC(combined, "Use combined transactions");
+
+struct bcm2708_i2c {
+	struct i2c_adapter adapter;
+
+	spinlock_t lock;
+	void __iomem *base;
+	int irq;
+	struct clk *clk;
+	u32 cdiv;
+	u32 clk_tout;
+
+	struct completion done;
+
+	struct i2c_msg *msg;
+	int pos;
+	int nmsgs;
+	bool error;
+};
+
+static inline u32 bcm2708_rd(struct bcm2708_i2c *bi, unsigned reg)
+{
+	return readl(bi->base + reg);
+}
+
+static inline void bcm2708_wr(struct bcm2708_i2c *bi, unsigned reg, u32 val)
+{
+	writel(val, bi->base + reg);
+}
+
+static inline void bcm2708_bsc_reset(struct bcm2708_i2c *bi)
+{
+	bcm2708_wr(bi, BSC_C, 0);
+	bcm2708_wr(bi, BSC_S, BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
+}
+
+static inline void bcm2708_bsc_fifo_drain(struct bcm2708_i2c *bi)
+{
+	while ((bi->pos < bi->msg->len) && (bcm2708_rd(bi, BSC_S) & BSC_S_RXD))
+		bi->msg->buf[bi->pos++] = bcm2708_rd(bi, BSC_FIFO);
+}
+
+static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi)
+{
+	while ((bi->pos < bi->msg->len) && (bcm2708_rd(bi, BSC_S) & BSC_S_TXD))
+		bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
+}
+
+static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi)
+{
+	u32 cdiv, s, clk_tout;
+	u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
+	int wait_loops = I2C_WAIT_LOOP_COUNT;
+
+	/* Can't call clk_get_rate as it locks a mutex and here we are spinlocked.
+	 * Use the value that we cached in the probe.
+	 */
+	cdiv = bi->cdiv;
+	clk_tout = bi->clk_tout;
+
+	if (bi->msg->flags & I2C_M_RD)
+		c |= BSC_C_INTR | BSC_C_READ;
+	else
+		c |= BSC_C_INTT;
+
+	bcm2708_wr(bi, BSC_CLKT, clk_tout);
+	bcm2708_wr(bi, BSC_DIV, cdiv);
+	bcm2708_wr(bi, BSC_A, bi->msg->addr);
+	bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
+	if (combined)
+	{
+		/* Do the next two messages meet combined transaction criteria?
+		   - Current message is a write, next message is a read
+		   - Both messages to same slave address
+		   - Write message can fit inside FIFO (16 bytes or less) */
+		if ( (bi->nmsgs > 1) &&
+			!(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) &&
+			 (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) {
+
+			/* Clear FIFO */
+			bcm2708_wr(bi, BSC_C, BSC_C_CLEAR_1);
+
+			/* Fill FIFO with entire write message (16 byte FIFO) */
+			while (bi->pos < bi->msg->len) {
+				bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
+			}
+			/* Start write transfer (no interrupts, don't clear FIFO) */
+			bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST);
+
+			/* poll for transfer start bit (should only take 1-20 polls) */
+			do {
+				s = bcm2708_rd(bi, BSC_S);
+			} while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE)) && --wait_loops >= 0);
+
+			/* did we time out or some error occured? */
+			if (wait_loops < 0 || (s & (BSC_S_ERR | BSC_S_CLKT))) {
+				return -1;
+			}
+
+			/* Send next read message before the write transfer finishes. */
+			bi->nmsgs--;
+			bi->msg++;
+			bi->pos = 0;
+			bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
+			c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ;
+		}
+	}
+	bcm2708_wr(bi, BSC_C, c);
+
+	return 0;
+}
+
+static irqreturn_t bcm2708_i2c_interrupt(int irq, void *dev_id)
+{
+	struct bcm2708_i2c *bi = dev_id;
+	bool handled = true;
+	u32 s;
+	int ret;
+
+	spin_lock(&bi->lock);
+
+	/* we may see camera interrupts on the "other" I2C channel
+		   Just return if we've not sent anything */
+	if (!bi->nmsgs || !bi->msg) {
+		goto early_exit;
+	}
+
+	s = bcm2708_rd(bi, BSC_S);
+
+	if (s & (BSC_S_CLKT | BSC_S_ERR)) {
+		bcm2708_bsc_reset(bi);
+		bi->error = true;
+
+		bi->msg = 0; /* to inform the that all work is done */
+		bi->nmsgs = 0;
+		/* wake up our bh */
+		complete(&bi->done);
+	} else if (s & BSC_S_DONE) {
+		bi->nmsgs--;
+
+		if (bi->msg->flags & I2C_M_RD) {
+			bcm2708_bsc_fifo_drain(bi);
+		}
+
+		bcm2708_bsc_reset(bi);
+
+		if (bi->nmsgs) {
+			/* advance to next message */
+			bi->msg++;
+			bi->pos = 0;
+			ret = bcm2708_bsc_setup(bi);
+			if (ret < 0) {
+				bcm2708_bsc_reset(bi);
+				bi->error = true;
+				bi->msg = 0; /* to inform the that all work is done */
+				bi->nmsgs = 0;
+				/* wake up our bh */
+				complete(&bi->done);
+				goto early_exit;
+			}
+		} else {
+			bi->msg = 0; /* to inform the that all work is done */
+			bi->nmsgs = 0;
+			/* wake up our bh */
+			complete(&bi->done);
+		}
+	} else if (s & BSC_S_TXW) {
+		bcm2708_bsc_fifo_fill(bi);
+	} else if (s & BSC_S_RXR) {
+		bcm2708_bsc_fifo_drain(bi);
+	} else {
+		handled = false;
+	}
+
+early_exit:
+	spin_unlock(&bi->lock);
+
+	return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int bcm2708_i2c_master_xfer(struct i2c_adapter *adap,
+	struct i2c_msg *msgs, int num)
+{
+	struct bcm2708_i2c *bi = adap->algo_data;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&bi->lock, flags);
+
+	reinit_completion(&bi->done);
+	bi->msg = msgs;
+	bi->pos = 0;
+	bi->nmsgs = num;
+	bi->error = false;
+
+	ret = bcm2708_bsc_setup(bi);
+
+	spin_unlock_irqrestore(&bi->lock, flags);
+
+	/* check the result of the setup */
+	if (ret < 0)
+	{
+		dev_err(&adap->dev, "transfer setup timed out\n");
+		goto error_timeout;
+	}
+
+	ret = wait_for_completion_timeout(&bi->done, adap->timeout);
+	if (ret == 0) {
+		dev_err(&adap->dev, "transfer timed out\n");
+		goto error_timeout;
+	}
+
+	ret = bi->error ? -EIO : num;
+	return ret;
+
+error_timeout:
+	spin_lock_irqsave(&bi->lock, flags);
+	bcm2708_bsc_reset(bi);
+	bi->msg = 0; /* to inform the interrupt handler that there's nothing else to be done */
+	bi->nmsgs = 0;
+	spin_unlock_irqrestore(&bi->lock, flags);
+	return -ETIMEDOUT;
+}
+
+static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | /*I2C_FUNC_10BIT_ADDR |*/ I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm bcm2708_i2c_algorithm = {
+	.master_xfer = bcm2708_i2c_master_xfer,
+	.functionality = bcm2708_i2c_functionality,
+};
+
+static int bcm2708_i2c_probe(struct platform_device *pdev)
+{
+	struct resource *regs;
+	int irq, err = -ENOMEM;
+	struct clk *clk;
+	struct bcm2708_i2c *bi;
+	struct i2c_adapter *adap;
+	unsigned long bus_hz;
+	u32 cdiv, clk_tout;
+	u32 baud;
+
+	baud = CONFIG_I2C_BCM2708_BAUDRATE;
+
+	if (pdev->dev.of_node) {
+		u32 bus_clk_rate;
+		pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
+		if (pdev->id < 0) {
+			dev_err(&pdev->dev, "alias is missing\n");
+			return -EINVAL;
+		}
+		if (!of_property_read_u32(pdev->dev.of_node,
+					"clock-frequency", &bus_clk_rate))
+			baud = bus_clk_rate;
+		else
+			dev_warn(&pdev->dev,
+				"Could not read clock-frequency property\n");
+	}
+
+	if (baudrate)
+		baud = baudrate;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		dev_err(&pdev->dev, "could not get IO memory\n");
+		return -ENXIO;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "could not get IRQ\n");
+		return irq;
+	}
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
+		return PTR_ERR(clk);
+	}
+
+	err = clk_prepare_enable(clk);
+	if (err) {
+		dev_err(&pdev->dev, "could not enable clk: %d\n", err);
+		goto out_clk_put;
+	}
+
+	bi = kzalloc(sizeof(*bi), GFP_KERNEL);
+	if (!bi)
+		goto out_clk_disable;
+
+	platform_set_drvdata(pdev, bi);
+
+	adap = &bi->adapter;
+	adap->class = I2C_CLASS_HWMON | I2C_CLASS_DDC;
+	adap->algo = &bcm2708_i2c_algorithm;
+	adap->algo_data = bi;
+	adap->dev.parent = &pdev->dev;
+	adap->nr = pdev->id;
+	strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
+	adap->dev.of_node = pdev->dev.of_node;
+
+	switch (pdev->id) {
+	case 0:
+		adap->class = I2C_CLASS_HWMON;
+		break;
+	case 1:
+		adap->class = I2C_CLASS_DDC;
+		break;
+	case 2:
+		adap->class = I2C_CLASS_DDC;
+		break;
+	default:
+		dev_err(&pdev->dev, "can only bind to BSC 0, 1 or 2\n");
+		err = -ENXIO;
+		goto out_free_bi;
+	}
+
+	spin_lock_init(&bi->lock);
+	init_completion(&bi->done);
+
+	bi->base = ioremap(regs->start, resource_size(regs));
+	if (!bi->base) {
+		dev_err(&pdev->dev, "could not remap memory\n");
+		goto out_free_bi;
+	}
+
+	bi->irq = irq;
+	bi->clk = clk;
+
+	err = request_irq(irq, bcm2708_i2c_interrupt, IRQF_SHARED,
+			dev_name(&pdev->dev), bi);
+	if (err) {
+		dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
+		goto out_iounmap;
+	}
+
+	bcm2708_bsc_reset(bi);
+
+	err = i2c_add_numbered_adapter(adap);
+	if (err < 0) {
+		dev_err(&pdev->dev, "could not add I2C adapter: %d\n", err);
+		goto out_free_irq;
+	}
+
+	bus_hz = clk_get_rate(bi->clk);
+	cdiv = bus_hz / baud;
+	if (cdiv > 0xffff) {
+		cdiv = 0xffff;
+		baud = bus_hz / cdiv;
+	}
+
+	clk_tout = 35/1000*baud; //35ms timeout as per SMBus specs.
+	if (clk_tout > 0xffff)
+		clk_tout = 0xffff;
+	
+	bi->cdiv = cdiv;
+	bi->clk_tout = clk_tout;
+
+	dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
+		pdev->id, (unsigned long)regs->start, irq, baud);
+
+	return 0;
+
+out_free_irq:
+	free_irq(bi->irq, bi);
+out_iounmap:
+	iounmap(bi->base);
+out_free_bi:
+	kfree(bi);
+out_clk_disable:
+	clk_disable_unprepare(clk);
+out_clk_put:
+	clk_put(clk);
+	return err;
+}
+
+static int bcm2708_i2c_remove(struct platform_device *pdev)
+{
+	struct bcm2708_i2c *bi = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	i2c_del_adapter(&bi->adapter);
+	free_irq(bi->irq, bi);
+	iounmap(bi->base);
+	clk_disable_unprepare(bi->clk);
+	clk_put(bi->clk);
+	kfree(bi);
+
+	return 0;
+}
+
+static const struct of_device_id bcm2708_i2c_of_match[] = {
+        { .compatible = "brcm,bcm2708-i2c" },
+        {},
+};
+MODULE_DEVICE_TABLE(of, bcm2708_i2c_of_match);
+
+static struct platform_driver bcm2708_i2c_driver = {
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = bcm2708_i2c_of_match,
+	},
+	.probe		= bcm2708_i2c_probe,
+	.remove		= bcm2708_i2c_remove,
+};
+
+// module_platform_driver(bcm2708_i2c_driver);
+
+
+static int __init bcm2708_i2c_init(void)
+{
+	return platform_driver_register(&bcm2708_i2c_driver);
+}
+
+static void __exit bcm2708_i2c_exit(void)
+{
+	platform_driver_unregister(&bcm2708_i2c_driver);
+}
+
+module_init(bcm2708_i2c_init);
+module_exit(bcm2708_i2c_exit);
+
+
+
+MODULE_DESCRIPTION("BSC controller driver for Broadcom BCM2708");
+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/i2c/busses/i2c-bcm2835.c linux-5.10.52-v7l+/drivers/i2c/busses/i2c-bcm2835.c
--- linux-5.10.52-orig/drivers/i2c/busses/i2c-bcm2835.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/i2c/busses/i2c-bcm2835.c	2021-07-25 16:46:02.118355394 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:54 @
 #define BCM2835_I2C_CDIV_MIN	0x0002
 #define BCM2835_I2C_CDIV_MAX	0xFFFE
 
+static unsigned int debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "1=err, 2=isr, 3=xfer");
+
+#define BCM2835_DEBUG_MAX	512
+struct bcm2835_debug {
+	struct i2c_msg *msg;
+	int msg_idx;
+	size_t remain;
+	u32 status;
+};
+
 struct bcm2835_i2c_dev {
 	struct device *dev;
 	void __iomem *regs;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:78 @
 	u32 msg_err;
 	u8 *msg_buf;
 	size_t msg_buf_remaining;
+	struct bcm2835_debug debug[BCM2835_DEBUG_MAX];
+	unsigned int debug_num;
+	unsigned int debug_num_msgs;
 };
 
+static inline void bcm2835_debug_add(struct bcm2835_i2c_dev *i2c_dev, u32 s)
+{
+	if (!i2c_dev->debug_num_msgs || i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
+		return;
+
+	i2c_dev->debug[i2c_dev->debug_num].msg = i2c_dev->curr_msg;
+	i2c_dev->debug[i2c_dev->debug_num].msg_idx =
+				i2c_dev->debug_num_msgs - i2c_dev->num_msgs;
+	i2c_dev->debug[i2c_dev->debug_num].remain = i2c_dev->msg_buf_remaining;
+	i2c_dev->debug[i2c_dev->debug_num].status = s;
+	i2c_dev->debug_num++;
+}
+
+static void bcm2835_debug_print_status(struct bcm2835_i2c_dev *i2c_dev,
+				       struct bcm2835_debug *d)
+{
+	u32 s = d->status;
+
+	pr_info("isr: remain=%zu, status=0x%x : %s%s%s%s%s%s%s%s%s%s [i2c%d]\n",
+		d->remain, s,
+		s & BCM2835_I2C_S_TA ? "TA " : "",
+		s & BCM2835_I2C_S_DONE ? "DONE " : "",
+		s & BCM2835_I2C_S_TXW ? "TXW " : "",
+		s & BCM2835_I2C_S_RXR ? "RXR " : "",
+		s & BCM2835_I2C_S_TXD ? "TXD " : "",
+		s & BCM2835_I2C_S_RXD ? "RXD " : "",
+		s & BCM2835_I2C_S_TXE ? "TXE " : "",
+		s & BCM2835_I2C_S_RXF ? "RXF " : "",
+		s & BCM2835_I2C_S_ERR ? "ERR " : "",
+		s & BCM2835_I2C_S_CLKT ? "CLKT " : "",
+		i2c_dev->adapter.nr);
+}
+
+static void bcm2835_debug_print_msg(struct bcm2835_i2c_dev *i2c_dev,
+				    struct i2c_msg *msg, int i, int total,
+				    const char *fname)
+{
+	pr_info("%s: msg(%d/%d) %s addr=0x%02x, len=%u flags=%s%s%s%s%s%s%s [i2c%d]\n",
+		fname, i, total,
+		msg->flags & I2C_M_RD ? "read" : "write", msg->addr, msg->len,
+		msg->flags & I2C_M_TEN ? "TEN" : "",
+		msg->flags & I2C_M_RECV_LEN ? "RECV_LEN" : "",
+		msg->flags & I2C_M_NO_RD_ACK ? "NO_RD_ACK" : "",
+		msg->flags & I2C_M_IGNORE_NAK ? "IGNORE_NAK" : "",
+		msg->flags & I2C_M_REV_DIR_ADDR ? "REV_DIR_ADDR" : "",
+		msg->flags & I2C_M_NOSTART ? "NOSTART" : "",
+		msg->flags & I2C_M_STOP ? "STOP" : "",
+		i2c_dev->adapter.nr);
+}
+
+static void bcm2835_debug_print(struct bcm2835_i2c_dev *i2c_dev)
+{
+	struct bcm2835_debug *d;
+	unsigned int i;
+
+	for (i = 0; i < i2c_dev->debug_num; i++) {
+		d = &i2c_dev->debug[i];
+		if (d->status == ~0)
+			bcm2835_debug_print_msg(i2c_dev, d->msg, d->msg_idx,
+				i2c_dev->debug_num_msgs, "start_transfer");
+		else
+			bcm2835_debug_print_status(i2c_dev, d);
+	}
+	if (i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
+		pr_info("BCM2835_DEBUG_MAX reached\n");
+}
+
 static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev,
 				      u32 reg, u32 val)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:191 @
 {
 	struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
 	u32 redl, fedl;
+	u32 clk_tout;
 	u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
 
 	if (divider == -EINVAL)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:215 @
 	bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
 			   (fedl << BCM2835_I2C_FEDL_SHIFT) |
 			   (redl << BCM2835_I2C_REDL_SHIFT));
+
+	/*
+	 * Set the clock stretch timeout to the SMBUs-recommended 35ms.
+	 */
+	if (rate > 0xffff*1000/35)
+	    clk_tout = 0xffff;
+	else
+	    clk_tout = 35*rate/1000;
+
+	bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_CLKT, clk_tout);
+
 	return 0;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:349 @
 	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
 	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
 	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
+	bcm2835_debug_add(i2c_dev, ~0);
 }
 
 static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c_dev *i2c_dev)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:376 @
 	u32 val, err;
 
 	val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+	bcm2835_debug_add(i2c_dev, val);
 
 	err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
 	if (err) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:443 @
 	unsigned long time_left;
 	int i;
 
+	if (debug)
+		i2c_dev->debug_num_msgs = num;
+
+	if (debug > 2)
+		for (i = 0; i < num; i++)
+			bcm2835_debug_print_msg(i2c_dev, &msgs[i], i + 1, num, __func__);
+
 	for (i = 0; i < (num - 1); i++)
 		if (msgs[i].flags & I2C_M_RD) {
 			dev_warn_once(i2c_dev->dev,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:468 @
 
 	bcm2835_i2c_finish_transfer(i2c_dev);
 
+	if (debug > 1 || (debug && (!time_left || i2c_dev->msg_err)))
+		bcm2835_debug_print(i2c_dev);
+	i2c_dev->debug_num_msgs = 0;
+	i2c_dev->debug_num = 0;
 	if (!time_left) {
 		bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
 				   BCM2835_I2C_C_CLEAR);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:482 @
 	if (!i2c_dev->msg_err)
 		return num;
 
-	dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
+	if (debug)
+		dev_err(i2c_dev->dev, "i2c transfer failed: %x\n",
+			i2c_dev->msg_err);
 
 	if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
 		return -EREMOTEIO;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/i2c/busses/i2c-gpio.c linux-5.10.52-v7l+/drivers/i2c/busses/i2c-gpio.c
--- linux-5.10.52-orig/drivers/i2c/busses/i2c-gpio.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/i2c/busses/i2c-gpio.c	2021-07-25 16:46:02.128355226 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:448 @
 	adap->dev.parent = dev;
 	adap->dev.of_node = np;
 
-	adap->nr = pdev->id;
+	if (pdev->id != PLATFORM_DEVID_NONE || !pdev->dev.of_node ||
+	    of_property_read_u32(pdev->dev.of_node, "reg", &adap->nr))
+		adap->nr = pdev->id;
 	ret = i2c_bit_add_numbered_bus(adap);
 	if (ret)
 		return ret;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/i2c/busses/Kconfig linux-5.10.52-v7l+/drivers/i2c/busses/Kconfig
--- linux-5.10.52-orig/drivers/i2c/busses/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/i2c/busses/Kconfig	2021-07-25 16:46:02.098355729 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:12 @
 comment "PC SMBus host controller drivers"
 	depends on PCI
 
+config I2C_BCM2708
+	tristate "BCM2708 BSC"
+	depends on ARCH_BCM2835
+	help
+	  Enabling this option will add BSC (Broadcom Serial Controller)
+	  support for the BCM2708. BSC is a Broadcom proprietary bus compatible
+	  with I2C/TWI/SMBus.
+
+config I2C_BCM2708_BAUDRATE
+	prompt "BCM2708 I2C baudrate"
+	depends on I2C_BCM2708
+	int
+	default 100000
+	help
+	  Set the I2C baudrate. This will alter the default value. A
+	  different baudrate can be set by using a module parameter as well. If
+	  no parameter is provided when loading, this is the value that will be
+	  used.
+
 config I2C_ALI1535
 	tristate "ALI 1535"
 	depends on PCI
diff -Nur --no-dereference linux-5.10.52-orig/drivers/i2c/busses/Makefile linux-5.10.52-v7l+/drivers/i2c/busses/Makefile
--- linux-5.10.52-orig/drivers/i2c/busses/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/i2c/busses/Makefile	2021-07-25 16:46:02.098355729 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6 @
 # Makefile for the i2c bus drivers.
 #
 
+obj-$(CONFIG_I2C_BCM2708)	+= i2c-bcm2708.o
+
 # ACPI drivers
 obj-$(CONFIG_I2C_SCMI)		+= i2c-scmi.o
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/input/joystick/Kconfig linux-5.10.52-v7l+/drivers/input/joystick/Kconfig
--- linux-5.10.52-orig/drivers/input/joystick/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/input/joystick/Kconfig	2021-07-25 16:46:03.218336952 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:385 @
 	  To compile this driver as a module, choose M here: the
 	  module will be called fsia6b.
 
+config JOYSTICK_RPISENSE
+	tristate "Raspberry Pi Sense HAT joystick"
+	depends on GPIOLIB && INPUT
+	select MFD_RPISENSE_CORE
+
+	help
+	  This is the joystick driver for the Raspberry Pi Sense HAT
+
 endif
diff -Nur --no-dereference linux-5.10.52-orig/drivers/input/joystick/Makefile linux-5.10.52-v7l+/drivers/input/joystick/Makefile
--- linux-5.10.52-orig/drivers/input/joystick/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/input/joystick/Makefile	2021-07-25 16:46:03.218336952 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:40 @
 obj-$(CONFIG_JOYSTICK_WALKERA0701)	+= walkera0701.o
 obj-$(CONFIG_JOYSTICK_XPAD)		+= xpad.o
 obj-$(CONFIG_JOYSTICK_ZHENHUA)		+= zhenhua.o
-
+obj-$(CONFIG_JOYSTICK_RPISENSE)		+= rpisense-js.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/input/joystick/rpisense-js.c linux-5.10.52-v7l+/drivers/input/joystick/rpisense-js.c
--- linux-5.10.52-orig/drivers/input/joystick/rpisense-js.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/input/joystick/rpisense-js.c	2021-07-25 16:46:03.248336449 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Raspberry Pi Sense HAT joystick driver
+ * http://raspberrypi.org
+ *
+ * Copyright (C) 2015 Raspberry Pi
+ *
+ * Author: Serge Schneider
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/mfd/rpisense/joystick.h>
+#include <linux/mfd/rpisense/core.h>
+
+static struct rpisense *rpisense;
+static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,};
+
+static void keys_work_fn(struct work_struct *work)
+{
+	int i;
+	static s32 prev_keys;
+	struct rpisense_js *rpisense_js = &rpisense->joystick;
+	s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS);
+	s32 changes = keys ^ prev_keys;
+
+	prev_keys = keys;
+	for (i = 0; i < 5; i++) {
+		if (changes & 1) {
+			input_report_key(rpisense_js->keys_dev,
+					 keymap[i], keys & 1);
+		}
+		changes >>= 1;
+		keys >>= 1;
+	}
+	input_sync(rpisense_js->keys_dev);
+}
+
+static irqreturn_t keys_irq_handler(int irq, void *pdev)
+{
+	struct rpisense_js *rpisense_js = &rpisense->joystick;
+
+	schedule_work(&rpisense_js->keys_work_s);
+	return IRQ_HANDLED;
+}
+
+static int rpisense_js_probe(struct platform_device *pdev)
+{
+	int ret;
+	int i;
+	struct rpisense_js *rpisense_js;
+
+	rpisense = rpisense_get_dev();
+	rpisense_js = &rpisense->joystick;
+
+	INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn);
+
+	rpisense_js->keys_dev = input_allocate_device();
+	if (!rpisense_js->keys_dev) {
+		dev_err(&pdev->dev, "Could not allocate input device.\n");
+		return -ENOMEM;
+	}
+
+	rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY);
+	for (i = 0; i < ARRAY_SIZE(keymap); i++) {
+		set_bit(keymap[i],
+			rpisense_js->keys_dev->keybit);
+	}
+
+	rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
+	rpisense_js->keys_dev->phys = "rpi-sense-joy/input0";
+	rpisense_js->keys_dev->id.bustype = BUS_I2C;
+	rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+	rpisense_js->keys_dev->keycode = keymap;
+	rpisense_js->keys_dev->keycodesize = sizeof(unsigned char);
+	rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap);
+
+	ret = input_register_device(rpisense_js->keys_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register input device.\n");
+		goto err_keys_alloc;
+	}
+
+	ret = gpiod_direction_input(rpisense_js->keys_desc);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not set keys-int direction.\n");
+		goto err_keys_reg;
+	}
+
+	rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc);
+	if (rpisense_js->keys_irq < 0) {
+		dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n");
+		ret = rpisense_js->keys_irq;
+		goto err_keys_reg;
+	}
+
+	ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq,
+			       keys_irq_handler, IRQF_TRIGGER_RISING,
+			       "keys", &pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "IRQ request failed.\n");
+		goto err_keys_reg;
+	}
+	return 0;
+err_keys_reg:
+	input_unregister_device(rpisense_js->keys_dev);
+err_keys_alloc:
+	input_free_device(rpisense_js->keys_dev);
+	return ret;
+}
+
+static int rpisense_js_remove(struct platform_device *pdev)
+{
+	struct rpisense_js *rpisense_js = &rpisense->joystick;
+
+	input_unregister_device(rpisense_js->keys_dev);
+	input_free_device(rpisense_js->keys_dev);
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rpisense_js_id[] = {
+	{ .compatible = "rpi,rpi-sense-js" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, rpisense_js_id);
+#endif
+
+static struct platform_device_id rpisense_js_device_id[] = {
+	{ .name = "rpi-sense-js" },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, rpisense_js_device_id);
+
+static struct platform_driver rpisense_js_driver = {
+	.probe = rpisense_js_probe,
+	.remove = rpisense_js_remove,
+	.driver = {
+		.name = "rpi-sense-js",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(rpisense_js_driver);
+
+MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
+MODULE_LICENSE("GPL");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/input/touchscreen/edt-ft5x06.c linux-5.10.52-v7l+/drivers/input/touchscreen/edt-ft5x06.c
--- linux-5.10.52-orig/drivers/input/touchscreen/edt-ft5x06.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/input/touchscreen/edt-ft5x06.c	2021-07-25 16:46:03.588330749 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:72 @
 #define EDT_RAW_DATA_RETRIES		100
 #define EDT_RAW_DATA_DELAY		1000 /* usec */
 
+#define POLL_INTERVAL_MS		17	/* 17ms = 60fps */
+
 enum edt_pmode {
 	EDT_PMODE_NOT_SUPPORTED,
 	EDT_PMODE_HIBERNATE,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:131 @
 
 	struct edt_reg_addr reg_addr;
 	enum edt_ver version;
+
+	struct timer_list timer;
+	struct work_struct work_i2c_poll;
 };
 
 struct edt_i2c_chip_data {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:283 @
 	return IRQ_HANDLED;
 }
 
+static void edt_ft5x06_ts_irq_poll_timer(struct timer_list *t)
+{
+	struct edt_ft5x06_ts_data *tsdata = from_timer(tsdata, t, timer);
+
+	schedule_work(&tsdata->work_i2c_poll);
+	mod_timer(&tsdata->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS));
+}
+
+static void edt_ft5x06_ts_work_i2c_poll(struct work_struct *work)
+{
+	struct edt_ft5x06_ts_data *tsdata = container_of(work,
+			struct edt_ft5x06_ts_data, work_i2c_poll);
+
+	edt_ft5x06_ts_isr(0, tsdata);
+}
+
 static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
 				     u8 addr, u8 value)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1245 @
 
 	i2c_set_clientdata(client, tsdata);
 
-	irq_flags = irq_get_trigger_type(client->irq);
-	if (irq_flags == IRQF_TRIGGER_NONE)
-		irq_flags = IRQF_TRIGGER_FALLING;
-	irq_flags |= IRQF_ONESHOT;
-
-	error = devm_request_threaded_irq(&client->dev, client->irq,
-					NULL, edt_ft5x06_ts_isr, irq_flags,
-					client->name, tsdata);
-	if (error) {
-		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
-		return error;
+	if (client->irq) {
+		irq_flags = irq_get_trigger_type(client->irq);
+		if (irq_flags == IRQF_TRIGGER_NONE)
+			irq_flags = IRQF_TRIGGER_FALLING;
+		irq_flags |= IRQF_ONESHOT;
+
+		error = devm_request_threaded_irq(&client->dev, client->irq,
+						  NULL, edt_ft5x06_ts_isr,
+						  irq_flags, client->name,
+						  tsdata);
+		if (error) {
+			dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+			return error;
+		}
+	} else {
+		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);
+		add_timer(&tsdata->timer);
 	}
 
 	error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/irqchip/irq-bcm2835.c linux-5.10.52-v7l+/drivers/irqchip/irq-bcm2835.c
--- linux-5.10.52-orig/drivers/irqchip/irq-bcm2835.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/irqchip/irq-bcm2835.c	2021-07-25 16:46:03.838326557 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:46 @
 #include <linux/irqdomain.h>
 
 #include <asm/exception.h>
+#ifndef CONFIG_ARM64
+#include <asm/mach/irq.h>
+#endif
 
 /* Put the bank and irq (32 bits) into the hwirq */
-#define MAKE_HWIRQ(b, n)	((b << 5) | (n))
+#define MAKE_HWIRQ(b, n)	(((b) << 5) | (n))
 #define HWIRQ_BANK(i)		(i >> 5)
 #define HWIRQ_BIT(i)		BIT(i & 0x1f)
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:66 @
 #define BANK0_VALID_MASK	(BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
 					| SHORTCUT1_MASK | SHORTCUT2_MASK)
 
+#undef ARM_LOCAL_GPU_INT_ROUTING
+#define ARM_LOCAL_GPU_INT_ROUTING 0x0c
+
 #define REG_FIQ_CONTROL		0x0c
 #define FIQ_CONTROL_ENABLE	BIT(7)
+#define REG_FIQ_ENABLE		FIQ_CONTROL_ENABLE
+#define REG_FIQ_DISABLE	0
 
 #define NR_BANKS		3
 #define IRQS_PER_BANK		32
+#define NUMBER_IRQS		MAKE_HWIRQ(NR_BANKS, 0)
 
 static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
 static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:94 @
 	void __iomem *enable[NR_BANKS];
 	void __iomem *disable[NR_BANKS];
 	struct irq_domain *domain;
+	void __iomem *local_base;
 };
 
 static struct armctrl_ic intc __read_mostly;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:102 @
 	struct pt_regs *regs);
 static void bcm2836_chained_handle_irq(struct irq_desc *desc);
 
+static inline unsigned int hwirq_to_fiq(unsigned long hwirq)
+{
+	hwirq -= NUMBER_IRQS;
+	/*
+	 * The hwirq numbering used in this driver is:
+	 *   BASE (0-7) GPU1 (32-63) GPU2 (64-95).
+	 * This differ from the one used in the FIQ register:
+	 *   GPU1 (0-31) GPU2 (32-63) BASE (64-71)
+	 */
+	if (hwirq >= 32)
+		return hwirq - 32;
+
+	return hwirq + 64;
+}
+
 static void armctrl_mask_irq(struct irq_data *d)
 {
-	writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]);
+	if (d->hwirq >= NUMBER_IRQS)
+		writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL);
+	else
+		writel_relaxed(HWIRQ_BIT(d->hwirq),
+			       intc.disable[HWIRQ_BANK(d->hwirq)]);
 }
 
 static void armctrl_unmask_irq(struct irq_data *d)
 {
-	writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]);
+	if (d->hwirq >= NUMBER_IRQS) {
+		if (num_online_cpus() > 1) {
+			unsigned int data;
+
+			if (!intc.local_base) {
+				pr_err("FIQ is disabled due to missing arm_local_intc\n");
+				return;
+			}
+
+			data = readl_relaxed(intc.local_base +
+					     ARM_LOCAL_GPU_INT_ROUTING);
+
+			data &= ~0xc;
+			data |= (1 << 2);
+			writel_relaxed(data,
+				       intc.local_base +
+				       ARM_LOCAL_GPU_INT_ROUTING);
+		}
+
+		writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
+			       intc.base + REG_FIQ_CONTROL);
+	} else {
+		writel_relaxed(HWIRQ_BIT(d->hwirq),
+			       intc.enable[HWIRQ_BANK(d->hwirq)]);
+	}
+}
+
+#ifdef CONFIG_ARM64
+void bcm2836_arm_irqchip_spin_gpu_irq(void);
+
+static void armctrl_ack_irq(struct irq_data *d)
+{
+	bcm2836_arm_irqchip_spin_gpu_irq();
 }
 
+#endif
+
 static struct irq_chip armctrl_chip = {
 	.name = "ARMCTRL-level",
 	.irq_mask = armctrl_mask_irq,
-	.irq_unmask = armctrl_unmask_irq
+	.irq_unmask = armctrl_unmask_irq,
+#ifdef CONFIG_ARM64
+	.irq_ack    = armctrl_ack_irq
+#endif
 };
 
 static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:204 @
 				  bool is_2836)
 {
 	void __iomem *base;
-	int irq, b, i;
+	int irq = 0, last_irq, b, i;
 	u32 reg;
 
 	base = of_iomap(node, 0);
 	if (!base)
 		panic("%pOF: unable to map IC registers\n", node);
 
-	intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0),
-			&armctrl_ops, NULL);
+	intc.base = base;
+	intc.domain = irq_domain_add_linear(node, NUMBER_IRQS * 2,
+					    &armctrl_ops, NULL);
 	if (!intc.domain)
 		panic("%pOF: unable to create IRQ domain\n", node);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:244 @
 		pr_err(FW_BUG "Bootloader left fiq enabled\n");
 	}
 
+	last_irq = irq;
+
 	if (is_2836) {
 		int parent_irq = irq_of_parse_and_map(node, 0);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:258 @
 		set_handle_irq(bcm2835_handle_irq);
 	}
 
+	if (is_2836) {
+		extern void __iomem * __attribute__((weak)) arm_local_intc;
+		intc.local_base = arm_local_intc;
+		if (!intc.local_base)
+			pr_err("Failed to get local intc base. FIQ is disabled for cpus > 1\n");
+	}
+
+	/* Make a duplicate irq range which is used to enable FIQ */
+	for (b = 0; b < NR_BANKS; b++) {
+		for (i = 0; i < bank_irqs[b]; i++) {
+			irq = irq_create_mapping(intc.domain,
+					MAKE_HWIRQ(b, i) + NUMBER_IRQS);
+			BUG_ON(irq <= 0);
+			irq_set_chip(irq, &armctrl_chip);
+			irq_set_probe(irq);
+		}
+	}
+#ifndef CONFIG_ARM64
+	init_FIQ(irq - last_irq);
+#endif
+
 	return 0;
 }
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/irqchip/irq-bcm2836.c linux-5.10.52-v7l+/drivers/irqchip/irq-bcm2836.c
--- linux-5.10.52-orig/drivers/irqchip/irq-bcm2836.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/irqchip/irq-bcm2836.c	2021-07-25 16:46:03.838326557 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:25 @
 
 static struct bcm2836_arm_irqchip_intc intc  __read_mostly;
 
+void __iomem *arm_local_intc;
+EXPORT_SYMBOL_GPL(arm_local_intc);
+
 static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset,
 						 unsigned int bit,
 						 int cpu)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:90 @
 {
 }
 
+#ifdef CONFIG_ARM64
+
+void bcm2836_arm_irqchip_spin_gpu_irq(void)
+{
+	u32 i;
+	void __iomem *gpurouting = (intc.base + LOCAL_GPU_ROUTING);
+	u32 routing_val = readl(gpurouting);
+
+	for (i = 1; i <= 3; i++) {
+		u32 new_routing_val = (routing_val + i) & 3;
+
+		if (cpu_active(new_routing_val)) {
+			writel(new_routing_val, gpurouting);
+			return;
+		}
+	}
+}
+EXPORT_SYMBOL(bcm2836_arm_irqchip_spin_gpu_irq);
+
+#endif
+
 static struct irq_chip bcm2836_arm_irqchip_gpu = {
 	.name		= "bcm2836-gpu",
 	.irq_mask	= bcm2836_arm_irqchip_mask_gpu_irq,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:155 @
 	irq_set_percpu_devid(irq);
 	irq_domain_set_info(d, irq, hw, chip, d->host_data,
 			    handle_percpu_devid_irq, NULL, NULL);
-	irq_set_status_flags(irq, IRQ_NOAUTOEN);
+	irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_TYPE_LEVEL_LOW);
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:350 @
 		panic("%pOF: unable to map local interrupt registers\n", node);
 	}
 
+	arm_local_intc = intc.base;
+
 	bcm2835_init_local_timer_frequency();
 
 	intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/leds/leds-gpio.c linux-5.10.52-v7l+/drivers/leds/leds-gpio.c
--- linux-5.10.52-orig/drivers/leds/leds-gpio.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/leds/leds-gpio.c	2021-07-25 16:46:04.058322869 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:49 @
 		led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
 						 NULL, NULL);
 		led_dat->blinking = 0;
+	} else if (led_dat->cdev.flags & SET_GPIO_INPUT) {
+		gpiod_direction_input(led_dat->gpiod);
+		led_dat->cdev.flags &= ~SET_GPIO_INPUT;
+	} else if (led_dat->cdev.flags & SET_GPIO_OUTPUT) {
+		gpiod_direction_output(led_dat->gpiod, level);
+		led_dat->cdev.flags &= ~SET_GPIO_OUTPUT;
 	} else {
-		if (led_dat->can_sleep)
+		if (led_dat->can_sleep ||
+			(led_dat->cdev.flags & (SET_GPIO_INPUT | SET_GPIO_OUTPUT) ))
 			gpiod_set_value_cansleep(led_dat->gpiod, level);
 		else
 			gpiod_set_value(led_dat->gpiod, level);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:71 @
 	return 0;
 }
 
+static enum led_brightness gpio_led_get(struct led_classdev *led_cdev)
+{
+	struct gpio_led_data *led_dat =
+		container_of(led_cdev, struct gpio_led_data, cdev);
+	return gpiod_get_value_cansleep(led_dat->gpiod) ? LED_FULL : LED_OFF;
+}
+
 static int gpio_blink_set(struct led_classdev *led_cdev,
 	unsigned long *delay_on, unsigned long *delay_off)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:106 @
 		led_dat->platform_gpio_blink_set = blink_set;
 		led_dat->cdev.blink_set = gpio_blink_set;
 	}
+	led_dat->cdev.brightness_get = gpio_led_get;
 	if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) {
 		state = gpiod_get_value_cansleep(led_dat->gpiod);
 		if (state < 0)
diff -Nur --no-dereference linux-5.10.52-orig/drivers/leds/trigger/Kconfig linux-5.10.52-v7l+/drivers/leds/trigger/Kconfig
--- linux-5.10.52-orig/drivers/leds/trigger/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/leds/trigger/Kconfig	2021-07-25 16:46:04.118321863 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:117 @
 	  This enables direct flash/torch on/off by the driver, kernel space.
 	  If unsure, say Y.
 
+config LEDS_TRIGGER_INPUT
+	tristate "LED Input Trigger"
+	depends on LEDS_TRIGGERS
+	help
+	  This allows the GPIOs assigned to be LEDs to be initialised to inputs.
+	  If unsure, say Y.
+
 config LEDS_TRIGGER_PANIC
 	bool "LED Panic Trigger"
 	help
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:154 @
 	  the audio mute and mic-mute changes.
 	  If unsure, say N
 
+config LEDS_TRIGGER_ACTPWR
+	tristate "ACT/PWR Input Trigger"
+	depends on LEDS_TRIGGERS
+	help
+	  This trigger is intended for platforms that have one software-
+	  controllable LED and no dedicated activity or power LEDs, hence the
+	  need to make the one LED perform both functions. It cycles between
+	  default-on and an inverted mmc0 every 500ms, guaranteeing that it is
+	  on for at least half of the time.
+	  If unsure, say N.
+
 endif # LEDS_TRIGGERS
diff -Nur --no-dereference linux-5.10.52-orig/drivers/leds/trigger/ledtrig-actpwr.c linux-5.10.52-v7l+/drivers/leds/trigger/ledtrig-actpwr.c
--- linux-5.10.52-orig/drivers/leds/trigger/ledtrig-actpwr.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/leds/trigger/ledtrig-actpwr.c	2021-07-25 16:46:04.118321863 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Activity/power trigger
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * Based on Atsushi Nemoto's ledtrig-heartbeat.c, although there may be
+ * nothing left of the original now.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/leds.h>
+#include "../leds.h"
+
+enum {
+	TRIG_ACT,
+	TRIG_PWR,
+
+	TRIG_COUNT
+};
+
+struct actpwr_trig_src {
+	const char *name;
+	int interval;
+	bool invert;
+};
+
+struct actpwr_vled {
+	struct led_classdev cdev;
+	struct actpwr_trig_data *parent;
+	enum led_brightness value;
+	unsigned int interval;
+	bool invert;
+};
+
+struct actpwr_trig_data {
+	struct led_trigger trig;
+	struct actpwr_vled virt_leds[TRIG_COUNT];
+	struct actpwr_vled *active;
+	struct timer_list timer;
+	int next_active;
+};
+
+static int actpwr_trig_activate(struct led_classdev *led_cdev);
+static void actpwr_trig_deactivate(struct led_classdev *led_cdev);
+
+static const struct actpwr_trig_src actpwr_trig_sources[TRIG_COUNT] = {
+	[TRIG_ACT] = { "mmc0", 500, true },
+	[TRIG_PWR] = { "default-on", 500, false },
+};
+
+static struct actpwr_trig_data actpwr_data = {
+	{
+		.name     = "actpwr",
+		.activate = actpwr_trig_activate,
+		.deactivate = actpwr_trig_deactivate,
+	}
+};
+
+static void actpwr_brightness_set(struct led_classdev *led_cdev,
+				  enum led_brightness value)
+{
+	struct actpwr_vled *vled = container_of(led_cdev, struct actpwr_vled,
+					       cdev);
+	struct actpwr_trig_data *trig = vled->parent;
+
+	if (vled->invert)
+		value = !value;
+	vled->value = value;
+
+	if (vled == trig->active)
+		led_trigger_event(&trig->trig, value);
+}
+
+static int actpwr_brightness_set_blocking(struct led_classdev *led_cdev,
+					  enum led_brightness value)
+{
+	actpwr_brightness_set(led_cdev, value);
+	return 0;
+}
+
+static enum led_brightness actpwr_brightness_get(struct led_classdev *led_cdev)
+{
+	struct actpwr_vled *vled = container_of(led_cdev, struct actpwr_vled,
+					      cdev);
+
+	return vled->value;
+}
+
+static void actpwr_trig_cycle(struct timer_list *t)
+{
+	struct actpwr_trig_data *trig  = &actpwr_data;
+	struct actpwr_vled *active;
+
+	active = &trig->virt_leds[trig->next_active];
+	trig->active = active;
+	trig->next_active = (trig->next_active + 1) % TRIG_COUNT;
+
+	led_trigger_event(&trig->trig, active->value);
+
+	mod_timer(&trig->timer, jiffies + msecs_to_jiffies(active->interval));
+}
+
+static int actpwr_trig_activate(struct led_classdev *led_cdev)
+{
+	struct actpwr_trig_data *trig  = &actpwr_data;
+
+	/* Start the timer if this is the first LED */
+	if (!trig->active)
+		actpwr_trig_cycle(&trig->timer);
+	else
+		led_set_brightness_nosleep(led_cdev, trig->active->value);
+
+	return 0;
+}
+
+static void actpwr_trig_deactivate(struct led_classdev *led_cdev)
+{
+	struct actpwr_trig_data *trig  = &actpwr_data;
+
+	if (list_empty(&trig->trig.led_cdevs)) {
+		del_timer_sync(&trig->timer);
+		trig->active = NULL;
+	}
+}
+
+static int __init actpwr_trig_init(void)
+{
+	struct actpwr_trig_data *trig  = &actpwr_data;
+	int ret = 0;
+	int i;
+
+	timer_setup(&trig->timer, actpwr_trig_cycle, 0);
+
+	/* Register one "LED" for each source trigger */
+	for (i = 0; i < TRIG_COUNT; i++)
+	{
+		struct actpwr_vled *vled = &trig->virt_leds[i];
+		struct led_classdev *cdev = &vled->cdev;
+		const struct actpwr_trig_src *src = &actpwr_trig_sources[i];
+
+		vled->parent = trig;
+		vled->interval = src->interval;
+		vled->invert = src->invert;
+		cdev->name = src->name;
+		cdev->brightness_set = actpwr_brightness_set;
+		cdev->brightness_set_blocking = actpwr_brightness_set_blocking;
+		cdev->brightness_get = actpwr_brightness_get;
+		cdev->default_trigger = src->name;
+		ret = led_classdev_register(NULL, cdev);
+		if (ret)
+			goto error_classdev;
+	}
+
+	ret = led_trigger_register(&trig->trig);
+	if (ret)
+		goto error_classdev;
+
+	return 0;
+
+error_classdev:
+	while (i > 0)
+	{
+		i--;
+		led_classdev_unregister(&trig->virt_leds[i].cdev);
+	}
+
+	return ret;
+}
+
+static void __exit actpwr_trig_exit(void)
+{
+	int i;
+
+	led_trigger_unregister(&actpwr_data.trig);
+	for (i = 0; i < TRIG_COUNT; i++)
+	{
+		led_classdev_unregister(&actpwr_data.virt_leds[i].cdev);
+	}
+}
+
+module_init(actpwr_trig_init);
+module_exit(actpwr_trig_exit);
+
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>");
+MODULE_DESCRIPTION("ACT/PWR LED trigger");
+MODULE_LICENSE("GPL v2");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/leds/trigger/ledtrig-input.c linux-5.10.52-v7l+/drivers/leds/trigger/ledtrig-input.c
--- linux-5.10.52-orig/drivers/leds/trigger/ledtrig-input.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/leds/trigger/ledtrig-input.c	2021-07-25 16:46:04.128321695 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Set LED GPIO to Input "Trigger"
+ *
+ * Copyright 2015 Phil Elwell <phil@raspberrypi.org>
+ *
+ * Based on Nick Forbes's ledtrig-default-on.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include "../leds.h"
+
+static int input_trig_activate(struct led_classdev *led_cdev)
+{
+	led_cdev->flags |= SET_GPIO_INPUT;
+	led_set_brightness(led_cdev, 0);
+	return 0;
+}
+
+static void input_trig_deactivate(struct led_classdev *led_cdev)
+{
+	led_cdev->flags |= SET_GPIO_OUTPUT;
+	led_set_brightness(led_cdev, 0);
+}
+
+static struct led_trigger input_led_trigger = {
+	.name     = "input",
+	.activate = input_trig_activate,
+	.deactivate = input_trig_deactivate,
+};
+
+static int __init input_trig_init(void)
+{
+	return led_trigger_register(&input_led_trigger);
+}
+
+static void __exit input_trig_exit(void)
+{
+	led_trigger_unregister(&input_led_trigger);
+}
+
+module_init(input_trig_init);
+module_exit(input_trig_exit);
+
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
+MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\"");
+MODULE_LICENSE("GPL");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/leds/trigger/Makefile linux-5.10.52-v7l+/drivers/leds/trigger/Makefile
--- linux-5.10.52-orig/drivers/leds/trigger/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/leds/trigger/Makefile	2021-07-25 16:46:04.118321863 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:14 @
 obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON)	+= ledtrig-default-on.o
 obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT)	+= ledtrig-transient.o
 obj-$(CONFIG_LEDS_TRIGGER_CAMERA)	+= ledtrig-camera.o
+obj-$(CONFIG_LEDS_TRIGGER_INPUT)	+= ledtrig-input.o
 obj-$(CONFIG_LEDS_TRIGGER_PANIC)	+= ledtrig-panic.o
 obj-$(CONFIG_LEDS_TRIGGER_NETDEV)	+= ledtrig-netdev.o
 obj-$(CONFIG_LEDS_TRIGGER_PATTERN)	+= ledtrig-pattern.o
 obj-$(CONFIG_LEDS_TRIGGER_AUDIO)	+= ledtrig-audio.o
+obj-$(CONFIG_LEDS_TRIGGER_ACTPWR)	+= ledtrig-actpwr.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mailbox/bcm2835-mailbox.c linux-5.10.52-v7l+/drivers/mailbox/bcm2835-mailbox.c
--- linux-5.10.52-orig/drivers/mailbox/bcm2835-mailbox.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mailbox/bcm2835-mailbox.c	2021-07-25 16:46:04.218320186 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:48 @
 #define MAIL1_WRT	(ARM_0_MAIL1 + 0x00)
 #define MAIL1_STA	(ARM_0_MAIL1 + 0x18)
 
+/* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
+#ifndef ARM_MS_FULL
 /* Status register: FIFO state. */
 #define ARM_MS_FULL		BIT(31)
 #define ARM_MS_EMPTY		BIT(30)
 
 /* Configuration register: Enable interrupts. */
 #define ARM_MC_IHAVEDATAIRQEN	BIT(0)
+#endif
 
 struct bcm2835_mbox {
 	void __iomem *regs;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:151 @
 		return -ENOMEM;
 	spin_lock_init(&mbox->lock);
 
-	ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
+	ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
 			       bcm2835_mbox_irq, 0, dev_name(dev), mbox);
 	if (ret) {
 		dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:201 @
 	},
 	.probe		= bcm2835_mbox_probe,
 };
-module_platform_driver(bcm2835_mbox_driver);
+
+static int __init bcm2835_mbox_init(void)
+{
+	return platform_driver_register(&bcm2835_mbox_driver);
+}
+arch_initcall(bcm2835_mbox_init);
+
+static void __init bcm2835_mbox_exit(void)
+{
+	platform_driver_unregister(&bcm2835_mbox_driver);
+}
+module_exit(bcm2835_mbox_exit);
 
 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
 MODULE_DESCRIPTION("BCM2835 mailbox IPC driver");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mailbox/mailbox.c linux-5.10.52-v7l+/drivers/mailbox/mailbox.c
--- linux-5.10.52-orig/drivers/mailbox/mailbox.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mailbox/mailbox.c	2021-07-25 16:46:04.238319851 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:85 @
 exit:
 	spin_unlock_irqrestore(&chan->lock, flags);
 
-	/* kick start the timer immediately to avoid delays */
-	if (!err && (chan->txdone_method & TXDONE_BY_POLL)) {
-		/* but only if not already active */
-		if (!hrtimer_active(&chan->mbox->poll_hrt))
-			hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
-	}
+	if (!err && (chan->txdone_method & TXDONE_BY_POLL))
+		/* kick start the timer immediately to avoid delays */
+		hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
 }
 
 static void tx_tick(struct mbox_chan *chan, int r)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:125 @
 		struct mbox_chan *chan = &mbox->chans[i];
 
 		if (chan->active_req && chan->cl) {
-			resched = true;
 			txdone = chan->mbox->ops->last_tx_done(chan);
 			if (txdone)
 				tx_tick(chan, 0);
+			else
+				resched = true;
 		}
 	}
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/common/videobuf2/videobuf2-core.c linux-5.10.52-v7l+/drivers/media/common/videobuf2/videobuf2-core.c
--- linux-5.10.52-orig/drivers/media/common/videobuf2/videobuf2-core.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/common/videobuf2/videobuf2-core.c	2021-07-25 16:46:04.798310463 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2132 @
 	return -EINVAL;
 }
 
-int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
-		unsigned int index, unsigned int plane, unsigned int flags)
+int vb2_core_expbuf_dmabuf(struct vb2_queue *q, unsigned int type,
+			   unsigned int index, unsigned int plane,
+			   unsigned int flags, struct dma_buf **dmabuf)
 {
 	struct vb2_buffer *vb = NULL;
 	struct vb2_plane *vb_plane;
-	int ret;
 	struct dma_buf *dbuf;
 
 	if (q->memory != VB2_MEMORY_MMAP) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2187 @
 		return -EINVAL;
 	}
 
+	*dmabuf = dbuf;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_core_expbuf_dmabuf);
+
+int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
+		    unsigned int index, unsigned int plane, unsigned int flags)
+{
+	struct dma_buf *dbuf;
+	int ret;
+
+	ret = vb2_core_expbuf_dmabuf(q, type, index, plane, flags, &dbuf);
+	if (ret)
+		return ret;
+
 	ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE);
 	if (ret < 0) {
 		dprintk(q, 3, "buffer %d, plane %d failed to export (%d)\n",
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/adv7180.c linux-5.10.52-v7l+/drivers/media/i2c/adv7180.c
--- linux-5.10.52-orig/drivers/media/i2c/adv7180.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/i2c/adv7180.c	2021-07-25 16:46:05.648296212 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1251 @
 		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
 		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
 		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
 		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
 		BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
 		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1263 @
 static int init_device(struct adv7180_state *state)
 {
 	int ret;
+	int i;
 
 	mutex_lock(&state->mutex);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1310 @
 			goto out_unlock;
 	}
 
+	/* Select first valid input */
+	for (i = 0; i < 32; i++) {
+		if (BIT(i) & state->chip_info->valid_input_mask) {
+			ret = state->chip_info->select_input(state, i);
+
+			if (ret == 0) {
+				state->input = i;
+				break;
+			}
+		}
+	}
+
 out_unlock:
 	mutex_unlock(&state->mutex);
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/imx219.c linux-5.10.52-v7l+/drivers/media/i2c/imx219.c
--- linux-5.10.52-orig/drivers/media/i2c/imx219.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/i2c/imx219.c	2021-07-25 16:46:05.698295374 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:121 @
 #define IMX219_PIXEL_ARRAY_WIDTH	3280U
 #define IMX219_PIXEL_ARRAY_HEIGHT	2464U
 
+/* Embedded metadata stream structure */
+#define IMX219_EMBEDDED_LINE_WIDTH 16384
+#define IMX219_NUM_EMBEDDED_LINES 1
+
+enum pad_types {
+	IMAGE_PAD,
+	METADATA_PAD,
+	NUM_PADS
+};
+
 struct imx219_reg {
 	u16 address;
 	u8 val;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:549 @
 
 struct imx219 {
 	struct v4l2_subdev sd;
-	struct media_pad pad;
+	struct media_pad pad[NUM_PADS];
 
 	struct v4l2_mbus_framefmt fmt;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:698 @
 static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
 	struct imx219 *imx219 = to_imx219(sd);
-	struct v4l2_mbus_framefmt *try_fmt =
-		v4l2_subdev_get_try_format(sd, fh->pad, 0);
+	struct v4l2_mbus_framefmt *try_fmt_img =
+		v4l2_subdev_get_try_format(sd, fh->pad, IMAGE_PAD);
+	struct v4l2_mbus_framefmt *try_fmt_meta =
+		v4l2_subdev_get_try_format(sd, fh->pad, METADATA_PAD);
 	struct v4l2_rect *try_crop;
 
 	mutex_lock(&imx219->mutex);
 
-	/* Initialize try_fmt */
-	try_fmt->width = supported_modes[0].width;
-	try_fmt->height = supported_modes[0].height;
-	try_fmt->code = imx219_get_format_code(imx219,
-					       MEDIA_BUS_FMT_SRGGB10_1X10);
-	try_fmt->field = V4L2_FIELD_NONE;
+	/* Initialize try_fmt for the image pad */
+	try_fmt_img->width = supported_modes[0].width;
+	try_fmt_img->height = supported_modes[0].height;
+	try_fmt_img->code = imx219_get_format_code(imx219,
+						   MEDIA_BUS_FMT_SRGGB10_1X10);
+	try_fmt_img->field = V4L2_FIELD_NONE;
+
+	/* Initialize try_fmt for the embedded metadata pad */
+	try_fmt_meta->width = IMX219_EMBEDDED_LINE_WIDTH;
+	try_fmt_meta->height = IMX219_NUM_EMBEDDED_LINES;
+	try_fmt_meta->code = MEDIA_BUS_FMT_SENSOR_DATA;
+	try_fmt_meta->field = V4L2_FIELD_NONE;
 
 	/* Initialize try_crop rectangle. */
 	try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:826 @
 {
 	struct imx219 *imx219 = to_imx219(sd);
 
-	if (code->index >= (ARRAY_SIZE(codes) / 4))
+	if (code->pad >= NUM_PADS)
 		return -EINVAL;
 
-	code->code = imx219_get_format_code(imx219, codes[code->index * 4]);
+	if (code->pad == IMAGE_PAD) {
+		if (code->index >= (ARRAY_SIZE(codes) / 4))
+			return -EINVAL;
+
+		code->code = imx219_get_format_code(imx219,
+						    codes[code->index * 4]);
+	} else {
+		if (code->index > 0)
+			return -EINVAL;
+
+		code->code = MEDIA_BUS_FMT_SENSOR_DATA;
+	}
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:851 @
 {
 	struct imx219 *imx219 = to_imx219(sd);
 
-	if (fse->index >= ARRAY_SIZE(supported_modes))
+	if (fse->pad >= NUM_PADS)
 		return -EINVAL;
 
-	if (fse->code != imx219_get_format_code(imx219, fse->code))
-		return -EINVAL;
+	if (fse->pad == IMAGE_PAD) {
+		if (fse->index >= ARRAY_SIZE(supported_modes))
+			return -EINVAL;
+
+		if (fse->code != imx219_get_format_code(imx219, fse->code))
+			return -EINVAL;
+
+		fse->min_width = supported_modes[fse->index].width;
+		fse->max_width = fse->min_width;
+		fse->min_height = supported_modes[fse->index].height;
+		fse->max_height = fse->min_height;
+	} else {
+		if (fse->code != MEDIA_BUS_FMT_SENSOR_DATA || fse->index > 0)
+			return -EINVAL;
 
-	fse->min_width = supported_modes[fse->index].width;
-	fse->max_width = fse->min_width;
-	fse->min_height = supported_modes[fse->index].height;
-	fse->max_height = fse->min_height;
+		fse->min_width = IMX219_EMBEDDED_LINE_WIDTH;
+		fse->max_width = fse->min_width;
+		fse->min_height = IMX219_NUM_EMBEDDED_LINES;
+		fse->max_height = fse->min_height;
+	}
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:888 @
 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
 }
 
-static void imx219_update_pad_format(struct imx219 *imx219,
-				     const struct imx219_mode *mode,
-				     struct v4l2_subdev_format *fmt)
+static void imx219_update_image_pad_format(struct imx219 *imx219,
+					   const struct imx219_mode *mode,
+					   struct v4l2_subdev_format *fmt)
 {
 	fmt->format.width = mode->width;
 	fmt->format.height = mode->height;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:898 @
 	imx219_reset_colorspace(&fmt->format);
 }
 
+static void imx219_update_metadata_pad_format(struct v4l2_subdev_format *fmt)
+{
+	fmt->format.width = IMX219_EMBEDDED_LINE_WIDTH;
+	fmt->format.height = IMX219_NUM_EMBEDDED_LINES;
+	fmt->format.code = MEDIA_BUS_FMT_SENSOR_DATA;
+	fmt->format.field = V4L2_FIELD_NONE;
+}
+
 static int __imx219_get_pad_format(struct imx219 *imx219,
 				   struct v4l2_subdev_pad_config *cfg,
 				   struct v4l2_subdev_format *fmt)
 {
+	if (fmt->pad >= NUM_PADS)
+		return -EINVAL;
+
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 		struct v4l2_mbus_framefmt *try_fmt =
 			v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad);
 		/* update the code which could change due to vflip or hflip: */
-		try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
+		try_fmt->code = fmt->pad == IMAGE_PAD ?
+				imx219_get_format_code(imx219, try_fmt->code) :
+				MEDIA_BUS_FMT_SENSOR_DATA;
 		fmt->format = *try_fmt;
 	} else {
-		imx219_update_pad_format(imx219, imx219->mode, fmt);
-		fmt->format.code = imx219_get_format_code(imx219,
-							  imx219->fmt.code);
+		if (fmt->pad == IMAGE_PAD) {
+			imx219_update_image_pad_format(imx219, imx219->mode,
+						       fmt);
+			fmt->format.code = imx219_get_format_code(imx219,
+							      imx219->fmt.code);
+		} else {
+			imx219_update_metadata_pad_format(fmt);
+		}
 	}
 
 	return 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:959 @
 	int exposure_max, exposure_def, hblank;
 	unsigned int i;
 
-	mutex_lock(&imx219->mutex);
-
-	for (i = 0; i < ARRAY_SIZE(codes); i++)
-		if (codes[i] == fmt->format.code)
-			break;
-	if (i >= ARRAY_SIZE(codes))
-		i = 0;
+	if (fmt->pad >= NUM_PADS)
+		return -EINVAL;
 
-	/* Bayer order varies with flips */
-	fmt->format.code = imx219_get_format_code(imx219, codes[i]);
+	mutex_lock(&imx219->mutex);
 
-	mode = v4l2_find_nearest_size(supported_modes,
-				      ARRAY_SIZE(supported_modes),
-				      width, height,
-				      fmt->format.width, fmt->format.height);
-	imx219_update_pad_format(imx219, mode, fmt);
-	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-		framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
-		*framefmt = fmt->format;
-	} else if (imx219->mode != mode ||
-		   imx219->fmt.code != fmt->format.code) {
-		imx219->fmt = fmt->format;
-		imx219->mode = mode;
-		/* Update limits and set FPS to default */
-		__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
-					 IMX219_VTS_MAX - mode->height, 1,
-					 mode->vts_def - mode->height);
-		__v4l2_ctrl_s_ctrl(imx219->vblank,
-				   mode->vts_def - mode->height);
-		/* Update max exposure while meeting expected vblanking */
-		exposure_max = mode->vts_def - 4;
-		exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
-			exposure_max : IMX219_EXPOSURE_DEFAULT;
-		__v4l2_ctrl_modify_range(imx219->exposure,
-					 imx219->exposure->minimum,
-					 exposure_max, imx219->exposure->step,
-					 exposure_def);
-		/*
-		 * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
-		 * depends on mode->width only, and is not changeble in any
-		 * way other than changing the mode.
-		 */
-		hblank = IMX219_PPL_DEFAULT - mode->width;
-		__v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
-					 hblank);
+	if (fmt->pad == IMAGE_PAD) {
+		for (i = 0; i < ARRAY_SIZE(codes); i++)
+			if (codes[i] == fmt->format.code)
+				break;
+		if (i >= ARRAY_SIZE(codes))
+			i = 0;
+
+		/* Bayer order varies with flips */
+		fmt->format.code = imx219_get_format_code(imx219, codes[i]);
+
+		mode = v4l2_find_nearest_size(supported_modes,
+					      ARRAY_SIZE(supported_modes),
+					      width, height,
+					      fmt->format.width,
+					      fmt->format.height);
+		imx219_update_image_pad_format(imx219, mode, fmt);
+		if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+			framefmt = v4l2_subdev_get_try_format(sd, cfg,
+							      fmt->pad);
+			*framefmt = fmt->format;
+		} else if (imx219->mode != mode ||
+			imx219->fmt.code != fmt->format.code) {
+			imx219->fmt = fmt->format;
+			imx219->mode = mode;
+			/* Update limits and set FPS to default */
+			__v4l2_ctrl_modify_range(imx219->vblank,
+						 IMX219_VBLANK_MIN,
+						 IMX219_VTS_MAX - mode->height,
+						 1,
+						 mode->vts_def - mode->height);
+			__v4l2_ctrl_s_ctrl(imx219->vblank,
+					   mode->vts_def - mode->height);
+			/*
+			 * Update max exposure while meeting
+			 * expected vblanking
+			 */
+			exposure_max = mode->vts_def - 4;
+			exposure_def =
+				(exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+					exposure_max : IMX219_EXPOSURE_DEFAULT;
+			__v4l2_ctrl_modify_range(imx219->exposure,
+						 imx219->exposure->minimum,
+						 exposure_max,
+						 imx219->exposure->step,
+						 exposure_def);
+			/*
+			 * Currently PPL is fixed to IMX219_PPL_DEFAULT, so
+			 * hblank depends on mode->width only, and is not
+			 * changeble in any way other than changing the mode.
+			 */
+			hblank = IMX219_PPL_DEFAULT - mode->width;
+			__v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank,
+						 1, hblank);
+		}
+	} else {
+		if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+			framefmt = v4l2_subdev_get_try_format(sd, cfg,
+							      fmt->pad);
+			*framefmt = fmt->format;
+		} else {
+			/* Only one embedded data mode is supported */
+			imx219_update_metadata_pad_format(fmt);
+		}
 	}
 
 	mutex_unlock(&imx219->mutex);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1594 @
 
 	/* Initialize subdev */
 	imx219->sd.internal_ops = &imx219_internal_ops;
-	imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+			    V4L2_SUBDEV_FL_HAS_EVENTS;
 	imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
 
-	/* Initialize source pad */
-	imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
+	/* Initialize source pads */
+	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, 1, &imx219->pad);
+	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);
 		goto error_handler_free;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/imx290.c linux-5.10.52-v7l+/drivers/media/i2c/imx290.c
--- linux-5.10.52-orig/drivers/media/i2c/imx290.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/i2c/imx290.c	2021-07-25 16:46:05.698295374 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Sony IMX290 CMOS Image Sensor Driver
+ * Sony IMX290 & IMX327 CMOS Image Sensor Driver
+ *
+ * The IMX290 and IMX327 are very similar 1920x1080 1/2.8 CMOS image sensors.
+ * IMX327 can support up to 60fps, whilst IMX290 can support up to 120fps, but
+ * only 10bit and when connected over 4 CSI-2 lanes.
+ * The modules don't appear to have a mechanism to identify whether the mono or
+ * colour variant is connected, therefore it is done via compatible string.
  *
  * Copyright (C) 2019 FRAMOS GmbH.
  *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:22 @
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:32 @
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-subdev.h>
 
+enum imx290_clk_index {
+	CLK_37_125,
+	CLK_74_25,
+};
+
 #define IMX290_STANDBY 0x3000
 #define IMX290_REGHOLD 0x3001
 #define IMX290_XMSTA 0x3002
+#define IMX290_FLIP_WINMODE 0x3007
 #define IMX290_FR_FDG_SEL 0x3009
 #define IMX290_BLKLEVEL_LOW 0x300a
 #define IMX290_BLKLEVEL_HIGH 0x300b
 #define IMX290_GAIN 0x3014
+#define IMX290_VMAX_LOW 0x3018
+#define IMX290_VMAX_MAX 0x3fff
 #define IMX290_HMAX_LOW 0x301c
 #define IMX290_HMAX_HIGH 0x301d
+#define IMX290_HMAX_MIN 2200 /* Min of 2200 pixels = 60fps */
+#define IMX290_HMAX_MAX 0xffff
+
+#define IMX290_EXPOSURE_MIN 1
+#define IMX290_EXPOSURE_STEP 1
+#define IMX290_EXPOSURE_LOW 0x3020
 #define IMX290_PGCTRL 0x308c
 #define IMX290_PHY_LANE_NUM 0x3407
 #define IMX290_CSI_LANE_MODE 0x3443
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:63 @
 #define IMX290_PGCTRL_THRU BIT(1)
 #define IMX290_PGCTRL_MODE(n) ((n) << 4)
 
+#define IMX290_NATIVE_WIDTH		1945U
+#define IMX290_NATIVE_HEIGHT		1109U
+#define IMX290_PIXEL_ARRAY_LEFT		4U
+#define IMX290_PIXEL_ARRAY_TOP		12U
+#define IMX290_PIXEL_ARRAY_WIDTH	1937U
+#define IMX290_PIXEL_ARRAY_HEIGHT	1097U
+
 static const char * const imx290_supply_name[] = {
 	"vdda",
 	"vddd",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:87 @
 	u32 width;
 	u32 height;
 	u32 hmax;
+	u32 vmax;
 	u8 link_freq_index;
+	struct v4l2_rect crop;
+
+	const struct imx290_regval *mode_data;
+	u32 mode_data_size;
+	const struct imx290_regval *lane_data;
+	u32 lane_data_size;
+
 
-	const struct imx290_regval *data;
-	u32 data_size;
+	/* Clock setup can vary. Index as enum imx290_clk_index */
+	const struct imx290_regval *clk_data[2];
+	u32 clk_size;
 };
 
 struct imx290 {
 	struct device *dev;
 	struct clk *xclk;
+	u32 xclk_freq;
 	struct regmap *regmap;
 	u8 nlanes;
 	u8 bpp;
+	u16 hmax_min;
+
+	const struct imx290_pixfmt *formats;
 
 	struct v4l2_subdev sd;
 	struct media_pad pad;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:124 @
 	struct v4l2_ctrl_handler ctrls;
 	struct v4l2_ctrl *link_freq;
 	struct v4l2_ctrl *pixel_rate;
+	struct v4l2_ctrl *hblank;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *exposure;
 
 	struct mutex lock;
 };
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:138 @
 	u8 bpp;
 };
 
-static const struct imx290_pixfmt imx290_formats[] = {
+#define IMX290_NUM_FORMATS 2
+
+static const struct imx290_pixfmt imx290_colour_formats[IMX290_NUM_FORMATS] = {
 	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
 	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
 };
 
+static const struct imx290_pixfmt imx290_mono_formats[IMX290_NUM_FORMATS] = {
+	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
+	{ MEDIA_BUS_FMT_Y12_1X12, 12 },
+};
+
 static const struct regmap_config imx290_regmap_config = {
 	.reg_bits = 16,
 	.val_bits = 8,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:169 @
 
 static const struct imx290_regval imx290_global_init_settings[] = {
 	{ 0x3007, 0x00 },
-	{ 0x3018, 0x65 },
-	{ 0x3019, 0x04 },
 	{ 0x301a, 0x00 },
-	{ 0x3444, 0x20 },
-	{ 0x3445, 0x25 },
 	{ 0x303a, 0x0c },
 	{ 0x3040, 0x00 },
 	{ 0x3041, 0x00 },
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:223 @
 	{ 0x33b3, 0x04 },
 };
 
-static const struct imx290_regval imx290_1080p_settings[] = {
+static const struct imx290_regval imx290_37_125mhz_clock_1080p[] = {
+	{ 0x305c, 0x18 },
+	{ 0x305d, 0x03 },
+	{ 0x305e, 0x20 },
+	{ 0x305f, 0x01 },
+	{ 0x315e, 0x1a },
+	{ 0x3164, 0x1a },
+	{ 0x3444, 0x20 },
+	{ 0x3445, 0x25 },
+	{ 0x3480, 0x49 },
+};
+
+static const struct imx290_regval imx290_74_250mhz_clock_1080p[] = {
+	{ 0x305c, 0x0c },
+	{ 0x305d, 0x03 },
+	{ 0x305e, 0x10 },
+	{ 0x305f, 0x01 },
+	{ 0x315e, 0x1b },
+	{ 0x3164, 0x1b },
+	{ 0x3444, 0x40 },
+	{ 0x3445, 0x4a },
+	{ 0x3480, 0x92 },
+};
+
+static const struct imx290_regval imx290_1080p_common_settings[] = {
 	/* mode settings */
+	{ IMX290_FR_FDG_SEL, 0x01 },
 	{ 0x3007, 0x00 },
 	{ 0x303a, 0x0c },
 	{ 0x3414, 0x0a },
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:259 @
 	{ 0x3419, 0x04 },
 	{ 0x3012, 0x64 },
 	{ 0x3013, 0x00 },
-	{ 0x305c, 0x18 },
-	{ 0x305d, 0x03 },
-	{ 0x305e, 0x20 },
-	{ 0x305f, 0x01 },
-	{ 0x315e, 0x1a },
-	{ 0x3164, 0x1a },
-	{ 0x3480, 0x49 },
+};
+
+static const struct imx290_regval imx290_1080p_2lane_settings[] = {
+	{ 0x3405, 0x00 },
 	/* data rate settings */
+	{ IMX290_PHY_LANE_NUM, 0x01 },
+	{ IMX290_CSI_LANE_MODE, 0x01 },
+	{ 0x3446, 0x77 },
+	{ 0x3447, 0x00 },
+	{ 0x3448, 0x67 },
+	{ 0x3449, 0x00 },
+	{ 0x344a, 0x47 },
+	{ 0x344b, 0x00 },
+	{ 0x344c, 0x37 },
+	{ 0x344d, 0x00 },
+	{ 0x344e, 0x3f },
+	{ 0x344f, 0x00 },
+	{ 0x3450, 0xff },
+	{ 0x3451, 0x00 },
+	{ 0x3452, 0x3f },
+	{ 0x3453, 0x00 },
+	{ 0x3454, 0x37 },
+	{ 0x3455, 0x00 },
+};
+
+static const struct imx290_regval imx290_1080p_4lane_settings[] = {
 	{ 0x3405, 0x10 },
+	/* data rate settings */
+	{ IMX290_PHY_LANE_NUM, 0x03 },
+	{ IMX290_CSI_LANE_MODE, 0x03 },
 	{ 0x3446, 0x57 },
 	{ 0x3447, 0x00 },
 	{ 0x3448, 0x37 },
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:307 @
 	{ 0x3455, 0x00 },
 };
 
-static const struct imx290_regval imx290_720p_settings[] = {
+static const struct imx290_regval imx290_37_125mhz_clock_720p[] = {
+	{ 0x305c, 0x20 },
+	{ 0x305d, 0x00 },
+	{ 0x305e, 0x20 },
+	{ 0x305f, 0x01 },
+	{ 0x315e, 0x1a },
+	{ 0x3164, 0x1a },
+	{ 0x3444, 0x20 },
+	{ 0x3445, 0x25 },
+	{ 0x3480, 0x49 },
+};
+
+static const struct imx290_regval imx290_74_250mhz_clock_720p[] = {
+	{ 0x305c, 0x10 },
+	{ 0x305d, 0x00 },
+	{ 0x305e, 0x10 },
+	{ 0x305f, 0x01 },
+	{ 0x315e, 0x1b },
+	{ 0x3164, 0x1b },
+	{ 0x3444, 0x40 },
+	{ 0x3445, 0x4a },
+	{ 0x3480, 0x92 },
+};
+
+static const struct imx290_regval imx290_720p_common_settings[] = {
 	/* mode settings */
+	{ IMX290_FR_FDG_SEL, 0x01 },
 	{ 0x3007, 0x10 },
 	{ 0x303a, 0x06 },
 	{ 0x3414, 0x04 },
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:343 @
 	{ 0x3419, 0x02 },
 	{ 0x3012, 0x64 },
 	{ 0x3013, 0x00 },
-	{ 0x305c, 0x20 },
-	{ 0x305d, 0x00 },
-	{ 0x305e, 0x20 },
-	{ 0x305f, 0x01 },
-	{ 0x315e, 0x1a },
-	{ 0x3164, 0x1a },
-	{ 0x3480, 0x49 },
+};
+
+static const struct imx290_regval imx290_720p_2lane_settings[] = {
+	{ 0x3405, 0x00 },
+	{ IMX290_PHY_LANE_NUM, 0x01 },
+	{ IMX290_CSI_LANE_MODE, 0x01 },
 	/* data rate settings */
+	{ 0x3446, 0x67 },
+	{ 0x3447, 0x00 },
+	{ 0x3448, 0x57 },
+	{ 0x3449, 0x00 },
+	{ 0x344a, 0x2f },
+	{ 0x344b, 0x00 },
+	{ 0x344c, 0x27 },
+	{ 0x344d, 0x00 },
+	{ 0x344e, 0x2f },
+	{ 0x344f, 0x00 },
+	{ 0x3450, 0xbf },
+	{ 0x3451, 0x00 },
+	{ 0x3452, 0x2f },
+	{ 0x3453, 0x00 },
+	{ 0x3454, 0x27 },
+	{ 0x3455, 0x00 },
+};
+
+static const struct imx290_regval imx290_720p_4lane_settings[] = {
 	{ 0x3405, 0x10 },
+	{ IMX290_PHY_LANE_NUM, 0x03 },
+	{ IMX290_CSI_LANE_MODE, 0x03 },
+	/* data rate settings */
 	{ 0x3446, 0x4f },
 	{ 0x3447, 0x00 },
 	{ 0x3448, 0x2f },
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:452 @
 	{
 		.width = 1920,
 		.height = 1080,
-		.hmax = 0x1130,
+		.hmax = 0x0898,
+		.vmax = 0x0465,
 		.link_freq_index = FREQ_INDEX_1080P,
-		.data = imx290_1080p_settings,
-		.data_size = ARRAY_SIZE(imx290_1080p_settings),
+		.crop = {
+			.left = 4 + 8,
+			.top = 12 + 8,
+			.width = 1920,
+			.height = 1080,
+		},
+		.mode_data = imx290_1080p_common_settings,
+		.mode_data_size = ARRAY_SIZE(imx290_1080p_common_settings),
+		.lane_data = imx290_1080p_2lane_settings,
+		.lane_data_size = ARRAY_SIZE(imx290_1080p_2lane_settings),
+		.clk_data = {
+			[CLK_37_125] = imx290_37_125mhz_clock_1080p,
+			[CLK_74_25] = imx290_74_250mhz_clock_1080p,
+		},
+		.clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_1080p),
 	},
 	{
 		.width = 1280,
 		.height = 720,
-		.hmax = 0x19c8,
+		.hmax = 0x0ce4,
+		.vmax = 0x02ee,
 		.link_freq_index = FREQ_INDEX_720P,
-		.data = imx290_720p_settings,
-		.data_size = ARRAY_SIZE(imx290_720p_settings),
+		.crop = {
+			.left = 4 + 8 + 320,
+			.top = 12 + 8 + 180,
+			.width = 1280,
+			.height = 720,
+		},
+		.mode_data = imx290_720p_common_settings,
+		.mode_data_size = ARRAY_SIZE(imx290_720p_common_settings),
+		.lane_data = imx290_720p_2lane_settings,
+		.lane_data_size = ARRAY_SIZE(imx290_720p_2lane_settings),
+		.clk_data = {
+			[CLK_37_125] = imx290_37_125mhz_clock_720p,
+			[CLK_74_25] = imx290_74_250mhz_clock_720p,
+		},
+		.clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_720p),
 	},
 };
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:500 @
 		.width = 1920,
 		.height = 1080,
 		.hmax = 0x0898,
+		.vmax = 0x0465,
 		.link_freq_index = FREQ_INDEX_1080P,
-		.data = imx290_1080p_settings,
-		.data_size = ARRAY_SIZE(imx290_1080p_settings),
+		.crop = {
+			.left = 4 + 8,
+			.top = 12 + 8,
+			.width = 1920,
+			.height = 1080,
+		},
+		.mode_data = imx290_1080p_common_settings,
+		.mode_data_size = ARRAY_SIZE(imx290_1080p_common_settings),
+		.lane_data = imx290_1080p_4lane_settings,
+		.lane_data_size = ARRAY_SIZE(imx290_1080p_4lane_settings),
+		.clk_data = {
+			[CLK_37_125] = imx290_37_125mhz_clock_1080p,
+			[CLK_74_25] = imx290_74_250mhz_clock_1080p,
+		},
+		.clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_1080p),
 	},
 	{
 		.width = 1280,
 		.height = 720,
 		.hmax = 0x0ce4,
+		.vmax = 0x02ee,
 		.link_freq_index = FREQ_INDEX_720P,
-		.data = imx290_720p_settings,
-		.data_size = ARRAY_SIZE(imx290_720p_settings),
+		.crop = {
+			.left = 4 + 8 + 320,
+			.top = 12 + 8 + 180,
+			.width = 1280,
+			.height = 720,
+		},
+		.mode_data = imx290_720p_common_settings,
+		.mode_data_size = ARRAY_SIZE(imx290_720p_common_settings),
+		.lane_data = imx290_720p_4lane_settings,
+		.lane_data_size = ARRAY_SIZE(imx290_720p_4lane_settings),
+		.clk_data = {
+			[CLK_37_125] = imx290_37_125mhz_clock_720p,
+			[CLK_74_25] = imx290_74_250mhz_clock_720p,
+		},
+		.clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_720p),
 	},
 };
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:652 @
 	return ret;
 }
 
+static int imx290_set_exposure(struct imx290 *imx290, u32 value)
+{
+	u32 exposure = (imx290->current_mode->height + imx290->vblank->val) -
+						value - 1;
+	int ret;
+
+	ret = imx290_write_buffered_reg(imx290, IMX290_EXPOSURE_LOW, 3,
+					exposure);
+	if (ret)
+		dev_err(imx290->dev, "Unable to write exposure\n");
+
+	return ret;
+}
+
+static int imx290_set_hmax(struct imx290 *imx290, u32 val)
+{
+	u32 hmax = val + imx290->current_mode->width;
+	int ret;
+
+	ret = imx290_write_buffered_reg(imx290, IMX290_HMAX_LOW, 2,
+					hmax);
+	if (ret)
+		dev_err(imx290->dev, "Error setting HMAX register\n");
+
+	return ret;
+}
+
+static int imx290_set_vmax(struct imx290 *imx290, u32 val)
+{
+	u32 vmax = val + imx290->current_mode->height;
+	int ret;
+
+	ret = imx290_write_buffered_reg(imx290, IMX290_VMAX_LOW, 3,
+					vmax);
+	if (ret)
+		dev_err(imx290->dev, "Unable to write vmax\n");
+
+	/*
+	 * Changing vblank changes the allowed range for exposure.
+	 * We don't supply the current exposure as default here as it
+	 * may lie outside the new range. We will reset it just below.
+	 */
+	__v4l2_ctrl_modify_range(imx290->exposure,
+				 IMX290_EXPOSURE_MIN,
+				 vmax - 2,
+				 IMX290_EXPOSURE_STEP,
+				 vmax - 2);
+
+	/*
+	 * Becuse of the way exposure works for this sensor, updating
+	 * vblank causes the effective exposure to change, so we must
+	 * set it back to the "new" correct value.
+	 */
+	imx290_set_exposure(imx290, imx290->exposure->val);
+
+	return ret;
+}
+
 /* Stop streaming */
 static int imx290_stop_streaming(struct imx290 *imx290)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:729 @
 	struct imx290 *imx290 = container_of(ctrl->handler,
 					     struct imx290, ctrls);
 	int ret = 0;
+	u8 val;
 
 	/* V4L2 controls values will be applied only when power is already up */
 	if (!pm_runtime_get_if_in_use(imx290->dev))
 		return 0;
 
 	switch (ctrl->id) {
-	case V4L2_CID_GAIN:
+	case V4L2_CID_ANALOGUE_GAIN:
 		ret = imx290_set_gain(imx290, ctrl->val);
 		break;
+	case V4L2_CID_EXPOSURE:
+		ret = imx290_set_exposure(imx290, ctrl->val);
+		break;
+	case V4L2_CID_HBLANK:
+		ret = imx290_set_hmax(imx290, ctrl->val);
+		break;
+	case V4L2_CID_VBLANK:
+		ret = imx290_set_vmax(imx290, ctrl->val);
+		break;
+	case V4L2_CID_HFLIP:
+	case V4L2_CID_VFLIP:
+		/* WINMODE is in bits [6:4], so need to read-modify-write */
+		ret = imx290_read_reg(imx290, IMX290_FLIP_WINMODE, &val);
+		if (ret)
+			break;
+		val &= ~0x03;
+		val |= imx290->vflip->val | (imx290->hflip->val << 1);
+		ret = imx290_write_reg(imx290, IMX290_FLIP_WINMODE, val);
+		break;
 	case V4L2_CID_TEST_PATTERN:
 		if (ctrl->val) {
 			imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:797 @
 				 struct v4l2_subdev_pad_config *cfg,
 				 struct v4l2_subdev_mbus_code_enum *code)
 {
-	if (code->index >= ARRAY_SIZE(imx290_formats))
+	const struct imx290 *imx290 = to_imx290(sd);
+
+	if (code->index >= IMX290_NUM_FORMATS)
 		return -EINVAL;
 
-	code->code = imx290_formats[code->index].code;
+	code->code = imx290->formats[code->index].code;
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:814 @
 	const struct imx290 *imx290 = to_imx290(sd);
 	const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290);
 
-	if ((fse->code != imx290_formats[0].code) &&
-	    (fse->code != imx290_formats[1].code))
+	if (fse->code != imx290->formats[0].code &&
+	    fse->code != imx290->formats[1].code)
 		return -EINVAL;
 
 	if (fse->index >= imx290_modes_num(imx290))
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:856 @
 	return imx290->current_mode->link_freq_index;
 }
 
-static s64 imx290_get_link_freq(struct imx290 *imx290)
-{
-	u8 index = imx290_get_link_freq_index(imx290);
-
-	return *(imx290_link_freqs_ptr(imx290) + index);
-}
-
 static u64 imx290_calc_pixel_rate(struct imx290 *imx290)
 {
-	s64 link_freq = imx290_get_link_freq(imx290);
-	u8 nlanes = imx290->nlanes;
-	u64 pixel_rate;
-
-	/* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
-	pixel_rate = link_freq * 2 * nlanes;
-	do_div(pixel_rate, imx290->bpp);
-	return pixel_rate;
+	return 148500000;
 }
 
 static int imx290_set_fmt(struct v4l2_subdev *sd,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:879 @
 	fmt->format.width = mode->width;
 	fmt->format.height = mode->height;
 
-	for (i = 0; i < ARRAY_SIZE(imx290_formats); i++)
-		if (imx290_formats[i].code == fmt->format.code)
+	for (i = 0; i < IMX290_NUM_FORMATS; i++)
+		if (imx290->formats[i].code == fmt->format.code)
 			break;
 
-	if (i >= ARRAY_SIZE(imx290_formats))
+	if (i >= IMX290_NUM_FORMATS)
 		i = 0;
 
-	fmt->format.code = imx290_formats[i].code;
+	fmt->format.code = imx290->formats[i].code;
 	fmt->format.field = V4L2_FIELD_NONE;
+	fmt->format.colorspace = V4L2_COLORSPACE_SRGB;
+	fmt->format.ycbcr_enc =
+			V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->format.colorspace);
+	fmt->format.quantization =
+		V4L2_MAP_QUANTIZATION_DEFAULT(true, fmt->format.colorspace,
+					      fmt->format.ycbcr_enc);
+	fmt->format.xfer_func =
+		V4L2_MAP_XFER_FUNC_DEFAULT(fmt->format.colorspace);
 
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 		format = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
 	} else {
 		format = &imx290->current_format;
 		imx290->current_mode = mode;
-		imx290->bpp = imx290_formats[i].bpp;
+		imx290->bpp = imx290->formats[i].bpp;
 
 		if (imx290->link_freq)
 			__v4l2_ctrl_s_ctrl(imx290->link_freq,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:910 @
 		if (imx290->pixel_rate)
 			__v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate,
 						 imx290_calc_pixel_rate(imx290));
+
+		if (imx290->hblank) {
+			__v4l2_ctrl_modify_range(imx290->hblank,
+						 imx290->hmax_min - mode->width,
+						 IMX290_HMAX_MAX - mode->width,
+						 1, mode->hmax - mode->width);
+			__v4l2_ctrl_s_ctrl(imx290->hblank,
+					   mode->hmax - mode->width);
+		}
+		if (imx290->vblank) {
+			__v4l2_ctrl_modify_range(imx290->vblank,
+						 mode->vmax - mode->height,
+						 IMX290_VMAX_MAX - mode->height,
+						 1,
+						 mode->vmax - mode->height);
+			__v4l2_ctrl_s_ctrl(imx290->vblank,
+					   mode->vmax - mode->height);
+		}
+		if (imx290->exposure)
+			__v4l2_ctrl_modify_range(imx290->exposure,
+						 IMX290_EXPOSURE_MIN,
+						 mode->vmax - 2,
+						 IMX290_EXPOSURE_STEP,
+						 mode->vmax - 2);
 	}
 
 	*format = fmt->format;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:963 @
 
 	switch (imx290->current_format.code) {
 	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_Y10_1X10:
 		ret = imx290_set_register_array(imx290, imx290_10bit_settings,
 						ARRAY_SIZE(
 							imx290_10bit_settings));
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:973 @
 		}
 		break;
 	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_Y12_1X12:
 		ret = imx290_set_register_array(imx290, imx290_12bit_settings,
 						ARRAY_SIZE(
 							imx290_12bit_settings));
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:990 @
 	return 0;
 }
 
-static int imx290_set_hmax(struct imx290 *imx290, u32 val)
+static const struct v4l2_rect *
+__imx290_get_pad_crop(struct imx290 *imx290, struct v4l2_subdev_pad_config *cfg,
+		      unsigned int pad, enum v4l2_subdev_format_whence which)
 {
-	int ret;
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(&imx290->sd, cfg, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &imx290->current_mode->crop;
+	}
 
-	ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (val & 0xff));
-	if (ret) {
-		dev_err(imx290->dev, "Error setting HMAX register\n");
-		return ret;
+	return NULL;
+}
+
+static int imx290_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_selection *sel)
+{
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP: {
+		struct imx290 *imx290 = to_imx290(sd);
+
+		mutex_lock(&imx290->lock);
+		sel->r = *__imx290_get_pad_crop(imx290, cfg, sel->pad,
+						sel->which);
+		mutex_unlock(&imx290->lock);
+
+		return 0;
 	}
 
-	ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((val >> 8) & 0xff));
-	if (ret) {
-		dev_err(imx290->dev, "Error setting HMAX register\n");
-		return ret;
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+		sel->r.top = 0;
+		sel->r.left = 0;
+		sel->r.width = IMX290_NATIVE_WIDTH;
+		sel->r.height = IMX290_NATIVE_HEIGHT;
+
+		return 0;
+
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.top = IMX290_PIXEL_ARRAY_TOP;
+		sel->r.left = IMX290_PIXEL_ARRAY_LEFT;
+		sel->r.width = IMX290_PIXEL_ARRAY_WIDTH;
+		sel->r.height = IMX290_PIXEL_ARRAY_HEIGHT;
+
+		return 0;
 	}
 
-	return 0;
+	return -EINVAL;
 }
 
 /* Start streaming */
 static int imx290_start_streaming(struct imx290 *imx290)
 {
+	enum imx290_clk_index clk_idx = imx290->xclk_freq == 37125000 ?
+					CLK_37_125 : CLK_74_25;
 	int ret;
 
 	/* Set init register settings */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1057 @
 		return ret;
 	}
 
+	ret = imx290_set_register_array(imx290,
+					imx290->current_mode->clk_data[clk_idx],
+					imx290->current_mode->clk_size);
+	if (ret < 0) {
+		dev_err(imx290->dev, "Could not set clock registers\n");
+		return ret;
+	}
+
 	/* Apply the register values related to current frame format */
 	ret = imx290_write_current_format(imx290);
 	if (ret < 0) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1073 @
 	}
 
 	/* Apply default values of current mode */
-	ret = imx290_set_register_array(imx290, imx290->current_mode->data,
-					imx290->current_mode->data_size);
+	ret = imx290_set_register_array(imx290,
+					imx290->current_mode->mode_data,
+					imx290->current_mode->mode_data_size);
 	if (ret < 0) {
 		dev_err(imx290->dev, "Could not set current mode\n");
 		return ret;
 	}
-	ret = imx290_set_hmax(imx290, imx290->current_mode->hmax);
-	if (ret < 0)
+
+	/* Apply lane config registers of current mode */
+	ret = imx290_set_register_array(imx290,
+					imx290->current_mode->lane_data,
+					imx290->current_mode->lane_data_size);
+	if (ret < 0) {
+		dev_err(imx290->dev, "Could not set current mode\n");
 		return ret;
+	}
 
 	/* Apply customized values from user */
 	ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1129 @
 		imx290_stop_streaming(imx290);
 		pm_runtime_put(imx290->dev);
 	}
+	/* vflip and hflip cannot change during streaming */
+	__v4l2_ctrl_grab(imx290->vflip, enable);
+	__v4l2_ctrl_grab(imx290->hflip, enable);
 
 unlock_and_return:
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1149 @
 				       imx290->supplies);
 }
 
-static int imx290_set_data_lanes(struct imx290 *imx290)
-{
-	int ret = 0, laneval, frsel;
-
-	switch (imx290->nlanes) {
-	case 2:
-		laneval = 0x01;
-		frsel = 0x02;
-		break;
-	case 4:
-		laneval = 0x03;
-		frsel = 0x01;
-		break;
-	default:
-		/*
-		 * We should never hit this since the data lane count is
-		 * validated in probe itself
-		 */
-		dev_err(imx290->dev, "Lane configuration not supported\n");
-		ret = -EINVAL;
-		goto exit;
-	}
-
-	ret = imx290_write_reg(imx290, IMX290_PHY_LANE_NUM, laneval);
-	if (ret) {
-		dev_err(imx290->dev, "Error setting Physical Lane number register\n");
-		goto exit;
-	}
-
-	ret = imx290_write_reg(imx290, IMX290_CSI_LANE_MODE, laneval);
-	if (ret) {
-		dev_err(imx290->dev, "Error setting CSI Lane mode register\n");
-		goto exit;
-	}
-
-	ret = imx290_write_reg(imx290, IMX290_FR_FDG_SEL, frsel);
-	if (ret)
-		dev_err(imx290->dev, "Error setting FR/FDG SEL register\n");
-
-exit:
-	return ret;
-}
-
 static int imx290_power_on(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1173 @
 	gpiod_set_value_cansleep(imx290->rst_gpio, 0);
 	usleep_range(30000, 31000);
 
-	/* Set data lane count */
-	imx290_set_data_lanes(imx290);
-
 	return 0;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1203 @
 	.enum_frame_size = imx290_enum_frame_size,
 	.get_fmt = imx290_get_fmt,
 	.set_fmt = imx290_set_fmt,
+	.get_selection = imx290_get_selection,
 };
 
 static const struct v4l2_subdev_ops imx290_subdev_ops = {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1237 @
 	return 0;
 }
 
+static const struct of_device_id imx290_of_match[] = {
+	{ .compatible = "sony,imx290", .data = imx290_colour_formats },
+	{ .compatible = "sony,imx290-mono", .data = imx290_mono_formats },
+	{ /* sentinel */ }
+};
+
 static int imx290_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1251 @
 	struct v4l2_fwnode_endpoint ep = {
 		.bus_type = V4L2_MBUS_CSI2_DPHY
 	};
+	const struct of_device_id *match;
+	const struct imx290_mode *mode;
 	struct imx290 *imx290;
-	u32 xclk_freq;
 	s64 fq;
 	int ret;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1268 @
 		return -ENODEV;
 	}
 
+	match = of_match_device(imx290_of_match, dev);
+	if (!match)
+		return -ENODEV;
+	imx290->formats = (const struct imx290_pixfmt *)match->data;
+
 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
 	if (!endpoint) {
 		dev_err(dev, "Endpoint node not found\n");
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1296 @
 		ret = -EINVAL;
 		goto free_err;
 	}
+	imx290->hmax_min = IMX290_HMAX_MIN;
 
 	dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1323 @
 	}
 
 	ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
-				       &xclk_freq);
+				       &imx290->xclk_freq);
 	if (ret) {
 		dev_err(dev, "Could not get xclk frequency\n");
 		goto free_err;
 	}
 
 	/* external clock must be 37.125 MHz */
-	if (xclk_freq != 37125000) {
+	if (imx290->xclk_freq != 37125000 && imx290->xclk_freq != 74250000) {
 		dev_err(dev, "External clock frequency %u is not supported\n",
-			xclk_freq);
+			imx290->xclk_freq);
 		ret = -EINVAL;
 		goto free_err;
 	}
 
-	ret = clk_set_rate(imx290->xclk, xclk_freq);
+	ret = clk_set_rate(imx290->xclk, imx290->xclk_freq);
 	if (ret) {
 		dev_err(dev, "Could not set xclk frequency\n");
 		goto free_err;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1366 @
 	 */
 	imx290_entity_init_cfg(&imx290->sd, NULL);
 
-	v4l2_ctrl_handler_init(&imx290->ctrls, 4);
+	v4l2_ctrl_handler_init(&imx290->ctrls, 9);
 
 	v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
-			  V4L2_CID_GAIN, 0, 72, 1, 0);
+			  V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0);
+
+	mode = imx290->current_mode;
+	imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+					   V4L2_CID_HBLANK,
+					   imx290->hmax_min - mode->width,
+					   IMX290_HMAX_MAX - mode->width, 1,
+					   mode->hmax - mode->width);
+
+	imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+					   V4L2_CID_VBLANK,
+					   mode->vmax - mode->height,
+					   IMX290_VMAX_MAX - mode->height, 1,
+					   mode->vmax - mode->height);
+
+	imx290->exposure = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+					     V4L2_CID_EXPOSURE,
+					     IMX290_EXPOSURE_MIN,
+					     mode->vmax - 2,
+					     IMX290_EXPOSURE_STEP,
+					     mode->vmax - 2);
+
+	imx290->hflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+					  V4L2_CID_HFLIP, 0, 1, 1, 0);
+	imx290->vflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+					  V4L2_CID_VFLIP, 0, 1, 1, 0);
 
 	imx290->link_freq =
 		v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1436 @
 		goto free_ctrl;
 	}
 
+	/* Initialize the frame format (this also sets imx290->current_mode) */
+	imx290_entity_init_cfg(&imx290->sd, NULL);
+
 	ret = v4l2_async_register_subdev(&imx290->sd);
 	if (ret < 0) {
 		dev_err(dev, "Could not register v4l2 device\n");
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1490 @
 	return 0;
 }
 
-static const struct of_device_id imx290_of_match[] = {
-	{ .compatible = "sony,imx290" },
-	{ /* sentinel */ }
-};
 MODULE_DEVICE_TABLE(of, imx290_of_match);
 
 static struct i2c_driver imx290_i2c_driver = {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/imx477.c linux-5.10.52-v7l+/drivers/media/i2c/imx477.c
--- linux-5.10.52-orig/drivers/media/i2c/imx477.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/media/i2c/imx477.c	2021-07-25 16:46:05.698295374 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A V4L2 driver for Sony IMX477 cameras.
+ * Copyright (C) 2020, Raspberry Pi (Trading) Ltd
+ *
+ * Based on Sony imx219 camera driver
+ * Copyright (C) 2019-2020 Raspberry Pi (Trading) Ltd
+ */
+#include <asm/unaligned.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+
+#define IMX477_REG_VALUE_08BIT		1
+#define IMX477_REG_VALUE_16BIT		2
+
+/* Chip ID */
+#define IMX477_REG_CHIP_ID		0x0016
+#define IMX477_CHIP_ID			0x0477
+#define IMX378_CHIP_ID			0x0378
+
+#define IMX477_REG_MODE_SELECT		0x0100
+#define IMX477_MODE_STANDBY		0x00
+#define IMX477_MODE_STREAMING		0x01
+
+#define IMX477_REG_ORIENTATION		0x101
+
+#define IMX477_XCLK_FREQ		24000000
+
+#define IMX477_DEFAULT_LINK_FREQ	450000000
+
+/* Pixel rate is fixed at 840MHz for all the modes */
+#define IMX477_PIXEL_RATE		840000000
+
+/* V_TIMING internal */
+#define IMX477_REG_FRAME_LENGTH		0x0340
+#define IMX477_FRAME_LENGTH_MAX		0xffdc
+
+/* Long exposure multiplier */
+#define IMX477_LONG_EXP_SHIFT_MAX	7
+#define IMX477_LONG_EXP_SHIFT_REG	0x3100
+
+/* Exposure control */
+#define IMX477_REG_EXPOSURE		0x0202
+#define IMX477_EXPOSURE_OFFSET		22
+#define IMX477_EXPOSURE_MIN		20
+#define IMX477_EXPOSURE_STEP		1
+#define IMX477_EXPOSURE_DEFAULT		0x640
+#define IMX477_EXPOSURE_MAX		(IMX477_FRAME_LENGTH_MAX - \
+					 IMX477_EXPOSURE_OFFSET)
+
+/* Analog gain control */
+#define IMX477_REG_ANALOG_GAIN		0x0204
+#define IMX477_ANA_GAIN_MIN		0
+#define IMX477_ANA_GAIN_MAX		978
+#define IMX477_ANA_GAIN_STEP		1
+#define IMX477_ANA_GAIN_DEFAULT		0x0
+
+/* Digital gain control */
+#define IMX477_REG_DIGITAL_GAIN		0x020e
+#define IMX477_DGTL_GAIN_MIN		0x0100
+#define IMX477_DGTL_GAIN_MAX		0xffff
+#define IMX477_DGTL_GAIN_DEFAULT	0x0100
+#define IMX477_DGTL_GAIN_STEP		1
+
+/* Test Pattern Control */
+#define IMX477_REG_TEST_PATTERN		0x0600
+#define IMX477_TEST_PATTERN_DISABLE	0
+#define IMX477_TEST_PATTERN_SOLID_COLOR	1
+#define IMX477_TEST_PATTERN_COLOR_BARS	2
+#define IMX477_TEST_PATTERN_GREY_COLOR	3
+#define IMX477_TEST_PATTERN_PN9		4
+
+/* Test pattern colour components */
+#define IMX477_REG_TEST_PATTERN_R	0x0602
+#define IMX477_REG_TEST_PATTERN_GR	0x0604
+#define IMX477_REG_TEST_PATTERN_B	0x0606
+#define IMX477_REG_TEST_PATTERN_GB	0x0608
+#define IMX477_TEST_PATTERN_COLOUR_MIN	0
+#define IMX477_TEST_PATTERN_COLOUR_MAX	0x0fff
+#define IMX477_TEST_PATTERN_COLOUR_STEP	1
+#define IMX477_TEST_PATTERN_R_DEFAULT	IMX477_TEST_PATTERN_COLOUR_MAX
+#define IMX477_TEST_PATTERN_GR_DEFAULT	0
+#define IMX477_TEST_PATTERN_B_DEFAULT	0
+#define IMX477_TEST_PATTERN_GB_DEFAULT	0
+
+/* Embedded metadata stream structure */
+#define IMX477_EMBEDDED_LINE_WIDTH 16384
+#define IMX477_NUM_EMBEDDED_LINES 1
+
+enum pad_types {
+	IMAGE_PAD,
+	METADATA_PAD,
+	NUM_PADS
+};
+
+/* IMX477 native and active pixel array size. */
+#define IMX477_NATIVE_WIDTH		4072U
+#define IMX477_NATIVE_HEIGHT		3176U
+#define IMX477_PIXEL_ARRAY_LEFT		8U
+#define IMX477_PIXEL_ARRAY_TOP		16U
+#define IMX477_PIXEL_ARRAY_WIDTH	4056U
+#define IMX477_PIXEL_ARRAY_HEIGHT	3040U
+
+struct imx477_reg {
+	u16 address;
+	u8 val;
+};
+
+struct imx477_reg_list {
+	unsigned int num_of_regs;
+	const struct imx477_reg *regs;
+};
+
+/* Mode : resolution and related config&values */
+struct imx477_mode {
+	/* Frame width */
+	unsigned int width;
+
+	/* Frame height */
+	unsigned int height;
+
+	/* H-timing in pixels */
+	unsigned int line_length_pix;
+
+	/* Analog crop rectangle. */
+	struct v4l2_rect crop;
+
+	/* Highest possible framerate. */
+	struct v4l2_fract timeperframe_min;
+
+	/* Default framerate. */
+	struct v4l2_fract timeperframe_default;
+
+	/* Default register values */
+	struct imx477_reg_list reg_list;
+};
+
+static const struct imx477_reg mode_common_regs[] = {
+	{0x0136, 0x18},
+	{0x0137, 0x00},
+	{0xe000, 0x00},
+	{0xe07a, 0x01},
+	{0x0808, 0x02},
+	{0x4ae9, 0x18},
+	{0x4aea, 0x08},
+	{0xf61c, 0x04},
+	{0xf61e, 0x04},
+	{0x4ae9, 0x21},
+	{0x4aea, 0x80},
+	{0x38a8, 0x1f},
+	{0x38a9, 0xff},
+	{0x38aa, 0x1f},
+	{0x38ab, 0xff},
+	{0x55d4, 0x00},
+	{0x55d5, 0x00},
+	{0x55d6, 0x07},
+	{0x55d7, 0xff},
+	{0x55e8, 0x07},
+	{0x55e9, 0xff},
+	{0x55ea, 0x00},
+	{0x55eb, 0x00},
+	{0x574c, 0x07},
+	{0x574d, 0xff},
+	{0x574e, 0x00},
+	{0x574f, 0x00},
+	{0x5754, 0x00},
+	{0x5755, 0x00},
+	{0x5756, 0x07},
+	{0x5757, 0xff},
+	{0x5973, 0x04},
+	{0x5974, 0x01},
+	{0x5d13, 0xc3},
+	{0x5d14, 0x58},
+	{0x5d15, 0xa3},
+	{0x5d16, 0x1d},
+	{0x5d17, 0x65},
+	{0x5d18, 0x8c},
+	{0x5d1a, 0x06},
+	{0x5d1b, 0xa9},
+	{0x5d1c, 0x45},
+	{0x5d1d, 0x3a},
+	{0x5d1e, 0xab},
+	{0x5d1f, 0x15},
+	{0x5d21, 0x0e},
+	{0x5d22, 0x52},
+	{0x5d23, 0xaa},
+	{0x5d24, 0x7d},
+	{0x5d25, 0x57},
+	{0x5d26, 0xa8},
+	{0x5d37, 0x5a},
+	{0x5d38, 0x5a},
+	{0x5d77, 0x7f},
+	{0x7b75, 0x0e},
+	{0x7b76, 0x0b},
+	{0x7b77, 0x08},
+	{0x7b78, 0x0a},
+	{0x7b79, 0x47},
+	{0x7b7c, 0x00},
+	{0x7b7d, 0x00},
+	{0x8d1f, 0x00},
+	{0x8d27, 0x00},
+	{0x9004, 0x03},
+	{0x9200, 0x50},
+	{0x9201, 0x6c},
+	{0x9202, 0x71},
+	{0x9203, 0x00},
+	{0x9204, 0x71},
+	{0x9205, 0x01},
+	{0x9371, 0x6a},
+	{0x9373, 0x6a},
+	{0x9375, 0x64},
+	{0x991a, 0x00},
+	{0x996b, 0x8c},
+	{0x996c, 0x64},
+	{0x996d, 0x50},
+	{0x9a4c, 0x0d},
+	{0x9a4d, 0x0d},
+	{0xa001, 0x0a},
+	{0xa003, 0x0a},
+	{0xa005, 0x0a},
+	{0xa006, 0x01},
+	{0xa007, 0xc0},
+	{0xa009, 0xc0},
+	{0x3d8a, 0x01},
+	{0x4421, 0x04},
+	{0x7b3b, 0x01},
+	{0x7b4c, 0x00},
+	{0x9905, 0x00},
+	{0x9907, 0x00},
+	{0x9909, 0x00},
+	{0x990b, 0x00},
+	{0x9944, 0x3c},
+	{0x9947, 0x3c},
+	{0x994a, 0x8c},
+	{0x994b, 0x50},
+	{0x994c, 0x1b},
+	{0x994d, 0x8c},
+	{0x994e, 0x50},
+	{0x994f, 0x1b},
+	{0x9950, 0x8c},
+	{0x9951, 0x1b},
+	{0x9952, 0x0a},
+	{0x9953, 0x8c},
+	{0x9954, 0x1b},
+	{0x9955, 0x0a},
+	{0x9a13, 0x04},
+	{0x9a14, 0x04},
+	{0x9a19, 0x00},
+	{0x9a1c, 0x04},
+	{0x9a1d, 0x04},
+	{0x9a26, 0x05},
+	{0x9a27, 0x05},
+	{0x9a2c, 0x01},
+	{0x9a2d, 0x03},
+	{0x9a2f, 0x05},
+	{0x9a30, 0x05},
+	{0x9a41, 0x00},
+	{0x9a46, 0x00},
+	{0x9a47, 0x00},
+	{0x9c17, 0x35},
+	{0x9c1d, 0x31},
+	{0x9c29, 0x50},
+	{0x9c3b, 0x2f},
+	{0x9c41, 0x6b},
+	{0x9c47, 0x2d},
+	{0x9c4d, 0x40},
+	{0x9c6b, 0x00},
+	{0x9c71, 0xc8},
+	{0x9c73, 0x32},
+	{0x9c75, 0x04},
+	{0x9c7d, 0x2d},
+	{0x9c83, 0x40},
+	{0x9c94, 0x3f},
+	{0x9c95, 0x3f},
+	{0x9c96, 0x3f},
+	{0x9c97, 0x00},
+	{0x9c98, 0x00},
+	{0x9c99, 0x00},
+	{0x9c9a, 0x3f},
+	{0x9c9b, 0x3f},
+	{0x9c9c, 0x3f},
+	{0x9ca0, 0x0f},
+	{0x9ca1, 0x0f},
+	{0x9ca2, 0x0f},
+	{0x9ca3, 0x00},
+	{0x9ca4, 0x00},
+	{0x9ca5, 0x00},
+	{0x9ca6, 0x1e},
+	{0x9ca7, 0x1e},
+	{0x9ca8, 0x1e},
+	{0x9ca9, 0x00},
+	{0x9caa, 0x00},
+	{0x9cab, 0x00},
+	{0x9cac, 0x09},
+	{0x9cad, 0x09},
+	{0x9cae, 0x09},
+	{0x9cbd, 0x50},
+	{0x9cbf, 0x50},
+	{0x9cc1, 0x50},
+	{0x9cc3, 0x40},
+	{0x9cc5, 0x40},
+	{0x9cc7, 0x40},
+	{0x9cc9, 0x0a},
+	{0x9ccb, 0x0a},
+	{0x9ccd, 0x0a},
+	{0x9d17, 0x35},
+	{0x9d1d, 0x31},
+	{0x9d29, 0x50},
+	{0x9d3b, 0x2f},
+	{0x9d41, 0x6b},
+	{0x9d47, 0x42},
+	{0x9d4d, 0x5a},
+	{0x9d6b, 0x00},
+	{0x9d71, 0xc8},
+	{0x9d73, 0x32},
+	{0x9d75, 0x04},
+	{0x9d7d, 0x42},
+	{0x9d83, 0x5a},
+	{0x9d94, 0x3f},
+	{0x9d95, 0x3f},
+	{0x9d96, 0x3f},
+	{0x9d97, 0x00},
+	{0x9d98, 0x00},
+	{0x9d99, 0x00},
+	{0x9d9a, 0x3f},
+	{0x9d9b, 0x3f},
+	{0x9d9c, 0x3f},
+	{0x9d9d, 0x1f},
+	{0x9d9e, 0x1f},
+	{0x9d9f, 0x1f},
+	{0x9da0, 0x0f},
+	{0x9da1, 0x0f},
+	{0x9da2, 0x0f},
+	{0x9da3, 0x00},
+	{0x9da4, 0x00},
+	{0x9da5, 0x00},
+	{0x9da6, 0x1e},
+	{0x9da7, 0x1e},
+	{0x9da8, 0x1e},
+	{0x9da9, 0x00},
+	{0x9daa, 0x00},
+	{0x9dab, 0x00},
+	{0x9dac, 0x09},
+	{0x9dad, 0x09},
+	{0x9dae, 0x09},
+	{0x9dc9, 0x0a},
+	{0x9dcb, 0x0a},
+	{0x9dcd, 0x0a},
+	{0x9e17, 0x35},
+	{0x9e1d, 0x31},
+	{0x9e29, 0x50},
+	{0x9e3b, 0x2f},
+	{0x9e41, 0x6b},
+	{0x9e47, 0x2d},
+	{0x9e4d, 0x40},
+	{0x9e6b, 0x00},
+	{0x9e71, 0xc8},
+	{0x9e73, 0x32},
+	{0x9e75, 0x04},
+	{0x9e94, 0x0f},
+	{0x9e95, 0x0f},
+	{0x9e96, 0x0f},
+	{0x9e97, 0x00},
+	{0x9e98, 0x00},
+	{0x9e99, 0x00},
+	{0x9ea0, 0x0f},
+	{0x9ea1, 0x0f},
+	{0x9ea2, 0x0f},
+	{0x9ea3, 0x00},
+	{0x9ea4, 0x00},
+	{0x9ea5, 0x00},
+	{0x9ea6, 0x3f},
+	{0x9ea7, 0x3f},
+	{0x9ea8, 0x3f},
+	{0x9ea9, 0x00},
+	{0x9eaa, 0x00},
+	{0x9eab, 0x00},
+	{0x9eac, 0x09},
+	{0x9ead, 0x09},
+	{0x9eae, 0x09},
+	{0x9ec9, 0x0a},
+	{0x9ecb, 0x0a},
+	{0x9ecd, 0x0a},
+	{0x9f17, 0x35},
+	{0x9f1d, 0x31},
+	{0x9f29, 0x50},
+	{0x9f3b, 0x2f},
+	{0x9f41, 0x6b},
+	{0x9f47, 0x42},
+	{0x9f4d, 0x5a},
+	{0x9f6b, 0x00},
+	{0x9f71, 0xc8},
+	{0x9f73, 0x32},
+	{0x9f75, 0x04},
+	{0x9f94, 0x0f},
+	{0x9f95, 0x0f},
+	{0x9f96, 0x0f},
+	{0x9f97, 0x00},
+	{0x9f98, 0x00},
+	{0x9f99, 0x00},
+	{0x9f9a, 0x2f},
+	{0x9f9b, 0x2f},
+	{0x9f9c, 0x2f},
+	{0x9f9d, 0x00},
+	{0x9f9e, 0x00},
+	{0x9f9f, 0x00},
+	{0x9fa0, 0x0f},
+	{0x9fa1, 0x0f},
+	{0x9fa2, 0x0f},
+	{0x9fa3, 0x00},
+	{0x9fa4, 0x00},
+	{0x9fa5, 0x00},
+	{0x9fa6, 0x1e},
+	{0x9fa7, 0x1e},
+	{0x9fa8, 0x1e},
+	{0x9fa9, 0x00},
+	{0x9faa, 0x00},
+	{0x9fab, 0x00},
+	{0x9fac, 0x09},
+	{0x9fad, 0x09},
+	{0x9fae, 0x09},
+	{0x9fc9, 0x0a},
+	{0x9fcb, 0x0a},
+	{0x9fcd, 0x0a},
+	{0xa14b, 0xff},
+	{0xa151, 0x0c},
+	{0xa153, 0x50},
+	{0xa155, 0x02},
+	{0xa157, 0x00},
+	{0xa1ad, 0xff},
+	{0xa1b3, 0x0c},
+	{0xa1b5, 0x50},
+	{0xa1b9, 0x00},
+	{0xa24b, 0xff},
+	{0xa257, 0x00},
+	{0xa2ad, 0xff},
+	{0xa2b9, 0x00},
+	{0xb21f, 0x04},
+	{0xb35c, 0x00},
+	{0xb35e, 0x08},
+	{0x0112, 0x0c},
+	{0x0113, 0x0c},
+	{0x0114, 0x01},
+	{0x0350, 0x00},
+	{0xbcf1, 0x02},
+	{0x3ff9, 0x01},
+};
+
+/* 12 mpix 10fps */
+static const struct imx477_reg mode_4056x3040_regs[] = {
+	{0x0342, 0x5d},
+	{0x0343, 0xc0},
+	{0x0344, 0x00},
+	{0x0345, 0x00},
+	{0x0346, 0x00},
+	{0x0347, 0x00},
+	{0x0348, 0x0f},
+	{0x0349, 0xd7},
+	{0x034a, 0x0b},
+	{0x034b, 0xdf},
+	{0x00e3, 0x00},
+	{0x00e4, 0x00},
+	{0x00fc, 0x0a},
+	{0x00fd, 0x0a},
+	{0x00fe, 0x0a},
+	{0x00ff, 0x0a},
+	{0x0220, 0x00},
+	{0x0221, 0x11},
+	{0x0381, 0x01},
+	{0x0383, 0x01},
+	{0x0385, 0x01},
+	{0x0387, 0x01},
+	{0x0900, 0x00},
+	{0x0901, 0x11},
+	{0x0902, 0x02},
+	{0x3140, 0x02},
+	{0x3c00, 0x00},
+	{0x3c01, 0x03},
+	{0x3c02, 0xa2},
+	{0x3f0d, 0x01},
+	{0x5748, 0x07},
+	{0x5749, 0xff},
+	{0x574a, 0x00},
+	{0x574b, 0x00},
+	{0x7b75, 0x0a},
+	{0x7b76, 0x0c},
+	{0x7b77, 0x07},
+	{0x7b78, 0x06},
+	{0x7b79, 0x3c},
+	{0x7b53, 0x01},
+	{0x9369, 0x5a},
+	{0x936b, 0x55},
+	{0x936d, 0x28},
+	{0x9304, 0x00},
+	{0x9305, 0x00},
+	{0x9e9a, 0x2f},
+	{0x9e9b, 0x2f},
+	{0x9e9c, 0x2f},
+	{0x9e9d, 0x00},
+	{0x9e9e, 0x00},
+	{0x9e9f, 0x00},
+	{0xa2a9, 0x60},
+	{0xa2b7, 0x00},
+	{0x0401, 0x00},
+	{0x0404, 0x00},
+	{0x0405, 0x10},
+	{0x0408, 0x00},
+	{0x0409, 0x00},
+	{0x040a, 0x00},
+	{0x040b, 0x00},
+	{0x040c, 0x0f},
+	{0x040d, 0xd8},
+	{0x040e, 0x0b},
+	{0x040f, 0xe0},
+	{0x034c, 0x0f},
+	{0x034d, 0xd8},
+	{0x034e, 0x0b},
+	{0x034f, 0xe0},
+	{0x0301, 0x05},
+	{0x0303, 0x02},
+	{0x0305, 0x04},
+	{0x0306, 0x01},
+	{0x0307, 0x5e},
+	{0x0309, 0x0c},
+	{0x030b, 0x02},
+	{0x030d, 0x02},
+	{0x030e, 0x00},
+	{0x030f, 0x96},
+	{0x0310, 0x01},
+	{0x0820, 0x07},
+	{0x0821, 0x08},
+	{0x0822, 0x00},
+	{0x0823, 0x00},
+	{0x080a, 0x00},
+	{0x080b, 0x7f},
+	{0x080c, 0x00},
+	{0x080d, 0x4f},
+	{0x080e, 0x00},
+	{0x080f, 0x77},
+	{0x0810, 0x00},
+	{0x0811, 0x5f},
+	{0x0812, 0x00},
+	{0x0813, 0x57},
+	{0x0814, 0x00},
+	{0x0815, 0x4f},
+	{0x0816, 0x01},
+	{0x0817, 0x27},
+	{0x0818, 0x00},
+	{0x0819, 0x3f},
+	{0xe04c, 0x00},
+	{0xe04d, 0x7f},
+	{0xe04e, 0x00},
+	{0xe04f, 0x1f},
+	{0x3e20, 0x01},
+	{0x3e37, 0x00},
+	{0x3f50, 0x00},
+	{0x3f56, 0x02},
+	{0x3f57, 0xae},
+};
+
+/* 2x2 binned. 40fps */
+static const struct imx477_reg mode_2028x1520_regs[] = {
+	{0x0342, 0x31},
+	{0x0343, 0xc4},
+	{0x0344, 0x00},
+	{0x0345, 0x00},
+	{0x0346, 0x00},
+	{0x0347, 0x00},
+	{0x0348, 0x0f},
+	{0x0349, 0xd7},
+	{0x034a, 0x0b},
+	{0x034b, 0xdf},
+	{0x0220, 0x00},
+	{0x0221, 0x11},
+	{0x0381, 0x01},
+	{0x0383, 0x01},
+	{0x0385, 0x01},
+	{0x0387, 0x01},
+	{0x0900, 0x01},
+	{0x0901, 0x12},
+	{0x0902, 0x02},
+	{0x3140, 0x02},
+	{0x3c00, 0x00},
+	{0x3c01, 0x03},
+	{0x3c02, 0xa2},
+	{0x3f0d, 0x01},
+	{0x5748, 0x07},
+	{0x5749, 0xff},
+	{0x574a, 0x00},
+	{0x574b, 0x00},
+	{0x7b53, 0x01},
+	{0x9369, 0x73},
+	{0x936b, 0x64},
+	{0x936d, 0x5f},
+	{0x9304, 0x00},
+	{0x9305, 0x00},
+	{0x9e9a, 0x2f},
+	{0x9e9b, 0x2f},
+	{0x9e9c, 0x2f},
+	{0x9e9d, 0x00},
+	{0x9e9e, 0x00},
+	{0x9e9f, 0x00},
+	{0xa2a9, 0x60},
+	{0xa2b7, 0x00},
+	{0x0401, 0x01},
+	{0x0404, 0x00},
+	{0x0405, 0x20},
+	{0x0408, 0x00},
+	{0x0409, 0x00},
+	{0x040a, 0x00},
+	{0x040b, 0x00},
+	{0x040c, 0x0f},
+	{0x040d, 0xd8},
+	{0x040e, 0x0b},
+	{0x040f, 0xe0},
+	{0x034c, 0x07},
+	{0x034d, 0xec},
+	{0x034e, 0x05},
+	{0x034f, 0xf0},
+	{0x0301, 0x05},
+	{0x0303, 0x02},
+	{0x0305, 0x04},
+	{0x0306, 0x01},
+	{0x0307, 0x5e},
+	{0x0309, 0x0c},
+	{0x030b, 0x02},
+	{0x030d, 0x02},
+	{0x030e, 0x00},
+	{0x030f, 0x96},
+	{0x0310, 0x01},
+	{0x0820, 0x07},
+	{0x0821, 0x08},
+	{0x0822, 0x00},
+	{0x0823, 0x00},
+	{0x080a, 0x00},
+	{0x080b, 0x7f},
+	{0x080c, 0x00},
+	{0x080d, 0x4f},
+	{0x080e, 0x00},
+	{0x080f, 0x77},
+	{0x0810, 0x00},
+	{0x0811, 0x5f},
+	{0x0812, 0x00},
+	{0x0813, 0x57},
+	{0x0814, 0x00},
+	{0x0815, 0x4f},
+	{0x0816, 0x01},
+	{0x0817, 0x27},
+	{0x0818, 0x00},
+	{0x0819, 0x3f},
+	{0xe04c, 0x00},
+	{0xe04d, 0x7f},
+	{0xe04e, 0x00},
+	{0xe04f, 0x1f},
+	{0x3e20, 0x01},
+	{0x3e37, 0x00},
+	{0x3f50, 0x00},
+	{0x3f56, 0x01},
+	{0x3f57, 0x6c},
+};
+
+/* 1080p cropped mode */
+static const struct imx477_reg mode_2028x1080_regs[] = {
+	{0x0342, 0x31},
+	{0x0343, 0xc4},
+	{0x0344, 0x00},
+	{0x0345, 0x00},
+	{0x0346, 0x01},
+	{0x0347, 0xb8},
+	{0x0348, 0x0f},
+	{0x0349, 0xd7},
+	{0x034a, 0x0a},
+	{0x034b, 0x27},
+	{0x0220, 0x00},
+	{0x0221, 0x11},
+	{0x0381, 0x01},
+	{0x0383, 0x01},
+	{0x0385, 0x01},
+	{0x0387, 0x01},
+	{0x0900, 0x01},
+	{0x0901, 0x12},
+	{0x0902, 0x02},
+	{0x3140, 0x02},
+	{0x3c00, 0x00},
+	{0x3c01, 0x03},
+	{0x3c02, 0xa2},
+	{0x3f0d, 0x01},
+	{0x5748, 0x07},
+	{0x5749, 0xff},
+	{0x574a, 0x00},
+	{0x574b, 0x00},
+	{0x7b53, 0x01},
+	{0x9369, 0x73},
+	{0x936b, 0x64},
+	{0x936d, 0x5f},
+	{0x9304, 0x00},
+	{0x9305, 0x00},
+	{0x9e9a, 0x2f},
+	{0x9e9b, 0x2f},
+	{0x9e9c, 0x2f},
+	{0x9e9d, 0x00},
+	{0x9e9e, 0x00},
+	{0x9e9f, 0x00},
+	{0xa2a9, 0x60},
+	{0xa2b7, 0x00},
+	{0x0401, 0x01},
+	{0x0404, 0x00},
+	{0x0405, 0x20},
+	{0x0408, 0x00},
+	{0x0409, 0x00},
+	{0x040a, 0x00},
+	{0x040b, 0x00},
+	{0x040c, 0x0f},
+	{0x040d, 0xd8},
+	{0x040e, 0x04},
+	{0x040f, 0x38},
+	{0x034c, 0x07},
+	{0x034d, 0xec},
+	{0x034e, 0x04},
+	{0x034f, 0x38},
+	{0x0301, 0x05},
+	{0x0303, 0x02},
+	{0x0305, 0x04},
+	{0x0306, 0x01},
+	{0x0307, 0x5e},
+	{0x0309, 0x0c},
+	{0x030b, 0x02},
+	{0x030d, 0x02},
+	{0x030e, 0x00},
+	{0x030f, 0x96},
+	{0x0310, 0x01},
+	{0x0820, 0x07},
+	{0x0821, 0x08},
+	{0x0822, 0x00},
+	{0x0823, 0x00},
+	{0x080a, 0x00},
+	{0x080b, 0x7f},
+	{0x080c, 0x00},
+	{0x080d, 0x4f},
+	{0x080e, 0x00},
+	{0x080f, 0x77},
+	{0x0810, 0x00},
+	{0x0811, 0x5f},
+	{0x0812, 0x00},
+	{0x0813, 0x57},
+	{0x0814, 0x00},
+	{0x0815, 0x4f},
+	{0x0816, 0x01},
+	{0x0817, 0x27},
+	{0x0818, 0x00},
+	{0x0819, 0x3f},
+	{0xe04c, 0x00},
+	{0xe04d, 0x7f},
+	{0xe04e, 0x00},
+	{0xe04f, 0x1f},
+	{0x3e20, 0x01},
+	{0x3e37, 0x00},
+	{0x3f50, 0x00},
+	{0x3f56, 0x01},
+	{0x3f57, 0x6c},
+};
+
+/* 4x4 binned. 120fps */
+static const struct imx477_reg mode_1332x990_regs[] = {
+	{0x420b, 0x01},
+	{0x990c, 0x00},
+	{0x990d, 0x08},
+	{0x9956, 0x8c},
+	{0x9957, 0x64},
+	{0x9958, 0x50},
+	{0x9a48, 0x06},
+	{0x9a49, 0x06},
+	{0x9a4a, 0x06},
+	{0x9a4b, 0x06},
+	{0x9a4c, 0x06},
+	{0x9a4d, 0x06},
+	{0x0112, 0x0a},
+	{0x0113, 0x0a},
+	{0x0114, 0x01},
+	{0x0342, 0x1a},
+	{0x0343, 0x08},
+	{0x0340, 0x04},
+	{0x0341, 0x1a},
+	{0x0344, 0x00},
+	{0x0345, 0x00},
+	{0x0346, 0x02},
+	{0x0347, 0x10},
+	{0x0348, 0x0f},
+	{0x0349, 0xd7},
+	{0x034a, 0x09},
+	{0x034b, 0xcf},
+	{0x00e3, 0x00},
+	{0x00e4, 0x00},
+	{0x00fc, 0x0a},
+	{0x00fd, 0x0a},
+	{0x00fe, 0x0a},
+	{0x00ff, 0x0a},
+	{0xe013, 0x00},
+	{0x0220, 0x00},
+	{0x0221, 0x11},
+	{0x0381, 0x01},
+	{0x0383, 0x01},
+	{0x0385, 0x01},
+	{0x0387, 0x01},
+	{0x0900, 0x01},
+	{0x0901, 0x22},
+	{0x0902, 0x02},
+	{0x3140, 0x02},
+	{0x3c00, 0x00},
+	{0x3c01, 0x01},
+	{0x3c02, 0x9c},
+	{0x3f0d, 0x00},
+	{0x5748, 0x00},
+	{0x5749, 0x00},
+	{0x574a, 0x00},
+	{0x574b, 0xa4},
+	{0x7b75, 0x0e},
+	{0x7b76, 0x09},
+	{0x7b77, 0x08},
+	{0x7b78, 0x06},
+	{0x7b79, 0x34},
+	{0x7b53, 0x00},
+	{0x9369, 0x73},
+	{0x936b, 0x64},
+	{0x936d, 0x5f},
+	{0x9304, 0x03},
+	{0x9305, 0x80},
+	{0x9e9a, 0x2f},
+	{0x9e9b, 0x2f},
+	{0x9e9c, 0x2f},
+	{0x9e9d, 0x00},
+	{0x9e9e, 0x00},
+	{0x9e9f, 0x00},
+	{0xa2a9, 0x27},
+	{0xa2b7, 0x03},
+	{0x0401, 0x00},
+	{0x0404, 0x00},
+	{0x0405, 0x10},
+	{0x0408, 0x01},
+	{0x0409, 0x5c},
+	{0x040a, 0x00},
+	{0x040b, 0x00},
+	{0x040c, 0x05},
+	{0x040d, 0x34},
+	{0x040e, 0x03},
+	{0x040f, 0xde},
+	{0x034c, 0x05},
+	{0x034d, 0x34},
+	{0x034e, 0x03},
+	{0x034f, 0xde},
+	{0x0301, 0x05},
+	{0x0303, 0x02},
+	{0x0305, 0x02},
+	{0x0306, 0x00},
+	{0x0307, 0xaf},
+	{0x0309, 0x0a},
+	{0x030b, 0x02},
+	{0x030d, 0x02},
+	{0x030e, 0x00},
+	{0x030f, 0x96},
+	{0x0310, 0x01},
+	{0x0820, 0x07},
+	{0x0821, 0x08},
+	{0x0822, 0x00},
+	{0x0823, 0x00},
+	{0x080a, 0x00},
+	{0x080b, 0x7f},
+	{0x080c, 0x00},
+	{0x080d, 0x4f},
+	{0x080e, 0x00},
+	{0x080f, 0x77},
+	{0x0810, 0x00},
+	{0x0811, 0x5f},
+	{0x0812, 0x00},
+	{0x0813, 0x57},
+	{0x0814, 0x00},
+	{0x0815, 0x4f},
+	{0x0816, 0x01},
+	{0x0817, 0x27},
+	{0x0818, 0x00},
+	{0x0819, 0x3f},
+	{0xe04c, 0x00},
+	{0xe04d, 0x5f},
+	{0xe04e, 0x00},
+	{0xe04f, 0x1f},
+	{0x3e20, 0x01},
+	{0x3e37, 0x00},
+	{0x3f50, 0x00},
+	{0x3f56, 0x00},
+	{0x3f57, 0xbf},
+};
+
+/* Mode configs */
+static const struct imx477_mode supported_modes_12bit[] = {
+	{
+		/* 12MPix 10fps mode */
+		.width = 4056,
+		.height = 3040,
+		.line_length_pix = 0x5dc0,
+		.crop = {
+			.left = IMX477_PIXEL_ARRAY_LEFT,
+			.top = IMX477_PIXEL_ARRAY_TOP,
+			.width = 4056,
+			.height = 3040,
+		},
+		.timeperframe_min = {
+			.numerator = 100,
+			.denominator = 1000
+		},
+		.timeperframe_default = {
+			.numerator = 100,
+			.denominator = 1000
+		},
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mode_4056x3040_regs),
+			.regs = mode_4056x3040_regs,
+		},
+	},
+	{
+		/* 2x2 binned 40fps mode */
+		.width = 2028,
+		.height = 1520,
+		.line_length_pix = 0x31c4,
+		.crop = {
+			.left = IMX477_PIXEL_ARRAY_LEFT,
+			.top = IMX477_PIXEL_ARRAY_TOP,
+			.width = 4056,
+			.height = 3040,
+		},
+		.timeperframe_min = {
+			.numerator = 100,
+			.denominator = 4000
+		},
+		.timeperframe_default = {
+			.numerator = 100,
+			.denominator = 3000
+		},
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mode_2028x1520_regs),
+			.regs = mode_2028x1520_regs,
+		},
+	},
+	{
+		/* 1080p 50fps cropped mode */
+		.width = 2028,
+		.height = 1080,
+		.line_length_pix = 0x31c4,
+		.crop = {
+			.left = IMX477_PIXEL_ARRAY_LEFT,
+			.top = IMX477_PIXEL_ARRAY_TOP + 440,
+			.width = 4056,
+			.height = 2160,
+		},
+		.timeperframe_min = {
+			.numerator = 100,
+			.denominator = 5000
+		},
+		.timeperframe_default = {
+			.numerator = 100,
+			.denominator = 3000
+		},
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mode_2028x1080_regs),
+			.regs = mode_2028x1080_regs,
+		},
+	}
+};
+
+static const struct imx477_mode supported_modes_10bit[] = {
+	{
+		/* 120fps. 2x2 binned and cropped */
+		.width = 1332,
+		.height = 990,
+		.line_length_pix = 6664,
+		.crop = {
+			/*
+			 * FIXME: the analog crop rectangle is actually
+			 * programmed with a horizontal displacement of 0
+			 * pixels, not 4. It gets shrunk after going through
+			 * the scaler. Move this information to the compose
+			 * rectangle once the driver is expanded to represent
+			 * its processing blocks with multiple subdevs.
+			 */
+			.left = IMX477_PIXEL_ARRAY_LEFT + 696,
+			.top = IMX477_PIXEL_ARRAY_TOP + 528,
+			.width = 2664,
+			.height = 1980,
+		},
+		.timeperframe_min = {
+			.numerator = 100,
+			.denominator = 12000
+		},
+		.timeperframe_default = {
+			.numerator = 100,
+			.denominator = 12000
+		},
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mode_1332x990_regs),
+			.regs = mode_1332x990_regs,
+		}
+	}
+};
+
+/*
+ * The supported formats.
+ * This table MUST contain 4 entries per format, to cover the various flip
+ * combinations in the order
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 codes[] = {
+	/* 12-bit modes. */
+	MEDIA_BUS_FMT_SRGGB12_1X12,
+	MEDIA_BUS_FMT_SGRBG12_1X12,
+	MEDIA_BUS_FMT_SGBRG12_1X12,
+	MEDIA_BUS_FMT_SBGGR12_1X12,
+	/* 10-bit modes. */
+	MEDIA_BUS_FMT_SRGGB10_1X10,
+	MEDIA_BUS_FMT_SGRBG10_1X10,
+	MEDIA_BUS_FMT_SGBRG10_1X10,
+	MEDIA_BUS_FMT_SBGGR10_1X10,
+};
+
+static const char * const imx477_test_pattern_menu[] = {
+	"Disabled",
+	"Color Bars",
+	"Solid Color",
+	"Grey Color Bars",
+	"PN9"
+};
+
+static const int imx477_test_pattern_val[] = {
+	IMX477_TEST_PATTERN_DISABLE,
+	IMX477_TEST_PATTERN_COLOR_BARS,
+	IMX477_TEST_PATTERN_SOLID_COLOR,
+	IMX477_TEST_PATTERN_GREY_COLOR,
+	IMX477_TEST_PATTERN_PN9,
+};
+
+/* regulator supplies */
+static const char * const imx477_supply_name[] = {
+	/* Supplies can be enabled in any order */
+	"VANA",  /* Analog (2.8V) supply */
+	"VDIG",  /* Digital Core (1.05V) supply */
+	"VDDL",  /* IF (1.8V) supply */
+};
+
+#define IMX477_NUM_SUPPLIES ARRAY_SIZE(imx477_supply_name)
+
+/*
+ * Initialisation delay between XCLR low->high and the moment when the sensor
+ * can start capture (i.e. can leave software standby), given by T7 in the
+ * datasheet is 8ms.  This does include I2C setup time as well.
+ *
+ * Note, that delay between XCLR low->high and reading the CCI ID register (T6
+ * in the datasheet) is much smaller - 600us.
+ */
+#define IMX477_XCLR_MIN_DELAY_US	8000
+#define IMX477_XCLR_DELAY_RANGE_US	1000
+
+struct imx477_compatible_data {
+	unsigned int chip_id;
+	struct imx477_reg_list extra_regs;
+};
+
+struct imx477 {
+	struct v4l2_subdev sd;
+	struct media_pad pad[NUM_PADS];
+
+	unsigned int fmt_code;
+
+	struct clk *xclk;
+	u32 xclk_freq;
+
+	struct gpio_desc *reset_gpio;
+	struct regulator_bulk_data supplies[IMX477_NUM_SUPPLIES];
+
+	struct v4l2_ctrl_handler ctrl_handler;
+	/* V4L2 Controls */
+	struct v4l2_ctrl *pixel_rate;
+	struct v4l2_ctrl *exposure;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *hblank;
+
+	/* Current mode */
+	const struct imx477_mode *mode;
+
+	/*
+	 * Mutex for serialized access:
+	 * Protect sensor module set pad format and start/stop streaming safely.
+	 */
+	struct mutex mutex;
+
+	/* Streaming on/off */
+	bool streaming;
+
+	/* Rewrite common registers on stream on? */
+	bool common_regs_written;
+
+	/* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
+	unsigned int long_exp_shift;
+
+	/* Any extra information related to different compatible sensors */
+	const struct imx477_compatible_data *compatible_data;
+};
+
+static inline struct imx477 *to_imx477(struct v4l2_subdev *_sd)
+{
+	return container_of(_sd, struct imx477, sd);
+}
+
+static inline void get_mode_table(unsigned int code,
+				  const struct imx477_mode **mode_list,
+				  unsigned int *num_modes)
+{
+	switch (code) {
+	/* 12-bit */
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+		*mode_list = supported_modes_12bit;
+		*num_modes = ARRAY_SIZE(supported_modes_12bit);
+		break;
+	/* 10-bit */
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+		*mode_list = supported_modes_10bit;
+		*num_modes = ARRAY_SIZE(supported_modes_10bit);
+		break;
+	default:
+		*mode_list = NULL;
+		*num_modes = 0;
+	}
+}
+
+/* Read registers up to 2 at a time */
+static int imx477_read_reg(struct imx477 *imx477, u16 reg, u32 len, u32 *val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
+	struct i2c_msg msgs[2];
+	u8 addr_buf[2] = { reg >> 8, reg & 0xff };
+	u8 data_buf[4] = { 0, };
+	int ret;
+
+	if (len > 4)
+		return -EINVAL;
+
+	/* Write register address */
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = ARRAY_SIZE(addr_buf);
+	msgs[0].buf = addr_buf;
+
+	/* Read data from register */
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = len;
+	msgs[1].buf = &data_buf[4 - len];
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	*val = get_unaligned_be32(data_buf);
+
+	return 0;
+}
+
+/* Write registers up to 2 at a time */
+static int imx477_write_reg(struct imx477 *imx477, u16 reg, u32 len, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
+	u8 buf[6];
+
+	if (len > 4)
+		return -EINVAL;
+
+	put_unaligned_be16(reg, buf);
+	put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
+	if (i2c_master_send(client, buf, len + 2) != len + 2)
+		return -EIO;
+
+	return 0;
+}
+
+/* Write a list of registers */
+static int imx477_write_regs(struct imx477 *imx477,
+			     const struct imx477_reg *regs, u32 len)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < len; i++) {
+		ret = imx477_write_reg(imx477, regs[i].address, 1, regs[i].val);
+		if (ret) {
+			dev_err_ratelimited(&client->dev,
+					    "Failed to write reg 0x%4.4x. error = %d\n",
+					    regs[i].address, ret);
+
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/* Get bayer order based on flip setting. */
+static u32 imx477_get_format_code(struct imx477 *imx477, u32 code)
+{
+	unsigned int i;
+
+	lockdep_assert_held(&imx477->mutex);
+
+	for (i = 0; i < ARRAY_SIZE(codes); i++)
+		if (codes[i] == code)
+			break;
+
+	if (i >= ARRAY_SIZE(codes))
+		i = 0;
+
+	i = (i & ~3) | (imx477->vflip->val ? 2 : 0) |
+	    (imx477->hflip->val ? 1 : 0);
+
+	return codes[i];
+}
+
+static void imx477_set_default_format(struct imx477 *imx477)
+{
+	/* Set default mode to max resolution */
+	imx477->mode = &supported_modes_12bit[0];
+	imx477->fmt_code = MEDIA_BUS_FMT_SRGGB12_1X12;
+}
+
+static int imx477_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct imx477 *imx477 = to_imx477(sd);
+	struct v4l2_mbus_framefmt *try_fmt_img =
+		v4l2_subdev_get_try_format(sd, fh->pad, IMAGE_PAD);
+	struct v4l2_mbus_framefmt *try_fmt_meta =
+		v4l2_subdev_get_try_format(sd, fh->pad, METADATA_PAD);
+	struct v4l2_rect *try_crop;
+
+	mutex_lock(&imx477->mutex);
+
+	/* Initialize try_fmt for the image pad */
+	try_fmt_img->width = supported_modes_12bit[0].width;
+	try_fmt_img->height = supported_modes_12bit[0].height;
+	try_fmt_img->code = imx477_get_format_code(imx477,
+						   MEDIA_BUS_FMT_SRGGB12_1X12);
+	try_fmt_img->field = V4L2_FIELD_NONE;
+
+	/* Initialize try_fmt for the embedded metadata pad */
+	try_fmt_meta->width = IMX477_EMBEDDED_LINE_WIDTH;
+	try_fmt_meta->height = IMX477_NUM_EMBEDDED_LINES;
+	try_fmt_meta->code = MEDIA_BUS_FMT_SENSOR_DATA;
+	try_fmt_meta->field = V4L2_FIELD_NONE;
+
+	/* Initialize try_crop */
+	try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, IMAGE_PAD);
+	try_crop->left = IMX477_PIXEL_ARRAY_LEFT;
+	try_crop->top = IMX477_PIXEL_ARRAY_TOP;
+	try_crop->width = IMX477_PIXEL_ARRAY_WIDTH;
+	try_crop->height = IMX477_PIXEL_ARRAY_HEIGHT;
+
+	mutex_unlock(&imx477->mutex);
+
+	return 0;
+}
+
+static void imx477_adjust_exposure_range(struct imx477 *imx477)
+{
+	int exposure_max, exposure_def;
+
+	/* Honour the VBLANK limits when setting exposure. */
+	exposure_max = imx477->mode->height + imx477->vblank->val -
+		       IMX477_EXPOSURE_OFFSET;
+	exposure_def = min(exposure_max, imx477->exposure->val);
+	__v4l2_ctrl_modify_range(imx477->exposure, imx477->exposure->minimum,
+				 exposure_max, imx477->exposure->step,
+				 exposure_def);
+}
+
+static int imx477_set_frame_length(struct imx477 *imx477, unsigned int val)
+{
+	int ret = 0;
+
+	imx477->long_exp_shift = 0;
+
+	while (val > IMX477_FRAME_LENGTH_MAX) {
+		imx477->long_exp_shift++;
+		val >>= 1;
+	}
+
+	ret = imx477_write_reg(imx477, IMX477_REG_FRAME_LENGTH,
+			       IMX477_REG_VALUE_16BIT, val);
+	if (ret)
+		return ret;
+
+	return imx477_write_reg(imx477, IMX477_LONG_EXP_SHIFT_REG,
+				IMX477_REG_VALUE_08BIT, imx477->long_exp_shift);
+}
+
+static int imx477_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct imx477 *imx477 =
+		container_of(ctrl->handler, struct imx477, ctrl_handler);
+	struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
+	int ret = 0;
+
+	/*
+	 * The VBLANK control may change the limits of usable exposure, so check
+	 * and adjust if necessary.
+	 */
+	if (ctrl->id == V4L2_CID_VBLANK)
+		imx477_adjust_exposure_range(imx477);
+
+	/*
+	 * Applying V4L2 control value only happens
+	 * when power is up for streaming
+	 */
+	if (pm_runtime_get_if_in_use(&client->dev) == 0)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ANALOGUE_GAIN:
+		ret = imx477_write_reg(imx477, IMX477_REG_ANALOG_GAIN,
+				       IMX477_REG_VALUE_16BIT, ctrl->val);
+		break;
+	case V4L2_CID_EXPOSURE:
+		ret = imx477_write_reg(imx477, IMX477_REG_EXPOSURE,
+				       IMX477_REG_VALUE_16BIT, ctrl->val >>
+							imx477->long_exp_shift);
+		break;
+	case V4L2_CID_DIGITAL_GAIN:
+		ret = imx477_write_reg(imx477, IMX477_REG_DIGITAL_GAIN,
+				       IMX477_REG_VALUE_16BIT, ctrl->val);
+		break;
+	case V4L2_CID_TEST_PATTERN:
+		ret = imx477_write_reg(imx477, IMX477_REG_TEST_PATTERN,
+				       IMX477_REG_VALUE_16BIT,
+				       imx477_test_pattern_val[ctrl->val]);
+		break;
+	case V4L2_CID_TEST_PATTERN_RED:
+		ret = imx477_write_reg(imx477, IMX477_REG_TEST_PATTERN_R,
+				       IMX477_REG_VALUE_16BIT, ctrl->val);
+		break;
+	case V4L2_CID_TEST_PATTERN_GREENR:
+		ret = imx477_write_reg(imx477, IMX477_REG_TEST_PATTERN_GR,
+				       IMX477_REG_VALUE_16BIT, ctrl->val);
+		break;
+	case V4L2_CID_TEST_PATTERN_BLUE:
+		ret = imx477_write_reg(imx477, IMX477_REG_TEST_PATTERN_B,
+				       IMX477_REG_VALUE_16BIT, ctrl->val);
+		break;
+	case V4L2_CID_TEST_PATTERN_GREENB:
+		ret = imx477_write_reg(imx477, IMX477_REG_TEST_PATTERN_GB,
+				       IMX477_REG_VALUE_16BIT, ctrl->val);
+		break;
+	case V4L2_CID_HFLIP:
+	case V4L2_CID_VFLIP:
+		ret = imx477_write_reg(imx477, IMX477_REG_ORIENTATION, 1,
+				       imx477->hflip->val |
+				       imx477->vflip->val << 1);
+		break;
+	case V4L2_CID_VBLANK:
+		ret = imx477_set_frame_length(imx477,
+					      imx477->mode->height + ctrl->val);
+		break;
+	default:
+		dev_info(&client->dev,
+			 "ctrl(id:0x%x,val:0x%x) is not handled\n",
+			 ctrl->id, ctrl->val);
+		ret = -EINVAL;
+		break;
+	}
+
+	pm_runtime_put(&client->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops imx477_ctrl_ops = {
+	.s_ctrl = imx477_set_ctrl,
+};
+
+static int imx477_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct imx477 *imx477 = to_imx477(sd);
+
+	if (code->pad >= NUM_PADS)
+		return -EINVAL;
+
+	if (code->pad == IMAGE_PAD) {
+		if (code->index >= (ARRAY_SIZE(codes) / 4))
+			return -EINVAL;
+
+		code->code = imx477_get_format_code(imx477,
+						    codes[code->index * 4]);
+	} else {
+		if (code->index > 0)
+			return -EINVAL;
+
+		code->code = MEDIA_BUS_FMT_SENSOR_DATA;
+	}
+
+	return 0;
+}
+
+static int imx477_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct imx477 *imx477 = to_imx477(sd);
+
+	if (fse->pad >= NUM_PADS)
+		return -EINVAL;
+
+	if (fse->pad == IMAGE_PAD) {
+		const struct imx477_mode *mode_list;
+		unsigned int num_modes;
+
+		get_mode_table(fse->code, &mode_list, &num_modes);
+
+		if (fse->index >= num_modes)
+			return -EINVAL;
+
+		if (fse->code != imx477_get_format_code(imx477, fse->code))
+			return -EINVAL;
+
+		fse->min_width = mode_list[fse->index].width;
+		fse->max_width = fse->min_width;
+		fse->min_height = mode_list[fse->index].height;
+		fse->max_height = fse->min_height;
+	} else {
+		if (fse->code != MEDIA_BUS_FMT_SENSOR_DATA || fse->index > 0)
+			return -EINVAL;
+
+		fse->min_width = IMX477_EMBEDDED_LINE_WIDTH;
+		fse->max_width = fse->min_width;
+		fse->min_height = IMX477_NUM_EMBEDDED_LINES;
+		fse->max_height = fse->min_height;
+	}
+
+	return 0;
+}
+
+static void imx477_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
+{
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+	fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+							  fmt->colorspace,
+							  fmt->ycbcr_enc);
+	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+}
+
+static void imx477_update_image_pad_format(struct imx477 *imx477,
+					   const struct imx477_mode *mode,
+					   struct v4l2_subdev_format *fmt)
+{
+	fmt->format.width = mode->width;
+	fmt->format.height = mode->height;
+	fmt->format.field = V4L2_FIELD_NONE;
+	imx477_reset_colorspace(&fmt->format);
+}
+
+static void imx477_update_metadata_pad_format(struct v4l2_subdev_format *fmt)
+{
+	fmt->format.width = IMX477_EMBEDDED_LINE_WIDTH;
+	fmt->format.height = IMX477_NUM_EMBEDDED_LINES;
+	fmt->format.code = MEDIA_BUS_FMT_SENSOR_DATA;
+	fmt->format.field = V4L2_FIELD_NONE;
+}
+
+static int imx477_get_pad_format(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_format *fmt)
+{
+	struct imx477 *imx477 = to_imx477(sd);
+
+	if (fmt->pad >= NUM_PADS)
+		return -EINVAL;
+
+	mutex_lock(&imx477->mutex);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		struct v4l2_mbus_framefmt *try_fmt =
+			v4l2_subdev_get_try_format(&imx477->sd, cfg, fmt->pad);
+		/* update the code which could change due to vflip or hflip: */
+		try_fmt->code = fmt->pad == IMAGE_PAD ?
+				imx477_get_format_code(imx477, try_fmt->code) :
+				MEDIA_BUS_FMT_SENSOR_DATA;
+		fmt->format = *try_fmt;
+	} else {
+		if (fmt->pad == IMAGE_PAD) {
+			imx477_update_image_pad_format(imx477, imx477->mode,
+						       fmt);
+			fmt->format.code =
+			       imx477_get_format_code(imx477, imx477->fmt_code);
+		} else {
+			imx477_update_metadata_pad_format(fmt);
+		}
+	}
+
+	mutex_unlock(&imx477->mutex);
+	return 0;
+}
+
+static
+unsigned int imx477_get_frame_length(const struct imx477_mode *mode,
+				     const struct v4l2_fract *timeperframe)
+{
+	u64 frame_length;
+
+	frame_length = (u64)timeperframe->numerator * IMX477_PIXEL_RATE;
+	do_div(frame_length,
+	       (u64)timeperframe->denominator * mode->line_length_pix);
+
+	if (WARN_ON(frame_length > IMX477_FRAME_LENGTH_MAX))
+		frame_length = IMX477_FRAME_LENGTH_MAX;
+
+	return max_t(unsigned int, frame_length, mode->height);
+}
+
+static void imx477_set_framing_limits(struct imx477 *imx477)
+{
+	unsigned int frm_length_min, frm_length_default, hblank;
+	const struct imx477_mode *mode = imx477->mode;
+
+	frm_length_min = imx477_get_frame_length(mode, &mode->timeperframe_min);
+	frm_length_default =
+		     imx477_get_frame_length(mode, &mode->timeperframe_default);
+
+	/* Default to no long exposure multiplier. */
+	imx477->long_exp_shift = 0;
+
+	/* Update limits and set FPS to default */
+	__v4l2_ctrl_modify_range(imx477->vblank, frm_length_min - mode->height,
+				 ((1 << IMX477_LONG_EXP_SHIFT_MAX) *
+					IMX477_FRAME_LENGTH_MAX) - mode->height,
+				 1, frm_length_default - mode->height);
+
+	/* Setting this will adjust the exposure limits as well. */
+	__v4l2_ctrl_s_ctrl(imx477->vblank, frm_length_default - mode->height);
+
+	/*
+	 * Currently PPL is fixed to the mode specified value, so hblank
+	 * depends on mode->width only, and is not changeable in any
+	 * way other than changing the mode.
+	 */
+	hblank = mode->line_length_pix - mode->width;
+	__v4l2_ctrl_modify_range(imx477->hblank, hblank, hblank, 1, hblank);
+}
+
+static int imx477_set_pad_format(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_format *fmt)
+{
+	struct v4l2_mbus_framefmt *framefmt;
+	const struct imx477_mode *mode;
+	struct imx477 *imx477 = to_imx477(sd);
+
+	if (fmt->pad >= NUM_PADS)
+		return -EINVAL;
+
+	mutex_lock(&imx477->mutex);
+
+	if (fmt->pad == IMAGE_PAD) {
+		const struct imx477_mode *mode_list;
+		unsigned int num_modes;
+
+		/* Bayer order varies with flips */
+		fmt->format.code = imx477_get_format_code(imx477,
+							  fmt->format.code);
+
+		get_mode_table(fmt->format.code, &mode_list, &num_modes);
+
+		mode = v4l2_find_nearest_size(mode_list,
+					      num_modes,
+					      width, height,
+					      fmt->format.width,
+					      fmt->format.height);
+		imx477_update_image_pad_format(imx477, mode, fmt);
+		if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+			framefmt = v4l2_subdev_get_try_format(sd, cfg,
+							      fmt->pad);
+			*framefmt = fmt->format;
+		} else {
+			imx477->mode = mode;
+			imx477->fmt_code = fmt->format.code;
+			imx477_set_framing_limits(imx477);
+		}
+	} else {
+		if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+			framefmt = v4l2_subdev_get_try_format(sd, cfg,
+							      fmt->pad);
+			*framefmt = fmt->format;
+		} else {
+			/* Only one embedded data mode is supported */
+			imx477_update_metadata_pad_format(fmt);
+		}
+	}
+
+	mutex_unlock(&imx477->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_rect *
+__imx477_get_pad_crop(struct imx477 *imx477, struct v4l2_subdev_pad_config *cfg,
+		      unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(&imx477->sd, cfg, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &imx477->mode->crop;
+	}
+
+	return NULL;
+}
+
+static int imx477_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_selection *sel)
+{
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP: {
+		struct imx477 *imx477 = to_imx477(sd);
+
+		mutex_lock(&imx477->mutex);
+		sel->r = *__imx477_get_pad_crop(imx477, cfg, sel->pad,
+						sel->which);
+		mutex_unlock(&imx477->mutex);
+
+		return 0;
+	}
+
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = IMX477_NATIVE_WIDTH;
+		sel->r.height = IMX477_NATIVE_HEIGHT;
+
+		return 0;
+
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.left = IMX477_PIXEL_ARRAY_LEFT;
+		sel->r.top = IMX477_PIXEL_ARRAY_TOP;
+		sel->r.width = IMX477_PIXEL_ARRAY_WIDTH;
+		sel->r.height = IMX477_PIXEL_ARRAY_HEIGHT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/* Start streaming */
+static int imx477_start_streaming(struct imx477 *imx477)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
+	const struct imx477_reg_list *reg_list;
+	const struct imx477_reg_list *extra_regs;
+	int ret;
+
+	if (!imx477->common_regs_written) {
+		ret = imx477_write_regs(imx477, mode_common_regs,
+					ARRAY_SIZE(mode_common_regs));
+		if (!ret) {
+			extra_regs = &imx477->compatible_data->extra_regs;
+			ret = imx477_write_regs(imx477,	extra_regs->regs,
+						extra_regs->num_of_regs);
+		}
+
+		if (ret) {
+			dev_err(&client->dev, "%s failed to set common settings\n",
+				__func__);
+			return ret;
+		}
+		imx477->common_regs_written = true;
+	}
+
+	/* Apply default values of current mode */
+	reg_list = &imx477->mode->reg_list;
+	ret = imx477_write_regs(imx477, reg_list->regs, reg_list->num_of_regs);
+	if (ret) {
+		dev_err(&client->dev, "%s failed to set mode\n", __func__);
+		return ret;
+	}
+
+	/* Apply customized values from user */
+	ret =  __v4l2_ctrl_handler_setup(imx477->sd.ctrl_handler);
+	if (ret)
+		return ret;
+
+	/* set stream on register */
+	return imx477_write_reg(imx477, IMX477_REG_MODE_SELECT,
+				IMX477_REG_VALUE_08BIT, IMX477_MODE_STREAMING);
+}
+
+/* Stop streaming */
+static void imx477_stop_streaming(struct imx477 *imx477)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
+	int ret;
+
+	/* set stream off register */
+	ret = imx477_write_reg(imx477, IMX477_REG_MODE_SELECT,
+			       IMX477_REG_VALUE_08BIT, IMX477_MODE_STANDBY);
+	if (ret)
+		dev_err(&client->dev, "%s failed to set stream\n", __func__);
+}
+
+static int imx477_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct imx477 *imx477 = to_imx477(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = 0;
+
+	mutex_lock(&imx477->mutex);
+	if (imx477->streaming == enable) {
+		mutex_unlock(&imx477->mutex);
+		return 0;
+	}
+
+	if (enable) {
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0) {
+			pm_runtime_put_noidle(&client->dev);
+			goto err_unlock;
+		}
+
+		/*
+		 * Apply default & customized values
+		 * and then start streaming.
+		 */
+		ret = imx477_start_streaming(imx477);
+		if (ret)
+			goto err_rpm_put;
+	} else {
+		imx477_stop_streaming(imx477);
+		pm_runtime_put(&client->dev);
+	}
+
+	imx477->streaming = enable;
+
+	/* vflip and hflip cannot change during streaming */
+	__v4l2_ctrl_grab(imx477->vflip, enable);
+	__v4l2_ctrl_grab(imx477->hflip, enable);
+
+	mutex_unlock(&imx477->mutex);
+
+	return ret;
+
+err_rpm_put:
+	pm_runtime_put(&client->dev);
+err_unlock:
+	mutex_unlock(&imx477->mutex);
+
+	return ret;
+}
+
+/* Power/clock management functions */
+static int imx477_power_on(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct imx477 *imx477 = to_imx477(sd);
+	int ret;
+
+	ret = regulator_bulk_enable(IMX477_NUM_SUPPLIES,
+				    imx477->supplies);
+	if (ret) {
+		dev_err(&client->dev, "%s: failed to enable regulators\n",
+			__func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(imx477->xclk);
+	if (ret) {
+		dev_err(&client->dev, "%s: failed to enable clock\n",
+			__func__);
+		goto reg_off;
+	}
+
+	gpiod_set_value_cansleep(imx477->reset_gpio, 1);
+	usleep_range(IMX477_XCLR_MIN_DELAY_US,
+		     IMX477_XCLR_MIN_DELAY_US + IMX477_XCLR_DELAY_RANGE_US);
+
+	return 0;
+
+reg_off:
+	regulator_bulk_disable(IMX477_NUM_SUPPLIES, imx477->supplies);
+	return ret;
+}
+
+static int imx477_power_off(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct imx477 *imx477 = to_imx477(sd);
+
+	gpiod_set_value_cansleep(imx477->reset_gpio, 0);
+	regulator_bulk_disable(IMX477_NUM_SUPPLIES, imx477->supplies);
+	clk_disable_unprepare(imx477->xclk);
+
+	/* Force reprogramming of the common registers when powered up again. */
+	imx477->common_regs_written = false;
+
+	return 0;
+}
+
+static int __maybe_unused imx477_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct imx477 *imx477 = to_imx477(sd);
+
+	if (imx477->streaming)
+		imx477_stop_streaming(imx477);
+
+	return 0;
+}
+
+static int __maybe_unused imx477_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct imx477 *imx477 = to_imx477(sd);
+	int ret;
+
+	if (imx477->streaming) {
+		ret = imx477_start_streaming(imx477);
+		if (ret)
+			goto error;
+	}
+
+	return 0;
+
+error:
+	imx477_stop_streaming(imx477);
+	imx477->streaming = 0;
+	return ret;
+}
+
+static int imx477_get_regulators(struct imx477 *imx477)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
+	unsigned int i;
+
+	for (i = 0; i < IMX477_NUM_SUPPLIES; i++)
+		imx477->supplies[i].supply = imx477_supply_name[i];
+
+	return devm_regulator_bulk_get(&client->dev,
+				       IMX477_NUM_SUPPLIES,
+				       imx477->supplies);
+}
+
+/* Verify chip ID */
+static int imx477_identify_module(struct imx477 *imx477, u32 expected_id)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
+	int ret;
+	u32 val;
+
+	ret = imx477_read_reg(imx477, IMX477_REG_CHIP_ID,
+			      IMX477_REG_VALUE_16BIT, &val);
+	if (ret) {
+		dev_err(&client->dev, "failed to read chip id %x, with error %d\n",
+			expected_id, ret);
+		return ret;
+	}
+
+	if (val != expected_id) {
+		dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+			expected_id, val);
+		return -EIO;
+	}
+
+	dev_info(&client->dev, "Device found is imx%x\n", val);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops imx477_core_ops = {
+	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops imx477_video_ops = {
+	.s_stream = imx477_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx477_pad_ops = {
+	.enum_mbus_code = imx477_enum_mbus_code,
+	.get_fmt = imx477_get_pad_format,
+	.set_fmt = imx477_set_pad_format,
+	.get_selection = imx477_get_selection,
+	.enum_frame_size = imx477_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops imx477_subdev_ops = {
+	.core = &imx477_core_ops,
+	.video = &imx477_video_ops,
+	.pad = &imx477_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx477_internal_ops = {
+	.open = imx477_open,
+};
+
+/* Initialize control handlers */
+static int imx477_init_controls(struct imx477 *imx477)
+{
+	struct v4l2_ctrl_handler *ctrl_hdlr;
+	struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd);
+	struct v4l2_fwnode_device_properties props;
+	unsigned int i;
+	int ret;
+
+	ctrl_hdlr = &imx477->ctrl_handler;
+	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16);
+	if (ret)
+		return ret;
+
+	mutex_init(&imx477->mutex);
+	ctrl_hdlr->lock = &imx477->mutex;
+
+	/* By default, PIXEL_RATE is read only */
+	imx477->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx477_ctrl_ops,
+					       V4L2_CID_PIXEL_RATE,
+					       IMX477_PIXEL_RATE,
+					       IMX477_PIXEL_RATE, 1,
+					       IMX477_PIXEL_RATE);
+
+	/*
+	 * Create the controls here, but mode specific limits are setup
+	 * in the imx477_set_framing_limits() call below.
+	 */
+	imx477->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx477_ctrl_ops,
+					   V4L2_CID_VBLANK, 0, 0xffff, 1, 0);
+	imx477->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx477_ctrl_ops,
+					   V4L2_CID_HBLANK, 0, 0xffff, 1, 0);
+
+	/* HBLANK is read-only for now, but does change with mode. */
+	if (imx477->hblank)
+		imx477->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	imx477->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx477_ctrl_ops,
+					     V4L2_CID_EXPOSURE,
+					     IMX477_EXPOSURE_MIN,
+					     IMX477_EXPOSURE_MAX,
+					     IMX477_EXPOSURE_STEP,
+					     IMX477_EXPOSURE_DEFAULT);
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &imx477_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+			  IMX477_ANA_GAIN_MIN, IMX477_ANA_GAIN_MAX,
+			  IMX477_ANA_GAIN_STEP, IMX477_ANA_GAIN_DEFAULT);
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &imx477_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+			  IMX477_DGTL_GAIN_MIN, IMX477_DGTL_GAIN_MAX,
+			  IMX477_DGTL_GAIN_STEP, IMX477_DGTL_GAIN_DEFAULT);
+
+	imx477->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx477_ctrl_ops,
+					  V4L2_CID_HFLIP, 0, 1, 1, 0);
+	if (imx477->hflip)
+		imx477->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+	imx477->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx477_ctrl_ops,
+					  V4L2_CID_VFLIP, 0, 1, 1, 0);
+	if (imx477->vflip)
+		imx477->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx477_ctrl_ops,
+				     V4L2_CID_TEST_PATTERN,
+				     ARRAY_SIZE(imx477_test_pattern_menu) - 1,
+				     0, 0, imx477_test_pattern_menu);
+	for (i = 0; i < 4; i++) {
+		/*
+		 * The assumption is that
+		 * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
+		 * V4L2_CID_TEST_PATTERN_BLUE   == V4L2_CID_TEST_PATTERN_RED + 2
+		 * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
+		 */
+		v4l2_ctrl_new_std(ctrl_hdlr, &imx477_ctrl_ops,
+				  V4L2_CID_TEST_PATTERN_RED + i,
+				  IMX477_TEST_PATTERN_COLOUR_MIN,
+				  IMX477_TEST_PATTERN_COLOUR_MAX,
+				  IMX477_TEST_PATTERN_COLOUR_STEP,
+				  IMX477_TEST_PATTERN_COLOUR_MAX);
+		/* The "Solid color" pattern is white by default */
+	}
+
+	if (ctrl_hdlr->error) {
+		ret = ctrl_hdlr->error;
+		dev_err(&client->dev, "%s control init failed (%d)\n",
+			__func__, ret);
+		goto error;
+	}
+
+	ret = v4l2_fwnode_device_parse(&client->dev, &props);
+	if (ret)
+		goto error;
+
+	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx477_ctrl_ops,
+					      &props);
+	if (ret)
+		goto error;
+
+	imx477->sd.ctrl_handler = ctrl_hdlr;
+
+	/* Setup exposure and frame/line length limits. */
+	imx477_set_framing_limits(imx477);
+
+	return 0;
+
+error:
+	v4l2_ctrl_handler_free(ctrl_hdlr);
+	mutex_destroy(&imx477->mutex);
+
+	return ret;
+}
+
+static void imx477_free_controls(struct imx477 *imx477)
+{
+	v4l2_ctrl_handler_free(imx477->sd.ctrl_handler);
+	mutex_destroy(&imx477->mutex);
+}
+
+static int imx477_check_hwcfg(struct device *dev)
+{
+	struct fwnode_handle *endpoint;
+	struct v4l2_fwnode_endpoint ep_cfg = {
+		.bus_type = V4L2_MBUS_CSI2_DPHY
+	};
+	int ret = -EINVAL;
+
+	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+	if (!endpoint) {
+		dev_err(dev, "endpoint node not found\n");
+		return -EINVAL;
+	}
+
+	if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
+		dev_err(dev, "could not parse endpoint\n");
+		goto error_out;
+	}
+
+	/* Check the number of MIPI CSI2 data lanes */
+	if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
+		dev_err(dev, "only 2 data lanes are currently supported\n");
+		goto error_out;
+	}
+
+	/* Check the link frequency set in device tree */
+	if (!ep_cfg.nr_of_link_frequencies) {
+		dev_err(dev, "link-frequency property not found in DT\n");
+		goto error_out;
+	}
+
+	if (ep_cfg.nr_of_link_frequencies != 1 ||
+	    ep_cfg.link_frequencies[0] != IMX477_DEFAULT_LINK_FREQ) {
+		dev_err(dev, "Link frequency not supported: %lld\n",
+			ep_cfg.link_frequencies[0]);
+		goto error_out;
+	}
+
+	ret = 0;
+
+error_out:
+	v4l2_fwnode_endpoint_free(&ep_cfg);
+	fwnode_handle_put(endpoint);
+
+	return ret;
+}
+
+static const struct imx477_compatible_data imx477_compatible = {
+	.chip_id = IMX477_CHIP_ID,
+	.extra_regs = {
+		.num_of_regs = 0,
+		.regs = NULL
+	}
+};
+
+static const struct imx477_reg imx378_regs[] = {
+	{0x3e35, 0x01},
+	{0x4421, 0x08},
+	{0x3ff9, 0x00},
+};
+
+static const struct imx477_compatible_data imx378_compatible = {
+	.chip_id = IMX378_CHIP_ID,
+	.extra_regs = {
+		.num_of_regs = ARRAY_SIZE(imx378_regs),
+		.regs = imx378_regs
+	}
+};
+
+static const struct of_device_id imx477_dt_ids[] = {
+	{ .compatible = "sony,imx477", .data = &imx477_compatible },
+	{ .compatible = "sony,imx378", .data = &imx378_compatible },
+	{ /* sentinel */ }
+};
+
+static int imx477_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct imx477 *imx477;
+	const struct of_device_id *match;
+	int ret;
+
+	imx477 = devm_kzalloc(&client->dev, sizeof(*imx477), GFP_KERNEL);
+	if (!imx477)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&imx477->sd, client, &imx477_subdev_ops);
+
+	match = of_match_device(imx477_dt_ids, dev);
+	if (!match)
+		return -ENODEV;
+	imx477->compatible_data =
+		(const struct imx477_compatible_data *)match->data;
+
+	/* Check the hardware configuration in device tree */
+	if (imx477_check_hwcfg(dev))
+		return -EINVAL;
+
+	/* Get system clock (xclk) */
+	imx477->xclk = devm_clk_get(dev, NULL);
+	if (IS_ERR(imx477->xclk)) {
+		dev_err(dev, "failed to get xclk\n");
+		return PTR_ERR(imx477->xclk);
+	}
+
+	imx477->xclk_freq = clk_get_rate(imx477->xclk);
+	if (imx477->xclk_freq != IMX477_XCLK_FREQ) {
+		dev_err(dev, "xclk frequency not supported: %d Hz\n",
+			imx477->xclk_freq);
+		return -EINVAL;
+	}
+
+	ret = imx477_get_regulators(imx477);
+	if (ret) {
+		dev_err(dev, "failed to get regulators\n");
+		return ret;
+	}
+
+	/* Request optional enable pin */
+	imx477->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						     GPIOD_OUT_HIGH);
+
+	/*
+	 * The sensor must be powered for imx477_identify_module()
+	 * to be able to read the CHIP_ID register
+	 */
+	ret = imx477_power_on(dev);
+	if (ret)
+		return ret;
+
+	ret = imx477_identify_module(imx477, imx477->compatible_data->chip_id);
+	if (ret)
+		goto error_power_off;
+
+	/* Initialize default format */
+	imx477_set_default_format(imx477);
+
+	/* Enable runtime PM and turn off the device */
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
+
+	/* This needs the pm runtime to be registered. */
+	ret = imx477_init_controls(imx477);
+	if (ret)
+		goto error_power_off;
+
+	/* Initialize subdev */
+	imx477->sd.internal_ops = &imx477_internal_ops;
+	imx477->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+			    V4L2_SUBDEV_FL_HAS_EVENTS;
+	imx477->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+	/* Initialize source pads */
+	imx477->pad[IMAGE_PAD].flags = MEDIA_PAD_FL_SOURCE;
+	imx477->pad[METADATA_PAD].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&imx477->sd.entity, NUM_PADS, imx477->pad);
+	if (ret) {
+		dev_err(dev, "failed to init entity pads: %d\n", ret);
+		goto error_handler_free;
+	}
+
+	ret = v4l2_async_register_subdev_sensor_common(&imx477->sd);
+	if (ret < 0) {
+		dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
+		goto error_media_entity;
+	}
+
+	return 0;
+
+error_media_entity:
+	media_entity_cleanup(&imx477->sd.entity);
+
+error_handler_free:
+	imx477_free_controls(imx477);
+
+error_power_off:
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	imx477_power_off(&client->dev);
+
+	return ret;
+}
+
+static int imx477_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct imx477 *imx477 = to_imx477(sd);
+
+	v4l2_async_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	imx477_free_controls(imx477);
+
+	pm_runtime_disable(&client->dev);
+	if (!pm_runtime_status_suspended(&client->dev))
+		imx477_power_off(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+
+	return 0;
+}
+
+MODULE_DEVICE_TABLE(of, imx477_dt_ids);
+
+static const struct dev_pm_ops imx477_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(imx477_suspend, imx477_resume)
+	SET_RUNTIME_PM_OPS(imx477_power_off, imx477_power_on, NULL)
+};
+
+static struct i2c_driver imx477_i2c_driver = {
+	.driver = {
+		.name = "imx477",
+		.of_match_table	= imx477_dt_ids,
+		.pm = &imx477_pm_ops,
+	},
+	.probe_new = imx477_probe,
+	.remove = imx477_remove,
+};
+
+module_i2c_driver(imx477_i2c_driver);
+
+MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>");
+MODULE_DESCRIPTION("Sony IMX477 sensor driver");
+MODULE_LICENSE("GPL v2");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/irs1125.c linux-5.10.52-v7l+/drivers/media/i2c/irs1125.c
--- linux-5.10.52-orig/drivers/media/i2c/irs1125.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/media/i2c/irs1125.c	2021-07-25 16:46:05.698295374 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A V4L2 driver for Infineon IRS1125 TOF cameras.
+ * Copyright (C) 2018, pieye GmbH
+ *
+ * Based on V4L2 OmniVision OV5647 Image Sensor driver
+ * Copyright (C) 2016 Ramiro Oliveira <roliveir@synopsys.com>
+ *
+ * DT / fwnode changes, and GPIO control taken from ov5640.c
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
+ *
+ */
+
+#include "irs1125.h"
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-mediabus.h>
+
+#define CHECK_BIT(val, pos) ((val) & BIT(pos))
+
+#define SENSOR_NAME "irs1125"
+
+#define RESET_ACTIVE_DELAY_MS	 20
+
+#define IRS1125_ALTERNATE_FW "irs1125_af.bin"
+
+#define IRS1125_REG_SAFE_RECONFIG	0xA850
+#define IRS1125_REG_CSICFG		0xA882
+#define IRS1125_REG_DESIGN_STEP		0xB0AD
+#define IRS1125_REG_EFUSEVAL2		0xB09F
+#define IRS1125_REG_EFUSEVAL3		0xB0A0
+#define IRS1125_REG_EFUSEVAL4		0xB0A1
+#define IRS1125_REG_DMEM_SHADOW		0xC320
+
+#define IRS1125_DESIGN_STEP_EXPECTED	0x0a12
+
+#define IRS1125_ROW_START_DEF		0
+#define IRS1125_COLUMN_START_DEF	0
+#define IRS1125_WINDOW_HEIGHT_DEF	288
+#define IRS1125_WINDOW_WIDTH_DEF	352
+
+struct regval_list {
+	u16 addr;
+	u16 data;
+};
+
+struct irs1125 {
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	/* the parsed DT endpoint info */
+	struct v4l2_fwnode_endpoint ep;
+
+	struct clk *xclk;
+	struct v4l2_ctrl_handler ctrl_handler;
+
+	/* To serialize asynchronus callbacks */
+	struct mutex lock;
+
+	/* image data layout */
+	unsigned int num_seq;
+
+	/* reset pin */
+	struct gpio_desc *reset;
+
+	/* V4l2 Controls to grab */
+	struct v4l2_ctrl *ctrl_modplls;
+	struct v4l2_ctrl *ctrl_numseq;
+
+	int power_count;
+	bool mod_pll_init;
+};
+
+static inline struct irs1125 *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct irs1125, sd);
+}
+
+static const char *expo_ctrl_names[IRS1125_NUM_SEQ_ENTRIES] = {
+	"safe reconfiguration of exposure of sequence 0",
+	"safe reconfiguration of exposure of sequence 1",
+	"safe reconfiguration of exposure of sequence 2",
+	"safe reconfiguration of exposure of sequence 3",
+	"safe reconfiguration of exposure of sequence 4",
+	"safe reconfiguration of exposure of sequence 5",
+	"safe reconfiguration of exposure of sequence 6",
+	"safe reconfiguration of exposure of sequence 7",
+	"safe reconfiguration of exposure of sequence 8",
+	"safe reconfiguration of exposure of sequence 9",
+	"safe reconfiguration of exposure of sequence 10",
+	"safe reconfiguration of exposure of sequence 11",
+	"safe reconfiguration of exposure of sequence 12",
+	"safe reconfiguration of exposure of sequence 13",
+	"safe reconfiguration of exposure of sequence 14",
+	"safe reconfiguration of exposure of sequence 15",
+	"safe reconfiguration of exposure of sequence 16",
+	"safe reconfiguration of exposure of sequence 17",
+	"safe reconfiguration of exposure of sequence 18",
+	"safe reconfiguration of exposure of sequence 19",
+};
+
+static const char *frame_ctrl_names[IRS1125_NUM_SEQ_ENTRIES] = {
+	"safe reconfiguration of framerate of sequence 0",
+	"safe reconfiguration of framerate of sequence 1",
+	"safe reconfiguration of framerate of sequence 2",
+	"safe reconfiguration of framerate of sequence 3",
+	"safe reconfiguration of framerate of sequence 4",
+	"safe reconfiguration of framerate of sequence 5",
+	"safe reconfiguration of framerate of sequence 6",
+	"safe reconfiguration of framerate of sequence 7",
+	"safe reconfiguration of framerate of sequence 8",
+	"safe reconfiguration of framerate of sequence 9",
+	"safe reconfiguration of framerate of sequence 10",
+	"safe reconfiguration of framerate of sequence 11",
+	"safe reconfiguration of framerate of sequence 12",
+	"safe reconfiguration of framerate of sequence 13",
+	"safe reconfiguration of framerate of sequence 14",
+	"safe reconfiguration of framerate of sequence 15",
+	"safe reconfiguration of framerate of sequence 16",
+	"safe reconfiguration of framerate of sequence 17",
+	"safe reconfiguration of framerate of sequence 18",
+	"safe reconfiguration of framerate of sequence 19",
+};
+
+static struct regval_list irs1125_26mhz[] = {
+	{0xB017, 0x0413},
+	{0xB086, 0x3535},
+	{0xB0AE, 0xEF02},
+	{0xA000, 0x0004},
+	{0xFFFF, 100},
+
+	{0xB062, 0x6383},
+	{0xB063, 0x55A8},
+	{0xB068, 0x7628},
+	{0xB069, 0x03E2},
+
+	{0xFFFF, 100},
+	{0xB05A, 0x01C5},
+	{0xB05C, 0x0206},
+	{0xB05D, 0x01C5},
+	{0xB05F, 0x0206},
+	{0xB016, 0x1335},
+	{0xFFFF, 100},
+	{0xA893, 0x8261},
+	{0xA894, 0x89d8},
+	{0xA895, 0x131d},
+	{0xA896, 0x4251},
+	{0xA897, 0x9D8A},
+	{0xA898, 0x0BD8},
+	{0xA899, 0x2245},
+	{0xA89A, 0xAB9B},
+	{0xA89B, 0x03B9},
+	{0xA89C, 0x8041},
+	{0xA89D, 0xE07E},
+	{0xA89E, 0x0307},
+	{0xFFFF, 100},
+	{0xA88D, 0x0004},
+	{0xA800, 0x0E68},
+	{0xA801, 0x0000},
+	{0xA802, 0x000C},
+	{0xA803, 0x0000},
+	{0xA804, 0x0E68},
+	{0xA805, 0x0000},
+	{0xA806, 0x0440},
+	{0xA807, 0x0000},
+	{0xA808, 0x0E68},
+	{0xA809, 0x0000},
+	{0xA80A, 0x0884},
+	{0xA80B, 0x0000},
+	{0xA80C, 0x0E68},
+	{0xA80D, 0x0000},
+	{0xA80E, 0x0CC8},
+	{0xA80F, 0x0000},
+	{0xA810, 0x0E68},
+	{0xA811, 0x0000},
+	{0xA812, 0x2000},
+	{0xA813, 0x0000},
+	{0xA882, 0x0081},
+	{0xA88C, 0x403A},
+	{0xA88F, 0x031E},
+	{0xA892, 0x0351},
+	{0x9813, 0x13FF},
+	{0x981B, 0x7608},
+
+	{0xB008, 0x0000},
+	{0xB015, 0x1513},
+
+	{0xFFFF, 100}
+};
+
+static struct regval_list irs1125_seq_cfg_init[] = {
+	{0xC3A0, 0x823D},
+	{0xC3A1, 0xB13B},
+	{0xC3A2, 0x0313},
+	{0xC3A3, 0x4659},
+	{0xC3A4, 0xC4EC},
+	{0xC3A5, 0x03CE},
+	{0xC3A6, 0x4259},
+	{0xC3A7, 0xC4EC},
+	{0xC3A8, 0x03CE},
+	{0xC3A9, 0x8839},
+	{0xC3AA, 0x89D8},
+	{0xC3AB, 0x031D},
+
+	{0xC24C, 0x5529},
+	{0xC24D, 0x0000},
+	{0xC24E, 0x1200},
+	{0xC24F, 0x6CB2},
+	{0xC250, 0x0000},
+	{0xC251, 0x5529},
+	{0xC252, 0x42F4},
+	{0xC253, 0xD1AF},
+	{0xC254, 0x8A18},
+	{0xC255, 0x0002},
+	{0xC256, 0x5529},
+	{0xC257, 0x6276},
+	{0xC258, 0x11A7},
+	{0xC259, 0xD907},
+	{0xC25A, 0x0000},
+	{0xC25B, 0x5529},
+	{0xC25C, 0x07E0},
+	{0xC25D, 0x7BFE},
+	{0xC25E, 0x6402},
+	{0xC25F, 0x0019},
+
+	{0xC3AC, 0x0007},
+	{0xC3AD, 0xED88},
+	{0xC320, 0x003E},
+	{0xC321, 0x0000},
+	{0xC322, 0x2000},
+	{0xC323, 0x0000},
+	{0xC324, 0x0271},
+	{0xC325, 0x0000},
+	{0xC326, 0x000C},
+	{0xC327, 0x0000},
+	{0xC328, 0x0271},
+	{0xC329, 0x0000},
+	{0xC32A, 0x0440},
+	{0xC32B, 0x0000},
+	{0xC32C, 0x0271},
+	{0xC32D, 0x0000},
+	{0xC32E, 0x0884},
+	{0xC32F, 0x0000},
+	{0xC330, 0x0271},
+	{0xC331, 0x0000},
+	{0xC332, 0x0CC8},
+	{0xC333, 0x0000},
+	{0xA88D, 0x0004},
+
+	{0xA890, 0x0000},
+	{0xC219, 0x0002},
+	{0xC21A, 0x0000},
+	{0xC21B, 0x0000},
+	{0xC21C, 0x00CD},
+	{0xC21D, 0x0009},
+	{0xC21E, 0x00CD},
+	{0xC21F, 0x0009},
+
+	{0xA87C, 0x0000},
+	{0xC032, 0x0001},
+	{0xC034, 0x0000},
+	{0xC035, 0x0001},
+	{0xC039, 0x0000},
+	{0xC401, 0x0002},
+
+	{0xFFFF, 1}
+};
+
+static int irs1125_write(struct v4l2_subdev *sd, u16 reg, u16 val)
+{
+	int ret;
+	unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff};
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	ret = i2c_master_send(client, data, 4);
+	if (ret < 0)
+		dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
+			__func__, reg);
+
+	dev_dbg(&client->dev, "write addr 0x%04x, val 0x%04x\n", reg, val);
+	return ret;
+}
+
+static int irs1125_read(struct v4l2_subdev *sd, u16 reg, u16 *val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct i2c_msg msgs[2];
+	u8 addr_buf[2] = { reg >> 8, reg & 0xff };
+	u8 data_buf[2] = { 0, };
+	int ret;
+
+	/* Write register address */
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = ARRAY_SIZE(addr_buf);
+	msgs[0].buf = addr_buf;
+
+	/* Read data from register */
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = 2;
+	msgs[1].buf = data_buf;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret != ARRAY_SIZE(msgs)) {
+		if (ret >= 0)
+			ret = -EIO;
+		return ret;
+	}
+
+	*val = data_buf[1] | (data_buf[0] << 8);
+
+	return 0;
+}
+
+static int irs1125_write_array(struct v4l2_subdev *sd,
+			       struct regval_list *regs, int array_size)
+{
+	int i, ret;
+
+	for (i = 0; i < array_size; i++) {
+		if (regs[i].addr == 0xFFFF) {
+			msleep(regs[i].data);
+		} else {
+			ret = irs1125_write(sd, regs[i].addr, regs[i].data);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int irs1125_stream_on(struct v4l2_subdev *sd)
+{
+	int ret;
+	struct irs1125 *irs1125 = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	v4l2_ctrl_grab(irs1125->ctrl_numseq, 1);
+	v4l2_ctrl_grab(irs1125->ctrl_modplls, 1);
+
+	ret = irs1125_write(sd, 0xC400, 0x0001);
+	if (ret < 0) {
+		dev_err(&client->dev, "error enabling firmware: %d", ret);
+		return ret;
+	}
+
+	msleep(100);
+
+	return irs1125_write(sd, 0xA87C, 0x0001);
+}
+
+static int irs1125_stream_off(struct v4l2_subdev *sd)
+{
+	int ret;
+	struct irs1125 *irs1125 = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	v4l2_ctrl_grab(irs1125->ctrl_numseq, 0);
+	v4l2_ctrl_grab(irs1125->ctrl_modplls, 0);
+
+	ret = irs1125_write(sd, 0xA87C, 0x0000);
+	if (ret < 0) {
+		dev_err(&client->dev, "error disabling trigger: %d", ret);
+		return ret;
+	}
+
+	msleep(100);
+
+	return irs1125_write(sd, 0xC400, 0x0002);
+}
+
+static int __sensor_init(struct v4l2_subdev *sd)
+{
+	unsigned int cnt, idx;
+	int ret;
+	u16 val;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct irs1125 *irs1125 = to_state(sd);
+	const struct firmware *fw;
+	struct regval_list *reg_data;
+
+	cnt = 0;
+	while (1) {
+		ret = irs1125_read(sd, 0xC40F, &val);
+		if (ret < 0) {
+			dev_err(&client->dev, "read register 0xC40F failed\n");
+			return ret;
+		}
+		if (CHECK_BIT(val, 14) == 0)
+			break;
+
+		if (cnt >= 5) {
+			dev_err(&client->dev, "timeout waiting for 0xC40F\n");
+			return -EAGAIN;
+		}
+
+		cnt++;
+	}
+
+	ret = irs1125_write_array(sd, irs1125_26mhz,
+				  ARRAY_SIZE(irs1125_26mhz));
+	if (ret < 0) {
+		dev_err(&client->dev, "write sensor default regs error\n");
+		return ret;
+	}
+
+	/* set CSI-2 number of data lanes */
+	if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 1) {
+		val = 0x0001;
+	} else if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 2) {
+		val = 0x0081;
+	} else {
+		dev_err(&client->dev, "invalid number of data lanes %d\n",
+			irs1125->ep.bus.mipi_csi2.num_data_lanes);
+		return -EINVAL;
+	}
+
+	ret = irs1125_write(sd, IRS1125_REG_CSICFG, val);
+	if (ret < 0) {
+		dev_err(&client->dev, "write sensor csi2 config error\n");
+		return ret;
+	}
+
+	/* request the firmware, this will block and timeout */
+	ret = request_firmware(&fw, IRS1125_ALTERNATE_FW, &client->dev);
+	if (ret) {
+		dev_err(&client->dev,
+			"did not find the firmware file '%s' (status %d)\n",
+			IRS1125_ALTERNATE_FW, ret);
+		return ret;
+	}
+
+	if (fw->size % 4) {
+		dev_err(&client->dev, "firmware file '%s' invalid\n",
+			IRS1125_ALTERNATE_FW);
+		release_firmware(fw);
+		return -EINVAL;
+	}
+
+	for (idx = 0; idx < fw->size; idx += 4)	{
+		reg_data = (struct regval_list *)&fw->data[idx];
+		ret = irs1125_write(sd, reg_data->addr, reg_data->data);
+		if (ret < 0) {
+			dev_err(&client->dev, "firmware write error\n");
+			release_firmware(fw);
+			return ret;
+		}
+	}
+	release_firmware(fw);
+
+	ret = irs1125_write_array(sd, irs1125_seq_cfg_init,
+				  ARRAY_SIZE(irs1125_seq_cfg_init));
+	if (ret < 0) {
+		dev_err(&client->dev, "write default sequence failed\n");
+		return ret;
+	}
+
+	irs1125->mod_pll_init = true;
+	v4l2_ctrl_handler_setup(&irs1125->ctrl_handler);
+	irs1125->mod_pll_init = false;
+
+	return irs1125_write(sd, 0xA87C, 0x0001);
+}
+
+static int irs1125_sensor_power(struct v4l2_subdev *sd, int on)
+{
+	int ret = 0;
+	struct irs1125 *irs1125 = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&irs1125->lock);
+
+	if (on && !irs1125->power_count) {
+		gpiod_set_value_cansleep(irs1125->reset, 1);
+		msleep(RESET_ACTIVE_DELAY_MS);
+
+		ret = clk_prepare_enable(irs1125->xclk);
+		if (ret < 0) {
+			dev_err(&client->dev, "clk prepare enable failed\n");
+			goto out;
+		}
+
+		ret = __sensor_init(sd);
+		if (ret < 0) {
+			clk_disable_unprepare(irs1125->xclk);
+			dev_err(&client->dev,
+				"Camera not available, check Power\n");
+			goto out;
+		}
+	} else if (!on && irs1125->power_count == 1) {
+		gpiod_set_value_cansleep(irs1125->reset, 0);
+	}
+
+	/* Update the power count. */
+	irs1125->power_count += on ? 1 : -1;
+	WARN_ON(irs1125->power_count < 0);
+
+out:
+	mutex_unlock(&irs1125->lock);
+
+	return ret;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int irs1125_sensor_get_register(struct v4l2_subdev *sd,
+				       struct v4l2_dbg_register *reg)
+{
+	u16 val;
+	int ret;
+
+	ret = irs1125_read(sd, reg->reg & 0xffff, &val);
+	if (ret < 0)
+		return ret;
+
+	reg->val = val;
+	reg->size = 1;
+
+	return 0;
+}
+
+static int irs1125_sensor_set_register(struct v4l2_subdev *sd,
+				       const struct v4l2_dbg_register *reg)
+{
+	return irs1125_write(sd, reg->reg & 0xffff, reg->val & 0xffff);
+}
+#endif
+
+static const struct v4l2_subdev_core_ops irs1125_subdev_core_ops = {
+	.s_power = irs1125_sensor_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = irs1125_sensor_get_register,
+	.s_register = irs1125_sensor_set_register,
+#endif
+};
+
+static int irs1125_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	if (enable)
+		return irs1125_stream_on(sd);
+	else
+		return irs1125_stream_off(sd);
+}
+
+static const struct v4l2_subdev_video_ops irs1125_subdev_video_ops = {
+	.s_stream = irs1125_s_stream,
+};
+
+static int irs1125_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+	struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index > 0)
+		return -EINVAL;
+
+	code->code = MEDIA_BUS_FMT_Y12_1X12;
+
+	return 0;
+}
+
+static int irs1125_set_get_fmt(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *fmt = &format->format;
+	struct irs1125 *irs1125 = to_state(sd);
+
+	if (format->pad != 0)
+		return -EINVAL;
+
+	/* Only one format is supported, so return that */
+	memset(fmt, 0, sizeof(*fmt));
+	fmt->code = MEDIA_BUS_FMT_Y12_1X12;
+	fmt->colorspace = V4L2_COLORSPACE_RAW;
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->width = IRS1125_WINDOW_WIDTH_DEF;
+	fmt->height = IRS1125_WINDOW_HEIGHT_DEF * irs1125->num_seq;
+
+	return 0;
+}
+
+static const struct v4l2_subdev_pad_ops irs1125_subdev_pad_ops = {
+	.enum_mbus_code = irs1125_enum_mbus_code,
+	.set_fmt = irs1125_set_get_fmt,
+	.get_fmt = irs1125_set_get_fmt,
+};
+
+static const struct v4l2_subdev_ops irs1125_subdev_ops = {
+	.core = &irs1125_subdev_core_ops,
+	.video = &irs1125_subdev_video_ops,
+	.pad = &irs1125_subdev_pad_ops,
+};
+
+static int irs1125_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct irs1125 *dev = container_of(ctrl->handler,
+					struct irs1125, ctrl_handler);
+	struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+	int err = 0, i;
+
+	switch (ctrl->id) {
+	case IRS1125_CID_SAFE_RECONFIG_S0_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S0_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S1_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S1_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S2_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S2_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S3_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S3_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S4_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S4_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S5_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S5_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S6_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S6_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S7_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S7_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S8_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S8_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S9_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S9_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S10_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S10_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S11_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S11_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S12_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S12_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S13_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S13_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S14_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S14_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S15_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S15_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S16_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S16_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S17_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S17_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S18_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S18_FRAME:
+	case IRS1125_CID_SAFE_RECONFIG_S19_EXPO:
+	case IRS1125_CID_SAFE_RECONFIG_S19_FRAME: {
+		unsigned int offset = ctrl->id -
+			IRS1125_CID_SAFE_RECONFIG_S0_EXPO;
+
+		err = irs1125_write(&dev->sd,
+				    IRS1125_REG_SAFE_RECONFIG + offset,
+				    ctrl->val);
+		break;
+	}
+	case IRS1125_CID_MOD_PLL: {
+		struct irs1125_mod_pll *mod_new;
+
+		if (dev->mod_pll_init)
+			break;
+
+		mod_new = (struct irs1125_mod_pll *)ctrl->p_new.p;
+		for (i = 0; i < IRS1125_NUM_MOD_PLLS; i++) {
+			unsigned int pll_offset, ssc_offset;
+
+			pll_offset = i * 3;
+			ssc_offset = i * 5;
+
+			err = irs1125_write(&dev->sd, 0xC3A0 + pll_offset,
+					    mod_new[i].pllcfg1);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC3A1 + pll_offset,
+					    mod_new[i].pllcfg2);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC3A2 + pll_offset,
+					    mod_new[i].pllcfg3);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC24C + ssc_offset,
+					    mod_new[i].pllcfg4);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC24D + ssc_offset,
+					    mod_new[i].pllcfg5);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC24E + ssc_offset,
+					    mod_new[i].pllcfg6);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC24F + ssc_offset,
+					    mod_new[i].pllcfg7);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC250 + ssc_offset,
+					    mod_new[i].pllcfg8);
+			if (err < 0)
+				break;
+		}
+		break;
+	}
+	case IRS1125_CID_SEQ_CONFIG: {
+		struct irs1125_seq_cfg *cfg_new;
+
+		cfg_new = (struct irs1125_seq_cfg *)ctrl->p_new.p;
+		for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
+			unsigned int seq_offset = i * 4;
+			u16 addr, val;
+
+			addr = IRS1125_REG_DMEM_SHADOW + seq_offset;
+			val = cfg_new[i].exposure;
+			err = irs1125_write(&dev->sd, addr, val);
+			if (err < 0)
+				break;
+
+			addr = IRS1125_REG_DMEM_SHADOW + 1 + seq_offset;
+			val = cfg_new[i].framerate;
+			err = irs1125_write(&dev->sd, addr, val);
+			if (err < 0)
+				break;
+
+			addr = IRS1125_REG_DMEM_SHADOW + 2 + seq_offset;
+			val = cfg_new[i].ps;
+			err = irs1125_write(&dev->sd, addr, val);
+			if (err < 0)
+				break;
+
+			addr = IRS1125_REG_DMEM_SHADOW + 3 + seq_offset;
+			val = cfg_new[i].pll;
+			err = irs1125_write(&dev->sd, addr, val);
+			if (err < 0)
+				break;
+		}
+		break;
+	}
+	case IRS1125_CID_NUM_SEQS:
+		err = irs1125_write(&dev->sd, 0xA88D, ctrl->val - 1);
+		if (err >= 0)
+			dev->num_seq = ctrl->val;
+		break;
+	case IRS1125_CID_CONTINUOUS_TRIG:
+		if (ctrl->val == 0)
+			err = irs1125_write(&dev->sd, 0xA87C, 0);
+		else
+			err = irs1125_write(&dev->sd, 0xA87C, 1);
+		break;
+	case IRS1125_CID_TRIGGER:
+		if (ctrl->val != 0) {
+			err = irs1125_write(&dev->sd, 0xA87C, 1);
+			if (err >= 0)
+				err = irs1125_write(&dev->sd, 0xA87C, 0);
+		}
+		break;
+	case IRS1125_CID_RECONFIG:
+		if (ctrl->val != 0)
+			err = irs1125_write(&dev->sd, 0xA87A, 1);
+		break;
+	case IRS1125_CID_ILLU_ON:
+		if (ctrl->val == 0)
+			err = irs1125_write(&dev->sd, 0xA892, 0x377);
+		else
+			err = irs1125_write(&dev->sd, 0xA892, 0x355);
+		break;
+	default:
+		break;
+	}
+
+	if (err < 0)
+		dev_err(&client->dev, "Error executing control ID: %d, val %d, err %d",
+			ctrl->id, ctrl->val, err);
+	else
+		err = 0;
+
+	return err;
+}
+
+static const struct v4l2_ctrl_ops irs1125_ctrl_ops = {
+	.s_ctrl = irs1125_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config irs1125_custom_ctrls[] = {
+	{
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_NUM_SEQS,
+		.name = "Change number of sequences",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
+		.min = 1,
+		.max = 20,
+		.step = 1,
+		.def = 5,
+	}, {
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_MOD_PLL,
+		.name = "Reconfigure modulation PLLs",
+		.type = V4L2_CTRL_TYPE_U16,
+		.flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
+		.min = 0,
+		.max = U16_MAX,
+		.step = 1,
+		.def = 0,
+		.elem_size = sizeof(u16),
+		.dims = {sizeof(struct irs1125_mod_pll) / sizeof(u16),
+			IRS1125_NUM_MOD_PLLS}
+	}, {
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_SEQ_CONFIG,
+		.name = "Change sequence settings",
+		.type = V4L2_CTRL_TYPE_U16,
+		.flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
+		.min = 0,
+		.max = U16_MAX,
+		.step = 1,
+		.def = 0,
+		.elem_size = sizeof(u16),
+		.dims = {sizeof(struct irs1125_seq_cfg) / sizeof(u16),
+			IRS1125_NUM_SEQ_ENTRIES}
+	}, {
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_CONTINUOUS_TRIG,
+		.name = "Enable/disable continuous trigger",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
+		.min = 0,
+		.max = 1,
+		.step = 1,
+		.def = 0
+	}, {
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_TRIGGER,
+		.name = "Capture a single sequence",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
+		.min = 0,
+		.max = 1,
+		.step = 1,
+		.def = 0
+	}, {
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_RECONFIG,
+		.name = "Trigger imager reconfiguration",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
+		.min = 0,
+		.max = 1,
+		.step = 1,
+		.def = 0
+	}, {
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_ILLU_ON,
+		.name = "Turn illu on or off",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
+		.min = 0,
+		.max = 1,
+		.step = 1,
+		.def = 1
+	}, {
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_IDENT0,
+		.name = "Get ident 0 information",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.flags = V4L2_CTRL_FLAG_READ_ONLY,
+		.min = S32_MIN,
+		.max = S32_MAX,
+		.step = 1,
+		.def = 0
+	}, {
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_IDENT1,
+		.name = "Get ident 1 information",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.flags = V4L2_CTRL_FLAG_READ_ONLY,
+		.min = S32_MIN,
+		.max = S32_MAX,
+		.step = 1,
+		.def = 0
+	}, {
+		.ops = &irs1125_ctrl_ops,
+		.id = IRS1125_CID_IDENT2,
+		.name = "Get ident 2 information",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.flags = V4L2_CTRL_FLAG_READ_ONLY,
+		.min = S32_MIN,
+		.max = S32_MAX,
+		.step = 1,
+		.def = 0
+	}
+};
+
+static int irs1125_detect(struct v4l2_subdev *sd)
+{
+	u16 read;
+	int ret;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	ret = irs1125_read(sd, IRS1125_REG_DESIGN_STEP, &read);
+	if (ret < 0) {
+		dev_err(&client->dev, "error reading from i2c\n");
+		return ret;
+	}
+
+	if (read != IRS1125_DESIGN_STEP_EXPECTED) {
+		dev_err(&client->dev, "Design step expected 0x%x got 0x%x",
+			IRS1125_DESIGN_STEP_EXPECTED, read);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int irs1125_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt *format =
+	v4l2_subdev_get_try_format(sd, fh->pad, 0);
+
+	format->code = MEDIA_BUS_FMT_Y12_1X12;
+	format->width = IRS1125_WINDOW_WIDTH_DEF;
+	format->height = IRS1125_WINDOW_HEIGHT_DEF;
+	format->field = V4L2_FIELD_NONE;
+	format->colorspace = V4L2_COLORSPACE_RAW;
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops irs1125_subdev_internal_ops = {
+	.open = irs1125_open,
+};
+
+static int irs1125_ctrls_init(struct irs1125 *sensor, struct device *dev)
+{
+	struct v4l2_ctrl *ctrl;
+	int err, i;
+	struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler;
+	struct v4l2_ctrl_config ctrl_cfg = {
+		.ops = &irs1125_ctrl_ops,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = U16_MAX,
+		.step = 1,
+		.def = 0x1000
+	};
+
+	v4l2_ctrl_handler_init(hdl, ARRAY_SIZE(irs1125_custom_ctrls));
+
+	for (i = 0; i < ARRAY_SIZE(irs1125_custom_ctrls); i++)	{
+		ctrl = v4l2_ctrl_new_custom(hdl, &irs1125_custom_ctrls[i],
+					    NULL);
+		if (!ctrl)
+			dev_err(dev, "Failed to init custom control %s\n",
+				irs1125_custom_ctrls[i].name);
+		else if (irs1125_custom_ctrls[i].id == IRS1125_CID_NUM_SEQS)
+			sensor->ctrl_numseq = ctrl;
+		else if (irs1125_custom_ctrls[i].id == IRS1125_CID_MOD_PLL)
+			sensor->ctrl_modplls = ctrl;
+	}
+
+	if (hdl->error)	{
+		dev_err(dev, "Error %d adding controls\n", hdl->error);
+		err = hdl->error;
+		goto error_ctrls;
+	}
+
+	for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
+		ctrl_cfg.name = expo_ctrl_names[i];
+		ctrl_cfg.id = IRS1125_CID_SAFE_RECONFIG_S0_EXPO + i * 2;
+		ctrl = v4l2_ctrl_new_custom(hdl, &ctrl_cfg,
+					    NULL);
+		if (!ctrl)
+			dev_err(dev, "Failed to init exposure control %s\n",
+				ctrl_cfg.name);
+	}
+
+	ctrl_cfg.def = 0;
+	for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
+		ctrl_cfg.name = frame_ctrl_names[i];
+		ctrl_cfg.id = IRS1125_CID_SAFE_RECONFIG_S0_FRAME + i * 2;
+		ctrl = v4l2_ctrl_new_custom(hdl, &ctrl_cfg,
+					    NULL);
+		if (!ctrl)
+			dev_err(dev, "Failed to init framerate control %s\n",
+				ctrl_cfg.name);
+	}
+
+	sensor->sd.ctrl_handler = hdl;
+	return 0;
+
+error_ctrls:
+	v4l2_ctrl_handler_free(&sensor->ctrl_handler);
+	return -err;
+}
+
+static int irs1125_ident_setup(struct irs1125 *sensor, struct device *dev)
+{
+	int ret;
+	struct v4l2_ctrl *ctrl;
+	struct v4l2_subdev *sd;
+	u16 read;
+
+	sd = &sensor->sd;
+
+	ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT0);
+	if (!ctrl) {
+		dev_err(dev, "could not find device ctrl.\n");
+		return -EINVAL;
+	}
+
+	ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL2, &read);
+	if (ret < 0) {
+		dev_err(dev, "error reading from i2c\n");
+		return -EIO;
+	}
+
+	v4l2_ctrl_s_ctrl(ctrl, read);
+
+	ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT1);
+	if (!ctrl) {
+		dev_err(dev, "could not find device ctrl.\n");
+		return -EINVAL;
+	}
+
+	ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL3, &read);
+	if (ret < 0) {
+		dev_err(dev, "error reading from i2c\n");
+		return -EIO;
+	}
+
+	v4l2_ctrl_s_ctrl(ctrl, read);
+
+	ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT2);
+	if (!ctrl) {
+		dev_err(dev, "could not find device ctrl.\n");
+		return -EINVAL;
+	}
+
+	ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL4, &read);
+	if (ret < 0) {
+		dev_err(dev, "error reading from i2c\n");
+		return -EIO;
+	}
+	v4l2_ctrl_s_ctrl(ctrl, read & 0xFFFC);
+
+	return 0;
+}
+
+static int irs1125_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct irs1125 *sensor;
+	int ret;
+	struct fwnode_handle *endpoint;
+	u32 xclk_freq;
+	int gpio_num;
+
+	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+	if (!sensor)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&sensor->sd, client, &irs1125_subdev_ops);
+
+	/* Get CSI2 bus config */
+	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev),
+						  NULL);
+	if (!endpoint) {
+		dev_err(dev, "endpoint node not found\n");
+		return -EINVAL;
+	}
+
+	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
+	fwnode_handle_put(endpoint);
+	if (ret) {
+		dev_err(dev, "Could not parse endpoint\n");
+		return ret;
+	}
+
+	/* get system clock (xclk) */
+	sensor->xclk = devm_clk_get(dev, NULL);
+	if (IS_ERR(sensor->xclk)) {
+		dev_err(dev, "could not get xclk");
+		return PTR_ERR(sensor->xclk);
+	}
+
+	xclk_freq = clk_get_rate(sensor->xclk);
+	if (xclk_freq != 26000000) {
+		dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq);
+		return -EINVAL;
+	}
+
+	sensor->num_seq = 5;
+
+	/* Request the power down GPIO */
+	sensor->reset = devm_gpiod_get(&client->dev, "pwdn",
+				       GPIOD_OUT_LOW);
+
+	if (IS_ERR(sensor->reset)) {
+		dev_err(dev, "could not get reset");
+		return PTR_ERR(sensor->reset);
+	}
+
+	gpio_num = desc_to_gpio(sensor->reset);
+	dev_dbg(&client->dev, "reset on GPIO num %d\n", gpio_num);
+
+	mutex_init(&sensor->lock);
+
+	ret = irs1125_ctrls_init(sensor, dev);
+	if (ret < 0)
+		goto mutex_remove;
+
+	sensor->sd.internal_ops = &irs1125_subdev_internal_ops;
+	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
+	if (ret < 0)
+		goto mutex_remove;
+
+	gpiod_set_value_cansleep(sensor->reset, 1);
+	msleep(RESET_ACTIVE_DELAY_MS);
+
+	ret = irs1125_detect(&sensor->sd);
+	if (ret < 0)
+		goto error;
+
+	ret = irs1125_ident_setup(sensor, dev);
+	if (ret < 0)
+		goto error;
+
+	gpiod_set_value_cansleep(sensor->reset, 0);
+
+	ret = v4l2_async_register_subdev(&sensor->sd);
+	if (ret < 0)
+		goto error;
+
+	dev_dbg(dev, "Infineon IRS1125 camera driver probed\n");
+
+	return 0;
+
+error:
+	media_entity_cleanup(&sensor->sd.entity);
+mutex_remove:
+	mutex_destroy(&sensor->lock);
+	return ret;
+}
+
+static int irs1125_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct irs1125 *irs1125 = to_state(sd);
+
+	v4l2_async_unregister_subdev(&irs1125->sd);
+	media_entity_cleanup(&irs1125->sd.entity);
+	v4l2_device_unregister_subdev(sd);
+	mutex_destroy(&irs1125->lock);
+	v4l2_ctrl_handler_free(&irs1125->ctrl_handler);
+
+	return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id irs1125_of_match[] = {
+	{ .compatible = "infineon,irs1125" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, irs1125_of_match);
+#endif
+
+static struct i2c_driver irs1125_driver = {
+	.driver = {
+		.of_match_table = of_match_ptr(irs1125_of_match),
+		.name	 = SENSOR_NAME,
+	},
+	.probe		= irs1125_probe,
+	.remove		= irs1125_remove,
+};
+
+module_i2c_driver(irs1125_driver);
+
+MODULE_AUTHOR("Markus Proeller <markus.proeller@pieye.org>");
+MODULE_DESCRIPTION("Infineon irs1125 sensor driver");
+MODULE_LICENSE("GPL v2");
+
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/irs1125.h linux-5.10.52-v7l+/drivers/media/i2c/irs1125.h
--- linux-5.10.52-orig/drivers/media/i2c/irs1125.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/media/i2c/irs1125.h	2021-07-25 16:46:05.698295374 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * A V4L2 driver for Infineon IRS1125 TOF cameras.
+ * Copyright (C) 2018, pieye GmbH
+ *
+ * Based on V4L2 OmniVision OV5647 Image Sensor driver
+ * Copyright (C) 2016 Ramiro Oliveira <roliveir@synopsys.com>
+ *
+ * DT / fwnode changes, and GPIO control taken from ov5640.c
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
+ *
+ */
+
+#ifndef IRS1125_H
+#define IRS1125_H
+
+#include <linux/v4l2-controls.h>
+#include <linux/types.h>
+
+#define IRS1125_NUM_SEQ_ENTRIES 20
+#define IRS1125_NUM_MOD_PLLS 4
+
+#define IRS1125_CID_CUSTOM_BASE			(V4L2_CID_USER_BASE | 0xf000)
+#define IRS1125_CID_CONTINUOUS_TRIG		(IRS1125_CID_CUSTOM_BASE + 1)
+#define IRS1125_CID_TRIGGER			(IRS1125_CID_CUSTOM_BASE + 2)
+#define IRS1125_CID_RECONFIG			(IRS1125_CID_CUSTOM_BASE + 3)
+#define IRS1125_CID_ILLU_ON			(IRS1125_CID_CUSTOM_BASE + 4)
+#define IRS1125_CID_NUM_SEQS			(IRS1125_CID_CUSTOM_BASE + 5)
+#define IRS1125_CID_MOD_PLL			(IRS1125_CID_CUSTOM_BASE + 6)
+#define IRS1125_CID_SEQ_CONFIG			(IRS1125_CID_CUSTOM_BASE + 7)
+#define IRS1125_CID_IDENT0			(IRS1125_CID_CUSTOM_BASE + 8)
+#define IRS1125_CID_IDENT1			(IRS1125_CID_CUSTOM_BASE + 9)
+#define IRS1125_CID_IDENT2			(IRS1125_CID_CUSTOM_BASE + 10)
+#define IRS1125_CID_SAFE_RECONFIG_S0_EXPO	(IRS1125_CID_CUSTOM_BASE + 11)
+#define IRS1125_CID_SAFE_RECONFIG_S0_FRAME	(IRS1125_CID_CUSTOM_BASE + 12)
+#define IRS1125_CID_SAFE_RECONFIG_S1_EXPO	(IRS1125_CID_CUSTOM_BASE + 13)
+#define IRS1125_CID_SAFE_RECONFIG_S1_FRAME	(IRS1125_CID_CUSTOM_BASE + 14)
+#define IRS1125_CID_SAFE_RECONFIG_S2_EXPO	(IRS1125_CID_CUSTOM_BASE + 15)
+#define IRS1125_CID_SAFE_RECONFIG_S2_FRAME	(IRS1125_CID_CUSTOM_BASE + 16)
+#define IRS1125_CID_SAFE_RECONFIG_S3_EXPO	(IRS1125_CID_CUSTOM_BASE + 17)
+#define IRS1125_CID_SAFE_RECONFIG_S3_FRAME	(IRS1125_CID_CUSTOM_BASE + 18)
+#define IRS1125_CID_SAFE_RECONFIG_S4_EXPO	(IRS1125_CID_CUSTOM_BASE + 19)
+#define IRS1125_CID_SAFE_RECONFIG_S4_FRAME	(IRS1125_CID_CUSTOM_BASE + 20)
+#define IRS1125_CID_SAFE_RECONFIG_S5_EXPO	(IRS1125_CID_CUSTOM_BASE + 21)
+#define IRS1125_CID_SAFE_RECONFIG_S5_FRAME	(IRS1125_CID_CUSTOM_BASE + 22)
+#define IRS1125_CID_SAFE_RECONFIG_S6_EXPO	(IRS1125_CID_CUSTOM_BASE + 23)
+#define IRS1125_CID_SAFE_RECONFIG_S6_FRAME	(IRS1125_CID_CUSTOM_BASE + 24)
+#define IRS1125_CID_SAFE_RECONFIG_S7_EXPO	(IRS1125_CID_CUSTOM_BASE + 25)
+#define IRS1125_CID_SAFE_RECONFIG_S7_FRAME	(IRS1125_CID_CUSTOM_BASE + 26)
+#define IRS1125_CID_SAFE_RECONFIG_S8_EXPO	(IRS1125_CID_CUSTOM_BASE + 27)
+#define IRS1125_CID_SAFE_RECONFIG_S8_FRAME	(IRS1125_CID_CUSTOM_BASE + 28)
+#define IRS1125_CID_SAFE_RECONFIG_S9_EXPO	(IRS1125_CID_CUSTOM_BASE + 29)
+#define IRS1125_CID_SAFE_RECONFIG_S9_FRAME	(IRS1125_CID_CUSTOM_BASE + 30)
+#define IRS1125_CID_SAFE_RECONFIG_S10_EXPO	(IRS1125_CID_CUSTOM_BASE + 31)
+#define IRS1125_CID_SAFE_RECONFIG_S10_FRAME	(IRS1125_CID_CUSTOM_BASE + 32)
+#define IRS1125_CID_SAFE_RECONFIG_S11_EXPO	(IRS1125_CID_CUSTOM_BASE + 33)
+#define IRS1125_CID_SAFE_RECONFIG_S11_FRAME	(IRS1125_CID_CUSTOM_BASE + 34)
+#define IRS1125_CID_SAFE_RECONFIG_S12_EXPO	(IRS1125_CID_CUSTOM_BASE + 35)
+#define IRS1125_CID_SAFE_RECONFIG_S12_FRAME	(IRS1125_CID_CUSTOM_BASE + 36)
+#define IRS1125_CID_SAFE_RECONFIG_S13_EXPO	(IRS1125_CID_CUSTOM_BASE + 37)
+#define IRS1125_CID_SAFE_RECONFIG_S13_FRAME	(IRS1125_CID_CUSTOM_BASE + 38)
+#define IRS1125_CID_SAFE_RECONFIG_S14_EXPO	(IRS1125_CID_CUSTOM_BASE + 39)
+#define IRS1125_CID_SAFE_RECONFIG_S14_FRAME	(IRS1125_CID_CUSTOM_BASE + 40)
+#define IRS1125_CID_SAFE_RECONFIG_S15_EXPO	(IRS1125_CID_CUSTOM_BASE + 41)
+#define IRS1125_CID_SAFE_RECONFIG_S15_FRAME	(IRS1125_CID_CUSTOM_BASE + 42)
+#define IRS1125_CID_SAFE_RECONFIG_S16_EXPO	(IRS1125_CID_CUSTOM_BASE + 43)
+#define IRS1125_CID_SAFE_RECONFIG_S16_FRAME	(IRS1125_CID_CUSTOM_BASE + 44)
+#define IRS1125_CID_SAFE_RECONFIG_S17_EXPO	(IRS1125_CID_CUSTOM_BASE + 45)
+#define IRS1125_CID_SAFE_RECONFIG_S17_FRAME	(IRS1125_CID_CUSTOM_BASE + 46)
+#define IRS1125_CID_SAFE_RECONFIG_S18_EXPO	(IRS1125_CID_CUSTOM_BASE + 47)
+#define IRS1125_CID_SAFE_RECONFIG_S18_FRAME	(IRS1125_CID_CUSTOM_BASE + 48)
+#define IRS1125_CID_SAFE_RECONFIG_S19_EXPO	(IRS1125_CID_CUSTOM_BASE + 49)
+#define IRS1125_CID_SAFE_RECONFIG_S19_FRAME	(IRS1125_CID_CUSTOM_BASE + 50)
+
+struct irs1125_seq_cfg {
+	__u16 exposure;
+	__u16 framerate;
+	__u16 ps;
+	__u16 pll;
+};
+
+struct irs1125_mod_pll {
+	__u16 pllcfg1;
+	__u16 pllcfg2;
+	__u16 pllcfg3;
+	__u16 pllcfg4;
+	__u16 pllcfg5;
+	__u16 pllcfg6;
+	__u16 pllcfg7;
+	__u16 pllcfg8;
+};
+
+#endif /* IRS1125 */
+
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/Kconfig linux-5.10.52-v7l+/drivers/media/i2c/Kconfig
--- linux-5.10.52-orig/drivers/media/i2c/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/i2c/Kconfig	2021-07-25 16:46:05.618296715 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:804 @
 	  To compile this driver as a module, choose M here: the
 	  module will be called imx290.
 
+config VIDEO_IMX477
+	tristate "Sony IMX477 sensor support"
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on MEDIA_CAMERA_SUPPORT
+	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_IMX319
 	tristate "Sony IMX319 sensor support"
 	depends on I2C && VIDEO_V4L2
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1054 @
 	  This is a Video4Linux2 sensor driver for the OmniVision
 	  OV9640 camera sensor.
 
+config VIDEO_OV9281
+	tristate "OmniVision OV9281 sensor support"
+	depends on I2C && VIDEO_V4L2
+	depends on MEDIA_CAMERA_SUPPORT
+	help
+	  This is a Video4Linux2 sensor-level driver for the OmniVision
+	  OV9281 camera.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ov9281.
+
 config VIDEO_OV9650
 	tristate "OmniVision OV9650/OV9652 sensor support"
 	depends on I2C && VIDEO_V4L2
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1085 @
 	  This is a Video4Linux2 sensor driver for the OmniVision
 	  OV13858 camera.
 
+config VIDEO_IRS1125
+	tristate "Infineon IRS1125 sensor support"
+	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on MEDIA_CAMERA_SUPPORT
+	select V4L2_FWNODE
+	help
+	  This is a Video4Linux2 sensor-level driver for the Infineon
+	  IRS1125 camera.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called irs1125.
+
 config VIDEO_VS6624
 	tristate "ST VS6624 sensor support"
 	depends on VIDEO_V4L2 && I2C
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/Makefile linux-5.10.52-v7l+/drivers/media/i2c/Makefile
--- linux-5.10.52-orig/drivers/media/i2c/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/i2c/Makefile	2021-07-25 16:46:05.618296715 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:84 @
 obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
 obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
 obj-$(CONFIG_VIDEO_OV8856) += ov8856.o
+obj-$(CONFIG_VIDEO_OV9281) += ov9281.o
 obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
 obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
 obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
+obj-$(CONFIG_VIDEO_IRS1125) += irs1125.o
 obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
 obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
 obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:122 @
 obj-$(CONFIG_VIDEO_IMX258)	+= imx258.o
 obj-$(CONFIG_VIDEO_IMX274)	+= imx274.o
 obj-$(CONFIG_VIDEO_IMX290)	+= imx290.o
+obj-$(CONFIG_VIDEO_IMX477)	+= imx477.o
 obj-$(CONFIG_VIDEO_IMX319)	+= imx319.o
 obj-$(CONFIG_VIDEO_IMX355)	+= imx355.o
 obj-$(CONFIG_VIDEO_MAX9286)	+= max9286.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/ov5647.c linux-5.10.52-v7l+/drivers/media/i2c/ov5647.c
--- linux-5.10.52-orig/drivers/media/i2c/ov5647.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/i2c/ov5647.c	2021-07-25 16:46:05.758294368 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:24 @
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/io.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:32 @
 #include <linux/of_graph.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-image-sizes.h>
 #include <media/v4l2-mediabus.h>
 
+
 #define SENSOR_NAME "ov5647"
 
+/*
+ * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes
+ * high if reset is inserted after PWDN goes high, host can access sensor's
+ * SCCB to initialize sensor."
+ */
+#define PWDN_ACTIVE_DELAY_MS	20
+
 #define MIPI_CTRL00_CLOCK_LANE_GATE		BIT(5)
+#define MIPI_CTRL00_LINE_SYNC_ENABLE		BIT(4)
 #define MIPI_CTRL00_BUS_IDLE			BIT(2)
 #define MIPI_CTRL00_CLOCK_LANE_DISABLE		BIT(0)
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:59 @
 #define OV5647_REG_CHIPID_H		0x300A
 #define OV5647_REG_CHIPID_L		0x300B
 #define OV5640_REG_PAD_OUT		0x300D
+#define OV5647_REG_EXP_HI		0x3500
+#define OV5647_REG_EXP_MID		0x3501
+#define OV5647_REG_EXP_LO		0x3502
+#define OV5647_REG_AEC_AGC		0x3503
+#define OV5647_REG_GAIN_HI		0x350A
+#define OV5647_REG_GAIN_LO		0x350B
+#define OV5647_REG_VTS_HI		0x380e
+#define OV5647_REG_VTS_LO		0x380f
 #define OV5647_REG_FRAME_OFF_NUMBER	0x4202
 #define OV5647_REG_MIPI_CTRL00		0x4800
 #define OV5647_REG_MIPI_CTRL14		0x4814
+#define OV5647_REG_AWB			0x5001
 
 #define REG_TERM 0xfffe
 #define VAL_TERM 0xfe
 #define REG_DLY  0xffff
 
-#define OV5647_ROW_START		0x01
-#define OV5647_ROW_START_MIN		0
-#define OV5647_ROW_START_MAX		2004
-#define OV5647_ROW_START_DEF		54
-
-#define OV5647_COLUMN_START		0x02
-#define OV5647_COLUMN_START_MIN		0
-#define OV5647_COLUMN_START_MAX		2750
-#define OV5647_COLUMN_START_DEF		16
-
-#define OV5647_WINDOW_HEIGHT		0x03
-#define OV5647_WINDOW_HEIGHT_MIN	2
-#define OV5647_WINDOW_HEIGHT_MAX	2006
-#define OV5647_WINDOW_HEIGHT_DEF	1944
-
-#define OV5647_WINDOW_WIDTH		0x04
-#define OV5647_WINDOW_WIDTH_MIN		2
-#define OV5647_WINDOW_WIDTH_MAX		2752
-#define OV5647_WINDOW_WIDTH_DEF		2592
+/* OV5647 native and active pixel array size */
+#define OV5647_NATIVE_WIDTH		2624U
+#define OV5647_NATIVE_HEIGHT		1956U
+
+#define OV5647_PIXEL_ARRAY_LEFT		16U
+#define OV5647_PIXEL_ARRAY_TOP		6U
+#define OV5647_PIXEL_ARRAY_WIDTH	2592U
+#define OV5647_PIXEL_ARRAY_HEIGHT	1944U
+
+#define OV5647_VBLANK_MIN		24
+#define OV5647_VTS_MAX			32767
+
+#define OV5647_EXPOSURE_MIN		4
+#define OV5647_EXPOSURE_STEP		1
+#define OV5647_EXPOSURE_DEFAULT		1000
+#define OV5647_EXPOSURE_MAX		65535
 
 struct regval_list {
 	u16 addr;
 	u8 data;
 };
 
+struct ov5647_mode {
+	struct v4l2_mbus_framefmt	format;
+	/* Analog crop rectangle. */
+	struct v4l2_rect crop;
+
+	u64 pixel_rate;
+	/* HTS as defined in the register set (0x380C/0x380D) */
+	int hts;
+	/* Default VTS value for this mode */
+	int vts_def;
+
+	struct regval_list		*reg_list;
+	unsigned int			num_regs;
+};
+
 struct ov5647 {
 	struct v4l2_subdev		sd;
 	struct media_pad		pad;
 	struct mutex			lock;
-	struct v4l2_mbus_framefmt	format;
-	unsigned int			width;
-	unsigned int			height;
+	const struct ov5647_mode	*mode;
 	int				power_count;
 	struct clk			*xclk;
+	struct gpio_desc		*pwdn;
+	unsigned int			flags;
+	struct v4l2_ctrl_handler	ctrls;
+	struct v4l2_ctrl		*pixel_rate;
+	struct v4l2_ctrl		*hblank;
+	struct v4l2_ctrl		*vblank;
+	struct v4l2_ctrl		*exposure;
+	bool				write_mode_regs;
 };
 
 static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:147 @
 	{0x3002, 0xe4},
 };
 
-static struct regval_list ov5647_640x480[] = {
+static struct regval_list ov5647_640x480_8bit[] = {
 	{0x0100, 0x00},
 	{0x0103, 0x01},
 	{0x3034, 0x08},
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:162 @
 	{0x3612, 0x59},
 	{0x3618, 0x00},
 	{0x5000, 0x06},
-	{0x5001, 0x01},
 	{0x5002, 0x41},
 	{0x5003, 0x08},
 	{0x5a00, 0x08},
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:179 @
 	{0x3b07, 0x0c},
 	{0x380c, 0x07},
 	{0x380d, 0x68},
-	{0x380e, 0x03},
-	{0x380f, 0xd8},
 	{0x3814, 0x31},
 	{0x3815, 0x31},
 	{0x3708, 0x64},
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:235 @
 	{0x0100, 0x01},
 };
 
+static struct regval_list ov5647_2592x1944_10bit[] = {
+	{0x0100, 0x00},
+	{0x0103, 0x01},
+	{0x3034, 0x1a},
+	{0x3035, 0x21},
+	{0x3036, 0x69},
+	{0x303c, 0x11},
+	{0x3106, 0xf5},
+	{0x3821, 0x06},
+	{0x3820, 0x00},
+	{0x3827, 0xec},
+	{0x370c, 0x03},
+	{0x3612, 0x5b},
+	{0x3618, 0x04},
+	{0x5000, 0x06},
+	{0x5002, 0x41},
+	{0x5003, 0x08},
+	{0x5a00, 0x08},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3016, 0x08},
+	{0x3017, 0xe0},
+	{0x3018, 0x44},
+	{0x301c, 0xf8},
+	{0x301d, 0xf0},
+	{0x3a18, 0x00},
+	{0x3a19, 0xf8},
+	{0x3c01, 0x80},
+	{0x3b07, 0x0c},
+	{0x380c, 0x0b},
+	{0x380d, 0x1c},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3708, 0x64},
+	{0x3709, 0x12},
+	{0x3808, 0x0a},
+	{0x3809, 0x20},
+	{0x380a, 0x07},
+	{0x380b, 0x98},
+	{0x3800, 0x00},
+	{0x3801, 0x00},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0a},
+	{0x3805, 0x3f},
+	{0x3806, 0x07},
+	{0x3807, 0xa3},
+	{0x3811, 0x10},
+	{0x3813, 0x06},
+	{0x3630, 0x2e},
+	{0x3632, 0xe2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3636, 0x06},
+	{0x3620, 0x64},
+	{0x3621, 0xe0},
+	{0x3600, 0x37},
+	{0x3704, 0xa0},
+	{0x3703, 0x5a},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370b, 0x60},
+	{0x3705, 0x1a},
+	{0x3f05, 0x02},
+	{0x3f06, 0x10},
+	{0x3f01, 0x0a},
+	{0x3a08, 0x01},
+	{0x3a09, 0x28},
+	{0x3a0a, 0x00},
+	{0x3a0b, 0xf6},
+	{0x3a0d, 0x08},
+	{0x3a0e, 0x06},
+	{0x3a0f, 0x58},
+	{0x3a10, 0x50},
+	{0x3a1b, 0x58},
+	{0x3a1e, 0x50},
+	{0x3a11, 0x60},
+	{0x3a1f, 0x28},
+	{0x4001, 0x02},
+	{0x4004, 0x04},
+	{0x4000, 0x09},
+	{0x4837, 0x19},
+	{0x4800, 0x24},
+	{0x3503, 0x03},
+	{0x0100, 0x01},
+};
+
+static struct regval_list ov5647_1080p30_10bit[] = {
+	{0x0100, 0x00},
+	{0x0103, 0x01},
+	{0x3034, 0x1a},
+	{0x3035, 0x21},
+	{0x3036, 0x62},
+	{0x303c, 0x11},
+	{0x3106, 0xf5},
+	{0x3821, 0x06},
+	{0x3820, 0x00},
+	{0x3827, 0xec},
+	{0x370c, 0x03},
+	{0x3612, 0x5b},
+	{0x3618, 0x04},
+	{0x5000, 0x06},
+	{0x5002, 0x41},
+	{0x5003, 0x08},
+	{0x5a00, 0x08},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3016, 0x08},
+	{0x3017, 0xe0},
+	{0x3018, 0x44},
+	{0x301c, 0xf8},
+	{0x301d, 0xf0},
+	{0x3a18, 0x00},
+	{0x3a19, 0xf8},
+	{0x3c01, 0x80},
+	{0x3b07, 0x0c},
+	{0x380c, 0x09},
+	{0x380d, 0x70},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3708, 0x64},
+	{0x3709, 0x12},
+	{0x3808, 0x07},
+	{0x3809, 0x80},
+	{0x380a, 0x04},
+	{0x380b, 0x38},
+	{0x3800, 0x01},
+	{0x3801, 0x5c},
+	{0x3802, 0x01},
+	{0x3803, 0xb2},
+	{0x3804, 0x08},
+	{0x3805, 0xe3},
+	{0x3806, 0x05},
+	{0x3807, 0xf1},
+	{0x3811, 0x04},
+	{0x3813, 0x02},
+	{0x3630, 0x2e},
+	{0x3632, 0xe2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3636, 0x06},
+	{0x3620, 0x64},
+	{0x3621, 0xe0},
+	{0x3600, 0x37},
+	{0x3704, 0xa0},
+	{0x3703, 0x5a},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370b, 0x60},
+	{0x3705, 0x1a},
+	{0x3f05, 0x02},
+	{0x3f06, 0x10},
+	{0x3f01, 0x0a},
+	{0x3a08, 0x01},
+	{0x3a09, 0x4b},
+	{0x3a0a, 0x01},
+	{0x3a0b, 0x13},
+	{0x3a0d, 0x04},
+	{0x3a0e, 0x03},
+	{0x3a0f, 0x58},
+	{0x3a10, 0x50},
+	{0x3a1b, 0x58},
+	{0x3a1e, 0x50},
+	{0x3a11, 0x60},
+	{0x3a1f, 0x28},
+	{0x4001, 0x02},
+	{0x4004, 0x04},
+	{0x4000, 0x09},
+	{0x4837, 0x19},
+	{0x4800, 0x34},
+	{0x3503, 0x03},
+	{0x0100, 0x01},
+};
+
+static struct regval_list ov5647_2x2binned_10bit[] = {
+	{0x0100, 0x00},
+	{0x0103, 0x01},
+	{0x3034, 0x1A},
+	{0x3035, 0x21},
+	{0x3036, 0x62},
+	{0x303C, 0x11},
+	{0x3106, 0xF5},
+	{0x3827, 0xEC},
+	{0x370C, 0x03},
+	{0x3612, 0x59},
+	{0x3618, 0x00},
+	{0x5000, 0x06},
+	{0x5002, 0x41},
+	{0x5003, 0x08},
+	{0x5A00, 0x08},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3016, 0x08},
+	{0x3017, 0xE0},
+	{0x3018, 0x44},
+	{0x301C, 0xF8},
+	{0x301D, 0xF0},
+	{0x3A18, 0x00},
+	{0x3A19, 0xF8},
+	{0x3C01, 0x80},
+	{0x3B07, 0x0C},
+	{0x3800, 0x00},
+	{0x3801, 0x00},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0A},
+	{0x3805, 0x3F},
+	{0x3806, 0x07},
+	{0x3807, 0xA3},
+	{0x3808, 0x05},
+	{0x3809, 0x10},
+	{0x380A, 0x03},
+	{0x380B, 0xCC},
+	{0x380C, 0x07},
+	{0x380D, 0x68},
+	{0x3811, 0x0c},
+	{0x3813, 0x06},
+	{0x3814, 0x31},
+	{0x3815, 0x31},
+	{0x3630, 0x2E},
+	{0x3632, 0xE2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3636, 0x06},
+	{0x3620, 0x64},
+	{0x3621, 0xE0},
+	{0x3600, 0x37},
+	{0x3704, 0xA0},
+	{0x3703, 0x5A},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370B, 0x60},
+	{0x3705, 0x1A},
+	{0x3F05, 0x02},
+	{0x3F06, 0x10},
+	{0x3F01, 0x0A},
+	{0x3A08, 0x01},
+	{0x3A09, 0x28},
+	{0x3A0A, 0x00},
+	{0x3A0B, 0xF6},
+	{0x3A0D, 0x08},
+	{0x3A0E, 0x06},
+	{0x3A0F, 0x58},
+	{0x3A10, 0x50},
+	{0x3A1B, 0x58},
+	{0x3A1E, 0x50},
+	{0x3A11, 0x60},
+	{0x3A1F, 0x28},
+	{0x4001, 0x02},
+	{0x4004, 0x04},
+	{0x4000, 0x09},
+	{0x4837, 0x16},
+	{0x4800, 0x24},
+	{0x3503, 0x03},
+	{0x3820, 0x41},
+	{0x3821, 0x07},
+	{0x350A, 0x00},
+	{0x350B, 0x10},
+	{0x3500, 0x00},
+	{0x3501, 0x1A},
+	{0x3502, 0xF0},
+	{0x3212, 0xA0},
+	{0x0100, 0x01},
+};
+
+static struct regval_list ov5647_640x480_10bit[] = {
+	{0x0100, 0x00},
+	{0x0103, 0x01},
+	{0x3035, 0x11},
+	{0x3036, 0x46},
+	{0x303c, 0x11},
+	{0x3821, 0x07},
+	{0x3820, 0x41},
+	{0x370c, 0x03},
+	{0x3612, 0x59},
+	{0x3618, 0x00},
+	{0x5000, 0x06},
+	{0x5003, 0x08},
+	{0x5a00, 0x08},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xff},
+	{0x301d, 0xf0},
+	{0x3a18, 0x00},
+	{0x3a19, 0xf8},
+	{0x3c01, 0x80},
+	{0x3b07, 0x0c},
+	{0x380c, 0x07},
+	{0x380d, 0x3c},
+	{0x3814, 0x35},
+	{0x3815, 0x35},
+	{0x3708, 0x64},
+	{0x3709, 0x52},
+	{0x3808, 0x02},
+	{0x3809, 0x80},
+	{0x380a, 0x01},
+	{0x380b, 0xe0},
+	{0x3800, 0x00},
+	{0x3801, 0x10},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0a},
+	{0x3805, 0x2f},
+	{0x3806, 0x07},
+	{0x3807, 0x9f},
+	{0x3630, 0x2e},
+	{0x3632, 0xe2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3620, 0x64},
+	{0x3621, 0xe0},
+	{0x3600, 0x37},
+	{0x3704, 0xa0},
+	{0x3703, 0x5a},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370b, 0x60},
+	{0x3705, 0x1a},
+	{0x3f05, 0x02},
+	{0x3f06, 0x10},
+	{0x3f01, 0x0a},
+	{0x3a08, 0x01},
+	{0x3a09, 0x2e},
+	{0x3a0a, 0x00},
+	{0x3a0b, 0xfb},
+	{0x3a0d, 0x02},
+	{0x3a0e, 0x01},
+	{0x3a0f, 0x58},
+	{0x3a10, 0x50},
+	{0x3a1b, 0x58},
+	{0x3a1e, 0x50},
+	{0x3a11, 0x60},
+	{0x3a1f, 0x28},
+	{0x4001, 0x02},
+	{0x4004, 0x02},
+	{0x4000, 0x09},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3017, 0xe0},
+	{0x301c, 0xfc},
+	{0x3636, 0x06},
+	{0x3016, 0x08},
+	{0x3827, 0xec},
+	{0x3018, 0x44},
+	{0x3035, 0x21},
+	{0x3106, 0xf5},
+	{0x3034, 0x1a},
+	{0x301c, 0xf8},
+	{0x4800, 0x34},
+	{0x3503, 0x03},
+	{0x0100, 0x01},
+};
+
+static struct ov5647_mode supported_modes_8bit[] = {
+	/*
+	 * MODE 0: Original 8-bit VGA mode.
+	 * Uncentred crop (top left quarter) from 2x2 binned 1296x972 image.
+	 */
+	{
+		.format = {
+			.code = MEDIA_BUS_FMT_SBGGR8_1X8,
+			.colorspace = V4L2_COLORSPACE_SRGB,
+			.field = V4L2_FIELD_NONE,
+			.width = 640,
+			.height = 480
+		},
+		.crop = {
+			.left = OV5647_PIXEL_ARRAY_LEFT,
+			.top = OV5647_PIXEL_ARRAY_TOP,
+			.width = 1280,
+			.height = 960,
+		},
+		.pixel_rate = 77291670,
+		.hts = 1896,
+		.vts_def = 0x3d8,
+		.reg_list = ov5647_640x480_8bit,
+		.num_regs = ARRAY_SIZE(ov5647_640x480_8bit)
+	},
+};
+
+static struct ov5647_mode supported_modes_10bit[] = {
+	/*
+	 * MODE 0: 2592x1944 full resolution full FOV 10-bit mode.
+	 */
+	{
+		.format = {
+			.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+			.colorspace = V4L2_COLORSPACE_SRGB,
+			.field = V4L2_FIELD_NONE,
+			.width = 2592,
+			.height = 1944
+		},
+		.crop = {
+			.left = OV5647_PIXEL_ARRAY_LEFT,
+			.top = OV5647_PIXEL_ARRAY_TOP,
+			.width = 2592,
+			.height = 1944
+		},
+		.pixel_rate = 87500000,
+		.hts = 2844,
+		.vts_def = 0x7b0,
+		.reg_list = ov5647_2592x1944_10bit,
+		.num_regs = ARRAY_SIZE(ov5647_2592x1944_10bit)
+	},
+	/*
+	 * MODE 1: 1080p30 10-bit mode.
+	 * Full resolution centre-cropped down to 1080p.
+	 */
+	{
+		.format = {
+			.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+			.colorspace = V4L2_COLORSPACE_SRGB,
+			.field = V4L2_FIELD_NONE,
+			.width = 1920,
+			.height = 1080
+		},
+		.crop = {
+			.left = 364,
+			.top = 450,
+			.width = 1928,
+			.height = 1080,
+		},
+		.pixel_rate = 81666700,
+		.hts = 2416,
+		.vts_def = 0x450,
+		.reg_list = ov5647_1080p30_10bit,
+		.num_regs = ARRAY_SIZE(ov5647_1080p30_10bit)
+	},
+	/*
+	 * MODE 2: 2x2 binned full FOV 10-bit mode.
+	 */
+	{
+		.format = {
+			.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+			.colorspace = V4L2_COLORSPACE_SRGB,
+			.field = V4L2_FIELD_NONE,
+			.width = 1296,
+			.height = 972
+		},
+		.crop = {
+			.left = OV5647_PIXEL_ARRAY_LEFT,
+			.top = OV5647_PIXEL_ARRAY_TOP,
+			.width = 2592,
+			.height = 1944,
+		},
+		.pixel_rate = 81666700,
+		.hts = 1896,
+		.vts_def = 0x59b,
+		.reg_list = ov5647_2x2binned_10bit,
+		.num_regs = ARRAY_SIZE(ov5647_2x2binned_10bit)
+	},
+	/*
+	 * MODE 3: 10-bit VGA full FOV mode 60fps.
+	 * 2x2 binned and subsampled down to VGA.
+	 */
+	{
+		.format = {
+			.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+			.colorspace = V4L2_COLORSPACE_SRGB,
+			.field = V4L2_FIELD_NONE,
+			.width = 640,
+			.height = 480
+		},
+		.crop = {
+			.left = OV5647_PIXEL_ARRAY_LEFT,
+			.top = OV5647_PIXEL_ARRAY_TOP,
+			.width = 2560,
+			.height = 1920,
+		},
+		.pixel_rate = 55000000,
+		.hts = 1852,
+		.vts_def = 0x1f8,
+		.reg_list = ov5647_640x480_10bit,
+		.num_regs = ARRAY_SIZE(ov5647_640x480_10bit)
+	},
+};
+
+/* Use 2x2 binned 10-bit mode as default. */
+#define OV5647_DEFAULT_MODE (&supported_modes_10bit[2])
+
+static int ov5647_write16(struct v4l2_subdev *sd, u16 reg, u16 val)
+{
+	int ret;
+	unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff};
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	ret = i2c_master_send(client, data, 4);
+	/*
+	 * Writing the wrong number of bytes also needs to be flagged as an
+	 * error. Success needs to produce a 0 return code.
+	 */
+	if (ret == 4) {
+		ret = 0;
+	} else {
+		dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
+			__func__, reg);
+		if (ret >= 0)
+			ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
 {
 	int ret;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:753 @
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
 	ret = i2c_master_send(client, data, 3);
-	if (ret < 0)
+	/*
+	 * Writing the wrong number of bytes also needs to be flagged as an
+	 * error. Success needs to produce a 0 return code.
+	 */
+	if (ret == 3) {
+		ret = 0;
+	} else {
 		dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
 				__func__, reg);
+		if (ret >= 0)
+			ret = -EINVAL;
+	}
 
 	return ret;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:776 @
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
 	ret = i2c_master_send(client, data_w, 2);
-	if (ret < 0) {
+	/*
+	 * A negative return code, or sending the wrong number of bytes, both
+	 * count as an error.
+	 */
+	if (ret != 2) {
 		dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
 			__func__, reg);
+		if (ret >= 0)
+			ret = -EINVAL;
 		return ret;
 	}
 
 	ret = i2c_master_recv(client, val, 1);
-	if (ret < 0)
+	/*
+	 * The only return value indicating success is 1. Anything else, even
+	 * a non-negative value, indicates something went wrong.
+	 */
+	if (ret == 1) {
+		ret = 0;
+	} else {
 		dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
 				__func__, reg);
+		if (ret >= 0)
+			ret = -EINVAL;
+	}
 
 	return ret;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:832 @
 	return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6));
 }
 
+static int __sensor_init(struct v4l2_subdev *sd)
+{
+	int ret;
+	u8 resetval, rdval;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5647 *state = to_state(sd);
+
+	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
+	if (ret < 0)
+		return ret;
+
+	if (state->write_mode_regs) {
+		ret = ov5647_write_array(sd, state->mode->reg_list,
+					 state->mode->num_regs);
+		if (ret < 0) {
+			dev_err(&client->dev, "write sensor default regs error\n");
+			return ret;
+		}
+		state->write_mode_regs = false;
+	}
+
+	ret = ov5647_set_virtual_channel(sd, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
+	if (ret < 0)
+		return ret;
+
+	if (!(resetval & 0x01)) {
+		dev_err(&client->dev, "Device was in SW standby");
+		ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int ov5647_stream_on(struct v4l2_subdev *sd)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5647 *ov5647 = to_state(sd);
+	u8 val = MIPI_CTRL00_BUS_IDLE;
 	int ret;
 
-	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_BUS_IDLE);
+	ret = __sensor_init(sd);
+	if (ret < 0) {
+		dev_err(&client->dev, "sensor_init failed\n");
+		return ret;
+	}
+
+	/* Apply customized values from user when stream starts */
+	ret =  __v4l2_ctrl_handler_setup(sd->ctrl_handler);
+	if (ret)
+		return ret;
+
+	if (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)
+		val |= MIPI_CTRL00_CLOCK_LANE_GATE |
+		       MIPI_CTRL00_LINE_SYNC_ENABLE;
+
+	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, val);
 	if (ret < 0)
 		return ret;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:937 @
 	return ov5647_write(sd, OV5647_SW_STANDBY, rdval);
 }
 
-static int __sensor_init(struct v4l2_subdev *sd)
-{
-	int ret;
-	u8 resetval, rdval;
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
-	if (ret < 0)
-		return ret;
-
-	ret = ov5647_write_array(sd, ov5647_640x480,
-					ARRAY_SIZE(ov5647_640x480));
-	if (ret < 0) {
-		dev_err(&client->dev, "write sensor default regs error\n");
-		return ret;
-	}
-
-	ret = ov5647_set_virtual_channel(sd, 0);
-	if (ret < 0)
-		return ret;
-
-	ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
-	if (ret < 0)
-		return ret;
-
-	if (!(resetval & 0x01)) {
-		dev_err(&client->dev, "Device was in SW standby");
-		ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
-		if (ret < 0)
-			return ret;
-	}
-
-	/*
-	 * stream off to make the clock lane into LP-11 state.
-	 */
-	return ov5647_stream_off(sd);
-}
-
 static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 {
 	int ret = 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:948 @
 	if (on && !ov5647->power_count)	{
 		dev_dbg(&client->dev, "OV5647 power on\n");
 
+		if (ov5647->pwdn) {
+			gpiod_set_value_cansleep(ov5647->pwdn, 0);
+			msleep(PWDN_ACTIVE_DELAY_MS);
+		}
+
 		ret = clk_prepare_enable(ov5647->xclk);
 		if (ret < 0) {
 			dev_err(&client->dev, "clk prepare enable failed\n");
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:960 @
 		}
 
 		ret = ov5647_write_array(sd, sensor_oe_enable_regs,
-				ARRAY_SIZE(sensor_oe_enable_regs));
+					 ARRAY_SIZE(sensor_oe_enable_regs));
 		if (ret < 0) {
 			clk_disable_unprepare(ov5647->xclk);
 			dev_err(&client->dev,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:968 @
 			goto out;
 		}
 
-		ret = __sensor_init(sd);
+		/*
+		 * Ensure streaming off to make clock lane go into LP-11 state.
+		 */
+		ret = ov5647_stream_off(sd);
 		if (ret < 0) {
 			clk_disable_unprepare(ov5647->xclk);
 			dev_err(&client->dev,
 				"Camera not available, check Power\n");
 			goto out;
 		}
+
+		/* Write out the register set over I2C on stream-on. */
+		ov5647->write_mode_regs = true;
 	} else if (!on && ov5647->power_count == 1) {
 		dev_dbg(&client->dev, "OV5647 power off\n");
 
 		ret = ov5647_write_array(sd, sensor_oe_disable_regs,
-				ARRAY_SIZE(sensor_oe_disable_regs));
+					 ARRAY_SIZE(sensor_oe_disable_regs));
 
 		if (ret < 0)
 			dev_dbg(&client->dev, "disable oe failed\n");
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:996 @
 			dev_dbg(&client->dev, "soft stby failed\n");
 
 		clk_disable_unprepare(ov5647->xclk);
+
+		gpiod_set_value_cansleep(ov5647->pwdn, 1);
 	}
 
 	/* Update the power count. */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1043 @
 	.g_register		= ov5647_sensor_get_register,
 	.s_register		= ov5647_sensor_set_register,
 #endif
+	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
 };
 
+static const struct v4l2_rect *
+__ov5647_get_pad_crop(struct ov5647 *ov5647, struct v4l2_subdev_pad_config *cfg,
+		      unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(&ov5647->sd, cfg, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &ov5647->mode->crop;
+	}
+
+	return NULL;
+}
+
+static int ov5647_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_selection *sel)
+{
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP: {
+		struct ov5647 *state = to_state(sd);
+
+		mutex_lock(&state->lock);
+		sel->r = *__ov5647_get_pad_crop(state, cfg, sel->pad,
+						sel->which);
+		mutex_unlock(&state->lock);
+
+		return 0;
+	}
+
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+		sel->r.top = 0;
+		sel->r.left = 0;
+		sel->r.width = OV5647_NATIVE_WIDTH;
+		sel->r.height = OV5647_NATIVE_HEIGHT;
+
+		return 0;
+
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.top = OV5647_PIXEL_ARRAY_TOP;
+		sel->r.left = OV5647_PIXEL_ARRAY_LEFT;
+		sel->r.width = OV5647_PIXEL_ARRAY_WIDTH;
+		sel->r.height = OV5647_PIXEL_ARRAY_HEIGHT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
 {
+	struct ov5647 *state = to_state(sd);
+	int ret = 0;
+
+	mutex_lock(&state->lock);
+
 	if (enable)
-		return ov5647_stream_on(sd);
+		ret = ov5647_stream_on(sd);
 	else
-		return ov5647_stream_off(sd);
+		ret = ov5647_stream_off(sd);
+
+	mutex_unlock(&state->lock);
+
+	return ret;
 }
 
 static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1123 @
 				struct v4l2_subdev_pad_config *cfg,
 				struct v4l2_subdev_mbus_code_enum *code)
 {
-	if (code->index > 0)
+	if (code->index == 0 && ARRAY_SIZE(supported_modes_8bit))
+		code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+	else if (code->index == 0 && ARRAY_SIZE(supported_modes_8bit) == 0 &&
+		 ARRAY_SIZE(supported_modes_10bit))
+		code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+	else if (code->index == 1 && ARRAY_SIZE(supported_modes_8bit) &&
+		 ARRAY_SIZE(supported_modes_10bit))
+		code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct ov5647_mode *mode = NULL;
+
+	if (fse->code == MEDIA_BUS_FMT_SBGGR8_1X8) {
+		if (fse->index >= ARRAY_SIZE(supported_modes_8bit))
+			return -EINVAL;
+		mode = &supported_modes_8bit[fse->index];
+	} else if (fse->code == MEDIA_BUS_FMT_SBGGR10_1X10) {
+		if (fse->index >= ARRAY_SIZE(supported_modes_10bit))
+			return -EINVAL;
+		mode = &supported_modes_10bit[fse->index];
+	} else {
 		return -EINVAL;
+	}
 
-	code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+	fse->min_width = mode->format.width;
+	fse->max_width = fse->min_width;
+	fse->min_height = mode->format.height;
+	fse->max_height = fse->min_height;
+
+	return 0;
+}
+
+static int ov5647_set_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *fmt = &format->format;
+	struct ov5647 *state = to_state(sd);
+	struct v4l2_mbus_framefmt *framefmt;
+	const struct ov5647_mode *mode_8bit, *mode_10bit, *mode = NULL;
+
+	if (format->pad != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->lock);
+
+	/*
+	 * Try to respect any given pixel format, otherwise try for a 10-bit
+	 * mode.
+	 */
+	mode_8bit = v4l2_find_nearest_size(supported_modes_8bit,
+					   ARRAY_SIZE(supported_modes_8bit),
+					   format.width, format.height,
+					   format->format.width,
+					   format->format.height);
+	mode_10bit = v4l2_find_nearest_size(supported_modes_10bit,
+					    ARRAY_SIZE(supported_modes_10bit),
+					    format.width, format.height,
+					    format->format.width,
+					    format->format.height);
+	if (format->format.code == MEDIA_BUS_FMT_SBGGR8_1X8 && mode_8bit)
+		mode = mode_8bit;
+	else if (format->format.code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
+		 mode_10bit)
+		mode = mode_10bit;
+	else if (mode_10bit)
+		mode = mode_10bit;
+	else
+		mode = mode_8bit;
+
+	if (!mode) {
+		mutex_unlock(&state->lock);
+		return -EINVAL;
+	}
+
+	*fmt = mode->format;
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+		*framefmt = format->format;
+	} else {
+		/*
+		 * If we have changed modes, write the I2C register list on
+		 * a stream_on().
+		 */
+		int exposure_max, exposure_def, hblank;
+
+		if (state->mode != mode)
+			state->write_mode_regs = true;
+		state->mode = mode;
+
+		__v4l2_ctrl_modify_range(state->pixel_rate,
+					 mode->pixel_rate,
+					 mode->pixel_rate, 1,
+					 mode->pixel_rate);
+		hblank = mode->hts - mode->format.width;
+		__v4l2_ctrl_modify_range(state->hblank, hblank, hblank, 1,
+					 hblank);
+
+		__v4l2_ctrl_modify_range(state->vblank,
+					 OV5647_VBLANK_MIN,
+					 OV5647_VTS_MAX - mode->format.height,
+					 1,
+					 mode->vts_def - mode->format.height);
+		__v4l2_ctrl_s_ctrl(state->vblank,
+				   mode->vts_def - mode->format.height);
+
+		exposure_max = mode->vts_def - 4;
+		exposure_def = (exposure_max < OV5647_EXPOSURE_DEFAULT) ?
+					exposure_max : OV5647_EXPOSURE_DEFAULT;
+		__v4l2_ctrl_modify_range(state->exposure,
+					 state->exposure->minimum,
+					 exposure_max,
+					 state->exposure->step,
+					 exposure_def);
+	}
+
+	mutex_unlock(&state->lock);
+
+	return 0;
+}
+
+static int ov5647_get_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *fmt = &format->format;
+	struct ov5647 *state = to_state(sd);
+
+	if (format->pad != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->lock);
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+		*fmt = *v4l2_subdev_get_try_format(sd, cfg, format->pad);
+	else
+		*fmt = state->mode->format;
+
+	mutex_unlock(&state->lock);
 
 	return 0;
 }
 
 static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
 	.enum_mbus_code = ov5647_enum_mbus_code,
+	.set_fmt =	  ov5647_set_fmt,
+	.get_fmt =	  ov5647_get_fmt,
+	.get_selection =  ov5647_get_selection,
+	.enum_frame_size = ov5647_enum_frame_size,
 };
 
 static const struct v4l2_subdev_ops ov5647_subdev_ops = {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1325 @
 				v4l2_subdev_get_try_format(sd, fh->pad, 0);
 	struct v4l2_rect *crop =
 				v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+	struct ov5647 *state = to_state(sd);
+
+	crop->left = OV5647_PIXEL_ARRAY_LEFT;
+	crop->top = OV5647_PIXEL_ARRAY_TOP;
+	crop->width = OV5647_PIXEL_ARRAY_WIDTH;
+	crop->height = OV5647_PIXEL_ARRAY_HEIGHT;
 
-	crop->left = OV5647_COLUMN_START_DEF;
-	crop->top = OV5647_ROW_START_DEF;
-	crop->width = OV5647_WINDOW_WIDTH_DEF;
-	crop->height = OV5647_WINDOW_HEIGHT_DEF;
-
-	format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
-
-	format->width = OV5647_WINDOW_WIDTH_DEF;
-	format->height = OV5647_WINDOW_HEIGHT_DEF;
-	format->field = V4L2_FIELD_NONE;
-	format->colorspace = V4L2_COLORSPACE_SRGB;
+	/* Set the default format to the same as the sensor. */
+	*format = state->mode->format;
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1342 @
 	.open = ov5647_open,
 };
 
-static int ov5647_parse_dt(struct device_node *np)
+static int ov5647_parse_dt(struct device_node *np, struct ov5647 *sensor)
 {
 	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
 	struct device_node *ep;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1355 @
 
 	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
 
+	if (!ret)
+		sensor->flags = bus_cfg.bus.mipi_csi2.flags;
+
 	of_node_put(ep);
 	return ret;
 }
 
+static int ov5647_s_auto_white_balance(struct v4l2_subdev *sd, u32 val)
+{
+	/* non-zero turns on AWB */
+	return ov5647_write(sd, OV5647_REG_AWB, val ? 1 : 0);
+}
+
+static int ov5647_s_autogain(struct v4l2_subdev *sd, u32 val)
+{
+	int ret;
+	u8 reg;
+
+	/* non-zero turns on AGC by clearing bit 1 */
+	ret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);
+	if (ret == 0)
+		ret = ov5647_write(sd, OV5647_REG_AEC_AGC,
+				   val ? reg & ~2 : reg | 2);
+
+	return ret;
+}
+
+static int ov5647_s_exposure_auto(struct v4l2_subdev *sd, u32 val)
+{
+	int ret;
+	u8 reg;
+
+	/* Everything except V4L2_EXPOSURE_MANUAL turns on AEC by
+	 * clearing bit 0
+	 */
+	ret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);
+	if (ret == 0)
+		ret = ov5647_write(sd, OV5647_REG_AEC_AGC,
+				   val == V4L2_EXPOSURE_MANUAL ?
+				   reg | 1 : reg & ~1);
+
+	return ret;
+}
+
+static int ov5647_s_analogue_gain(struct v4l2_subdev *sd, u32 val)
+{
+	int ret;
+
+	/* 10 bits of gain, 2 in the high register */
+	ret = ov5647_write(sd, OV5647_REG_GAIN_HI, (val >> 8) & 3);
+	if (ret == 0)
+		ret = ov5647_write(sd, OV5647_REG_GAIN_LO, val & 0xff);
+
+	return ret;
+}
+
+static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val)
+{
+	int ret;
+
+	/* Sensor has 20 bits, but the bottom 4 bits are fractions of a line
+	 * which we leave as zero (and don't receive in "val").
+	 */
+	ret = ov5647_write(sd, OV5647_REG_EXP_HI, (val >> 12) & 0xf);
+	if (ret == 0)
+		ov5647_write(sd, OV5647_REG_EXP_MID, (val >> 4) & 0xff);
+	if (ret == 0)
+		ov5647_write(sd, OV5647_REG_EXP_LO, (val & 0xf) << 4);
+
+	return ret;
+}
+
+static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov5647 *state = container_of(ctrl->handler,
+					     struct ov5647, ctrls);
+	struct v4l2_subdev *sd = &state->sd;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = 0;
+
+	/* v4l2_ctrl_lock() locks our own mutex */
+
+	if (ctrl->id == V4L2_CID_VBLANK) {
+		int exposure_max, exposure_def;
+
+		/* Update max exposure while meeting expected vblanking */
+		exposure_max = state->mode->format.height + ctrl->val - 4;
+		exposure_def = (exposure_max < OV5647_EXPOSURE_DEFAULT) ?
+			exposure_max : OV5647_EXPOSURE_DEFAULT;
+		__v4l2_ctrl_modify_range(state->exposure,
+					 state->exposure->minimum,
+					 exposure_max, state->exposure->step,
+					 exposure_def);
+	}
+
+	/*
+	 * If the device is not powered up by the host driver do
+	 * not apply any controls to H/W at this time. Instead
+	 * the controls will be restored right after power-up.
+	 */
+	if (state->power_count == 0)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		ret = ov5647_s_auto_white_balance(sd, ctrl->val);
+		break;
+	case V4L2_CID_AUTOGAIN:
+		ret = ov5647_s_autogain(sd, ctrl->val);
+		break;
+	case V4L2_CID_EXPOSURE_AUTO:
+		ret = ov5647_s_exposure_auto(sd, ctrl->val);
+		break;
+	case V4L2_CID_ANALOGUE_GAIN:
+		ret = ov5647_s_analogue_gain(sd, ctrl->val);
+		break;
+	case V4L2_CID_EXPOSURE:
+		ret = ov5647_s_exposure(sd, ctrl->val);
+		break;
+	case V4L2_CID_PIXEL_RATE:
+		/* Read-only, but we adjust it based on mode. */
+		break;
+	case V4L2_CID_HBLANK:
+		/* Read-only, but we adjust it based on mode. */
+		break;
+	case V4L2_CID_VBLANK:
+		ret = ov5647_write16(sd, OV5647_REG_VTS_HI,
+				     state->mode->format.height + ctrl->val);
+		break;
+	default:
+		dev_info(&client->dev,
+			 "ctrl(id:0x%x,val:0x%x) is not handled\n",
+			 ctrl->id, ctrl->val);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
+	.s_ctrl = ov5647_s_ctrl,
+};
+
 static int ov5647_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1507 @
 	struct v4l2_subdev *sd;
 	struct device_node *np = client->dev.of_node;
 	u32 xclk_freq;
+	int hblank, exposure_max, exposure_def;
+	struct v4l2_fwnode_device_properties props;
 
 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
 	if (!sensor)
 		return -ENOMEM;
 
 	if (IS_ENABLED(CONFIG_OF) && np) {
-		ret = ov5647_parse_dt(np);
+		ret = ov5647_parse_dt(np, sensor);
 		if (ret) {
 			dev_err(dev, "DT parsing error: %d\n", ret);
 			return ret;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1535 @
 		return -EINVAL;
 	}
 
+	/* Request the power down GPIO asserted */
+	sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn",
+					       GPIOD_OUT_HIGH);
+
 	mutex_init(&sensor->lock);
 
+	/* Initialise controls. */
+	v4l2_ctrl_handler_init(&sensor->ctrls, 9);
+	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+			  V4L2_CID_AUTOGAIN,
+			  0,  /* min */
+			  1,  /* max */
+			  1,  /* step */
+			  0); /* default */
+	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+			  V4L2_CID_AUTO_WHITE_BALANCE,
+			  0,  /* min */
+			  1,  /* max */
+			  1,  /* step */
+			  0); /* default */
+	v4l2_ctrl_new_std_menu(&sensor->ctrls, &ov5647_ctrl_ops,
+			       V4L2_CID_EXPOSURE_AUTO,
+			       V4L2_EXPOSURE_MANUAL,  /* max */
+			       0,                     /* skip_mask */
+			       V4L2_EXPOSURE_MANUAL); /* default */
+	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+			  V4L2_CID_ANALOGUE_GAIN,
+			  16,   /* min, 16 = 1.0x */
+			  1023, /* max (10 bits) */
+			  1,    /* step */
+			  32);  /* default, 32 = 2.0x */
+
+	/* Set the default mode before we init the subdev */
+	sensor->mode = OV5647_DEFAULT_MODE;
+
+	exposure_max = sensor->mode->vts_def - 4;
+	exposure_def = (exposure_max < OV5647_EXPOSURE_DEFAULT) ?
+		exposure_max : OV5647_EXPOSURE_DEFAULT;
+	sensor->exposure = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+					     V4L2_CID_EXPOSURE,
+					     OV5647_EXPOSURE_MIN, exposure_max,
+					     OV5647_EXPOSURE_STEP,
+					     exposure_def);
+
+	/* By default, PIXEL_RATE is read only, but it does change per mode */
+	sensor->pixel_rate = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+					       V4L2_CID_PIXEL_RATE,
+					       sensor->mode->pixel_rate,
+					       sensor->mode->pixel_rate, 1,
+					       sensor->mode->pixel_rate);
+
+	/* By default, HBLANK is read only, but it does change per mode */
+	hblank = sensor->mode->hts - sensor->mode->format.width;
+	sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+					   V4L2_CID_HBLANK, hblank, hblank, 1,
+					   hblank);
+	sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+					   V4L2_CID_VBLANK, OV5647_VBLANK_MIN,
+					   OV5647_VTS_MAX -
+						sensor->mode->format.height, 1,
+					   sensor->mode->vts_def -
+						sensor->mode->format.height);
+
+	if (sensor->ctrls.error) {
+		ret = sensor->ctrls.error;
+		dev_err(&client->dev, "%s control init failed (%d)\n",
+			__func__, ret);
+		goto error;
+	}
+
+	ret = v4l2_fwnode_device_parse(&client->dev, &props);
+	if (ret)
+		goto error;
+
+	ret = v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &ov5647_ctrl_ops,
+					      &props);
+	if (ret)
+		goto error;
+
+	sensor->sd.ctrl_handler = &sensor->ctrls;
+
+	/* Write out the register set over I2C on stream-on. */
+	sensor->write_mode_regs = true;
+
 	sd = &sensor->sd;
 	v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
 	sensor->sd.internal_ops = &ov5647_subdev_internal_ops;
-	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+			    V4L2_SUBDEV_FL_HAS_EVENTS;
 
 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1633 @
 	if (ret < 0)
 		goto mutex_remove;
 
+	if (sensor->pwdn) {
+		gpiod_set_value_cansleep(sensor->pwdn, 0);
+		msleep(PWDN_ACTIVE_DELAY_MS);
+	}
+
 	ret = ov5647_detect(sd);
+
+	gpiod_set_value_cansleep(sensor->pwdn, 1);
+
 	if (ret < 0)
 		goto error;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1654 @
 error:
 	media_entity_cleanup(&sd->entity);
 mutex_remove:
+	v4l2_ctrl_handler_free(&sensor->ctrls);
 	mutex_destroy(&sensor->lock);
 	return ret;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1666 @
 
 	v4l2_async_unregister_subdev(&ov5647->sd);
 	media_entity_cleanup(&ov5647->sd.entity);
+	v4l2_ctrl_handler_free(&ov5647->ctrls);
 	v4l2_device_unregister_subdev(sd);
 	mutex_destroy(&ov5647->lock);
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/ov9281.c linux-5.10.52-v7l+/drivers/media/i2c/ov9281.c
--- linux-5.10.52-orig/drivers/media/i2c/ov9281.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/media/i2c/ov9281.c	2021-07-25 16:46:05.788293865 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Omnivision OV9281 1280x800 global shutter image sensor driver
+ *
+ * This driver has been taken from
+ * https://github.com/rockchip-linux/kernel/blob/develop-4.4/drivers/media/i2c/ov9281.c
+ * cleaned up, made to compile against mainline kernels instead of the Rockchip
+ * vendor kernel, and the relevant controls added to work with libcamera.
+ *
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
+ * V0.0X01.0X02 fix mclk issue when probe multiple camera.
+ * V0.0X01.0X03 add enum_frame_interval function.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#define OV9281_LINK_FREQ_400MHZ		400000000
+#define OV9281_LANES			2
+
+/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
+#define OV9281_PIXEL_RATE_10BIT		(OV9281_LINK_FREQ_400MHZ * 2 * \
+					 OV9281_LANES / 10)
+#define OV9281_PIXEL_RATE_8BIT		(OV9281_LINK_FREQ_400MHZ * 2 * \
+					 OV9281_LANES / 8)
+#define OV9281_XVCLK_FREQ		24000000
+
+#define CHIP_ID				0x9281
+#define OV9281_REG_CHIP_ID		0x300a
+
+#define OV9281_REG_TIMING_FORMAT_1		0x3820
+#define OV9281_REG_TIMING_FORMAT_2		0x3821
+#define OV9281_FLIP_BIT				BIT(2)
+
+#define OV9281_REG_CTRL_MODE		0x0100
+#define OV9281_MODE_SW_STANDBY		0x0
+#define OV9281_MODE_STREAMING		BIT(0)
+
+#define OV9281_REG_EXPOSURE		0x3500
+#define	OV9281_EXPOSURE_MIN		4
+#define	OV9281_EXPOSURE_STEP		1
+#define OV9281_VTS_MAX			0x7fff
+
+#define OV9281_REG_GAIN_H		0x3508
+#define OV9281_REG_GAIN_L		0x3509
+#define OV9281_GAIN_H_MASK		0x07
+#define OV9281_GAIN_H_SHIFT		8
+#define OV9281_GAIN_L_MASK		0xff
+#define OV9281_GAIN_MIN			0x10
+#define OV9281_GAIN_MAX			0xf8
+#define OV9281_GAIN_STEP		1
+#define OV9281_GAIN_DEFAULT		0x10
+
+#define OV9281_REG_TEST_PATTERN		0x5e00
+#define OV9281_TEST_PATTERN_ENABLE	0x80
+#define OV9281_TEST_PATTERN_DISABLE	0x0
+
+#define OV9281_REG_VTS			0x380e
+
+/*
+ * OV9281 native and active pixel array size.
+ * Datasheet not available to confirm these values, so assume there are no
+ * border pixels.
+ */
+#define OV9281_NATIVE_WIDTH		1280U
+#define OV9281_NATIVE_HEIGHT		800U
+#define OV9281_PIXEL_ARRAY_LEFT		0U
+#define OV9281_PIXEL_ARRAY_TOP		0U
+#define OV9281_PIXEL_ARRAY_WIDTH	1280U
+#define OV9281_PIXEL_ARRAY_HEIGHT	800U
+
+#define REG_NULL			0xFFFF
+
+#define OV9281_REG_VALUE_08BIT		1
+#define OV9281_REG_VALUE_16BIT		2
+#define OV9281_REG_VALUE_24BIT		3
+
+#define OV9281_NAME			"ov9281"
+
+static const char * const ov9281_supply_names[] = {
+	"avdd",		/* Analog power */
+	"dovdd",	/* Digital I/O power */
+	"dvdd",		/* Digital core power */
+};
+
+#define OV9281_NUM_SUPPLIES ARRAY_SIZE(ov9281_supply_names)
+
+struct regval {
+	u16 addr;
+	u8 val;
+};
+
+struct ov9281_mode {
+	u32 width;
+	u32 height;
+	u32 hts_def;
+	u32 vts_def;
+	u32 exp_def;
+	struct v4l2_rect crop;
+	const struct regval *reg_list;
+};
+
+struct ov9281 {
+	struct i2c_client	*client;
+	struct clk		*xvclk;
+	struct gpio_desc	*reset_gpio;
+	struct gpio_desc	*pwdn_gpio;
+	struct regulator_bulk_data supplies[OV9281_NUM_SUPPLIES];
+
+	struct v4l2_subdev	subdev;
+	struct media_pad	pad;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_ctrl	*exposure;
+	struct v4l2_ctrl	*anal_gain;
+	struct v4l2_ctrl	*digi_gain;
+	struct v4l2_ctrl	*hblank;
+	struct v4l2_ctrl	*vblank;
+	struct v4l2_ctrl	*hflip;
+	struct v4l2_ctrl	*vflip;
+	struct v4l2_ctrl	*pixel_rate;
+	struct v4l2_ctrl	*test_pattern;
+	struct mutex		mutex;
+	bool			streaming;
+	bool			power_on;
+	const struct ov9281_mode *cur_mode;
+	u32			code;
+};
+
+#define to_ov9281(sd) container_of(sd, struct ov9281, subdev)
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 120fps for 10 bit, 144fps for 8 bit.
+ * mipi_datarate per lane 800Mbps
+ */
+static const struct regval ov9281_common_regs[] = {
+	{0x0103, 0x01},
+	{0x0302, 0x32},
+	{0x030e, 0x02},
+	{0x3001, 0x00},
+	{0x3004, 0x00},
+	{0x3005, 0x00},
+	{0x3006, 0x04},
+	{0x3011, 0x0a},
+	{0x3013, 0x18},
+	{0x3022, 0x01},
+	{0x3023, 0x00},
+	{0x302c, 0x00},
+	{0x302f, 0x00},
+	{0x3030, 0x04},
+	{0x3039, 0x32},
+	{0x303a, 0x00},
+	{0x303f, 0x01},
+	{0x3500, 0x00},
+	{0x3501, 0x2a},
+	{0x3502, 0x90},
+	{0x3503, 0x08},
+	{0x3505, 0x8c},
+	{0x3507, 0x03},
+	{0x3508, 0x00},
+	{0x3509, 0x10},
+	{0x3610, 0x80},
+	{0x3611, 0xa0},
+	{0x3620, 0x6f},
+	{0x3632, 0x56},
+	{0x3633, 0x78},
+	{0x3666, 0x00},
+	{0x366f, 0x5a},
+	{0x3680, 0x84},
+	{0x3712, 0x80},
+	{0x372d, 0x22},
+	{0x3731, 0x80},
+	{0x3732, 0x30},
+	{0x377d, 0x22},
+	{0x3788, 0x02},
+	{0x3789, 0xa4},
+	{0x378a, 0x00},
+	{0x378b, 0x4a},
+	{0x3799, 0x20},
+	{0x3881, 0x42},
+	{0x38b1, 0x00},
+	{0x3920, 0xff},
+	{0x4010, 0x40},
+	{0x4043, 0x40},
+	{0x4307, 0x30},
+	{0x4317, 0x00},
+	{0x4501, 0x00},
+	{0x450a, 0x08},
+	{0x4601, 0x04},
+	{0x470f, 0x00},
+	{0x4f07, 0x00},
+	{0x4800, 0x00},
+	{0x5000, 0x9f},
+	{0x5001, 0x00},
+	{0x5e00, 0x00},
+	{0x5d00, 0x07},
+	{0x5d01, 0x00},
+	{REG_NULL, 0x00},
+};
+
+static const struct regval ov9281_1280x800_regs[] = {
+	{0x3778, 0x00},
+	{0x3800, 0x00},
+	{0x3801, 0x00},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x05},
+	{0x3805, 0x0f},
+	{0x3806, 0x03},
+	{0x3807, 0x2f},
+	{0x3808, 0x05},
+	{0x3809, 0x00},
+	{0x380a, 0x03},
+	{0x380b, 0x20},
+	{0x380c, 0x02},
+	{0x380d, 0xd8},
+	{0x380e, 0x03},
+	{0x380f, 0x8e},
+	{0x3810, 0x00},
+	{0x3811, 0x08},
+	{0x3812, 0x00},
+	{0x3813, 0x08},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3820, 0x40},
+	{0x3821, 0x00},
+	{0x4003, 0x40},
+	{0x4008, 0x04},
+	{0x4009, 0x0b},
+	{0x400c, 0x00},
+	{0x400d, 0x07},
+	{0x4507, 0x00},
+	{0x4509, 0x00},
+	{REG_NULL, 0x00},
+};
+
+static const struct regval ov9281_1280x720_regs[] = {
+	{0x3778, 0x00},
+	{0x3800, 0x00},
+	{0x3801, 0x00},
+	{0x3802, 0x00},
+	{0x3803, 0x28},
+	{0x3804, 0x05},
+	{0x3805, 0x0f},
+	{0x3806, 0x03},
+	{0x3807, 0x07},
+	{0x3808, 0x05},
+	{0x3809, 0x00},
+	{0x380a, 0x02},
+	{0x380b, 0xd0},
+	{0x380c, 0x02},
+	{0x380d, 0xd8},
+	{0x380e, 0x03},
+	{0x380f, 0x8e},
+	{0x3810, 0x00},
+	{0x3811, 0x08},
+	{0x3812, 0x00},
+	{0x3813, 0x08},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3820, 0x40},
+	{0x3821, 0x00},
+	{0x4003, 0x40},
+	{0x4008, 0x04},
+	{0x4009, 0x0b},
+	{0x400c, 0x00},
+	{0x400d, 0x07},
+	{0x4507, 0x00},
+	{0x4509, 0x00},
+	{REG_NULL, 0x00},
+};
+
+static const struct regval ov9281_640x400_regs[] = {
+	{0x3778, 0x10},
+	{0x3800, 0x00},
+	{0x3801, 0x00},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x05},
+	{0x3805, 0x0f},
+	{0x3806, 0x03},
+	{0x3807, 0x2f},
+	{0x3808, 0x02},
+	{0x3809, 0x80},
+	{0x380a, 0x01},
+	{0x380b, 0x90},
+	{0x380c, 0x02},
+	{0x380d, 0xd8},
+	{0x380e, 0x02},
+	{0x380f, 0x08},
+	{0x3810, 0x00},
+	{0x3811, 0x04},
+	{0x3812, 0x00},
+	{0x3813, 0x04},
+	{0x3814, 0x31},
+	{0x3815, 0x22},
+	{0x3820, 0x60},
+	{0x3821, 0x01},
+	{0x4008, 0x02},
+	{0x4009, 0x05},
+	{0x400c, 0x00},
+	{0x400d, 0x03},
+	{0x4507, 0x03},
+	{0x4509, 0x80},
+	{REG_NULL, 0x00},
+};
+
+static const struct regval op_10bit[] = {
+	{0x030d, 0x50},
+	{0x3662, 0x05},
+	{REG_NULL, 0x00},
+};
+
+static const struct regval op_8bit[] = {
+	{0x030d, 0x60},
+	{0x3662, 0x07},
+	{REG_NULL, 0x00},
+};
+
+static const struct ov9281_mode supported_modes[] = {
+	{
+		.width = 1280,
+		.height = 800,
+		.exp_def = 0x0320,
+		.hts_def = 0x05b0,	/* 0x2d8*2 */
+		.vts_def = 0x038e,
+		.crop = {
+			.left = 0,
+			.top = 0,
+			.width = 1280,
+			.height = 800
+		},
+		.reg_list = ov9281_1280x800_regs,
+	},
+	{
+		.width = 1280,
+		.height = 720,
+		.exp_def = 0x0320,
+		.hts_def = 0x05b0,
+		.vts_def = 761,
+		.crop = {
+			.left = 0,
+			.top = 40,
+			.width = 1280,
+			.height = 720
+		},
+		.reg_list = ov9281_1280x720_regs,
+	},
+	{
+		.width = 640,
+		.height = 400,
+		.exp_def = 0x0320,
+		.hts_def = 0x05b0,
+		.vts_def = 421,
+		.crop = {
+			.left = 0,
+			.top = 0,
+			.width = 1280,
+			.height = 800
+		},
+		.reg_list = ov9281_640x400_regs,
+	},
+};
+
+static const s64 link_freq_menu_items[] = {
+	OV9281_LINK_FREQ_400MHZ
+};
+
+static const char * const ov9281_test_pattern_menu[] = {
+	"Disabled",
+	"Vertical Color Bar Type 1",
+	"Vertical Color Bar Type 2",
+	"Vertical Color Bar Type 3",
+	"Vertical Color Bar Type 4"
+};
+
+/* Write registers up to 4 at a time */
+static int ov9281_write_reg(struct i2c_client *client, u16 reg,
+			    u32 len, u32 val)
+{
+	u32 buf_i, val_i;
+	u8 buf[6];
+	u8 *val_p;
+	__be32 val_be;
+
+	if (len > 4)
+		return -EINVAL;
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+
+	val_be = cpu_to_be32(val);
+	val_p = (u8 *)&val_be;
+	buf_i = 2;
+	val_i = 4 - len;
+
+	while (val_i < 4)
+		buf[buf_i++] = val_p[val_i++];
+
+	if (i2c_master_send(client, buf, len + 2) != len + 2)
+		return -EIO;
+
+	return 0;
+}
+
+static int ov9281_write_array(struct i2c_client *client,
+			      const struct regval *regs)
+{
+	u32 i;
+	int ret = 0;
+
+	for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
+		ret = ov9281_write_reg(client, regs[i].addr,
+				       OV9281_REG_VALUE_08BIT, regs[i].val);
+
+	return ret;
+}
+
+/* Read registers up to 4 at a time */
+static int ov9281_read_reg(struct i2c_client *client, u16 reg, unsigned int len,
+			   u32 *val)
+{
+	struct i2c_msg msgs[2];
+	u8 *data_be_p;
+	__be32 data_be = 0;
+	__be16 reg_addr_be = cpu_to_be16(reg);
+	int ret;
+
+	if (len > 4 || !len)
+		return -EINVAL;
+
+	data_be_p = (u8 *)&data_be;
+	/* Write register address */
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = 2;
+	msgs[0].buf = (u8 *)&reg_addr_be;
+
+	/* Read data from register */
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = len;
+	msgs[1].buf = &data_be_p[4 - len];
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	*val = be32_to_cpu(data_be);
+
+	return 0;
+}
+
+static int ov9281_get_reso_dist(const struct ov9281_mode *mode,
+				struct v4l2_mbus_framefmt *framefmt)
+{
+	return abs(mode->width - framefmt->width) +
+	       abs(mode->height - framefmt->height);
+}
+
+static const struct ov9281_mode *
+ov9281_find_best_fit(struct v4l2_subdev_format *fmt)
+{
+	struct v4l2_mbus_framefmt *framefmt = &fmt->format;
+	int dist;
+	int cur_best_fit = 0;
+	int cur_best_fit_dist = -1;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
+		dist = ov9281_get_reso_dist(&supported_modes[i], framefmt);
+		if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
+			cur_best_fit_dist = dist;
+			cur_best_fit = i;
+		}
+	}
+
+	return &supported_modes[cur_best_fit];
+}
+
+static int ov9281_set_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *fmt)
+{
+	struct ov9281 *ov9281 = to_ov9281(sd);
+	const struct ov9281_mode *mode;
+	s64 h_blank, vblank_def, pixel_rate;
+
+	mutex_lock(&ov9281->mutex);
+
+	mode = ov9281_find_best_fit(fmt);
+	if (fmt->format.code != MEDIA_BUS_FMT_Y8_1X8)
+		fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
+	fmt->format.width = mode->width;
+	fmt->format.height = mode->height;
+	fmt->format.field = V4L2_FIELD_NONE;
+	fmt->format.colorspace = V4L2_COLORSPACE_SRGB;
+	fmt->format.ycbcr_enc =
+			V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->format.colorspace);
+	fmt->format.quantization =
+		V4L2_MAP_QUANTIZATION_DEFAULT(true, fmt->format.colorspace,
+					      fmt->format.ycbcr_enc);
+	fmt->format.xfer_func =
+		V4L2_MAP_XFER_FUNC_DEFAULT(fmt->format.colorspace);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+	} else {
+		ov9281->cur_mode = mode;
+		ov9281->code = fmt->format.code;
+		h_blank = mode->hts_def - mode->width;
+		__v4l2_ctrl_modify_range(ov9281->hblank, h_blank,
+					 h_blank, 1, h_blank);
+		__v4l2_ctrl_s_ctrl(ov9281->hblank, h_blank);
+		vblank_def = mode->vts_def - mode->height;
+		__v4l2_ctrl_modify_range(ov9281->vblank, vblank_def,
+					 OV9281_VTS_MAX - mode->height,
+					 1, vblank_def);
+		__v4l2_ctrl_s_ctrl(ov9281->vblank, vblank_def);
+
+		pixel_rate = (fmt->format.code == MEDIA_BUS_FMT_Y10_1X10) ?
+			OV9281_PIXEL_RATE_10BIT : OV9281_PIXEL_RATE_8BIT;
+		__v4l2_ctrl_modify_range(ov9281->pixel_rate, pixel_rate,
+					 pixel_rate, 1, pixel_rate);
+	}
+
+	mutex_unlock(&ov9281->mutex);
+
+	return 0;
+}
+
+static int ov9281_get_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *fmt)
+{
+	struct ov9281 *ov9281 = to_ov9281(sd);
+	const struct ov9281_mode *mode = ov9281->cur_mode;
+
+	mutex_lock(&ov9281->mutex);
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+	} else {
+		fmt->format.width = mode->width;
+		fmt->format.height = mode->height;
+		fmt->format.code = ov9281->code;
+		fmt->format.field = V4L2_FIELD_NONE;
+		fmt->format.colorspace = V4L2_COLORSPACE_SRGB;
+		fmt->format.ycbcr_enc =
+			V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->format.colorspace);
+		fmt->format.quantization =
+			V4L2_MAP_QUANTIZATION_DEFAULT(true,
+						      fmt->format.colorspace,
+						      fmt->format.ycbcr_enc);
+		fmt->format.xfer_func =
+			V4L2_MAP_XFER_FUNC_DEFAULT(fmt->format.colorspace);
+	}
+	mutex_unlock(&ov9281->mutex);
+
+	return 0;
+}
+
+static int ov9281_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	switch (code->index) {
+	default:
+		return -EINVAL;
+	case 0:
+		code->code = MEDIA_BUS_FMT_Y10_1X10;
+		break;
+	case 1:
+		code->code = MEDIA_BUS_FMT_Y8_1X8;
+		break;
+	}
+
+	return 0;
+}
+
+static int ov9281_enum_frame_sizes(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index >= ARRAY_SIZE(supported_modes))
+		return -EINVAL;
+
+	if (fse->code != MEDIA_BUS_FMT_Y10_1X10 &&
+	    fse->code != MEDIA_BUS_FMT_Y8_1X8)
+		return -EINVAL;
+
+	fse->min_width  = supported_modes[fse->index].width;
+	fse->max_width  = supported_modes[fse->index].width;
+	fse->max_height = supported_modes[fse->index].height;
+	fse->min_height = supported_modes[fse->index].height;
+
+	return 0;
+}
+
+static int ov9281_enable_test_pattern(struct ov9281 *ov9281, u32 pattern)
+{
+	u32 val;
+
+	if (pattern)
+		val = (pattern - 1) | OV9281_TEST_PATTERN_ENABLE;
+	else
+		val = OV9281_TEST_PATTERN_DISABLE;
+
+	return ov9281_write_reg(ov9281->client, OV9281_REG_TEST_PATTERN,
+				OV9281_REG_VALUE_08BIT, val);
+}
+
+static int ov9281_set_ctrl_hflip(struct ov9281 *ov9281, int value)
+{
+	u32 current_val;
+	int ret = ov9281_read_reg(ov9281->client, OV9281_REG_TIMING_FORMAT_2,
+					OV9281_REG_VALUE_08BIT, &current_val);
+	if (!ret) {
+		if (value)
+			current_val |= OV9281_FLIP_BIT;
+		else
+			current_val &= ~OV9281_FLIP_BIT;
+		return ov9281_write_reg(ov9281->client,
+						OV9281_REG_TIMING_FORMAT_2,
+						OV9281_REG_VALUE_08BIT,
+						current_val);
+	}
+	return ret;
+}
+
+static int ov9281_set_ctrl_vflip(struct ov9281 *ov9281, int value)
+{
+	u32 current_val;
+	int ret = ov9281_read_reg(ov9281->client, OV9281_REG_TIMING_FORMAT_1,
+					OV9281_REG_VALUE_08BIT, &current_val);
+	if (!ret) {
+		if (value)
+			current_val |= OV9281_FLIP_BIT;
+		else
+			current_val &= ~OV9281_FLIP_BIT;
+		return ov9281_write_reg(ov9281->client,
+						OV9281_REG_TIMING_FORMAT_1,
+						OV9281_REG_VALUE_08BIT,
+						current_val);
+	}
+	return ret;
+}
+
+static const struct v4l2_rect *
+__ov9281_get_pad_crop(struct ov9281 *ov9281, struct v4l2_subdev_pad_config *cfg,
+		      unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(&ov9281->subdev, cfg, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &ov9281->cur_mode->crop;
+	}
+
+	return NULL;
+}
+
+static int ov9281_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_selection *sel)
+{
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP: {
+		struct ov9281 *ov9281 = to_ov9281(sd);
+
+		mutex_lock(&ov9281->mutex);
+		sel->r = *__ov9281_get_pad_crop(ov9281, cfg, sel->pad,
+						sel->which);
+		mutex_unlock(&ov9281->mutex);
+
+		return 0;
+	}
+
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+		sel->r.top = 0;
+		sel->r.left = 0;
+		sel->r.width = OV9281_NATIVE_WIDTH;
+		sel->r.height = OV9281_NATIVE_HEIGHT;
+
+		return 0;
+
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.top = OV9281_PIXEL_ARRAY_TOP;
+		sel->r.left = OV9281_PIXEL_ARRAY_LEFT;
+		sel->r.width = OV9281_PIXEL_ARRAY_WIDTH;
+		sel->r.height = OV9281_PIXEL_ARRAY_HEIGHT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int __ov9281_start_stream(struct ov9281 *ov9281)
+{
+	int ret;
+
+	ret = ov9281_write_array(ov9281->client, ov9281_common_regs);
+	if (ret)
+		return ret;
+
+	ret = ov9281_write_array(ov9281->client, ov9281->cur_mode->reg_list);
+	if (ret)
+		return ret;
+
+	if (ov9281->code == MEDIA_BUS_FMT_Y10_1X10)
+		ret = ov9281_write_array(ov9281->client, op_10bit);
+	else
+		ret = ov9281_write_array(ov9281->client, op_8bit);
+	if (ret)
+		return ret;
+
+	/* In case these controls are set before streaming */
+	mutex_unlock(&ov9281->mutex);
+	ret = v4l2_ctrl_handler_setup(&ov9281->ctrl_handler);
+	mutex_lock(&ov9281->mutex);
+	if (ret)
+		return ret;
+
+	return ov9281_write_reg(ov9281->client, OV9281_REG_CTRL_MODE,
+				OV9281_REG_VALUE_08BIT, OV9281_MODE_STREAMING);
+}
+
+static int __ov9281_stop_stream(struct ov9281 *ov9281)
+{
+	return ov9281_write_reg(ov9281->client, OV9281_REG_CTRL_MODE,
+				OV9281_REG_VALUE_08BIT, OV9281_MODE_SW_STANDBY);
+}
+
+static int ov9281_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct ov9281 *ov9281 = to_ov9281(sd);
+	struct i2c_client *client = ov9281->client;
+	int ret = 0;
+
+	mutex_lock(&ov9281->mutex);
+	on = !!on;
+	if (on == ov9281->streaming)
+		goto unlock_and_return;
+
+	if (on) {
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0) {
+			pm_runtime_put_noidle(&client->dev);
+			goto unlock_and_return;
+		}
+
+		ret = __ov9281_start_stream(ov9281);
+		if (ret) {
+			v4l2_err(sd, "start stream failed while write regs\n");
+			pm_runtime_put(&client->dev);
+			goto unlock_and_return;
+		}
+	} else {
+		__ov9281_stop_stream(ov9281);
+		pm_runtime_put(&client->dev);
+	}
+
+	ov9281->streaming = on;
+
+unlock_and_return:
+	mutex_unlock(&ov9281->mutex);
+
+	return ret;
+}
+
+static int ov9281_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct ov9281 *ov9281 = to_ov9281(sd);
+	struct i2c_client *client = ov9281->client;
+	int ret = 0;
+
+	mutex_lock(&ov9281->mutex);
+
+	/* If the power state is not modified - no work to do. */
+	if (ov9281->power_on == !!on)
+		goto unlock_and_return;
+
+	if (on) {
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0) {
+			pm_runtime_put_noidle(&client->dev);
+			goto unlock_and_return;
+		}
+		ov9281->power_on = true;
+	} else {
+		pm_runtime_put(&client->dev);
+		ov9281->power_on = false;
+	}
+
+unlock_and_return:
+	mutex_unlock(&ov9281->mutex);
+
+	return ret;
+}
+
+/* Calculate the delay in us by clock rate and clock cycles */
+static inline u32 ov9281_cal_delay(u32 cycles)
+{
+	return DIV_ROUND_UP(cycles, OV9281_XVCLK_FREQ / 1000 / 1000);
+}
+
+static int __ov9281_power_on(struct ov9281 *ov9281)
+{
+	int ret;
+	u32 delay_us;
+	struct device *dev = &ov9281->client->dev;
+
+	ret = clk_set_rate(ov9281->xvclk, OV9281_XVCLK_FREQ);
+	if (ret < 0)
+		dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
+	if (clk_get_rate(ov9281->xvclk) != OV9281_XVCLK_FREQ)
+		dev_warn(dev, "xvclk mismatched, modes are based on 24MHz - rate is %lu\n",
+			 clk_get_rate(ov9281->xvclk));
+
+	ret = clk_prepare_enable(ov9281->xvclk);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable xvclk\n");
+		return ret;
+	}
+
+	if (!IS_ERR(ov9281->reset_gpio))
+		gpiod_set_value_cansleep(ov9281->reset_gpio, 0);
+
+	ret = regulator_bulk_enable(OV9281_NUM_SUPPLIES, ov9281->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators\n");
+		goto disable_clk;
+	}
+
+	if (!IS_ERR(ov9281->reset_gpio))
+		gpiod_set_value_cansleep(ov9281->reset_gpio, 1);
+
+	usleep_range(500, 1000);
+	if (!IS_ERR(ov9281->pwdn_gpio))
+		gpiod_set_value_cansleep(ov9281->pwdn_gpio, 1);
+
+	/* 8192 cycles prior to first SCCB transaction */
+	delay_us = ov9281_cal_delay(8192);
+	usleep_range(delay_us, delay_us * 2);
+
+	return 0;
+
+disable_clk:
+	clk_disable_unprepare(ov9281->xvclk);
+
+	return ret;
+}
+
+static void __ov9281_power_off(struct ov9281 *ov9281)
+{
+	if (!IS_ERR(ov9281->pwdn_gpio))
+		gpiod_set_value_cansleep(ov9281->pwdn_gpio, 0);
+	clk_disable_unprepare(ov9281->xvclk);
+	if (!IS_ERR(ov9281->reset_gpio))
+		gpiod_set_value_cansleep(ov9281->reset_gpio, 0);
+	regulator_bulk_disable(OV9281_NUM_SUPPLIES, ov9281->supplies);
+}
+
+static int ov9281_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov9281 *ov9281 = to_ov9281(sd);
+
+	return __ov9281_power_on(ov9281);
+}
+
+static int ov9281_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov9281 *ov9281 = to_ov9281(sd);
+
+	__ov9281_power_off(ov9281);
+
+	return 0;
+}
+
+static int ov9281_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct ov9281 *ov9281 = to_ov9281(sd);
+	struct v4l2_mbus_framefmt *try_fmt =
+				v4l2_subdev_get_try_format(sd, fh->pad, 0);
+	const struct ov9281_mode *def_mode = &supported_modes[0];
+
+	mutex_lock(&ov9281->mutex);
+	/* Initialize try_fmt */
+	try_fmt->width = def_mode->width;
+	try_fmt->height = def_mode->height;
+	try_fmt->code = MEDIA_BUS_FMT_Y10_1X10;
+	try_fmt->field = V4L2_FIELD_NONE;
+	try_fmt->colorspace = V4L2_COLORSPACE_SRGB;
+	try_fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(try_fmt->colorspace);
+	try_fmt->quantization =
+		V4L2_MAP_QUANTIZATION_DEFAULT(true, try_fmt->colorspace,
+					      try_fmt->ycbcr_enc);
+	try_fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(try_fmt->colorspace);
+
+	mutex_unlock(&ov9281->mutex);
+	/* No crop or compose */
+
+	return 0;
+}
+
+static const struct dev_pm_ops ov9281_pm_ops = {
+	SET_RUNTIME_PM_OPS(ov9281_runtime_suspend,
+			   ov9281_runtime_resume, NULL)
+};
+
+static const struct v4l2_subdev_internal_ops ov9281_internal_ops = {
+	.open = ov9281_open,
+};
+
+static const struct v4l2_subdev_core_ops ov9281_core_ops = {
+	.s_power = ov9281_s_power,
+};
+
+static const struct v4l2_subdev_video_ops ov9281_video_ops = {
+	.s_stream = ov9281_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov9281_pad_ops = {
+	.enum_mbus_code = ov9281_enum_mbus_code,
+	.enum_frame_size = ov9281_enum_frame_sizes,
+	.get_fmt = ov9281_get_fmt,
+	.set_fmt = ov9281_set_fmt,
+	.get_selection = ov9281_get_selection,
+};
+
+static const struct v4l2_subdev_ops ov9281_subdev_ops = {
+	.core	= &ov9281_core_ops,
+	.video	= &ov9281_video_ops,
+	.pad	= &ov9281_pad_ops,
+};
+
+static int ov9281_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov9281 *ov9281 = container_of(ctrl->handler,
+					     struct ov9281, ctrl_handler);
+	struct i2c_client *client = ov9281->client;
+	s64 max;
+	int ret = 0;
+
+	/* Propagate change of current control to all related controls */
+	switch (ctrl->id) {
+	case V4L2_CID_VBLANK:
+		/* Update max exposure while meeting expected vblanking */
+		max = ov9281->cur_mode->height + ctrl->val - 4;
+		__v4l2_ctrl_modify_range(ov9281->exposure,
+					 ov9281->exposure->minimum, max,
+					 ov9281->exposure->step,
+					 ov9281->exposure->default_value);
+		break;
+	}
+
+	if (pm_runtime_get(&client->dev) <= 0)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		ret = ov9281_set_ctrl_hflip(ov9281, ctrl->val);
+		break;
+	case V4L2_CID_VFLIP:
+		ret = ov9281_set_ctrl_vflip(ov9281, ctrl->val);
+		break;
+	case V4L2_CID_EXPOSURE:
+		/* 4 least significant bits of expsoure are fractional part */
+		ret = ov9281_write_reg(ov9281->client, OV9281_REG_EXPOSURE,
+				       OV9281_REG_VALUE_24BIT, ctrl->val << 4);
+		break;
+	case V4L2_CID_ANALOGUE_GAIN:
+		ret = ov9281_write_reg(ov9281->client, OV9281_REG_GAIN_H,
+				       OV9281_REG_VALUE_08BIT,
+				       (ctrl->val >> OV9281_GAIN_H_SHIFT) &
+							OV9281_GAIN_H_MASK);
+		ret |= ov9281_write_reg(ov9281->client, OV9281_REG_GAIN_L,
+				       OV9281_REG_VALUE_08BIT,
+				       ctrl->val & OV9281_GAIN_L_MASK);
+		break;
+	case V4L2_CID_VBLANK:
+		ret = ov9281_write_reg(ov9281->client, OV9281_REG_VTS,
+				       OV9281_REG_VALUE_16BIT,
+				       ctrl->val + ov9281->cur_mode->height);
+		break;
+	case V4L2_CID_TEST_PATTERN:
+		ret = ov9281_enable_test_pattern(ov9281, ctrl->val);
+		break;
+	default:
+		dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
+			 __func__, ctrl->id, ctrl->val);
+		break;
+	}
+
+	pm_runtime_put(&client->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov9281_ctrl_ops = {
+	.s_ctrl = ov9281_set_ctrl,
+};
+
+static int ov9281_initialize_controls(struct ov9281 *ov9281)
+{
+	const struct ov9281_mode *mode;
+	struct v4l2_ctrl_handler *handler;
+	struct v4l2_ctrl *ctrl;
+	s64 exposure_max, vblank_def;
+	u32 h_blank;
+	int ret;
+
+	handler = &ov9281->ctrl_handler;
+	mode = ov9281->cur_mode;
+	ret = v4l2_ctrl_handler_init(handler, 9);
+	if (ret)
+		return ret;
+	handler->lock = &ov9281->mutex;
+
+	ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
+				      0, 0, link_freq_menu_items);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	ov9281->pixel_rate = v4l2_ctrl_new_std(handler, NULL,
+					       V4L2_CID_PIXEL_RATE,
+					       OV9281_PIXEL_RATE_10BIT,
+					       OV9281_PIXEL_RATE_10BIT, 1,
+					       OV9281_PIXEL_RATE_10BIT);
+
+	h_blank = mode->hts_def - mode->width;
+	ov9281->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
+					   h_blank, h_blank, 1, h_blank);
+	if (ov9281->hblank)
+		ov9281->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	vblank_def = mode->vts_def - mode->height;
+	ov9281->vblank = v4l2_ctrl_new_std(handler, &ov9281_ctrl_ops,
+					   V4L2_CID_VBLANK, vblank_def,
+					   OV9281_VTS_MAX - mode->height, 1,
+					   vblank_def);
+
+	exposure_max = mode->vts_def - 4;
+	ov9281->exposure = v4l2_ctrl_new_std(handler, &ov9281_ctrl_ops,
+					     V4L2_CID_EXPOSURE,
+					     OV9281_EXPOSURE_MIN, exposure_max,
+					     OV9281_EXPOSURE_STEP,
+					     mode->exp_def);
+
+	ov9281->anal_gain = v4l2_ctrl_new_std(handler, &ov9281_ctrl_ops,
+					      V4L2_CID_ANALOGUE_GAIN,
+					      OV9281_GAIN_MIN, OV9281_GAIN_MAX,
+					      OV9281_GAIN_STEP,
+					      OV9281_GAIN_DEFAULT);
+
+	ov9281->vflip = v4l2_ctrl_new_std(handler, &ov9281_ctrl_ops,
+					  V4L2_CID_VFLIP,
+						0, 1, 1, 0);
+
+	ov9281->hflip = v4l2_ctrl_new_std(handler, &ov9281_ctrl_ops,
+					  V4L2_CID_HFLIP,
+						0, 1, 1, 0);
+
+	ov9281->test_pattern =
+		v4l2_ctrl_new_std_menu_items(handler, &ov9281_ctrl_ops,
+					     V4L2_CID_TEST_PATTERN,
+					     ARRAY_SIZE(ov9281_test_pattern_menu) - 1,
+					     0, 0, ov9281_test_pattern_menu);
+
+	if (handler->error) {
+		ret = handler->error;
+		dev_err(&ov9281->client->dev,
+			"Failed to init controls(%d)\n", ret);
+		goto err_free_handler;
+	}
+
+	ov9281->subdev.ctrl_handler = handler;
+
+	return 0;
+
+err_free_handler:
+	v4l2_ctrl_handler_free(handler);
+
+	return ret;
+}
+
+static int ov9281_check_sensor_id(struct ov9281 *ov9281,
+				  struct i2c_client *client)
+{
+	struct device *dev = &ov9281->client->dev;
+	u32 id = 0, id_msb;
+	int ret;
+
+	ret = ov9281_read_reg(client, OV9281_REG_CHIP_ID + 1,
+			      OV9281_REG_VALUE_08BIT, &id);
+	if (!ret)
+		ret = ov9281_read_reg(client, OV9281_REG_CHIP_ID,
+				      OV9281_REG_VALUE_08BIT, &id_msb);
+	id |= (id_msb << 8);
+	if (ret || id != CHIP_ID) {
+		dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret);
+		return -ENODEV;
+	}
+
+	dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID);
+
+	return 0;
+}
+
+static int ov9281_configure_regulators(struct ov9281 *ov9281)
+{
+	unsigned int i;
+
+	for (i = 0; i < OV9281_NUM_SUPPLIES; i++)
+		ov9281->supplies[i].supply = ov9281_supply_names[i];
+
+	return devm_regulator_bulk_get(&ov9281->client->dev,
+				       OV9281_NUM_SUPPLIES,
+				       ov9281->supplies);
+}
+
+static int ov9281_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct ov9281 *ov9281;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	ov9281 = devm_kzalloc(dev, sizeof(*ov9281), GFP_KERNEL);
+	if (!ov9281)
+		return -ENOMEM;
+
+	ov9281->client = client;
+	ov9281->cur_mode = &supported_modes[0];
+
+	ov9281->xvclk = devm_clk_get(dev, "xvclk");
+	if (IS_ERR(ov9281->xvclk)) {
+		dev_err(dev, "Failed to get xvclk\n");
+		return -EINVAL;
+	}
+
+	ov9281->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						     GPIOD_OUT_LOW);
+	if (IS_ERR(ov9281->reset_gpio))
+		dev_warn(dev, "Failed to get reset-gpios\n");
+
+	ov9281->pwdn_gpio = devm_gpiod_get_optional(dev, "pwdn", GPIOD_OUT_LOW);
+	if (IS_ERR(ov9281->pwdn_gpio))
+		dev_warn(dev, "Failed to get pwdn-gpios\n");
+
+	ret = ov9281_configure_regulators(ov9281);
+	if (ret) {
+		dev_err(dev, "Failed to get power regulators\n");
+		return ret;
+	}
+
+	mutex_init(&ov9281->mutex);
+
+	sd = &ov9281->subdev;
+	v4l2_i2c_subdev_init(sd, client, &ov9281_subdev_ops);
+	ret = ov9281_initialize_controls(ov9281);
+	if (ret)
+		goto err_destroy_mutex;
+
+	ret = __ov9281_power_on(ov9281);
+	if (ret)
+		goto err_free_handler;
+
+	ret = ov9281_check_sensor_id(ov9281, client);
+	if (ret)
+		goto err_power_off;
+
+	sd->internal_ops = &ov9281_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	ov9281->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	ret = media_entity_pads_init(&sd->entity, 1, &ov9281->pad);
+	if (ret < 0)
+		goto err_power_off;
+
+	ret = v4l2_async_register_subdev_sensor_common(sd);
+	if (ret) {
+		dev_err(dev, "v4l2 async register subdev failed\n");
+		goto err_clean_entity;
+	}
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
+
+	return 0;
+
+err_clean_entity:
+	media_entity_cleanup(&sd->entity);
+err_power_off:
+	__ov9281_power_off(ov9281);
+err_free_handler:
+	v4l2_ctrl_handler_free(&ov9281->ctrl_handler);
+err_destroy_mutex:
+	mutex_destroy(&ov9281->mutex);
+
+	return ret;
+}
+
+static int ov9281_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov9281 *ov9281 = to_ov9281(sd);
+
+	v4l2_async_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(&ov9281->ctrl_handler);
+	mutex_destroy(&ov9281->mutex);
+
+	pm_runtime_disable(&client->dev);
+	if (!pm_runtime_status_suspended(&client->dev))
+		__ov9281_power_off(ov9281);
+	pm_runtime_set_suspended(&client->dev);
+
+	return 0;
+}
+
+static const struct of_device_id ov9281_of_match[] = {
+	{ .compatible = "ovti,ov9281" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ov9281_of_match);
+
+static const struct i2c_device_id ov9281_match_id[] = {
+	{ "ovti,ov9281", 0 },
+	{ },
+};
+
+static struct i2c_driver ov9281_i2c_driver = {
+	.driver = {
+		.name = OV9281_NAME,
+		.pm = &ov9281_pm_ops,
+		.of_match_table = of_match_ptr(ov9281_of_match),
+	},
+	.probe		= &ov9281_probe,
+	.remove		= &ov9281_remove,
+	.id_table	= ov9281_match_id,
+};
+
+static int __init sensor_mod_init(void)
+{
+	return i2c_add_driver(&ov9281_i2c_driver);
+}
+
+static void __exit sensor_mod_exit(void)
+{
+	i2c_del_driver(&ov9281_i2c_driver);
+}
+
+device_initcall_sync(sensor_mod_init);
+module_exit(sensor_mod_exit);
+
+MODULE_DESCRIPTION("OmniVision ov9281 sensor driver");
+MODULE_LICENSE("GPL v2");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/i2c/tc358743.c linux-5.10.52-v7l+/drivers/media/i2c/tc358743.c
--- linux-5.10.52-orig/drivers/media/i2c/tc358743.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/i2c/tc358743.c	2021-07-25 16:46:05.818293362 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:113 @
 
 /* --------------- I2C --------------- */
 
-static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
+static int i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
 {
 	struct tc358743_state *state = to_state(sd);
 	struct i2c_client *client = state->i2c_client;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:139 @
 		v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n",
 				__func__, reg, client->addr);
 	}
+	return err != ARRAY_SIZE(msgs);
 }
 
 static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:196 @
 	}
 }
 
-static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
+static noinline u32 i2c_rdreg_err(struct v4l2_subdev *sd, u16 reg, u32 n,
+				  int *err)
 {
+	int error;
 	__le32 val = 0;
 
-	i2c_rd(sd, reg, (u8 __force *)&val, n);
+	error = i2c_rd(sd, reg, (u8 __force *)&val, n);
+	if (err)
+		*err = error;
 
 	return le32_to_cpu(val);
 }
 
+static inline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
+{
+	return i2c_rdreg_err(sd, reg, n, NULL);
+}
+
 static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
 {
 	__le32 raw = cpu_to_le32(val);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:242 @
 	return i2c_rdreg(sd, reg, 2);
 }
 
+static int i2c_rd16_err(struct v4l2_subdev *sd, u16 reg, u16 *value)
+{
+	int err;
+	*value = i2c_rdreg_err(sd, reg, 2, &err);
+	return err;
+}
+
 static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
 {
 	i2c_wrreg(sd, reg, val, 2);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1629 @
 				    struct v4l2_mbus_config *cfg)
 {
 	struct tc358743_state *state = to_state(sd);
+	const u32 mask = V4L2_MBUS_CSI2_LANE_MASK;
+
+	if (state->csi_lanes_in_use > state->bus.num_data_lanes)
+		return -EINVAL;
 
 	cfg->type = V4L2_MBUS_CSI2_DPHY;
+	cfg->flags = (state->csi_lanes_in_use << __ffs(mask)) & mask;
 
-	/* Support for non-continuous CSI-2 clock is missing in the driver */
-	cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+	/* In DT mode, only report the number of active lanes */
+	if (sd->dev->of_node)
+		return 0;
+
+	/* Support for non-continuous CSI-2 clock is missing in pdate mode */
+	cfg->flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
 
 	switch (state->csi_lanes_in_use) {
 	case 1:
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1694 @
 	return 0;
 }
 
+static u32 tc358743_g_colorspace(u32 code)
+{
+	switch (code) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		return V4L2_COLORSPACE_SRGB;
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+		return V4L2_COLORSPACE_SMPTE170M;
+	default:
+		return 0;
+	}
+}
+
 static int tc358743_get_fmt(struct v4l2_subdev *sd,
 		struct v4l2_subdev_pad_config *cfg,
 		struct v4l2_subdev_format *format)
 {
 	struct tc358743_state *state = to_state(sd);
-	u8 vi_rep = i2c_rd8(sd, VI_REP);
 
 	if (format->pad != 0)
 		return -EINVAL;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1720 @
 	format->format.height = state->timings.bt.height;
 	format->format.field = V4L2_FIELD_NONE;
 
-	switch (vi_rep & MASK_VOUT_COLOR_SEL) {
-	case MASK_VOUT_COLOR_RGB_FULL:
-	case MASK_VOUT_COLOR_RGB_LIMITED:
-		format->format.colorspace = V4L2_COLORSPACE_SRGB;
-		break;
-	case MASK_VOUT_COLOR_601_YCBCR_LIMITED:
-	case MASK_VOUT_COLOR_601_YCBCR_FULL:
-		format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
-		break;
-	case MASK_VOUT_COLOR_709_YCBCR_FULL:
-	case MASK_VOUT_COLOR_709_YCBCR_LIMITED:
-		format->format.colorspace = V4L2_COLORSPACE_REC709;
-		break;
-	default:
-		format->format.colorspace = 0;
-		break;
-	}
+	format->format.colorspace = tc358743_g_colorspace(format->format.code);
 
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1734 @
 	u32 code = format->format.code; /* is overwritten by get_fmt */
 	int ret = tc358743_get_fmt(sd, cfg, format);
 
-	format->format.code = code;
+	if (code == MEDIA_BUS_FMT_RGB888_1X24 ||
+	    code == MEDIA_BUS_FMT_UYVY8_1X16)
+		format->format.code = code;
+	format->format.colorspace = tc358743_g_colorspace(format->format.code);
 
 	if (ret)
 		return ret;
 
-	switch (code) {
-	case MEDIA_BUS_FMT_RGB888_1X24:
-	case MEDIA_BUS_FMT_UYVY8_1X16:
-		break;
-	default:
-		return -EINVAL;
-	}
-
 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
 		return 0;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1969 @
 	state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS;
 	state->pdata.enable_hdcp = false;
 	/* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */
-	state->pdata.fifo_level = 16;
+	state->pdata.fifo_level = 374;
 	/*
 	 * The PLL input clock is obtained by dividing refclk by pll_prd.
 	 * It must be between 6 MHz and 40 MHz, lower frequency is better.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1989 @
 	/*
 	 * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
 	 * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60.
+	 * 972 Mbps allows 1080P50 UYVY over 2-lane.
 	 */
 	bps_pr_lane = 2 * endpoint.link_frequencies[0];
 	if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2003 @
 			       state->pdata.refclk_hz * state->pdata.pll_prd;
 
 	/*
-	 * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz
-	 * link frequency). In principle it should be possible to calculate
+	 * FIXME: These timings are from REF_02 for 594 or 972 Mbps per lane
+	 * (297 MHz or 486 MHz link frequency).
+	 * In principle it should be possible to calculate
 	 * them based on link frequency and resolution.
 	 */
-	if (bps_pr_lane != 594000000U)
+	switch (bps_pr_lane) {
+	default:
 		dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane);
-	state->pdata.lineinitcnt = 0xe80;
-	state->pdata.lptxtimecnt = 0x003;
-	/* tclk-preparecnt: 3, tclk-zerocnt: 20 */
-	state->pdata.tclk_headercnt = 0x1403;
-	state->pdata.tclk_trailcnt = 0x00;
-	/* ths-preparecnt: 3, ths-zerocnt: 1 */
-	state->pdata.ths_headercnt = 0x0103;
-	state->pdata.twakeup = 0x4882;
-	state->pdata.tclk_postcnt = 0x008;
-	state->pdata.ths_trailcnt = 0x2;
-	state->pdata.hstxvregcnt = 0;
+		/* fall through */
+	case 594000000U:
+		state->pdata.lineinitcnt = 0xe80;
+		state->pdata.lptxtimecnt = 0x003;
+		/* tclk-preparecnt: 3, tclk-zerocnt: 20 */
+		state->pdata.tclk_headercnt = 0x1403;
+		state->pdata.tclk_trailcnt = 0x00;
+		/* ths-preparecnt: 3, ths-zerocnt: 1 */
+		state->pdata.ths_headercnt = 0x0103;
+		state->pdata.twakeup = 0x4882;
+		state->pdata.tclk_postcnt = 0x008;
+		state->pdata.ths_trailcnt = 0x2;
+		state->pdata.hstxvregcnt = 0;
+		break;
+	case 972000000U:
+		state->pdata.lineinitcnt = 0x1b58;
+		state->pdata.lptxtimecnt = 0x007;
+		/* tclk-preparecnt: 6, tclk-zerocnt: 40 */
+		state->pdata.tclk_headercnt = 0x2806;
+		state->pdata.tclk_trailcnt = 0x00;
+		/* ths-preparecnt: 6, ths-zerocnt: 8 */
+		state->pdata.ths_headercnt = 0x0806;
+		state->pdata.twakeup = 0x4268;
+		state->pdata.tclk_postcnt = 0x008;
+		state->pdata.ths_trailcnt = 0x5;
+		state->pdata.hstxvregcnt = 0;
+		break;
+	}
 
 	state->reset_gpio = devm_gpiod_get_optional(dev, "reset",
 						    GPIOD_OUT_LOW);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2077 @
 	struct tc358743_platform_data *pdata = client->dev.platform_data;
 	struct v4l2_subdev *sd;
 	u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK;
+	u16 chipid;
 	int err;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2096 @
 	if (pdata) {
 		state->pdata = *pdata;
 		state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+		state->bus.num_data_lanes = 4;
 	} else {
 		err = tc358743_probe_of(state);
 		if (err == -ENODEV)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2110 @
 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 
 	/* i2c access */
-	if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) {
+	if (i2c_rd16_err(sd, CHIPID, &chipid) ||
+	    (chipid & MASK_CHIPID) != 0) {
 		v4l2_info(sd, "not a TC358743 on address 0x%x\n",
 			  client->addr << 1);
 		return -ENODEV;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/mc/mc-request.c linux-5.10.52-v7l+/drivers/media/mc/mc-request.c
--- linux-5.10.52-orig/drivers/media/mc/mc-request.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/mc/mc-request.c	2021-07-25 16:46:05.888292189 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:507 @
 		media_request_put(req);
 }
 EXPORT_SYMBOL_GPL(media_request_object_complete);
+
+void media_request_pin(struct media_request *req)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&req->lock, flags);
+	if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
+		goto unlock;
+	req->num_incomplete_objects++;
+unlock:
+	spin_unlock_irqrestore(&req->lock, flags);
+}
+EXPORT_SYMBOL_GPL(media_request_pin);
+
+void media_request_unpin(struct media_request *req)
+{
+	unsigned long flags;
+	bool completed = false;
+
+	spin_lock_irqsave(&req->lock, flags);
+	if (WARN_ON(!req->num_incomplete_objects) ||
+	    WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
+		goto unlock;
+
+	if (!--req->num_incomplete_objects) {
+		req->state = MEDIA_REQUEST_STATE_COMPLETE;
+		wake_up_interruptible_all(&req->poll_wait);
+		completed = true;
+	}
+unlock:
+	spin_unlock_irqrestore(&req->lock, flags);
+	if (completed)
+		media_request_put(req);
+}
+EXPORT_SYMBOL_GPL(media_request_unpin);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/platform/bcm2835/bcm2835-unicam.c linux-5.10.52-v7l+/drivers/media/platform/bcm2835/bcm2835-unicam.c
--- linux-5.10.52-orig/drivers/media/platform/bcm2835/bcm2835-unicam.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/media/platform/bcm2835/bcm2835-unicam.c	2021-07-25 16:46:06.388283806 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * BCM283x / BCM271x Unicam Capture Driver
+ *
+ * Copyright (C) 2017-2020 - Raspberry Pi (Trading) Ltd.
+ *
+ * Dave Stevenson <dave.stevenson@raspberrypi.com>
+ *
+ * Based on TI am437x driver by
+ *   Benoit Parrot <bparrot@ti.com>
+ *   Lad, Prabhakar <prabhakar.csengg@gmail.com>
+ *
+ * and TI CAL camera interface driver by
+ *    Benoit Parrot <bparrot@ti.com>
+ *
+ *
+ * There are two camera drivers in the kernel for BCM283x - this one
+ * and bcm2835-camera (currently in staging).
+ *
+ * This driver directly controls the Unicam peripheral - there is no
+ * involvement with the VideoCore firmware. Unicam receives CSI-2 or
+ * CCP2 data and writes it into SDRAM.
+ * The only potential processing options are to repack Bayer data into an
+ * alternate format, and applying windowing.
+ * The repacking does not shift the data, so can repack V4L2_PIX_FMT_Sxxxx10P
+ * to V4L2_PIX_FMT_Sxxxx10, or V4L2_PIX_FMT_Sxxxx12P to V4L2_PIX_FMT_Sxxxx12,
+ * but not generically up to V4L2_PIX_FMT_Sxxxx16. The driver will add both
+ * formats where the relevant formats are defined, and will automatically
+ * configure the repacking as required.
+ * Support for windowing may be added later.
+ *
+ * It should be possible to connect this driver to any sensor with a
+ * suitable output interface and V4L2 subdevice driver.
+ *
+ * bcm2835-camera uses the VideoCore firmware to control the sensor,
+ * Unicam, ISP, and all tuner control loops. Fully processed frames are
+ * delivered to the driver by the firmware. It only has sensor drivers
+ * for Omnivision OV5647, and Sony IMX219 sensors.
+ *
+ * The two drivers are mutually exclusive for the same Unicam instance.
+ * The VideoCore firmware checks the device tree configuration during boot.
+ * If it finds device tree nodes called csi0 or csi1 it will block the
+ * firmware from accessing the peripheral, and bcm2835-camera will
+ * not be able to stream data.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fwnode.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "vc4-regs-unicam.h"
+
+#define UNICAM_MODULE_NAME	"unicam"
+#define UNICAM_VERSION		"0.1.0"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-3");
+
+#define unicam_dbg(level, dev, fmt, arg...)	\
+		v4l2_dbg(level, debug, &(dev)->v4l2_dev, fmt, ##arg)
+#define unicam_info(dev, fmt, arg...)	\
+		v4l2_info(&(dev)->v4l2_dev, fmt, ##arg)
+#define unicam_err(dev, fmt, arg...)	\
+		v4l2_err(&(dev)->v4l2_dev, fmt, ##arg)
+
+/*
+ * Unicam must request a minimum of 250Mhz from the VPU clock.
+ * Otherwise the input FIFOs overrun and cause image corruption.
+ */
+#define MIN_VPU_CLOCK_RATE (250 * 1000 * 1000)
+/*
+ * To protect against a dodgy sensor driver never returning an error from
+ * enum_mbus_code, set a maximum index value to be used.
+ */
+#define MAX_ENUM_MBUS_CODE	128
+
+/*
+ * Stride is a 16 bit register, but also has to be a multiple of 32.
+ */
+#define BPL_ALIGNMENT		32
+#define MAX_BYTESPERLINE	((1 << 16) - BPL_ALIGNMENT)
+/*
+ * Max width is therefore determined by the max stride divided by
+ * the number of bits per pixel. Take 32bpp as a
+ * worst case.
+ * No imposed limit on the height, so adopt a square image for want
+ * of anything better.
+ */
+#define MAX_WIDTH		(MAX_BYTESPERLINE / 4)
+#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 UNICAM_EMBEDDED_SIZE	8192
+
+/*
+ * Size of the dummy buffer. Can be any size really, but the DMA
+ * allocation works in units of page sizes.
+ */
+#define DUMMY_BUF_SIZE		(PAGE_SIZE)
+
+enum pad_types {
+	IMAGE_PAD,
+	METADATA_PAD,
+	MAX_NODES
+};
+
+/*
+ * struct unicam_fmt - Unicam media bus format information
+ * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a.
+ * @repacked_fourcc: V4L2 pixel format FCC identifier if the data is expanded
+ * out to 16bpp. 0 if n/a.
+ * @code: V4L2 media bus format code.
+ * @depth: Bits per pixel as delivered from the source.
+ * @csi_dt: CSI data type.
+ * @check_variants: Flag to denote that there are multiple mediabus formats
+ *		still in the list that could match this V4L2 format.
+ */
+struct unicam_fmt {
+	u32	fourcc;
+	u32	repacked_fourcc;
+	u32	code;
+	u8	depth;
+	u8	csi_dt;
+	u8	check_variants;
+};
+
+static const struct unicam_fmt formats[] = {
+	/* YUV Formats */
+	{
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.code		= MEDIA_BUS_FMT_YUYV8_2X8,
+		.depth		= 16,
+		.csi_dt		= 0x1e,
+		.check_variants = 1,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_UYVY,
+		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
+		.depth		= 16,
+		.csi_dt		= 0x1e,
+		.check_variants = 1,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_YVYU,
+		.code		= MEDIA_BUS_FMT_YVYU8_2X8,
+		.depth		= 16,
+		.csi_dt		= 0x1e,
+		.check_variants = 1,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_VYUY,
+		.code		= MEDIA_BUS_FMT_VYUY8_2X8,
+		.depth		= 16,
+		.csi_dt		= 0x1e,
+		.check_variants = 1,
+	}, {
+		.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,
+		.repacked_fourcc = V4L2_PIX_FMT_SBGGR10,
+		.code		= MEDIA_BUS_FMT_SBGGR10_1X10,
+		.depth		= 10,
+		.csi_dt		= 0x2b,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SGBRG10P,
+		.repacked_fourcc = V4L2_PIX_FMT_SGBRG10,
+		.code		= MEDIA_BUS_FMT_SGBRG10_1X10,
+		.depth		= 10,
+		.csi_dt		= 0x2b,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SGRBG10P,
+		.repacked_fourcc = V4L2_PIX_FMT_SGRBG10,
+		.code		= MEDIA_BUS_FMT_SGRBG10_1X10,
+		.depth		= 10,
+		.csi_dt		= 0x2b,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SRGGB10P,
+		.repacked_fourcc = V4L2_PIX_FMT_SRGGB10,
+		.code		= MEDIA_BUS_FMT_SRGGB10_1X10,
+		.depth		= 10,
+		.csi_dt		= 0x2b,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SBGGR12P,
+		.repacked_fourcc = V4L2_PIX_FMT_SBGGR12,
+		.code		= MEDIA_BUS_FMT_SBGGR12_1X12,
+		.depth		= 12,
+		.csi_dt		= 0x2c,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SGBRG12P,
+		.repacked_fourcc = V4L2_PIX_FMT_SGBRG12,
+		.code		= MEDIA_BUS_FMT_SGBRG12_1X12,
+		.depth		= 12,
+		.csi_dt		= 0x2c,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SGRBG12P,
+		.repacked_fourcc = V4L2_PIX_FMT_SGRBG12,
+		.code		= MEDIA_BUS_FMT_SGRBG12_1X12,
+		.depth		= 12,
+		.csi_dt		= 0x2c,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SRGGB12P,
+		.repacked_fourcc = V4L2_PIX_FMT_SRGGB12,
+		.code		= MEDIA_BUS_FMT_SRGGB12_1X12,
+		.depth		= 12,
+		.csi_dt		= 0x2c,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SBGGR14P,
+		.repacked_fourcc = V4L2_PIX_FMT_SBGGR14,
+		.code		= MEDIA_BUS_FMT_SBGGR14_1X14,
+		.depth		= 14,
+		.csi_dt		= 0x2d,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SGBRG14P,
+		.repacked_fourcc = V4L2_PIX_FMT_SGBRG14,
+		.code		= MEDIA_BUS_FMT_SGBRG14_1X14,
+		.depth		= 14,
+		.csi_dt		= 0x2d,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SGRBG14P,
+		.repacked_fourcc = V4L2_PIX_FMT_SGRBG14,
+		.code		= MEDIA_BUS_FMT_SGRBG14_1X14,
+		.depth		= 14,
+		.csi_dt		= 0x2d,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_SRGGB14P,
+		.repacked_fourcc = V4L2_PIX_FMT_SRGGB14,
+		.code		= MEDIA_BUS_FMT_SRGGB14_1X14,
+		.depth		= 14,
+		.csi_dt		= 0x2d,
+	}, {
+	/*
+	 * 16 bit Bayer formats could be supported, but there is no CSI2
+	 * data_type defined for raw 16, and no sensors that produce it at
+	 * present.
+	 */
+
+	/* Greyscale formats */
+		.fourcc		= V4L2_PIX_FMT_GREY,
+		.code		= MEDIA_BUS_FMT_Y8_1X8,
+		.depth		= 8,
+		.csi_dt		= 0x2a,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_Y10P,
+		.repacked_fourcc = V4L2_PIX_FMT_Y10,
+		.code		= MEDIA_BUS_FMT_Y10_1X10,
+		.depth		= 10,
+		.csi_dt		= 0x2b,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_Y12P,
+		.repacked_fourcc = V4L2_PIX_FMT_Y12,
+		.code		= MEDIA_BUS_FMT_Y12_1X12,
+		.depth		= 12,
+		.csi_dt		= 0x2c,
+	}, {
+		.fourcc		= V4L2_PIX_FMT_Y14P,
+		.repacked_fourcc = V4L2_PIX_FMT_Y14,
+		.code		= MEDIA_BUS_FMT_Y14_1X14,
+		.depth		= 14,
+		.csi_dt		= 0x2d,
+	},
+	/* Embedded data format */
+	{
+		.fourcc		= V4L2_META_FMT_SENSOR_DATA,
+		.code		= MEDIA_BUS_FMT_SENSOR_DATA,
+		.depth		= 8,
+	}
+};
+
+struct unicam_buffer {
+	struct vb2_v4l2_buffer vb;
+	struct list_head list;
+};
+
+static inline struct unicam_buffer *to_unicam_buffer(struct vb2_buffer *vb)
+{
+	return container_of(vb, struct unicam_buffer, vb.vb2_buf);
+}
+
+struct unicam_node {
+	bool registered;
+	int open;
+	bool streaming;
+	unsigned int pad_id;
+	/* Pointer pointing to current v4l2_buffer */
+	struct unicam_buffer *cur_frm;
+	/* Pointer pointing to next v4l2_buffer */
+	struct unicam_buffer *next_frm;
+	/* video capture */
+	const struct unicam_fmt *fmt;
+	/* Used to store current pixel format */
+	struct v4l2_format v_fmt;
+	/* Used to store current mbus frame format */
+	struct v4l2_mbus_framefmt m_fmt;
+	/* Buffer queue used in video-buf */
+	struct vb2_queue buffer_queue;
+	/* Queue of filled frames */
+	struct list_head dma_queue;
+	/* IRQ lock for DMA queue */
+	spinlock_t dma_queue_lock;
+	/* 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 unicam_device *dev;
+	struct media_pad pad;
+	unsigned int embedded_lines;
+	/*
+	 * Dummy buffer intended to be used by unicam
+	 * if we have no other queued buffers to swap to.
+	 */
+	void *dummy_buf_cpu_addr;
+	dma_addr_t dummy_buf_dma_addr;
+};
+
+struct unicam_device {
+	struct kref kref;
+
+	/* V4l2 specific parameters */
+	struct v4l2_async_subdev asd;
+
+	/* peripheral base address */
+	void __iomem *base;
+	/* clock gating base address */
+	void __iomem *clk_gate_base;
+	/* lp clock handle */
+	struct clk *clock;
+	/* vpu clock handle */
+	struct clk *vpu_clock;
+	/* vpu clock request */
+	struct clk_request *vpu_req;
+	/* clock status for error handling */
+	bool clocks_enabled;
+	/* V4l2 device */
+	struct v4l2_device v4l2_dev;
+	struct media_device mdev;
+
+	/* parent device */
+	struct platform_device *pdev;
+	/* subdevice async Notifier */
+	struct v4l2_async_notifier notifier;
+	unsigned int sequence;
+
+	/* ptr to  sub device */
+	struct v4l2_subdev *sensor;
+	/* Pad config for the sensor */
+	struct v4l2_subdev_pad_config *sensor_config;
+
+	enum v4l2_mbus_type bus_type;
+	/*
+	 * Stores bus.mipi_csi2.flags for CSI2 sensors, or
+	 * bus.mipi_csi1.strobe for CCP2.
+	 */
+	unsigned int bus_flags;
+	unsigned int max_data_lanes;
+	unsigned int active_data_lanes;
+	bool sensor_embedded_data;
+
+	struct unicam_node node[MAX_NODES];
+	struct v4l2_ctrl_handler ctrl_handler;
+};
+
+static inline struct unicam_device *
+to_unicam_device(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct unicam_device, v4l2_dev);
+}
+
+/* Hardware access */
+static inline void clk_write(struct unicam_device *dev, u32 val)
+{
+	writel(val | 0x5a000000, dev->clk_gate_base);
+}
+
+static inline u32 reg_read(struct unicam_device *dev, u32 offset)
+{
+	return readl(dev->base + offset);
+}
+
+static inline void reg_write(struct unicam_device *dev, u32 offset, u32 val)
+{
+	writel(val, dev->base + offset);
+}
+
+static inline int get_field(u32 value, u32 mask)
+{
+	return (value & mask) >> __ffs(mask);
+}
+
+static inline void set_field(u32 *valp, u32 field, u32 mask)
+{
+	u32 val = *valp;
+
+	val &= ~mask;
+	val |= (field << __ffs(mask)) & mask;
+	*valp = val;
+}
+
+static inline u32 reg_read_field(struct unicam_device *dev, u32 offset,
+				 u32 mask)
+{
+	return get_field(reg_read(dev, offset), mask);
+}
+
+static inline void reg_write_field(struct unicam_device *dev, u32 offset,
+				   u32 field, u32 mask)
+{
+	u32 val = reg_read(dev, offset);
+
+	set_field(&val, field, mask);
+	reg_write(dev, offset, val);
+}
+
+/* Power management functions */
+static inline int unicam_runtime_get(struct unicam_device *dev)
+{
+	return pm_runtime_get_sync(&dev->pdev->dev);
+}
+
+static inline void unicam_runtime_put(struct unicam_device *dev)
+{
+	pm_runtime_put_sync(&dev->pdev->dev);
+}
+
+/* Format setup functions */
+static const struct unicam_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 int check_mbus_format(struct unicam_device *dev,
+			     const struct unicam_fmt *format)
+{
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) {
+		struct v4l2_subdev_mbus_code_enum mbus_code = {
+			.index = i,
+			.pad = IMAGE_PAD,
+			.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		};
+
+		ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code,
+				       NULL, &mbus_code);
+
+		if (!ret && mbus_code.code == format->code)
+			return 1;
+	}
+
+	return 0;
+}
+
+static const struct unicam_fmt *find_format_by_pix(struct unicam_device *dev,
+						   u32 pixelformat)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (formats[i].fourcc == pixelformat ||
+		    formats[i].repacked_fourcc == pixelformat) {
+			if (formats[i].check_variants &&
+			    !check_mbus_format(dev, &formats[i]))
+				continue;
+			return &formats[i];
+		}
+	}
+
+	return NULL;
+}
+
+static unsigned int bytes_per_line(u32 width, const struct unicam_fmt *fmt,
+				   u32 v4l2_fourcc)
+{
+	if (v4l2_fourcc == fmt->repacked_fourcc)
+		/* Repacking always goes to 16bpp */
+		return ALIGN(width << 1, BPL_ALIGNMENT);
+	else
+		return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
+}
+
+static int __subdev_get_format(struct unicam_device *dev,
+			       struct v4l2_mbus_framefmt *fmt, int pad_id)
+{
+	struct v4l2_subdev_format sd_fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = pad_id
+	};
+	int ret;
+
+	ret = v4l2_subdev_call(dev->sensor, pad, get_fmt, dev->sensor_config,
+			       &sd_fmt);
+	if (ret < 0)
+		return ret;
+
+	*fmt = sd_fmt.format;
+
+	unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__,
+		   fmt->width, fmt->height, fmt->code);
+
+	return 0;
+}
+
+static int __subdev_set_format(struct unicam_device *dev,
+			       struct v4l2_mbus_framefmt *fmt, int pad_id)
+{
+	struct v4l2_subdev_format sd_fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = pad_id
+	};
+	int ret;
+
+	sd_fmt.format = *fmt;
+
+	ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_config,
+			       &sd_fmt);
+	if (ret < 0)
+		return ret;
+
+	*fmt = sd_fmt.format;
+
+	if (pad_id == IMAGE_PAD)
+		unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__, fmt->width,
+			   fmt->height, fmt->code);
+	else
+		unicam_dbg(1, dev, "%s Embedded data code:%04x\n", __func__,
+			   sd_fmt.format.code);
+
+	return 0;
+}
+
+static int unicam_calc_format_size_bpl(struct unicam_device *dev,
+				       const struct unicam_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 = bytes_per_line(f->fmt.pix.width, fmt,
+					  f->fmt.pix.pixelformat);
+
+	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;
+
+	unicam_dbg(3, dev, "%s: fourcc: %08X size: %dx%d bpl:%d img_size:%d\n",
+		   __func__,
+		   f->fmt.pix.pixelformat,
+		   f->fmt.pix.width, f->fmt.pix.height,
+		   f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
+
+	return 0;
+}
+
+static int unicam_reset_format(struct unicam_node *node)
+{
+	struct unicam_device *dev = node->dev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int ret;
+
+	if (dev->sensor_embedded_data || node->pad_id != METADATA_PAD) {
+		ret = __subdev_get_format(dev, &mbus_fmt, node->pad_id);
+		if (ret) {
+			unicam_err(dev, "Failed to get_format - ret %d\n", ret);
+			return ret;
+		}
+
+		if (mbus_fmt.code != node->fmt->code) {
+			unicam_err(dev, "code mismatch - fmt->code %08x, mbus_fmt.code %08x\n",
+				   node->fmt->code, mbus_fmt.code);
+			return ret;
+		}
+	}
+
+	if (node->pad_id == IMAGE_PAD) {
+		v4l2_fill_pix_format(&node->v_fmt.fmt.pix, &mbus_fmt);
+		node->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		unicam_calc_format_size_bpl(dev, node->fmt, &node->v_fmt);
+	} else {
+		node->v_fmt.type = V4L2_BUF_TYPE_META_CAPTURE;
+		node->v_fmt.fmt.meta.dataformat = V4L2_META_FMT_SENSOR_DATA;
+		if (dev->sensor_embedded_data) {
+			node->v_fmt.fmt.meta.buffersize =
+					mbus_fmt.width * mbus_fmt.height;
+			node->embedded_lines = mbus_fmt.height;
+		} else {
+			node->v_fmt.fmt.meta.buffersize = UNICAM_EMBEDDED_SIZE;
+			node->embedded_lines = 1;
+		}
+	}
+
+	node->m_fmt = mbus_fmt;
+	return 0;
+}
+
+static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr,
+			       unsigned int buffer_size, int pad_id)
+{
+	dma_addr_t endaddr = dmaaddr + buffer_size;
+
+	if (pad_id == IMAGE_PAD) {
+		reg_write(dev, UNICAM_IBSA0, dmaaddr);
+		reg_write(dev, UNICAM_IBEA0, endaddr);
+	} else {
+		reg_write(dev, UNICAM_DBSA0, dmaaddr);
+		reg_write(dev, UNICAM_DBEA0, endaddr);
+	}
+}
+
+static unsigned int unicam_get_lines_done(struct unicam_device *dev)
+{
+	dma_addr_t start_addr, cur_addr;
+	unsigned int stride = dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline;
+	struct unicam_buffer *frm = dev->node[IMAGE_PAD].cur_frm;
+
+	if (!frm)
+		return 0;
+
+	start_addr = vb2_dma_contig_plane_dma_addr(&frm->vb.vb2_buf, 0);
+	cur_addr = reg_read(dev, UNICAM_IBWP);
+	return (unsigned int)(cur_addr - start_addr) / stride;
+}
+
+static void unicam_schedule_next_buffer(struct unicam_node *node)
+{
+	struct unicam_device *dev = node->dev;
+	struct unicam_buffer *buf;
+	unsigned int size;
+	dma_addr_t addr;
+
+	buf = list_first_entry(&node->dma_queue, struct unicam_buffer, list);
+	node->next_frm = buf;
+	list_del(&buf->list);
+
+	addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+	size = (node->pad_id == IMAGE_PAD) ?
+			node->v_fmt.fmt.pix.sizeimage :
+			node->v_fmt.fmt.meta.buffersize;
+
+	unicam_wr_dma_addr(dev, addr, size, node->pad_id);
+}
+
+static void unicam_schedule_dummy_buffer(struct unicam_node *node)
+{
+	struct unicam_device *dev = node->dev;
+
+	unicam_dbg(3, dev, "Scheduling dummy buffer for node %d\n",
+		   node->pad_id);
+
+	unicam_wr_dma_addr(dev, node->dummy_buf_dma_addr, DUMMY_BUF_SIZE,
+			   node->pad_id);
+	node->next_frm = NULL;
+}
+
+static void unicam_process_buffer_complete(struct unicam_node *node,
+					   unsigned int sequence)
+{
+	node->cur_frm->vb.field = node->m_fmt.field;
+	node->cur_frm->vb.sequence = sequence;
+
+	vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
+}
+
+static void unicam_queue_event_sof(struct unicam_device *unicam)
+{
+	struct v4l2_event event = {
+		.type = V4L2_EVENT_FRAME_SYNC,
+		.u.frame_sync.frame_sequence = unicam->sequence,
+	};
+
+	v4l2_event_queue(&unicam->node[IMAGE_PAD].video_dev, &event);
+}
+
+/*
+ * unicam_isr : ISR handler for unicam capture
+ * @irq: irq number
+ * @dev_id: dev_id ptr
+ *
+ * It changes status of the captured buffer, takes next buffer from the queue
+ * and sets its address in unicam registers
+ */
+static irqreturn_t unicam_isr(int irq, void *dev)
+{
+	struct unicam_device *unicam = dev;
+	unsigned int lines_done = unicam_get_lines_done(dev);
+	unsigned int sequence = unicam->sequence;
+	unsigned int i;
+	u32 ista, sta;
+	bool fe;
+	u64 ts;
+
+	sta = reg_read(unicam, UNICAM_STA);
+	/* Write value back to clear the interrupts */
+	reg_write(unicam, UNICAM_STA, sta);
+
+	ista = reg_read(unicam, UNICAM_ISTA);
+	/* Write value back to clear the interrupts */
+	reg_write(unicam, UNICAM_ISTA, ista);
+
+	unicam_dbg(3, unicam, "ISR: ISTA: 0x%X, STA: 0x%X, sequence %d, lines done %d",
+		   ista, sta, sequence, lines_done);
+
+	if (!(sta & (UNICAM_IS | UNICAM_PI0)))
+		return IRQ_HANDLED;
+
+	/*
+	 * Look for either the Frame End interrupt or the Packet Capture status
+	 * to signal a frame end.
+	 */
+	fe = (ista & UNICAM_FEI || sta & UNICAM_PI0);
+
+	/*
+	 * We must run the frame end handler first. If we have a valid next_frm
+	 * and we get a simultaneout FE + FS interrupt, running the FS handler
+	 * first would null out the next_frm ptr and we would have lost the
+	 * buffer forever.
+	 */
+	if (fe) {
+		/*
+		 * Ensure we have swapped buffers already as we can't
+		 * stop the peripheral. If no buffer is available, use a
+		 * dummy buffer to dump out frames until we get a new buffer
+		 * to use.
+		 */
+		for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
+			if (!unicam->node[i].streaming)
+				continue;
+
+			/*
+			 * If cur_frm == next_frm, it means we have not had
+			 * a chance to swap buffers, likely due to having
+			 * multiple interrupts occurring simultaneously (like FE
+			 * + FS + LS). In this case, we cannot signal the buffer
+			 * as complete, as the HW will reuse that buffer.
+			 */
+			if (unicam->node[i].cur_frm &&
+			    unicam->node[i].cur_frm != unicam->node[i].next_frm)
+				unicam_process_buffer_complete(&unicam->node[i],
+							       sequence);
+			unicam->node[i].cur_frm = unicam->node[i].next_frm;
+		}
+		unicam->sequence++;
+	}
+
+	if (ista & UNICAM_FSI) {
+		/*
+		 * Timestamp is to be when the first data byte was captured,
+		 * aka frame start.
+		 */
+		ts = ktime_get_ns();
+		for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
+			if (!unicam->node[i].streaming)
+				continue;
+
+			if (unicam->node[i].cur_frm)
+				unicam->node[i].cur_frm->vb.vb2_buf.timestamp =
+								ts;
+			/*
+			 * Set the next frame output to go to a dummy frame
+			 * if we have not managed to obtain another frame
+			 * from the queue.
+			 */
+			unicam_schedule_dummy_buffer(&unicam->node[i]);
+		}
+
+		unicam_queue_event_sof(unicam);
+	}
+
+	/*
+	 * Cannot swap buffer at frame end, there may be a race condition
+	 * where the HW does not actually swap it if the new frame has
+	 * already started.
+	 */
+	if (ista & (UNICAM_FSI | UNICAM_LCI) && !fe) {
+		for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
+			if (!unicam->node[i].streaming)
+				continue;
+
+			spin_lock(&unicam->node[i].dma_queue_lock);
+			if (!list_empty(&unicam->node[i].dma_queue) &&
+			    !unicam->node[i].next_frm)
+				unicam_schedule_next_buffer(&unicam->node[i]);
+			spin_unlock(&unicam->node[i].dma_queue_lock);
+		}
+	}
+
+	if (reg_read(unicam, UNICAM_ICTL) & UNICAM_FCM) {
+		/* Switch out of trigger mode if selected */
+		reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
+		reg_write_field(unicam, UNICAM_ICTL, 0, UNICAM_FCM);
+	}
+	return IRQ_HANDLED;
+}
+
+static int unicam_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	strscpy(cap->driver, UNICAM_MODULE_NAME, sizeof(cap->driver));
+	strscpy(cap->card, UNICAM_MODULE_NAME, sizeof(cap->card));
+
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "platform:%s", dev_name(&dev->pdev->dev));
+
+	cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE;
+
+	return 0;
+}
+
+static int unicam_enum_fmt_vid_cap(struct file *file, void  *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	unsigned int index = 0;
+	unsigned int i;
+	int ret = 0;
+
+	if (node->pad_id != IMAGE_PAD)
+		return -EINVAL;
+
+	for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) {
+		struct v4l2_subdev_mbus_code_enum mbus_code = {
+			.index = i,
+			.pad = IMAGE_PAD,
+			.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		};
+		const struct unicam_fmt *fmt;
+
+		ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code,
+				       NULL, &mbus_code);
+		if (ret < 0) {
+			unicam_dbg(2, dev,
+				   "subdev->enum_mbus_code idx %d returned %d - index invalid\n",
+				   i, ret);
+			return -EINVAL;
+		}
+
+		fmt = find_format_by_code(mbus_code.code);
+		if (fmt) {
+			if (fmt->fourcc) {
+				if (index == f->index) {
+					f->pixelformat = fmt->fourcc;
+					break;
+				}
+				index++;
+			}
+			if (fmt->repacked_fourcc) {
+				if (index == f->index) {
+					f->pixelformat = fmt->repacked_fourcc;
+					break;
+				}
+				index++;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int unicam_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct v4l2_mbus_framefmt mbus_fmt = {0};
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	const struct unicam_fmt *fmt = NULL;
+	int ret;
+
+	if (node->pad_id != IMAGE_PAD)
+		return -EINVAL;
+
+	/*
+	 * If a flip has occurred in the sensor, the fmt code might have
+	 * changed. So we will need to re-fetch the format from the subdevice.
+	 */
+	ret = __subdev_get_format(dev, &mbus_fmt, node->pad_id);
+	if (ret)
+		return -EINVAL;
+
+	/* Find the V4L2 format from mbus code. We must match a known format. */
+	fmt = find_format_by_code(mbus_fmt.code);
+	if (!fmt)
+		return -EINVAL;
+
+	if (node->fmt != fmt) {
+		/*
+		 * The sensor format has changed so the pixelformat needs to
+		 * be updated. Try and retain the packed/unpacked choice if
+		 * at all possible.
+		 */
+		if (node->fmt->repacked_fourcc ==
+						node->v_fmt.fmt.pix.pixelformat)
+			/* Using the repacked format */
+			node->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc;
+		else
+			/* Using the native format */
+			node->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
+
+		node->fmt = fmt;
+	}
+
+	*f = node->v_fmt;
+
+	return 0;
+}
+
+static const struct unicam_fmt *
+get_first_supported_format(struct unicam_device *dev)
+{
+	struct v4l2_subdev_mbus_code_enum mbus_code;
+	const struct unicam_fmt *fmt = NULL;
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; ret != -EINVAL && ret != -ENOIOCTLCMD; ++i) {
+		memset(&mbus_code, 0, sizeof(mbus_code));
+		mbus_code.index = i;
+		mbus_code.pad = IMAGE_PAD;
+		mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+
+		ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, NULL,
+				       &mbus_code);
+		if (ret < 0) {
+			unicam_dbg(2, dev,
+				   "subdev->enum_mbus_code idx %u returned %d - continue\n",
+				   i, ret);
+			continue;
+		}
+
+		unicam_dbg(2, dev, "subdev %s: code: 0x%08x idx: %u\n",
+			   dev->sensor->name, mbus_code.code, i);
+
+		fmt = find_format_by_code(mbus_code.code);
+		unicam_dbg(2, dev, "fmt 0x%08x returned as %p, V4L2 FOURCC 0x%08x, csi_dt 0x%02x\n",
+			   mbus_code.code, fmt, fmt ? fmt->fourcc : 0,
+			   fmt ? fmt->csi_dt : 0);
+		if (fmt)
+			return fmt;
+	}
+
+	return NULL;
+}
+
+static int unicam_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	struct v4l2_subdev_format sd_fmt = {
+		.which = V4L2_SUBDEV_FORMAT_TRY,
+		.pad = IMAGE_PAD
+	};
+	struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
+	const struct unicam_fmt *fmt;
+	int ret;
+
+	if (node->pad_id != IMAGE_PAD)
+		return -EINVAL;
+
+	fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
+	if (!fmt) {
+		/*
+		 * Pixel format not supported by unicam. Choose the first
+		 * supported format, and let the sensor choose something else.
+		 */
+		unicam_dbg(3, dev, "Fourcc format (0x%08x) not found. Use first format.\n",
+			   f->fmt.pix.pixelformat);
+
+		fmt = &formats[0];
+		f->fmt.pix.pixelformat = fmt->fourcc;
+	}
+
+	v4l2_fill_mbus_format(mbus_fmt, &f->fmt.pix, fmt->code);
+	/*
+	 * No support for receiving interlaced video, so never
+	 * request it from the sensor subdev.
+	 */
+	mbus_fmt->field = V4L2_FIELD_NONE;
+
+	ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_config,
+			       &sd_fmt);
+	if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+		return ret;
+
+	if (mbus_fmt->field != V4L2_FIELD_NONE)
+		unicam_info(dev, "Sensor trying to send interlaced video - results may be unpredictable\n");
+
+	v4l2_fill_pix_format(&f->fmt.pix, &sd_fmt.format);
+	if (mbus_fmt->code != fmt->code) {
+		/* Sensor has returned an alternate format */
+		fmt = find_format_by_code(mbus_fmt->code);
+		if (!fmt) {
+			/*
+			 * The alternate format is one unicam can't support.
+			 * Find the first format that is supported by both, and
+			 * then set that.
+			 */
+			fmt = get_first_supported_format(dev);
+			mbus_fmt->code = fmt->code;
+
+			ret = v4l2_subdev_call(dev->sensor, pad, set_fmt,
+					       dev->sensor_config, &sd_fmt);
+			if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+				return ret;
+
+			if (mbus_fmt->field != V4L2_FIELD_NONE)
+				unicam_info(dev, "Sensor trying to send interlaced video - results may be unpredictable\n");
+
+			v4l2_fill_pix_format(&f->fmt.pix, &sd_fmt.format);
+
+			if (mbus_fmt->code != fmt->code) {
+				/*
+				 * We've set a format that the sensor reports
+				 * as being supported, but it refuses to set it.
+				 * Not much else we can do.
+				 * Assume that the sensor driver may accept the
+				 * format when it is set (rather than tried).
+				 */
+				unicam_err(dev, "Sensor won't accept default format, and Unicam can't support sensor default\n");
+			}
+		}
+
+		if (fmt->fourcc)
+			f->fmt.pix.pixelformat = fmt->fourcc;
+		else
+			f->fmt.pix.pixelformat = fmt->repacked_fourcc;
+	}
+
+	return unicam_calc_format_size_bpl(dev, fmt, f);
+}
+
+static int unicam_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	struct vb2_queue *q = &node->buffer_queue;
+	struct v4l2_mbus_framefmt mbus_fmt = {0};
+	const struct unicam_fmt *fmt;
+	int ret;
+
+	if (vb2_is_busy(q))
+		return -EBUSY;
+
+	ret = unicam_try_fmt_vid_cap(file, priv, f);
+	if (ret < 0)
+		return ret;
+
+	fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
+	if (!fmt) {
+		/*
+		 * Unknown pixel format - adopt a default.
+		 * This shouldn't happen as try_fmt should have resolved any
+		 * issues first.
+		 */
+		fmt = get_first_supported_format(dev);
+		if (!fmt)
+			/*
+			 * It shouldn't be possible to get here with no
+			 * supported formats
+			 */
+			return -EINVAL;
+		f->fmt.pix.pixelformat = fmt->fourcc;
+		return -EINVAL;
+	}
+
+	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code);
+
+	ret = __subdev_set_format(dev, &mbus_fmt, node->pad_id);
+	if (ret) {
+		unicam_dbg(3, dev, "%s __subdev_set_format failed %d\n",
+			   __func__, ret);
+		return ret;
+	}
+
+	/* Just double check nothing has gone wrong */
+	if (mbus_fmt.code != fmt->code) {
+		unicam_dbg(3, dev,
+			   "%s subdev changed format on us, this should not happen\n",
+			   __func__);
+		return -EINVAL;
+	}
+
+	node->fmt = fmt;
+	node->v_fmt.fmt.pix.pixelformat = f->fmt.pix.pixelformat;
+	node->v_fmt.fmt.pix.bytesperline = f->fmt.pix.bytesperline;
+	unicam_reset_format(node);
+
+	unicam_dbg(3, dev,
+		   "%s %dx%d, mbus_fmt 0x%08X, V4L2 pix 0x%08X.\n",
+		   __func__, node->v_fmt.fmt.pix.width,
+		   node->v_fmt.fmt.pix.height, mbus_fmt.code,
+		   node->v_fmt.fmt.pix.pixelformat);
+
+	*f = node->v_fmt;
+
+	return 0;
+}
+
+static int unicam_enum_fmt_meta_cap(struct file *file, void *priv,
+				    struct v4l2_fmtdesc *f)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	const struct unicam_fmt *fmt;
+	u32 code;
+	int ret = 0;
+
+	if (node->pad_id != METADATA_PAD || f->index != 0)
+		return -EINVAL;
+
+	if (dev->sensor_embedded_data) {
+		struct v4l2_subdev_mbus_code_enum mbus_code = {
+			.index = f->index,
+			.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+			.pad = METADATA_PAD,
+		};
+
+		ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, NULL,
+				       &mbus_code);
+		if (ret < 0) {
+			unicam_dbg(2, dev,
+				   "subdev->enum_mbus_code idx 0 returned %d - index invalid\n",
+				   ret);
+			return -EINVAL;
+		}
+
+		code = mbus_code.code;
+	} else {
+		code = MEDIA_BUS_FMT_SENSOR_DATA;
+	}
+
+	fmt = find_format_by_code(code);
+	if (fmt)
+		f->pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static int unicam_g_fmt_meta_cap(struct file *file, void *priv,
+				 struct v4l2_format *f)
+{
+	struct unicam_node *node = video_drvdata(file);
+
+	if (node->pad_id != METADATA_PAD)
+		return -EINVAL;
+
+	*f = node->v_fmt;
+
+	return 0;
+}
+
+static int unicam_queue_setup(struct vb2_queue *vq,
+			      unsigned int *nbuffers,
+			      unsigned int *nplanes,
+			      unsigned int sizes[],
+			      struct device *alloc_devs[])
+{
+	struct unicam_node *node = vb2_get_drv_priv(vq);
+	struct unicam_device *dev = node->dev;
+	unsigned int size = node->pad_id == IMAGE_PAD ?
+				    node->v_fmt.fmt.pix.sizeimage :
+				    node->v_fmt.fmt.meta.buffersize;
+
+	if (vq->num_buffers + *nbuffers < 3)
+		*nbuffers = 3 - vq->num_buffers;
+
+	if (*nplanes) {
+		if (sizes[0] < size) {
+			unicam_err(dev, "sizes[0] %i < size %u\n", sizes[0],
+				   size);
+			return -EINVAL;
+		}
+		size = sizes[0];
+	}
+
+	*nplanes = 1;
+	sizes[0] = size;
+
+	return 0;
+}
+
+static int unicam_buffer_prepare(struct vb2_buffer *vb)
+{
+	struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue);
+	struct unicam_device *dev = node->dev;
+	struct unicam_buffer *buf = to_unicam_buffer(vb);
+	unsigned long size;
+
+	if (WARN_ON(!node->fmt))
+		return -EINVAL;
+
+	size = node->pad_id == IMAGE_PAD ? node->v_fmt.fmt.pix.sizeimage :
+					   node->v_fmt.fmt.meta.buffersize;
+	if (vb2_plane_size(vb, 0) < size) {
+		unicam_err(dev, "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);
+	return 0;
+}
+
+static void unicam_buffer_queue(struct vb2_buffer *vb)
+{
+	struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue);
+	struct unicam_buffer *buf = to_unicam_buffer(vb);
+	unsigned long flags;
+
+	spin_lock_irqsave(&node->dma_queue_lock, flags);
+	list_add_tail(&buf->list, &node->dma_queue);
+	spin_unlock_irqrestore(&node->dma_queue_lock, flags);
+}
+
+static void unicam_set_packing_config(struct unicam_device *dev)
+{
+	u32 pack, unpack;
+	u32 val;
+
+	if (dev->node[IMAGE_PAD].v_fmt.fmt.pix.pixelformat ==
+	    dev->node[IMAGE_PAD].fmt->fourcc) {
+		unpack = UNICAM_PUM_NONE;
+		pack = UNICAM_PPM_NONE;
+	} else {
+		switch (dev->node[IMAGE_PAD].fmt->depth) {
+		case 8:
+			unpack = UNICAM_PUM_UNPACK8;
+			break;
+		case 10:
+			unpack = UNICAM_PUM_UNPACK10;
+			break;
+		case 12:
+			unpack = UNICAM_PUM_UNPACK12;
+			break;
+		case 14:
+			unpack = UNICAM_PUM_UNPACK14;
+			break;
+		case 16:
+			unpack = UNICAM_PUM_UNPACK16;
+			break;
+		default:
+			unpack = UNICAM_PUM_NONE;
+			break;
+		}
+
+		/* Repacking is always to 16bpp */
+		pack = UNICAM_PPM_PACK16;
+	}
+
+	val = 0;
+	set_field(&val, unpack, UNICAM_PUM_MASK);
+	set_field(&val, pack, UNICAM_PPM_MASK);
+	reg_write(dev, UNICAM_IPIPE, val);
+}
+
+static void unicam_cfg_image_id(struct unicam_device *dev)
+{
+	if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
+		/* CSI2 mode, hardcode VC 0 for now. */
+		reg_write(dev, UNICAM_IDI0,
+			  (0 << 6) | dev->node[IMAGE_PAD].fmt->csi_dt);
+	} else {
+		/* CCP2 mode */
+		reg_write(dev, UNICAM_IDI0,
+			  0x80 | dev->node[IMAGE_PAD].fmt->csi_dt);
+	}
+}
+
+static void unicam_enable_ed(struct unicam_device *dev)
+{
+	u32 val = reg_read(dev, UNICAM_DCS);
+
+	set_field(&val, 2, UNICAM_EDL_MASK);
+	/* Do not wrap at the end of the embedded data buffer */
+	set_field(&val, 0, UNICAM_DBOB);
+
+	reg_write(dev, UNICAM_DCS, val);
+}
+
+static void unicam_start_rx(struct unicam_device *dev, dma_addr_t *addr)
+{
+	int line_int_freq = dev->node[IMAGE_PAD].v_fmt.fmt.pix.height >> 2;
+	unsigned int size, i;
+	u32 val;
+
+	if (line_int_freq < 128)
+		line_int_freq = 128;
+
+	/* Enable lane clocks */
+	val = 1;
+	for (i = 0; i < dev->active_data_lanes; i++)
+		val = val << 2 | 1;
+	clk_write(dev, val);
+
+	/* Basic init */
+	reg_write(dev, UNICAM_CTRL, UNICAM_MEM);
+
+	/* Enable analogue control, and leave in reset. */
+	val = UNICAM_AR;
+	set_field(&val, 7, UNICAM_CTATADJ_MASK);
+	set_field(&val, 7, UNICAM_PTATADJ_MASK);
+	reg_write(dev, UNICAM_ANA, val);
+	usleep_range(1000, 2000);
+
+	/* Come out of reset */
+	reg_write_field(dev, UNICAM_ANA, 0, UNICAM_AR);
+
+	/* Peripheral reset */
+	reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPR);
+	reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPR);
+
+	reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPE);
+
+	/* Enable Rx control. */
+	val = reg_read(dev, UNICAM_CTRL);
+	if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
+		set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK);
+		set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK);
+	} else {
+		set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK);
+		set_field(&val, dev->bus_flags, UNICAM_DCM_MASK);
+	}
+	/* Packet framer timeout */
+	set_field(&val, 0xf, UNICAM_PFT_MASK);
+	set_field(&val, 128, UNICAM_OET_MASK);
+	reg_write(dev, UNICAM_CTRL, val);
+
+	reg_write(dev, UNICAM_IHWIN, 0);
+	reg_write(dev, UNICAM_IVWIN, 0);
+
+	/* AXI bus access QoS setup */
+	val = reg_read(dev, UNICAM_PRI);
+	set_field(&val, 0, UNICAM_BL_MASK);
+	set_field(&val, 0, UNICAM_BS_MASK);
+	set_field(&val, 0xe, UNICAM_PP_MASK);
+	set_field(&val, 8, UNICAM_NP_MASK);
+	set_field(&val, 2, UNICAM_PT_MASK);
+	set_field(&val, 1, UNICAM_PE);
+	reg_write(dev, UNICAM_PRI, val);
+
+	reg_write_field(dev, UNICAM_ANA, 0, UNICAM_DDL);
+
+	/* Always start in trigger frame capture mode (UNICAM_FCM set) */
+	val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB;
+	set_field(&val, line_int_freq, UNICAM_LCIE_MASK);
+	reg_write(dev, UNICAM_ICTL, val);
+	reg_write(dev, UNICAM_STA, UNICAM_STA_MASK_ALL);
+	reg_write(dev, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL);
+
+	/* tclk_term_en */
+	reg_write_field(dev, UNICAM_CLT, 2, UNICAM_CLT1_MASK);
+	/* tclk_settle */
+	reg_write_field(dev, UNICAM_CLT, 6, UNICAM_CLT2_MASK);
+	/* td_term_en */
+	reg_write_field(dev, UNICAM_DLT, 2, UNICAM_DLT1_MASK);
+	/* ths_settle */
+	reg_write_field(dev, UNICAM_DLT, 6, UNICAM_DLT2_MASK);
+	/* trx_enable */
+	reg_write_field(dev, UNICAM_DLT, 0, UNICAM_DLT3_MASK);
+
+	reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_SOE);
+
+	/* Packet compare setup - required to avoid missing frame ends */
+	val = 0;
+	set_field(&val, 1, UNICAM_PCE);
+	set_field(&val, 1, UNICAM_GI);
+	set_field(&val, 1, UNICAM_CPH);
+	set_field(&val, 0, UNICAM_PCVC_MASK);
+	set_field(&val, 1, UNICAM_PCDT_MASK);
+	reg_write(dev, UNICAM_CMP0, val);
+
+	/* Enable clock lane and set up terminations */
+	val = 0;
+	if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
+		/* CSI2 */
+		set_field(&val, 1, UNICAM_CLE);
+		set_field(&val, 1, UNICAM_CLLPE);
+		if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) {
+			set_field(&val, 1, UNICAM_CLTRE);
+			set_field(&val, 1, UNICAM_CLHSE);
+		}
+	} else {
+		/* CCP2 */
+		set_field(&val, 1, UNICAM_CLE);
+		set_field(&val, 1, UNICAM_CLHSE);
+		set_field(&val, 1, UNICAM_CLTRE);
+	}
+	reg_write(dev, UNICAM_CLK, val);
+
+	/*
+	 * Enable required data lanes with appropriate terminations.
+	 * The same value needs to be written to UNICAM_DATn registers for
+	 * the active lanes, and 0 for inactive ones.
+	 */
+	val = 0;
+	if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
+		/* CSI2 */
+		set_field(&val, 1, UNICAM_DLE);
+		set_field(&val, 1, UNICAM_DLLPE);
+		if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) {
+			set_field(&val, 1, UNICAM_DLTRE);
+			set_field(&val, 1, UNICAM_DLHSE);
+		}
+	} else {
+		/* CCP2 */
+		set_field(&val, 1, UNICAM_DLE);
+		set_field(&val, 1, UNICAM_DLHSE);
+		set_field(&val, 1, UNICAM_DLTRE);
+	}
+	reg_write(dev, UNICAM_DAT0, val);
+
+	if (dev->active_data_lanes == 1)
+		val = 0;
+	reg_write(dev, UNICAM_DAT1, val);
+
+	if (dev->max_data_lanes > 2) {
+		/*
+		 * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the
+		 * instance supports more than 2 data lanes.
+		 */
+		if (dev->active_data_lanes == 2)
+			val = 0;
+		reg_write(dev, UNICAM_DAT2, val);
+
+		if (dev->active_data_lanes == 3)
+			val = 0;
+		reg_write(dev, UNICAM_DAT3, val);
+	}
+
+	reg_write(dev, UNICAM_IBLS,
+		  dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline);
+	size = dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage;
+	unicam_wr_dma_addr(dev, addr[IMAGE_PAD], size, IMAGE_PAD);
+	unicam_set_packing_config(dev);
+	unicam_cfg_image_id(dev);
+
+	val = reg_read(dev, UNICAM_MISC);
+	set_field(&val, 1, UNICAM_FL0);
+	set_field(&val, 1, UNICAM_FL1);
+	reg_write(dev, UNICAM_MISC, val);
+
+	if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) {
+		size = dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize;
+		unicam_enable_ed(dev);
+		unicam_wr_dma_addr(dev, addr[METADATA_PAD], size, METADATA_PAD);
+	}
+
+	/* Enable peripheral */
+	reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPE);
+
+	/* Load image pointers */
+	reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_LIP_MASK);
+
+	/* Load embedded data buffer pointers if needed */
+	if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data)
+		reg_write_field(dev, UNICAM_DCS, 1, UNICAM_LDP);
+
+	/*
+	 * Enable trigger only for the first frame to
+	 * sync correctly to the FS from the source.
+	 */
+	reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_TFC);
+}
+
+static void unicam_disable(struct unicam_device *dev)
+{
+	/* Analogue lane control disable */
+	reg_write_field(dev, UNICAM_ANA, 1, UNICAM_DDL);
+
+	/* Stop the output engine */
+	reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_SOE);
+
+	/* Disable the data lanes. */
+	reg_write(dev, UNICAM_DAT0, 0);
+	reg_write(dev, UNICAM_DAT1, 0);
+
+	if (dev->max_data_lanes > 2) {
+		reg_write(dev, UNICAM_DAT2, 0);
+		reg_write(dev, UNICAM_DAT3, 0);
+	}
+
+	/* Peripheral reset */
+	reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPR);
+	usleep_range(50, 100);
+	reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPR);
+
+	/* Disable peripheral */
+	reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPE);
+
+	/* Clear ED setup */
+	reg_write(dev, UNICAM_DCS, 0);
+
+	/* Disable all lane clocks */
+	clk_write(dev, 0);
+}
+
+static void unicam_return_buffers(struct unicam_node *node,
+				  enum vb2_buffer_state state)
+{
+	struct unicam_buffer *buf, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&node->dma_queue_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(&node->dma_queue_lock, flags);
+}
+
+static int unicam_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct unicam_node *node = vb2_get_drv_priv(vq);
+	struct unicam_device *dev = node->dev;
+	dma_addr_t buffer_addr[MAX_NODES] = { 0 };
+	unsigned long flags;
+	unsigned int i;
+	int ret;
+
+	node->streaming = true;
+	if (!(dev->node[IMAGE_PAD].open && dev->node[IMAGE_PAD].streaming &&
+	      (!dev->node[METADATA_PAD].open ||
+	       dev->node[METADATA_PAD].streaming))) {
+		/*
+		 * Metadata pad must be enabled before image pad if it is
+		 * wanted.
+		 */
+		unicam_dbg(3, dev, "Not all nodes are streaming yet.");
+		return 0;
+	}
+
+	dev->sequence = 0;
+	ret = unicam_runtime_get(dev);
+	if (ret < 0) {
+		unicam_dbg(3, dev, "unicam_runtime_get failed\n");
+		goto err_streaming;
+	}
+
+	dev->active_data_lanes = dev->max_data_lanes;
+
+	if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
+		struct v4l2_mbus_config mbus_config = { 0 };
+
+		ret = v4l2_subdev_call(dev->sensor, pad, get_mbus_config,
+				       0, &mbus_config);
+		if (ret < 0 && ret != -ENOIOCTLCMD) {
+			unicam_dbg(3, dev, "g_mbus_config failed\n");
+			goto err_pm_put;
+		}
+
+		dev->active_data_lanes =
+			(mbus_config.flags & V4L2_MBUS_CSI2_LANE_MASK) >>
+					__ffs(V4L2_MBUS_CSI2_LANE_MASK);
+		if (!dev->active_data_lanes)
+			dev->active_data_lanes = dev->max_data_lanes;
+		if (dev->active_data_lanes > dev->max_data_lanes) {
+			unicam_err(dev, "Device has requested %u data lanes, which is >%u configured in DT\n",
+				   dev->active_data_lanes,
+				   dev->max_data_lanes);
+			ret = -EINVAL;
+			goto err_pm_put;
+		}
+	}
+
+	unicam_dbg(1, dev, "Running with %u data lanes\n",
+		   dev->active_data_lanes);
+
+	dev->vpu_req = clk_request_start(dev->vpu_clock, MIN_VPU_CLOCK_RATE);
+	if (!dev->vpu_req) {
+		unicam_err(dev, "failed to set up VPU clock\n");
+		goto err_pm_put;
+	}
+
+	ret = clk_prepare_enable(dev->vpu_clock);
+	if (ret) {
+		unicam_err(dev, "Failed to enable VPU clock: %d\n", ret);
+		goto err_pm_put;
+	}
+
+	ret = clk_set_rate(dev->clock, 100 * 1000 * 1000);
+	if (ret) {
+		unicam_err(dev, "failed to set up CSI clock\n");
+		goto err_vpu_clock;
+	}
+
+	ret = clk_prepare_enable(dev->clock);
+	if (ret) {
+		unicam_err(dev, "Failed to enable CSI clock: %d\n", ret);
+		goto err_vpu_clock;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(dev->node); i++) {
+		struct unicam_buffer *buf;
+
+		if (!dev->node[i].streaming)
+			continue;
+
+		spin_lock_irqsave(&dev->node[i].dma_queue_lock, flags);
+		buf = list_first_entry(&dev->node[i].dma_queue,
+				       struct unicam_buffer, list);
+		dev->node[i].cur_frm = buf;
+		dev->node[i].next_frm = buf;
+		list_del(&buf->list);
+		spin_unlock_irqrestore(&dev->node[i].dma_queue_lock, flags);
+
+		buffer_addr[i] =
+			vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+	}
+
+	unicam_start_rx(dev, buffer_addr);
+
+	ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1);
+	if (ret < 0) {
+		unicam_err(dev, "stream on failed in subdev\n");
+		goto err_disable_unicam;
+	}
+
+	dev->clocks_enabled = true;
+	return 0;
+
+err_disable_unicam:
+	unicam_disable(dev);
+	clk_disable_unprepare(dev->clock);
+err_vpu_clock:
+	clk_request_done(dev->vpu_req);
+	clk_disable_unprepare(dev->vpu_clock);
+err_pm_put:
+	unicam_runtime_put(dev);
+err_streaming:
+	unicam_return_buffers(node, VB2_BUF_STATE_QUEUED);
+	node->streaming = false;
+
+	return ret;
+}
+
+static void unicam_stop_streaming(struct vb2_queue *vq)
+{
+	struct unicam_node *node = vb2_get_drv_priv(vq);
+	struct unicam_device *dev = node->dev;
+
+	node->streaming = false;
+
+	if (node->pad_id == IMAGE_PAD) {
+		/*
+		 * Stop streaming the sensor and disable the peripheral.
+		 * We cannot continue streaming embedded data with the
+		 * image pad disabled.
+		 */
+		if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0)
+			unicam_err(dev, "stream off failed in subdev\n");
+
+		unicam_disable(dev);
+
+		if (dev->clocks_enabled) {
+			clk_request_done(dev->vpu_req);
+			clk_disable_unprepare(dev->vpu_clock);
+			clk_disable_unprepare(dev->clock);
+			dev->clocks_enabled = false;
+		}
+		unicam_runtime_put(dev);
+
+	} else if (node->pad_id == METADATA_PAD) {
+		/*
+		 * Allow the hardware to spin in the dummy buffer.
+		 * This is only really needed if the embedded data pad is
+		 * disabled before the image pad.
+		 */
+		unicam_wr_dma_addr(dev, node->dummy_buf_dma_addr,
+				   DUMMY_BUF_SIZE, METADATA_PAD);
+	}
+
+	/* Clear all queued buffers for the node */
+	unicam_return_buffers(node, VB2_BUF_STATE_ERROR);
+}
+
+static int unicam_enum_input(struct file *file, void *priv,
+			     struct v4l2_input *inp)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	int ret;
+
+	if (inp->index != 0)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	if (v4l2_subdev_has_op(dev->sensor, video, s_dv_timings)) {
+		inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
+		inp->std = 0;
+	} else if (v4l2_subdev_has_op(dev->sensor, video, s_std)) {
+		inp->capabilities = V4L2_IN_CAP_STD;
+		if (v4l2_subdev_call(dev->sensor, video, g_tvnorms, &inp->std) < 0)
+			inp->std = V4L2_STD_ALL;
+	} else {
+		inp->capabilities = 0;
+		inp->std = 0;
+	}
+
+	if (v4l2_subdev_has_op(dev->sensor, video, g_input_status)) {
+		ret = v4l2_subdev_call(dev->sensor, video, g_input_status,
+				       &inp->status);
+		if (ret < 0)
+			return ret;
+	}
+
+	snprintf(inp->name, sizeof(inp->name), "Camera 0");
+	return 0;
+}
+
+static int unicam_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+
+	return 0;
+}
+
+static int unicam_s_input(struct file *file, void *priv, unsigned int i)
+{
+	/*
+	 * FIXME: Ideally we would like to be able to query the source
+	 * subdevice for information over the input connectors it supports,
+	 * and map that through in to a call to video_ops->s_routing.
+	 * There is no infrastructure support for defining that within
+	 * devicetree at present. Until that is implemented we can't
+	 * map a user physical connector number to s_routing input number.
+	 */
+	if (i > 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int unicam_querystd(struct file *file, void *priv,
+			   v4l2_std_id *std)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_subdev_call(dev->sensor, video, querystd, std);
+}
+
+static int unicam_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_subdev_call(dev->sensor, video, g_std, std);
+}
+
+static int unicam_s_std(struct file *file, void *priv, v4l2_std_id std)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	int ret;
+	v4l2_std_id current_std;
+
+	ret = v4l2_subdev_call(dev->sensor, video, g_std, &current_std);
+	if (ret)
+		return ret;
+
+	if (std == current_std)
+		return 0;
+
+	if (vb2_is_busy(&node->buffer_queue))
+		return -EBUSY;
+
+	ret = v4l2_subdev_call(dev->sensor, video, s_std, std);
+
+	/* Force recomputation of bytesperline */
+	node->v_fmt.fmt.pix.bytesperline = 0;
+
+	unicam_reset_format(node);
+
+	return ret;
+}
+
+static int unicam_s_edid(struct file *file, void *priv, struct v4l2_edid *edid)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_subdev_call(dev->sensor, pad, set_edid, edid);
+}
+
+static int unicam_g_edid(struct file *file, void *priv, struct v4l2_edid *edid)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_subdev_call(dev->sensor, pad, get_edid, edid);
+}
+
+static int unicam_s_selection(struct file *file, void *priv,
+			      struct v4l2_selection *sel)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	struct v4l2_subdev_selection sdsel = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.target = sel->target,
+		.flags = sel->flags,
+		.r = sel->r,
+	};
+
+	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	return v4l2_subdev_call(dev->sensor, pad, set_selection, NULL, &sdsel);
+}
+
+static int unicam_g_selection(struct file *file, void *priv,
+			      struct v4l2_selection *sel)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	struct v4l2_subdev_selection sdsel = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.target = sel->target,
+	};
+	int ret;
+
+	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	ret = v4l2_subdev_call(dev->sensor, pad, get_selection, NULL, &sdsel);
+	if (!ret)
+		sel->r = sdsel.r;
+
+	return ret;
+}
+
+static int unicam_enum_framesizes(struct file *file, void *priv,
+				  struct v4l2_frmsizeenum *fsize)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	const struct unicam_fmt *fmt;
+	struct v4l2_subdev_frame_size_enum fse;
+	int ret;
+
+	/* check for valid format */
+	fmt = find_format_by_pix(dev, fsize->pixel_format);
+	if (!fmt) {
+		unicam_dbg(3, dev, "Invalid pixel code: %x\n",
+			   fsize->pixel_format);
+		return -EINVAL;
+	}
+	fse.code = fmt->code;
+
+	fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	fse.index = fsize->index;
+	fse.pad = node->pad_id;
+
+	ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse);
+	if (ret)
+		return ret;
+
+	unicam_dbg(1, dev, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
+		   __func__, fse.index, fse.code, fse.min_width, fse.max_width,
+		   fse.min_height, fse.max_height);
+
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete.width = fse.max_width;
+	fsize->discrete.height = fse.max_height;
+
+	return 0;
+}
+
+static int unicam_enum_frameintervals(struct file *file, void *priv,
+				      struct v4l2_frmivalenum *fival)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	const struct unicam_fmt *fmt;
+	struct v4l2_subdev_frame_interval_enum fie = {
+		.index = fival->index,
+		.width = fival->width,
+		.height = fival->height,
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	int ret;
+
+	fmt = find_format_by_pix(dev, fival->pixel_format);
+	if (!fmt)
+		return -EINVAL;
+
+	fie.code = fmt->code;
+	ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_interval,
+			       NULL, &fie);
+	if (ret)
+		return ret;
+
+	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fival->discrete = fie.interval;
+
+	return 0;
+}
+
+static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a);
+}
+
+static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a);
+}
+
+static int unicam_g_dv_timings(struct file *file, void *priv,
+			       struct v4l2_dv_timings *timings)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_subdev_call(dev->sensor, video, g_dv_timings, timings);
+}
+
+static int unicam_s_dv_timings(struct file *file, void *priv,
+			       struct v4l2_dv_timings *timings)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	struct v4l2_dv_timings current_timings;
+	int ret;
+
+	ret = v4l2_subdev_call(dev->sensor, video, g_dv_timings,
+			       &current_timings);
+
+	if (ret < 0)
+		return ret;
+
+	if (v4l2_match_dv_timings(timings, &current_timings, 0, false))
+		return 0;
+
+	if (vb2_is_busy(&node->buffer_queue))
+		return -EBUSY;
+
+	ret = v4l2_subdev_call(dev->sensor, video, s_dv_timings, timings);
+
+	/* Force recomputation of bytesperline */
+	node->v_fmt.fmt.pix.bytesperline = 0;
+
+	unicam_reset_format(node);
+
+	return ret;
+}
+
+static int unicam_query_dv_timings(struct file *file, void *priv,
+				   struct v4l2_dv_timings *timings)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_subdev_call(dev->sensor, video, query_dv_timings, timings);
+}
+
+static int unicam_enum_dv_timings(struct file *file, void *priv,
+				  struct v4l2_enum_dv_timings *timings)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings);
+}
+
+static int unicam_dv_timings_cap(struct file *file, void *priv,
+				 struct v4l2_dv_timings_cap *cap)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+
+	return v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap);
+}
+
+static int unicam_subscribe_event(struct v4l2_fh *fh,
+				  const struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_FRAME_SYNC:
+		return v4l2_event_subscribe(fh, sub, 2, NULL);
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_event_subscribe(fh, sub, 4, NULL);
+	}
+
+	return v4l2_ctrl_subscribe_event(fh, sub);
+}
+
+static int unicam_log_status(struct file *file, void *fh)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	u32 reg;
+
+	/* status for sub devices */
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, log_status);
+
+	unicam_info(dev, "-----Receiver status-----\n");
+	unicam_info(dev, "V4L2 width/height:   %ux%u\n",
+		    node->v_fmt.fmt.pix.width, node->v_fmt.fmt.pix.height);
+	unicam_info(dev, "Mediabus format:     %08x\n", node->fmt->code);
+	unicam_info(dev, "V4L2 format:         %08x\n",
+		    node->v_fmt.fmt.pix.pixelformat);
+	reg = reg_read(dev, UNICAM_IPIPE);
+	unicam_info(dev, "Unpacking/packing:   %u / %u\n",
+		    get_field(reg, UNICAM_PUM_MASK),
+		    get_field(reg, UNICAM_PPM_MASK));
+	unicam_info(dev, "----Live data----\n");
+	unicam_info(dev, "Programmed stride:   %4u\n",
+		    reg_read(dev, UNICAM_IBLS));
+	unicam_info(dev, "Detected resolution: %ux%u\n",
+		    reg_read(dev, UNICAM_IHSTA),
+		    reg_read(dev, UNICAM_IVSTA));
+	unicam_info(dev, "Write pointer:       %08x\n",
+		    reg_read(dev, UNICAM_IBWP));
+
+	return 0;
+}
+
+static void unicam_notify(struct v4l2_subdev *sd,
+			  unsigned int notification, void *arg)
+{
+	struct unicam_device *dev = to_unicam_device(sd->v4l2_dev);
+
+	switch (notification) {
+	case V4L2_DEVICE_NOTIFY_EVENT:
+		v4l2_event_queue(&dev->node[IMAGE_PAD].video_dev, arg);
+		break;
+	default:
+		break;
+	}
+}
+
+static const struct vb2_ops unicam_video_qops = {
+	.wait_prepare		= vb2_ops_wait_prepare,
+	.wait_finish		= vb2_ops_wait_finish,
+	.queue_setup		= unicam_queue_setup,
+	.buf_prepare		= unicam_buffer_prepare,
+	.buf_queue		= unicam_buffer_queue,
+	.start_streaming	= unicam_start_streaming,
+	.stop_streaming		= unicam_stop_streaming,
+};
+
+/*
+ * unicam_v4l2_open : This function is based on the v4l2_fh_open helper
+ * function. It has been augmented to handle sensor subdevice power management,
+ */
+static int unicam_v4l2_open(struct file *file)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	int ret;
+
+	mutex_lock(&node->lock);
+
+	ret = v4l2_fh_open(file);
+	if (ret) {
+		unicam_err(dev, "v4l2_fh_open failed\n");
+		goto unlock;
+	}
+
+	node->open++;
+
+	if (!v4l2_fh_is_singular_file(file))
+		goto unlock;
+
+	ret = v4l2_subdev_call(dev->sensor, core, s_power, 1);
+	if (ret < 0 && ret != -ENOIOCTLCMD) {
+		v4l2_fh_release(file);
+		node->open--;
+		goto unlock;
+	}
+
+	ret = 0;
+
+unlock:
+	mutex_unlock(&node->lock);
+	return ret;
+}
+
+static int unicam_v4l2_release(struct file *file)
+{
+	struct unicam_node *node = video_drvdata(file);
+	struct unicam_device *dev = node->dev;
+	struct v4l2_subdev *sd = dev->sensor;
+	bool fh_singular;
+	int ret;
+
+	mutex_lock(&node->lock);
+
+	fh_singular = v4l2_fh_is_singular_file(file);
+
+	ret = _vb2_fop_release(file, NULL);
+
+	if (fh_singular)
+		v4l2_subdev_call(sd, core, s_power, 0);
+
+	node->open--;
+	mutex_unlock(&node->lock);
+
+	return ret;
+}
+
+/* unicam capture driver file operations */
+static const struct v4l2_file_operations unicam_fops = {
+	.owner		= THIS_MODULE,
+	.open		= unicam_v4l2_open,
+	.release	= unicam_v4l2_release,
+	.read		= vb2_fop_read,
+	.poll		= vb2_fop_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= vb2_fop_mmap,
+};
+
+/* unicam capture ioctl operations */
+static const struct v4l2_ioctl_ops unicam_ioctl_ops = {
+	.vidioc_querycap		= unicam_querycap,
+	.vidioc_enum_fmt_vid_cap	= unicam_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap		= unicam_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= unicam_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		= unicam_try_fmt_vid_cap,
+
+	.vidioc_enum_fmt_meta_cap	= unicam_enum_fmt_meta_cap,
+	.vidioc_g_fmt_meta_cap		= unicam_g_fmt_meta_cap,
+	.vidioc_s_fmt_meta_cap		= unicam_g_fmt_meta_cap,
+	.vidioc_try_fmt_meta_cap	= unicam_g_fmt_meta_cap,
+
+	.vidioc_enum_input		= unicam_enum_input,
+	.vidioc_g_input			= unicam_g_input,
+	.vidioc_s_input			= unicam_s_input,
+
+	.vidioc_querystd		= unicam_querystd,
+	.vidioc_s_std			= unicam_s_std,
+	.vidioc_g_std			= unicam_g_std,
+
+	.vidioc_g_edid			= unicam_g_edid,
+	.vidioc_s_edid			= unicam_s_edid,
+
+	.vidioc_enum_framesizes		= unicam_enum_framesizes,
+	.vidioc_enum_frameintervals	= unicam_enum_frameintervals,
+
+	.vidioc_g_selection		= unicam_g_selection,
+	.vidioc_s_selection		= unicam_s_selection,
+
+	.vidioc_g_parm			= unicam_g_parm,
+	.vidioc_s_parm			= unicam_s_parm,
+
+	.vidioc_s_dv_timings		= unicam_s_dv_timings,
+	.vidioc_g_dv_timings		= unicam_g_dv_timings,
+	.vidioc_query_dv_timings	= unicam_query_dv_timings,
+	.vidioc_enum_dv_timings		= unicam_enum_dv_timings,
+	.vidioc_dv_timings_cap		= unicam_dv_timings_cap,
+
+	.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_log_status		= unicam_log_status,
+	.vidioc_subscribe_event		= unicam_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+};
+
+static int
+unicam_async_bound(struct v4l2_async_notifier *notifier,
+		   struct v4l2_subdev *subdev,
+		   struct v4l2_async_subdev *asd)
+{
+	struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev);
+
+	if (unicam->sensor) {
+		unicam_info(unicam, "Rejecting subdev %s (Already set!!)",
+			    subdev->name);
+		return 0;
+	}
+
+	unicam->sensor = subdev;
+	unicam_dbg(1, unicam, "Using sensor %s for capture\n", subdev->name);
+
+	return 0;
+}
+
+static void unicam_release(struct kref *kref)
+{
+	struct unicam_device *unicam =
+		container_of(kref, struct unicam_device, kref);
+
+	v4l2_ctrl_handler_free(&unicam->ctrl_handler);
+	media_device_cleanup(&unicam->mdev);
+
+	if (unicam->sensor_config)
+		v4l2_subdev_free_pad_config(unicam->sensor_config);
+
+	kfree(unicam);
+}
+
+static void unicam_put(struct unicam_device *unicam)
+{
+	kref_put(&unicam->kref, unicam_release);
+}
+
+static void unicam_get(struct unicam_device *unicam)
+{
+	kref_get(&unicam->kref);
+}
+
+static void unicam_node_release(struct video_device *vdev)
+{
+	struct unicam_node *node = video_get_drvdata(vdev);
+
+	unicam_put(node->dev);
+}
+
+static int register_node(struct unicam_device *unicam, struct unicam_node *node,
+			 enum v4l2_buf_type type, int pad_id)
+{
+	struct video_device *vdev;
+	struct vb2_queue *q;
+	struct v4l2_mbus_framefmt mbus_fmt = {0};
+	const struct unicam_fmt *fmt;
+	int ret;
+
+	if (pad_id == IMAGE_PAD) {
+		ret = __subdev_get_format(unicam, &mbus_fmt, pad_id);
+		if (ret) {
+			unicam_err(unicam, "Failed to get_format - ret %d\n",
+				   ret);
+			return ret;
+		}
+
+		fmt = find_format_by_code(mbus_fmt.code);
+		if (!fmt) {
+			/*
+			 * Find the first format that the sensor and unicam both
+			 * support
+			 */
+			fmt = get_first_supported_format(unicam);
+
+			if (!fmt)
+				/* No compatible formats */
+				return -EINVAL;
+
+			mbus_fmt.code = fmt->code;
+			ret = __subdev_set_format(unicam, &mbus_fmt, pad_id);
+			if (ret)
+				return -EINVAL;
+		}
+		if (mbus_fmt.field != V4L2_FIELD_NONE) {
+			/* Interlaced not supported - disable it now. */
+			mbus_fmt.field = V4L2_FIELD_NONE;
+			ret = __subdev_set_format(unicam, &mbus_fmt, pad_id);
+			if (ret)
+				return -EINVAL;
+		}
+
+		node->v_fmt.fmt.pix.pixelformat = fmt->fourcc ? fmt->fourcc
+						: fmt->repacked_fourcc;
+	} else {
+		/* Fix this node format as embedded data. */
+		fmt = find_format_by_code(MEDIA_BUS_FMT_SENSOR_DATA);
+		node->v_fmt.fmt.meta.dataformat = fmt->fourcc;
+	}
+
+	node->dev = unicam;
+	node->pad_id = pad_id;
+	node->fmt = fmt;
+
+	/* Read current subdev format */
+	unicam_reset_format(node);
+
+	if (v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
+		v4l2_std_id tvnorms;
+
+		if (WARN_ON(!v4l2_subdev_has_op(unicam->sensor, video,
+						g_tvnorms)))
+			/*
+			 * Subdevice should not advertise s_std but not
+			 * g_tvnorms
+			 */
+			return -EINVAL;
+
+		ret = v4l2_subdev_call(unicam->sensor, video,
+				       g_tvnorms, &tvnorms);
+		if (WARN_ON(ret))
+			return -EINVAL;
+		node->video_dev.tvnorms |= tvnorms;
+	}
+
+	spin_lock_init(&node->dma_queue_lock);
+	mutex_init(&node->lock);
+
+	vdev = &node->video_dev;
+	if (pad_id == IMAGE_PAD) {
+		/* Add controls from the subdevice */
+		ret = v4l2_ctrl_add_handler(&unicam->ctrl_handler,
+					    unicam->sensor->ctrl_handler, NULL,
+					    true);
+		if (ret < 0)
+			return ret;
+
+		/*
+		 * If the sensor subdevice has any controls, associate the node
+		 *  with the ctrl handler to allow access from userland.
+		 */
+		if (!list_empty(&unicam->ctrl_handler.ctrls))
+			vdev->ctrl_handler = &unicam->ctrl_handler;
+	}
+
+	q = &node->buffer_queue;
+	q->type = type;
+	q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+	q->drv_priv = node;
+	q->ops = &unicam_video_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct unicam_buffer);
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->lock = &node->lock;
+	q->min_buffers_needed = 1;
+	q->dev = &unicam->pdev->dev;
+
+	ret = vb2_queue_init(q);
+	if (ret) {
+		unicam_err(unicam, "vb2_queue_init() failed\n");
+		return ret;
+	}
+
+	INIT_LIST_HEAD(&node->dma_queue);
+
+	vdev->release = unicam_node_release;
+	vdev->fops = &unicam_fops;
+	vdev->ioctl_ops = &unicam_ioctl_ops;
+	vdev->v4l2_dev = &unicam->v4l2_dev;
+	vdev->vfl_dir = VFL_DIR_RX;
+	vdev->queue = q;
+	vdev->lock = &node->lock;
+	vdev->device_caps = (pad_id == IMAGE_PAD) ?
+				V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_META_CAPTURE;
+	vdev->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+
+	/* Define the device names */
+	snprintf(vdev->name, sizeof(vdev->name), "%s-%s", UNICAM_MODULE_NAME,
+		 pad_id == IMAGE_PAD ? "image" : "embedded");
+
+	video_set_drvdata(vdev, node);
+	if (pad_id == IMAGE_PAD)
+		vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
+	node->pad.flags = MEDIA_PAD_FL_SINK;
+	media_entity_pads_init(&vdev->entity, 1, &node->pad);
+
+	node->dummy_buf_cpu_addr = dma_alloc_coherent(&unicam->pdev->dev,
+						      DUMMY_BUF_SIZE,
+						      &node->dummy_buf_dma_addr,
+						      GFP_KERNEL);
+	if (!node->dummy_buf_cpu_addr) {
+		unicam_err(unicam, "Unable to allocate dummy buffer.\n");
+		return -ENOMEM;
+	}
+	if (pad_id == METADATA_PAD ||
+	    !v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD);
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_STD);
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUMSTD);
+	}
+	if (pad_id == METADATA_PAD ||
+	    !v4l2_subdev_has_op(unicam->sensor, video, querystd))
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERYSTD);
+	if (pad_id == METADATA_PAD ||
+	    !v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) {
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_EDID);
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_EDID);
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_DV_TIMINGS_CAP);
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_DV_TIMINGS);
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_DV_TIMINGS);
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_DV_TIMINGS);
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERY_DV_TIMINGS);
+	}
+	if (pad_id == METADATA_PAD ||
+	    !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval))
+		v4l2_disable_ioctl(&node->video_dev,
+				   VIDIOC_ENUM_FRAMEINTERVALS);
+	if (pad_id == METADATA_PAD ||
+	    !v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval))
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_PARM);
+	if (pad_id == METADATA_PAD ||
+	    !v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval))
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_PARM);
+
+	if (pad_id == METADATA_PAD ||
+	    !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size))
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES);
+
+	if (node->pad_id == METADATA_PAD ||
+	    !v4l2_subdev_has_op(unicam->sensor, pad, set_selection))
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_SELECTION);
+
+	if (node->pad_id == METADATA_PAD ||
+	    !v4l2_subdev_has_op(unicam->sensor, pad, get_selection))
+		v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_SELECTION);
+
+	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+	if (ret) {
+		unicam_err(unicam, "Unable to register video device %s\n",
+			   vdev->name);
+		return ret;
+	}
+
+	/*
+	 * Acquire a reference to unicam, which will be released when the video
+	 * device will be unregistered and userspace will have closed all open
+	 * file handles.
+	 */
+	unicam_get(unicam);
+	node->registered = true;
+
+	if (pad_id != METADATA_PAD || unicam->sensor_embedded_data) {
+		ret = media_create_pad_link(&unicam->sensor->entity, pad_id,
+					    &node->video_dev.entity, 0,
+					    MEDIA_LNK_FL_ENABLED |
+					    MEDIA_LNK_FL_IMMUTABLE);
+		if (ret)
+			unicam_err(unicam, "Unable to create pad link for %s\n",
+				   vdev->name);
+	}
+
+	return ret;
+}
+
+static void unregister_nodes(struct unicam_device *unicam)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
+		struct unicam_node *node = &unicam->node[i];
+
+		if (node->dummy_buf_cpu_addr) {
+			dma_free_coherent(&unicam->pdev->dev, DUMMY_BUF_SIZE,
+					  node->dummy_buf_cpu_addr,
+					  node->dummy_buf_dma_addr);
+		}
+
+		if (node->registered) {
+			node->registered = false;
+			video_unregister_device(&node->video_dev);
+		}
+	}
+}
+
+static int unicam_probe_complete(struct unicam_device *unicam)
+{
+	int ret;
+
+	unicam->v4l2_dev.notify = unicam_notify;
+
+	unicam->sensor_config = v4l2_subdev_alloc_pad_config(unicam->sensor);
+	if (!unicam->sensor_config)
+		return -ENOMEM;
+
+	unicam->sensor_embedded_data = (unicam->sensor->entity.num_pads >= 2);
+
+	ret = register_node(unicam, &unicam->node[IMAGE_PAD],
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE, IMAGE_PAD);
+	if (ret) {
+		unicam_err(unicam, "Unable to register image video device.\n");
+		goto unregister;
+	}
+
+	ret = register_node(unicam, &unicam->node[METADATA_PAD],
+			    V4L2_BUF_TYPE_META_CAPTURE, METADATA_PAD);
+	if (ret) {
+		unicam_err(unicam, "Unable to register metadata video device.\n");
+		goto unregister;
+	}
+
+	ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev);
+	if (ret) {
+		unicam_err(unicam, "Unable to register subdev nodes.\n");
+		goto unregister;
+	}
+
+	/*
+	 * Release the initial reference, all references are now owned by the
+	 * video devices.
+	 */
+	unicam_put(unicam);
+	return 0;
+
+unregister:
+	unregister_nodes(unicam);
+	unicam_put(unicam);
+
+	return ret;
+}
+
+static int unicam_async_complete(struct v4l2_async_notifier *notifier)
+{
+	struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev);
+
+	return unicam_probe_complete(unicam);
+}
+
+static const struct v4l2_async_notifier_operations unicam_async_ops = {
+	.bound = unicam_async_bound,
+	.complete = unicam_async_complete,
+};
+
+static int of_unicam_connect_subdevs(struct unicam_device *dev)
+{
+	struct platform_device *pdev = dev->pdev;
+	struct v4l2_fwnode_endpoint ep = { };
+	struct device_node *ep_node;
+	struct device_node *sensor_node;
+	unsigned int lane;
+	int ret = -EINVAL;
+
+	if (of_property_read_u32(pdev->dev.of_node, "brcm,num-data-lanes",
+				 &dev->max_data_lanes) < 0) {
+		unicam_err(dev, "number of data lanes not set\n");
+		return -EINVAL;
+	}
+
+	/* Get the local endpoint and remote device. */
+	ep_node = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
+	if (!ep_node) {
+		unicam_dbg(3, dev, "can't get next endpoint\n");
+		return -EINVAL;
+	}
+
+	unicam_dbg(3, dev, "ep_node is %pOF\n", ep_node);
+
+	sensor_node = of_graph_get_remote_port_parent(ep_node);
+	if (!sensor_node) {
+		unicam_dbg(3, dev, "can't get remote parent\n");
+		goto cleanup_exit;
+	}
+
+	unicam_dbg(1, dev, "found subdevice %pOF\n", sensor_node);
+
+	/* Parse the local endpoint and validate its configuration. */
+	v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep);
+
+	unicam_dbg(3, dev, "parsed local endpoint, bus_type %u\n",
+		   ep.bus_type);
+
+	dev->bus_type = ep.bus_type;
+
+	switch (ep.bus_type) {
+	case V4L2_MBUS_CSI2_DPHY:
+		switch (ep.bus.mipi_csi2.num_data_lanes) {
+		case 1:
+		case 2:
+		case 4:
+			break;
+
+		default:
+			unicam_err(dev, "subdevice %pOF: %u data lanes not supported\n",
+				   sensor_node,
+				   ep.bus.mipi_csi2.num_data_lanes);
+			goto cleanup_exit;
+		}
+
+		for (lane = 0; lane < ep.bus.mipi_csi2.num_data_lanes; lane++) {
+			if (ep.bus.mipi_csi2.data_lanes[lane] != lane + 1) {
+				unicam_err(dev, "subdevice %pOF: data lanes reordering not supported\n",
+					   sensor_node);
+				goto cleanup_exit;
+			}
+		}
+
+		if (ep.bus.mipi_csi2.num_data_lanes > dev->max_data_lanes) {
+			unicam_err(dev, "subdevice requires %u data lanes when %u are supported\n",
+				   ep.bus.mipi_csi2.num_data_lanes,
+				   dev->max_data_lanes);
+		}
+
+		dev->max_data_lanes = ep.bus.mipi_csi2.num_data_lanes;
+		dev->bus_flags = ep.bus.mipi_csi2.flags;
+
+		break;
+
+	case V4L2_MBUS_CCP2:
+		if (ep.bus.mipi_csi1.clock_lane != 0 ||
+		    ep.bus.mipi_csi1.data_lane != 1) {
+			unicam_err(dev, "subdevice %pOF: unsupported lanes configuration\n",
+				   sensor_node);
+			goto cleanup_exit;
+		}
+
+		dev->max_data_lanes = 1;
+		dev->bus_flags = ep.bus.mipi_csi1.strobe;
+		break;
+
+	default:
+		/* Unsupported bus type */
+		unicam_err(dev, "subdevice %pOF: unsupported bus type %u\n",
+			   sensor_node, ep.bus_type);
+		goto cleanup_exit;
+	}
+
+	unicam_dbg(3, dev, "subdevice %pOF: %s bus, %u data lanes, flags=0x%08x\n",
+		   sensor_node,
+		   dev->bus_type == V4L2_MBUS_CSI2_DPHY ? "CSI-2" : "CCP2",
+		   dev->max_data_lanes, dev->bus_flags);
+
+	/* Initialize and register the async notifier. */
+	v4l2_async_notifier_init(&dev->notifier);
+	dev->notifier.ops = &unicam_async_ops;
+
+	dev->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+	dev->asd.match.fwnode = of_fwnode_handle(sensor_node);
+	ret = v4l2_async_notifier_add_subdev(&dev->notifier, &dev->asd);
+	if (ret) {
+		unicam_err(dev, "Error adding subdevice: %d\n", ret);
+		goto cleanup_exit;
+	}
+
+	ret = v4l2_async_notifier_register(&dev->v4l2_dev, &dev->notifier);
+	if (ret) {
+		unicam_err(dev, "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 unicam_probe(struct platform_device *pdev)
+{
+	struct unicam_device *unicam;
+	int ret;
+
+	unicam = kzalloc(sizeof(*unicam), GFP_KERNEL);
+	if (!unicam)
+		return -ENOMEM;
+
+	kref_init(&unicam->kref);
+	unicam->pdev = pdev;
+
+	unicam->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(unicam->base)) {
+		unicam_err(unicam, "Failed to get main io block\n");
+		ret = PTR_ERR(unicam->base);
+		goto err_unicam_put;
+	}
+
+	unicam->clk_gate_base = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(unicam->clk_gate_base)) {
+		unicam_err(unicam, "Failed to get 2nd io block\n");
+		ret = PTR_ERR(unicam->clk_gate_base);
+		goto err_unicam_put;
+	}
+
+	unicam->clock = devm_clk_get(&pdev->dev, "lp");
+	if (IS_ERR(unicam->clock)) {
+		unicam_err(unicam, "Failed to get lp clock\n");
+		ret = PTR_ERR(unicam->clock);
+		goto err_unicam_put;
+	}
+
+	unicam->vpu_clock = devm_clk_get(&pdev->dev, "vpu");
+	if (IS_ERR(unicam->vpu_clock)) {
+		unicam_err(unicam, "Failed to get vpu clock\n");
+		ret = PTR_ERR(unicam->vpu_clock);
+		goto err_unicam_put;
+	}
+
+	ret = platform_get_irq(pdev, 0);
+	if (ret <= 0) {
+		dev_err(&pdev->dev, "No IRQ resource\n");
+		ret = -EINVAL;
+		goto err_unicam_put;
+	}
+
+	ret = devm_request_irq(&pdev->dev, ret, unicam_isr, 0,
+			       "unicam_capture0", unicam);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to request interrupt\n");
+		ret = -EINVAL;
+		goto err_unicam_put;
+	}
+
+	unicam->mdev.dev = &pdev->dev;
+	strscpy(unicam->mdev.model, UNICAM_MODULE_NAME,
+		sizeof(unicam->mdev.model));
+	strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial));
+	snprintf(unicam->mdev.bus_info, sizeof(unicam->mdev.bus_info),
+		 "platform:%s", dev_name(&pdev->dev));
+	unicam->mdev.hw_revision = 0;
+
+	media_device_init(&unicam->mdev);
+
+	unicam->v4l2_dev.mdev = &unicam->mdev;
+
+	ret = v4l2_device_register(&pdev->dev, &unicam->v4l2_dev);
+	if (ret) {
+		unicam_err(unicam,
+			   "Unable to register v4l2 device.\n");
+		goto err_unicam_put;
+	}
+
+	ret = media_device_register(&unicam->mdev);
+	if (ret < 0) {
+		unicam_err(unicam,
+			   "Unable to register media-controller device.\n");
+		goto err_v4l2_unregister;
+	}
+
+	/* Reserve space for the controls */
+	ret = v4l2_ctrl_handler_init(&unicam->ctrl_handler, 16);
+	if (ret < 0)
+		goto err_media_unregister;
+
+	/* set the driver data in platform device */
+	platform_set_drvdata(pdev, unicam);
+
+	ret = of_unicam_connect_subdevs(unicam);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to connect subdevs\n");
+		goto err_media_unregister;
+	}
+
+	/* Enable the block power domain */
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+
+err_media_unregister:
+	media_device_unregister(&unicam->mdev);
+err_v4l2_unregister:
+	v4l2_device_unregister(&unicam->v4l2_dev);
+err_unicam_put:
+	unicam_put(unicam);
+
+	return ret;
+}
+
+static int unicam_remove(struct platform_device *pdev)
+{
+	struct unicam_device *unicam = platform_get_drvdata(pdev);
+
+	unicam_dbg(2, unicam, "%s\n", __func__);
+
+	v4l2_async_notifier_unregister(&unicam->notifier);
+	v4l2_device_unregister(&unicam->v4l2_dev);
+	media_device_unregister(&unicam->mdev);
+	unregister_nodes(unicam);
+
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id unicam_of_match[] = {
+	{ .compatible = "brcm,bcm2835-unicam", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, unicam_of_match);
+
+static struct platform_driver unicam_driver = {
+	.probe		= unicam_probe,
+	.remove		= unicam_remove,
+	.driver = {
+		.name	= UNICAM_MODULE_NAME,
+		.of_match_table = of_match_ptr(unicam_of_match),
+	},
+};
+
+module_platform_driver(unicam_driver);
+
+MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>");
+MODULE_DESCRIPTION("BCM2835 Unicam driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(UNICAM_VERSION);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/platform/bcm2835/Kconfig linux-5.10.52-v7l+/drivers/media/platform/bcm2835/Kconfig
--- linux-5.10.52-orig/drivers/media/platform/bcm2835/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/media/platform/bcm2835/Kconfig	2021-07-25 16:46:06.388283806 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# Broadcom VideoCore4 V4L2 camera support
+
+config VIDEO_BCM2835_UNICAM
+	tristate "Broadcom BCM283x/BCM271x Unicam video capture driver"
+	depends on VIDEO_V4L2
+	depends on ARCH_BCM2835 || COMPILE_TEST
+	select VIDEO_V4L2_SUBDEV_API
+	select MEDIA_CONTROLLER
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_FWNODE
+	help
+	  Say Y here to enable support for the BCM283x/BCM271x CSI-2 receiver.
+	  This is a V4L2 driver that controls the CSI-2 receiver directly,
+	  independently from the VC4 firmware.
+	  This driver is mutually exclusive with the use of bcm2835-camera. The
+	  firmware will disable all access to the peripheral from within the
+	  firmware if it finds a DT node using it, and bcm2835-camera will
+	  therefore fail to probe.
+
+	  To compile this driver as a module, choose M here. The module will be
+	  called bcm2835-unicam.
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/platform/bcm2835/Makefile linux-5.10.52-v7l+/drivers/media/platform/bcm2835/Makefile
--- linux-5.10.52-orig/drivers/media/platform/bcm2835/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/media/platform/bcm2835/Makefile	2021-07-25 16:46:06.388283806 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1 @
+# Makefile for BCM2835 Unicam driver
+
+obj-$(CONFIG_VIDEO_BCM2835_UNICAM) += bcm2835-unicam.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/platform/bcm2835/vc4-regs-unicam.h linux-5.10.52-v7l+/drivers/media/platform/bcm2835/vc4-regs-unicam.h
--- linux-5.10.52-orig/drivers/media/platform/bcm2835/vc4-regs-unicam.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/media/platform/bcm2835/vc4-regs-unicam.h	2021-07-25 16:46:06.388283806 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * Copyright (C) 2017-2020 Raspberry Pi Trading.
+ * Dave Stevenson <dave.stevenson@raspberrypi.com>
+ */
+
+#ifndef VC4_REGS_UNICAM_H
+#define VC4_REGS_UNICAM_H
+
+/*
+ * The following values are taken from files found within the code drop
+ * made by Broadcom for the BCM21553 Graphics Driver, predominantly in
+ * brcm_usrlib/dag/vmcsx/vcinclude/hardware_vc4.h.
+ * They have been modified to be only the register offset.
+ */
+#define UNICAM_CTRL	0x000
+#define UNICAM_STA	0x004
+#define UNICAM_ANA	0x008
+#define UNICAM_PRI	0x00c
+#define UNICAM_CLK	0x010
+#define UNICAM_CLT	0x014
+#define UNICAM_DAT0	0x018
+#define UNICAM_DAT1	0x01c
+#define UNICAM_DAT2	0x020
+#define UNICAM_DAT3	0x024
+#define UNICAM_DLT	0x028
+#define UNICAM_CMP0	0x02c
+#define UNICAM_CMP1	0x030
+#define UNICAM_CAP0	0x034
+#define UNICAM_CAP1	0x038
+#define UNICAM_ICTL	0x100
+#define UNICAM_ISTA	0x104
+#define UNICAM_IDI0	0x108
+#define UNICAM_IPIPE	0x10c
+#define UNICAM_IBSA0	0x110
+#define UNICAM_IBEA0	0x114
+#define UNICAM_IBLS	0x118
+#define UNICAM_IBWP	0x11c
+#define UNICAM_IHWIN	0x120
+#define UNICAM_IHSTA	0x124
+#define UNICAM_IVWIN	0x128
+#define UNICAM_IVSTA	0x12c
+#define UNICAM_ICC	0x130
+#define UNICAM_ICS	0x134
+#define UNICAM_IDC	0x138
+#define UNICAM_IDPO	0x13c
+#define UNICAM_IDCA	0x140
+#define UNICAM_IDCD	0x144
+#define UNICAM_IDS	0x148
+#define UNICAM_DCS	0x200
+#define UNICAM_DBSA0	0x204
+#define UNICAM_DBEA0	0x208
+#define UNICAM_DBWP	0x20c
+#define UNICAM_DBCTL	0x300
+#define UNICAM_IBSA1	0x304
+#define UNICAM_IBEA1	0x308
+#define UNICAM_IDI1	0x30c
+#define UNICAM_DBSA1	0x310
+#define UNICAM_DBEA1	0x314
+#define UNICAM_MISC	0x400
+
+/*
+ * The following bitmasks are from the kernel released by Broadcom
+ * for Android - https://android.googlesource.com/kernel/bcm/
+ * The Rhea, Hawaii, and Java chips all contain the same VideoCore4
+ * Unicam block as BCM2835, as defined in eg
+ * arch/arm/mach-rhea/include/mach/rdb_A0/brcm_rdb_cam.h and similar.
+ * Values reworked to use the kernel BIT and GENMASK macros.
+ *
+ * Some of the bit mnenomics have been amended to match the datasheet.
+ */
+/* UNICAM_CTRL Register */
+#define UNICAM_CPE		BIT(0)
+#define UNICAM_MEM		BIT(1)
+#define UNICAM_CPR		BIT(2)
+#define UNICAM_CPM_MASK		GENMASK(3, 3)
+#define UNICAM_CPM_CSI2		0
+#define UNICAM_CPM_CCP2		1
+#define UNICAM_SOE		BIT(4)
+#define UNICAM_DCM_MASK		GENMASK(5, 5)
+#define UNICAM_DCM_STROBE	0
+#define UNICAM_DCM_DATA		1
+#define UNICAM_SLS		BIT(6)
+#define UNICAM_PFT_MASK		GENMASK(11, 8)
+#define UNICAM_OET_MASK		GENMASK(20, 12)
+
+/* UNICAM_STA Register */
+#define UNICAM_SYN		BIT(0)
+#define UNICAM_CS		BIT(1)
+#define UNICAM_SBE		BIT(2)
+#define UNICAM_PBE		BIT(3)
+#define UNICAM_HOE		BIT(4)
+#define UNICAM_PLE		BIT(5)
+#define UNICAM_SSC		BIT(6)
+#define UNICAM_CRCE		BIT(7)
+#define UNICAM_OES		BIT(8)
+#define UNICAM_IFO		BIT(9)
+#define UNICAM_OFO		BIT(10)
+#define UNICAM_BFO		BIT(11)
+#define UNICAM_DL		BIT(12)
+#define UNICAM_PS		BIT(13)
+#define UNICAM_IS		BIT(14)
+#define UNICAM_PI0		BIT(15)
+#define UNICAM_PI1		BIT(16)
+#define UNICAM_FSI_S		BIT(17)
+#define UNICAM_FEI_S		BIT(18)
+#define UNICAM_LCI_S		BIT(19)
+#define UNICAM_BUF0_RDY		BIT(20)
+#define UNICAM_BUF0_NO		BIT(21)
+#define UNICAM_BUF1_RDY		BIT(22)
+#define UNICAM_BUF1_NO		BIT(23)
+#define UNICAM_DI		BIT(24)
+
+#define UNICAM_STA_MASK_ALL \
+		(UNICAM_DL + \
+		UNICAM_SBE + \
+		UNICAM_PBE + \
+		UNICAM_HOE + \
+		UNICAM_PLE + \
+		UNICAM_SSC + \
+		UNICAM_CRCE + \
+		UNICAM_IFO + \
+		UNICAM_OFO + \
+		UNICAM_PS + \
+		UNICAM_PI0 + \
+		UNICAM_PI1)
+
+/* UNICAM_ANA Register */
+#define UNICAM_APD		BIT(0)
+#define UNICAM_BPD		BIT(1)
+#define UNICAM_AR		BIT(2)
+#define UNICAM_DDL		BIT(3)
+#define UNICAM_CTATADJ_MASK	GENMASK(7, 4)
+#define UNICAM_PTATADJ_MASK	GENMASK(11, 8)
+
+/* UNICAM_PRI Register */
+#define UNICAM_PE		BIT(0)
+#define UNICAM_PT_MASK		GENMASK(2, 1)
+#define UNICAM_NP_MASK		GENMASK(7, 4)
+#define UNICAM_PP_MASK		GENMASK(11, 8)
+#define UNICAM_BS_MASK		GENMASK(15, 12)
+#define UNICAM_BL_MASK		GENMASK(17, 16)
+
+/* UNICAM_CLK Register */
+#define UNICAM_CLE		BIT(0)
+#define UNICAM_CLPD		BIT(1)
+#define UNICAM_CLLPE		BIT(2)
+#define UNICAM_CLHSE		BIT(3)
+#define UNICAM_CLTRE		BIT(4)
+#define UNICAM_CLAC_MASK	GENMASK(8, 5)
+#define UNICAM_CLSTE		BIT(29)
+
+/* UNICAM_CLT Register */
+#define UNICAM_CLT1_MASK	GENMASK(7, 0)
+#define UNICAM_CLT2_MASK	GENMASK(15, 8)
+
+/* UNICAM_DATn Registers */
+#define UNICAM_DLE		BIT(0)
+#define UNICAM_DLPD		BIT(1)
+#define UNICAM_DLLPE		BIT(2)
+#define UNICAM_DLHSE		BIT(3)
+#define UNICAM_DLTRE		BIT(4)
+#define UNICAM_DLSM		BIT(5)
+#define UNICAM_DLFO		BIT(28)
+#define UNICAM_DLSTE		BIT(29)
+
+#define UNICAM_DAT_MASK_ALL (UNICAM_DLSTE + UNICAM_DLFO)
+
+/* UNICAM_DLT Register */
+#define UNICAM_DLT1_MASK	GENMASK(7, 0)
+#define UNICAM_DLT2_MASK	GENMASK(15, 8)
+#define UNICAM_DLT3_MASK	GENMASK(23, 16)
+
+/* UNICAM_ICTL Register */
+#define UNICAM_FSIE		BIT(0)
+#define UNICAM_FEIE		BIT(1)
+#define UNICAM_IBOB		BIT(2)
+#define UNICAM_FCM		BIT(3)
+#define UNICAM_TFC		BIT(4)
+#define UNICAM_LIP_MASK		GENMASK(6, 5)
+#define UNICAM_LCIE_MASK	GENMASK(28, 16)
+
+/* UNICAM_IDI0/1 Register */
+#define UNICAM_ID0_MASK		GENMASK(7, 0)
+#define UNICAM_ID1_MASK		GENMASK(15, 8)
+#define UNICAM_ID2_MASK		GENMASK(23, 16)
+#define UNICAM_ID3_MASK		GENMASK(31, 24)
+
+/* UNICAM_ISTA Register */
+#define UNICAM_FSI		BIT(0)
+#define UNICAM_FEI		BIT(1)
+#define UNICAM_LCI		BIT(2)
+
+#define UNICAM_ISTA_MASK_ALL (UNICAM_FSI + UNICAM_FEI + UNICAM_LCI)
+
+/* UNICAM_IPIPE Register */
+#define UNICAM_PUM_MASK		GENMASK(2, 0)
+		/* Unpacking modes */
+		#define UNICAM_PUM_NONE		0
+		#define UNICAM_PUM_UNPACK6	1
+		#define UNICAM_PUM_UNPACK7	2
+		#define UNICAM_PUM_UNPACK8	3
+		#define UNICAM_PUM_UNPACK10	4
+		#define UNICAM_PUM_UNPACK12	5
+		#define UNICAM_PUM_UNPACK14	6
+		#define UNICAM_PUM_UNPACK16	7
+#define UNICAM_DDM_MASK		GENMASK(6, 3)
+#define UNICAM_PPM_MASK		GENMASK(9, 7)
+		/* Packing modes */
+		#define UNICAM_PPM_NONE		0
+		#define UNICAM_PPM_PACK8	1
+		#define UNICAM_PPM_PACK10	2
+		#define UNICAM_PPM_PACK12	3
+		#define UNICAM_PPM_PACK14	4
+		#define UNICAM_PPM_PACK16	5
+#define UNICAM_DEM_MASK		GENMASK(11, 10)
+#define UNICAM_DEBL_MASK	GENMASK(14, 12)
+#define UNICAM_ICM_MASK		GENMASK(16, 15)
+#define UNICAM_IDM_MASK		GENMASK(17, 17)
+
+/* UNICAM_ICC Register */
+#define UNICAM_ICFL_MASK	GENMASK(4, 0)
+#define UNICAM_ICFH_MASK	GENMASK(9, 5)
+#define UNICAM_ICST_MASK	GENMASK(12, 10)
+#define UNICAM_ICLT_MASK	GENMASK(15, 13)
+#define UNICAM_ICLL_MASK	GENMASK(31, 16)
+
+/* UNICAM_DCS Register */
+#define UNICAM_DIE		BIT(0)
+#define UNICAM_DIM		BIT(1)
+#define UNICAM_DBOB		BIT(3)
+#define UNICAM_FDE		BIT(4)
+#define UNICAM_LDP		BIT(5)
+#define UNICAM_EDL_MASK		GENMASK(15, 8)
+
+/* UNICAM_DBCTL Register */
+#define UNICAM_DBEN		BIT(0)
+#define UNICAM_BUF0_IE		BIT(1)
+#define UNICAM_BUF1_IE		BIT(2)
+
+/* UNICAM_CMP[0,1] register */
+#define UNICAM_PCE		BIT(31)
+#define UNICAM_GI		BIT(9)
+#define UNICAM_CPH		BIT(8)
+#define UNICAM_PCVC_MASK	GENMASK(7, 6)
+#define UNICAM_PCDT_MASK	GENMASK(5, 0)
+
+/* UNICAM_MISC register */
+#define UNICAM_FL0		BIT(6)
+#define UNICAM_FL1		BIT(9)
+
+#endif
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/platform/Kconfig linux-5.10.52-v7l+/drivers/media/platform/Kconfig
--- linux-5.10.52-orig/drivers/media/platform/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/platform/Kconfig	2021-07-25 16:46:06.368284141 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:155 @
 source "drivers/media/platform/xilinx/Kconfig"
 source "drivers/media/platform/rcar-vin/Kconfig"
 source "drivers/media/platform/atmel/Kconfig"
+source "drivers/media/platform/bcm2835/Kconfig"
 source "drivers/media/platform/sunxi/Kconfig"
 
 config VIDEO_TI_CAL
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/platform/Makefile linux-5.10.52-v7l+/drivers/media/platform/Makefile
--- linux-5.10.52-orig/drivers/media/platform/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/platform/Makefile	2021-07-25 16:46:06.368284141 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:82 @
 
 obj-$(CONFIG_VIDEO_QCOM_VENUS)		+= qcom/venus/
 
+obj-y					+= bcm2835/
+
 obj-y					+= sunxi/
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/spi/Kconfig linux-5.10.52-v7l+/drivers/media/spi/Kconfig
--- linux-5.10.52-orig/drivers/media/spi/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/spi/Kconfig	2021-07-25 16:46:07.098271903 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:28 @
 config CXD2880_SPI_DRV
 	tristate "Sony CXD2880 SPI support"
 	depends on DVB_CORE && SPI
+	select DVB_CXD2880 if MEDIA_SUBDRV_AUTOSELECT
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
 	  Choose if you would like to have SPI interface support for Sony CXD2880.
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/usb/dvb-usb-v2/rtl28xxu.c linux-5.10.52-v7l+/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
--- linux-5.10.52-orig/drivers/media/usb/dvb-usb-v2/rtl28xxu.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/usb/dvb-usb-v2/rtl28xxu.c	2021-07-25 16:46:07.678262179 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1947 @
 		&rtl28xxu_props, "Compro VideoMate U650F", NULL) },
 	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
 		&rtl28xxu_props, "MaxMedia HU394-T", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_GTEK, 0xb803 /*USB_PID_AUGUST_DVBT205*/,
+		&rtl28xxu_props, "August DVB-T 205", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_GTEK, 0xa803 /*USB_PID_AUGUST_DVBT205*/,
+		&rtl28xxu_props, "August DVB-T 205", NULL) },
 	{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
 		&rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) },
 	{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/v4l2-core/v4l2-ctrls.c linux-5.10.52-v7l+/drivers/media/v4l2-core/v4l2-ctrls.c
--- linux-5.10.52-orig/drivers/media/v4l2-core/v4l2-ctrls.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/v4l2-core/v4l2-ctrls.c	2021-07-25 16:46:08.048255976 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:278 @
 		"Flash",
 		"Cloudy",
 		"Shade",
+		"Greyworld",
 		NULL,
 	};
 	static const char * const camera_iso_sensitivity_auto[] = {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1025 @
 	case V4L2_CID_MPEG_VIDEO_HEVC_SPS:			return "HEVC Sequence Parameter Set";
 	case V4L2_CID_MPEG_VIDEO_HEVC_PPS:			return "HEVC Picture Parameter Set";
 	case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:		return "HEVC Slice Parameters";
+	case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX:		return "HEVC Scaling Matrix";
 	case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:		return "HEVC Decode Mode";
 	case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:		return "HEVC Start Code";
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1466 @
 	case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:
 		*type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS;
 		break;
+	case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX:
+		*type = V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX;
+		break;
 	case V4L2_CID_UNIT_CELL_SIZE:
 		*type = V4L2_CTRL_TYPE_AREA;
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1942 @
 		zero_padding(*p_hevc_slice_params);
 		break;
 
+	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
+		break;
+
 	case V4L2_CTRL_TYPE_AREA:
 		area = p;
 		if (!area->width || !area->height)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2655 @
 	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
 		elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
 		break;
+	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
+		elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix);
+		break;
 	case V4L2_CTRL_TYPE_AREA:
 		elem_size = sizeof(struct v4l2_area);
 		break;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/v4l2-core/v4l2-ioctl.c linux-5.10.52-v7l+/drivers/media/v4l2-core/v4l2-ioctl.c
--- linux-5.10.52-orig/drivers/media/v4l2-core/v4l2-ioctl.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/v4l2-core/v4l2-ioctl.c	2021-07-25 16:46:08.108254970 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1286 @
 	case V4L2_PIX_FMT_Y16_BE:	descr = "16-bit Greyscale BE"; break;
 	case V4L2_PIX_FMT_Y10BPACK:	descr = "10-bit Greyscale (Packed)"; break;
 	case V4L2_PIX_FMT_Y10P:		descr = "10-bit Greyscale (MIPI Packed)"; break;
+	case V4L2_PIX_FMT_Y12P:		descr = "12-bit Greyscale (MIPI Packed)"; break;
+	case V4L2_PIX_FMT_Y14P:		descr = "14-bit Greyscale (MIPI Packed)"; break;
 	case V4L2_PIX_FMT_Y8I:		descr = "Interleaved 8-bit Greyscale"; break;
 	case V4L2_PIX_FMT_Y12I:		descr = "Interleaved 12-bit Greyscale"; break;
 	case V4L2_PIX_FMT_Z16:		descr = "16-bit Depth"; break;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1330 @
 	case V4L2_PIX_FMT_NV61M:	descr = "Y/CrCb 4:2:2 (N-C)"; break;
 	case V4L2_PIX_FMT_NV12MT:	descr = "Y/CbCr 4:2:0 (64x32 MB, N-C)"; break;
 	case V4L2_PIX_FMT_NV12MT_16X16:	descr = "Y/CbCr 4:2:0 (16x16 MB, N-C)"; break;
+	case V4L2_PIX_FMT_NV12_COL128:	descr = "Y/CbCr 4:2:0 (128b cols)"; break;
+	case V4L2_PIX_FMT_NV12_10_COL128: descr = "10-bit Y/CbCr 4:2:0 (128b cols)"; break;
 	case V4L2_PIX_FMT_YUV420M:	descr = "Planar YUV 4:2:0 (N-C)"; break;
 	case V4L2_PIX_FMT_YVU420M:	descr = "Planar YVU 4:2:0 (N-C)"; break;
 	case V4L2_PIX_FMT_YUV422M:	descr = "Planar YUV 4:2:2 (N-C)"; break;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1409 @
 	case V4L2_META_FMT_UVC:		descr = "UVC Payload Header Metadata"; break;
 	case V4L2_META_FMT_D4XX:	descr = "Intel D4xx UVC Metadata"; break;
 	case V4L2_META_FMT_VIVID:       descr = "Vivid Metadata"; 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;
 
 	default:
 		/* Compressed formats */
diff -Nur --no-dereference linux-5.10.52-orig/drivers/media/v4l2-core/v4l2-mem2mem.c linux-5.10.52-v7l+/drivers/media/v4l2-core/v4l2-mem2mem.c
--- linux-5.10.52-orig/drivers/media/v4l2-core/v4l2-mem2mem.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/media/v4l2-core/v4l2-mem2mem.c	2021-07-25 16:46:08.108254970 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:304 @
 
 	dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx);
 
-	if (!m2m_ctx->out_q_ctx.q.streaming
-	    || !m2m_ctx->cap_q_ctx.q.streaming) {
-		dprintk("Streaming needs to be on for both queues\n");
+	if (!(m2m_ctx->out_q_ctx.q.streaming &&
+	      m2m_ctx->cap_q_ctx.q.streaming) &&
+	    !(m2m_ctx->out_q_ctx.buffered && m2m_ctx->out_q_ctx.q.streaming)) {
+		dprintk("Streaming needs to be on for both queues, or buffered and OUTPUT streaming\n");
 		return;
 	}
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:495 @
 	 * holding capture buffers. Those should use
 	 * v4l2_m2m_buf_done_and_job_finish() instead.
 	 */
-	WARN_ON(m2m_ctx->out_q_ctx.q.subsystem_flags &
-		VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF);
 	spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
 	schedule_next = _v4l2_m2m_job_finish(m2m_dev, m2m_ctx);
 	spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mfd/bcm2835-pm.c linux-5.10.52-v7l+/drivers/mfd/bcm2835-pm.c
--- linux-5.10.52-orig/drivers/mfd/bcm2835-pm.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mfd/bcm2835-pm.c	2021-07-25 16:46:08.398250108 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:53 @
 	if (ret)
 		return ret;
 
+	/* Map the RPiVid ASB regs if present. */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (res) {
+		pm->rpivid_asb = devm_ioremap_resource(dev, res);
+		if (IS_ERR(pm->rpivid_asb)) {
+			dev_err(dev, "Failed to map RPiVid ASB: %ld\n",
+				PTR_ERR(pm->rpivid_asb));
+			return PTR_ERR(pm->rpivid_asb);
+		}
+	}
+
 	/* We'll use the presence of the AXI ASB regs in the
 	 * bcm2835-pm binding as the key for whether we can reference
 	 * the full PM register range and support power domains.
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mfd/Kconfig linux-5.10.52-v7l+/drivers/mfd/Kconfig
--- linux-5.10.52-orig/drivers/mfd/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mfd/Kconfig	2021-07-25 16:46:08.368250611 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:14 @
 	select IRQ_DOMAIN
 	default n
 
+config MFD_RPISENSE_CORE
+	tristate "Raspberry Pi Sense HAT core functions"
+	depends on I2C
+	select MFD_CORE
+	help
+	  This is the core driver for the Raspberry Pi Sense HAT. This provides
+	  the necessary functions to communicate with the hardware.
+
 config MFD_CS5535
 	tristate "AMD CS5535 and CS5536 southbridge core functions"
 	select MFD_CORE
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mfd/Makefile linux-5.10.52-v7l+/drivers/mfd/Makefile
--- linux-5.10.52-orig/drivers/mfd/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mfd/Makefile	2021-07-25 16:46:08.368250611 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:266 @
 obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o
 obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
 obj-$(CONFIG_MFD_KHADAS_MCU) 	+= khadas-mcu.o
+obj-$(CONFIG_MFD_RPISENSE_CORE)	+= rpisense-core.o
 
 obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
 obj-$(CONFIG_MFD_SIMPLE_MFD_I2C)	+= simple-mfd-i2c.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mfd/rpisense-core.c linux-5.10.52-v7l+/drivers/mfd/rpisense-core.c
--- linux-5.10.52-orig/drivers/mfd/rpisense-core.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/mfd/rpisense-core.c	2021-07-25 16:46:08.548247593 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Raspberry Pi Sense HAT core driver
+ * http://raspberrypi.org
+ *
+ * Copyright (C) 2015 Raspberry Pi
+ *
+ * Author: Serge Schneider
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  This driver is based on wm8350 implementation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/rpisense/core.h>
+#include <linux/slab.h>
+
+static struct rpisense *rpisense;
+
+static void rpisense_client_dev_register(struct rpisense *rpisense,
+					 const char *name,
+					 struct platform_device **pdev)
+{
+	int ret;
+
+	*pdev = platform_device_alloc(name, -1);
+	if (*pdev == NULL) {
+		dev_err(rpisense->dev, "Failed to allocate %s\n", name);
+		return;
+	}
+
+	(*pdev)->dev.parent = rpisense->dev;
+	platform_set_drvdata(*pdev, rpisense);
+	ret = platform_device_add(*pdev);
+	if (ret != 0) {
+		dev_err(rpisense->dev, "Failed to register %s: %d\n",
+			name, ret);
+		platform_device_put(*pdev);
+		*pdev = NULL;
+	}
+}
+
+static int rpisense_probe(struct i2c_client *i2c,
+			       const struct i2c_device_id *id)
+{
+	int ret;
+	struct rpisense_js *rpisense_js;
+
+	rpisense = devm_kzalloc(&i2c->dev, sizeof(struct rpisense), GFP_KERNEL);
+	if (rpisense == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rpisense);
+	rpisense->dev = &i2c->dev;
+	rpisense->i2c_client = i2c;
+
+	ret = rpisense_reg_read(rpisense, RPISENSE_WAI);
+	if (ret > 0) {
+		if (ret != 's')
+			return -EINVAL;
+	} else {
+		return ret;
+	}
+	ret = rpisense_reg_read(rpisense, RPISENSE_VER);
+	if (ret < 0)
+		return ret;
+
+	dev_info(rpisense->dev,
+		 "Raspberry Pi Sense HAT firmware version %i\n", ret);
+
+	rpisense_js = &rpisense->joystick;
+	rpisense_js->keys_desc = devm_gpiod_get(&i2c->dev,
+						"keys-int", GPIOD_IN);
+	if (IS_ERR(rpisense_js->keys_desc)) {
+		dev_warn(&i2c->dev, "Failed to get keys-int descriptor.\n");
+		rpisense_js->keys_desc = gpio_to_desc(23);
+		if (rpisense_js->keys_desc == NULL) {
+			dev_err(&i2c->dev, "GPIO23 fallback failed.\n");
+			return PTR_ERR(rpisense_js->keys_desc);
+		}
+	}
+	rpisense_client_dev_register(rpisense, "rpi-sense-js",
+				     &(rpisense->joystick.pdev));
+	rpisense_client_dev_register(rpisense, "rpi-sense-fb",
+				     &(rpisense->framebuffer.pdev));
+
+	return 0;
+}
+
+static int rpisense_remove(struct i2c_client *i2c)
+{
+	struct rpisense *rpisense = i2c_get_clientdata(i2c);
+
+	platform_device_unregister(rpisense->joystick.pdev);
+	return 0;
+}
+
+struct rpisense *rpisense_get_dev(void)
+{
+	return rpisense;
+}
+EXPORT_SYMBOL_GPL(rpisense_get_dev);
+
+s32 rpisense_reg_read(struct rpisense *rpisense, int reg)
+{
+	int ret = i2c_smbus_read_byte_data(rpisense->i2c_client, reg);
+
+	if (ret < 0)
+		dev_err(rpisense->dev, "Read from reg %d failed\n", reg);
+	/* Due to the BCM270x I2C clock stretching bug, some values
+	 * may have MSB set. Clear it to avoid incorrect values.
+	 * */
+	return ret & 0x7F;
+}
+EXPORT_SYMBOL_GPL(rpisense_reg_read);
+
+int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count)
+{
+	int ret = i2c_master_send(rpisense->i2c_client, buf, count);
+
+	if (ret < 0)
+		dev_err(rpisense->dev, "Block write failed\n");
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rpisense_block_write);
+
+static const struct i2c_device_id rpisense_i2c_id[] = {
+	{ "rpi-sense", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id rpisense_core_id[] = {
+	{ .compatible = "rpi,rpi-sense" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, rpisense_core_id);
+#endif
+
+
+static struct i2c_driver rpisense_driver = {
+	.driver = {
+		   .name = "rpi-sense",
+		   .owner = THIS_MODULE,
+	},
+	.probe = rpisense_probe,
+	.remove = rpisense_remove,
+	.id_table = rpisense_i2c_id,
+};
+
+module_i2c_driver(rpisense_driver);
+
+MODULE_DESCRIPTION("Raspberry Pi Sense HAT core driver");
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
+MODULE_LICENSE("GPL");
+
diff -Nur --no-dereference linux-5.10.52-orig/drivers/misc/bcm2835_smi.c linux-5.10.52-v7l+/drivers/misc/bcm2835_smi.c
--- linux-5.10.52-orig/drivers/misc/bcm2835_smi.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/misc/bcm2835_smi.c	2021-07-25 16:46:08.688245246 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/**
+ * Broadcom Secondary Memory Interface driver
+ *
+ * Written by Luke Wren <luke@raspberrypi.org>
+ * 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 <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+#define BCM2835_SMI_IMPLEMENTATION
+#include <linux/broadcom/bcm2835_smi.h>
+
+#define DRIVER_NAME "smi-bcm2835"
+
+#define N_PAGES_FROM_BYTES(n) ((n + PAGE_SIZE-1) / PAGE_SIZE)
+
+#define DMA_WRITE_TO_MEM true
+#define DMA_READ_FROM_MEM false
+
+struct bcm2835_smi_instance {
+	struct device *dev;
+	struct smi_settings settings;
+	__iomem void *smi_regs_ptr;
+	dma_addr_t smi_regs_busaddr;
+
+	struct dma_chan *dma_chan;
+	struct dma_slave_config dma_config;
+
+	struct bcm2835_smi_bounce_info bounce;
+
+	struct scatterlist buffer_sgl;
+
+	struct clk *clk;
+
+	/* Sometimes we are called into in an atomic context (e.g. by
+	   JFFS2 + MTD) so we can't use a mutex */
+	spinlock_t transaction_lock;
+};
+
+/****************************************************************************
+*
+*   SMI peripheral setup
+*
+***************************************************************************/
+
+static inline void write_smi_reg(struct bcm2835_smi_instance *inst,
+	u32 val, unsigned reg)
+{
+	writel(val, inst->smi_regs_ptr + reg);
+}
+
+static inline u32 read_smi_reg(struct bcm2835_smi_instance *inst, unsigned reg)
+{
+	return readl(inst->smi_regs_ptr + reg);
+}
+
+/* Token-paste macro for e.g SMIDSR_RSTROBE ->  value of SMIDSR_RSTROBE_MASK */
+#define _CONCAT(x, y) x##y
+#define CONCAT(x, y) _CONCAT(x, y)
+
+#define SET_BIT_FIELD(dest, field, bits) ((dest) = \
+	((dest) & ~CONCAT(field, _MASK)) | (((bits) << CONCAT(field, _OFFS))& \
+	 CONCAT(field, _MASK)))
+#define GET_BIT_FIELD(src, field) (((src) & \
+	CONCAT(field, _MASK)) >> CONCAT(field, _OFFS))
+
+static void smi_dump_context_labelled(struct bcm2835_smi_instance *inst,
+	const char *label)
+{
+	dev_err(inst->dev, "SMI context dump: %s", label);
+	dev_err(inst->dev, "SMICS:  0x%08x", read_smi_reg(inst, SMICS));
+	dev_err(inst->dev, "SMIL:   0x%08x", read_smi_reg(inst, SMIL));
+	dev_err(inst->dev, "SMIDSR: 0x%08x", read_smi_reg(inst, SMIDSR0));
+	dev_err(inst->dev, "SMIDSW: 0x%08x", read_smi_reg(inst, SMIDSW0));
+	dev_err(inst->dev, "SMIDC:  0x%08x", read_smi_reg(inst, SMIDC));
+	dev_err(inst->dev, "SMIFD:  0x%08x", read_smi_reg(inst, SMIFD));
+	dev_err(inst->dev, " ");
+}
+
+static inline void smi_dump_context(struct bcm2835_smi_instance *inst)
+{
+	smi_dump_context_labelled(inst, "");
+}
+
+static void smi_get_default_settings(struct bcm2835_smi_instance *inst)
+{
+	struct smi_settings *settings = &inst->settings;
+
+	settings->data_width = SMI_WIDTH_16BIT;
+	settings->pack_data = true;
+
+	settings->read_setup_time = 1;
+	settings->read_hold_time = 1;
+	settings->read_pace_time = 1;
+	settings->read_strobe_time = 3;
+
+	settings->write_setup_time = settings->read_setup_time;
+	settings->write_hold_time = settings->read_hold_time;
+	settings->write_pace_time = settings->read_pace_time;
+	settings->write_strobe_time = settings->read_strobe_time;
+
+	settings->dma_enable = true;
+	settings->dma_passthrough_enable = false;
+	settings->dma_read_thresh = 0x01;
+	settings->dma_write_thresh = 0x3f;
+	settings->dma_panic_read_thresh = 0x20;
+	settings->dma_panic_write_thresh = 0x20;
+}
+
+void bcm2835_smi_set_regs_from_settings(struct bcm2835_smi_instance *inst)
+{
+	struct smi_settings *settings = &inst->settings;
+	int smidsr_temp = 0, smidsw_temp = 0, smics_temp,
+	    smidcs_temp, smidc_temp = 0;
+
+	spin_lock(&inst->transaction_lock);
+
+	/* temporarily disable the peripheral: */
+	smics_temp = read_smi_reg(inst, SMICS);
+	write_smi_reg(inst, 0, SMICS);
+	smidcs_temp = read_smi_reg(inst, SMIDCS);
+	write_smi_reg(inst, 0, SMIDCS);
+
+	if (settings->pack_data)
+		smics_temp |= SMICS_PXLDAT;
+	else
+		smics_temp &= ~SMICS_PXLDAT;
+
+	SET_BIT_FIELD(smidsr_temp, SMIDSR_RWIDTH, settings->data_width);
+	SET_BIT_FIELD(smidsr_temp, SMIDSR_RSETUP, settings->read_setup_time);
+	SET_BIT_FIELD(smidsr_temp, SMIDSR_RHOLD, settings->read_hold_time);
+	SET_BIT_FIELD(smidsr_temp, SMIDSR_RPACE, settings->read_pace_time);
+	SET_BIT_FIELD(smidsr_temp, SMIDSR_RSTROBE, settings->read_strobe_time);
+	write_smi_reg(inst, smidsr_temp, SMIDSR0);
+
+	SET_BIT_FIELD(smidsw_temp, SMIDSW_WWIDTH, settings->data_width);
+	if (settings->data_width == SMI_WIDTH_8BIT)
+		smidsw_temp |= SMIDSW_WSWAP;
+	else
+		smidsw_temp &= ~SMIDSW_WSWAP;
+	SET_BIT_FIELD(smidsw_temp, SMIDSW_WSETUP, settings->write_setup_time);
+	SET_BIT_FIELD(smidsw_temp, SMIDSW_WHOLD, settings->write_hold_time);
+	SET_BIT_FIELD(smidsw_temp, SMIDSW_WPACE, settings->write_pace_time);
+	SET_BIT_FIELD(smidsw_temp, SMIDSW_WSTROBE,
+			settings->write_strobe_time);
+	write_smi_reg(inst, smidsw_temp, SMIDSW0);
+
+	SET_BIT_FIELD(smidc_temp, SMIDC_REQR, settings->dma_read_thresh);
+	SET_BIT_FIELD(smidc_temp, SMIDC_REQW, settings->dma_write_thresh);
+	SET_BIT_FIELD(smidc_temp, SMIDC_PANICR,
+		      settings->dma_panic_read_thresh);
+	SET_BIT_FIELD(smidc_temp, SMIDC_PANICW,
+		      settings->dma_panic_write_thresh);
+	if (settings->dma_passthrough_enable) {
+		smidc_temp |= SMIDC_DMAP;
+		smidsr_temp |= SMIDSR_RDREQ;
+		write_smi_reg(inst, smidsr_temp, SMIDSR0);
+		smidsw_temp |= SMIDSW_WDREQ;
+		write_smi_reg(inst, smidsw_temp, SMIDSW0);
+	} else
+		smidc_temp &= ~SMIDC_DMAP;
+	if (settings->dma_enable)
+		smidc_temp |= SMIDC_DMAEN;
+	else
+		smidc_temp &= ~SMIDC_DMAEN;
+
+	write_smi_reg(inst, smidc_temp, SMIDC);
+
+	/* re-enable (if was previously enabled) */
+	write_smi_reg(inst, smics_temp, SMICS);
+	write_smi_reg(inst, smidcs_temp, SMIDCS);
+
+	spin_unlock(&inst->transaction_lock);
+}
+EXPORT_SYMBOL(bcm2835_smi_set_regs_from_settings);
+
+struct smi_settings *bcm2835_smi_get_settings_from_regs
+	(struct bcm2835_smi_instance *inst)
+{
+	struct smi_settings *settings = &inst->settings;
+	int smidsr, smidsw, smidc;
+
+	spin_lock(&inst->transaction_lock);
+
+	smidsr = read_smi_reg(inst, SMIDSR0);
+	smidsw = read_smi_reg(inst, SMIDSW0);
+	smidc = read_smi_reg(inst, SMIDC);
+
+	settings->pack_data = (read_smi_reg(inst, SMICS) & SMICS_PXLDAT) ?
+	    true : false;
+
+	settings->data_width = GET_BIT_FIELD(smidsr, SMIDSR_RWIDTH);
+	settings->read_setup_time = GET_BIT_FIELD(smidsr, SMIDSR_RSETUP);
+	settings->read_hold_time = GET_BIT_FIELD(smidsr, SMIDSR_RHOLD);
+	settings->read_pace_time = GET_BIT_FIELD(smidsr, SMIDSR_RPACE);
+	settings->read_strobe_time = GET_BIT_FIELD(smidsr, SMIDSR_RSTROBE);
+
+	settings->write_setup_time = GET_BIT_FIELD(smidsw, SMIDSW_WSETUP);
+	settings->write_hold_time = GET_BIT_FIELD(smidsw, SMIDSW_WHOLD);
+	settings->write_pace_time = GET_BIT_FIELD(smidsw, SMIDSW_WPACE);
+	settings->write_strobe_time = GET_BIT_FIELD(smidsw, SMIDSW_WSTROBE);
+
+	settings->dma_read_thresh = GET_BIT_FIELD(smidc, SMIDC_REQR);
+	settings->dma_write_thresh = GET_BIT_FIELD(smidc, SMIDC_REQW);
+	settings->dma_panic_read_thresh = GET_BIT_FIELD(smidc, SMIDC_PANICR);
+	settings->dma_panic_write_thresh = GET_BIT_FIELD(smidc, SMIDC_PANICW);
+	settings->dma_passthrough_enable = (smidc & SMIDC_DMAP) ? true : false;
+	settings->dma_enable = (smidc & SMIDC_DMAEN) ? true : false;
+
+	spin_unlock(&inst->transaction_lock);
+
+	return settings;
+}
+EXPORT_SYMBOL(bcm2835_smi_get_settings_from_regs);
+
+static inline void smi_set_address(struct bcm2835_smi_instance *inst,
+	unsigned int address)
+{
+	int smia_temp = 0, smida_temp = 0;
+
+	SET_BIT_FIELD(smia_temp, SMIA_ADDR, address);
+	SET_BIT_FIELD(smida_temp, SMIDA_ADDR, address);
+
+	/* Write to both address registers - user doesn't care whether we're
+	   doing programmed or direct transfers. */
+	write_smi_reg(inst, smia_temp, SMIA);
+	write_smi_reg(inst, smida_temp, SMIDA);
+}
+
+static void smi_setup_regs(struct bcm2835_smi_instance *inst)
+{
+
+	dev_dbg(inst->dev, "Initialising SMI registers...");
+	/* Disable the peripheral if already enabled */
+	write_smi_reg(inst, 0, SMICS);
+	write_smi_reg(inst, 0, SMIDCS);
+
+	smi_get_default_settings(inst);
+	bcm2835_smi_set_regs_from_settings(inst);
+	smi_set_address(inst, 0);
+
+	write_smi_reg(inst, read_smi_reg(inst, SMICS) | SMICS_ENABLE, SMICS);
+	write_smi_reg(inst, read_smi_reg(inst, SMIDCS) | SMIDCS_ENABLE,
+		SMIDCS);
+}
+
+/****************************************************************************
+*
+*   Low-level SMI access functions
+*   Other modules should use the exported higher-level functions e.g.
+*   bcm2835_smi_write_buf() unless they have a good reason to use these
+*
+***************************************************************************/
+
+static inline uint32_t smi_read_single_word(struct bcm2835_smi_instance *inst)
+{
+	int timeout = 0;
+
+	write_smi_reg(inst, SMIDCS_ENABLE, SMIDCS);
+	write_smi_reg(inst, SMIDCS_ENABLE | SMIDCS_START, SMIDCS);
+	/* Make sure things happen in the right order...*/
+	mb();
+	while (!(read_smi_reg(inst, SMIDCS) & SMIDCS_DONE) &&
+		++timeout < 10000)
+		;
+	if (timeout < 10000)
+		return read_smi_reg(inst, SMIDD);
+
+	dev_err(inst->dev,
+		"SMI direct read timed out (is the clock set up correctly?)");
+	return 0;
+}
+
+static inline void smi_write_single_word(struct bcm2835_smi_instance *inst,
+	uint32_t data)
+{
+	int timeout = 0;
+
+	write_smi_reg(inst, SMIDCS_ENABLE | SMIDCS_WRITE, SMIDCS);
+	write_smi_reg(inst, data, SMIDD);
+	write_smi_reg(inst, SMIDCS_ENABLE | SMIDCS_WRITE | SMIDCS_START,
+		SMIDCS);
+
+	while (!(read_smi_reg(inst, SMIDCS) & SMIDCS_DONE) &&
+		++timeout < 10000)
+		;
+	if (timeout >= 10000)
+		dev_err(inst->dev,
+		"SMI direct write timed out (is the clock set up correctly?)");
+}
+
+/* Initiates a programmed read into the read FIFO. It is up to the caller to
+ * read data from the FIFO -  either via paced DMA transfer,
+ * or polling SMICS_RXD to check whether data is available.
+ * SMICS_ACTIVE will go low upon completion. */
+static void smi_init_programmed_read(struct bcm2835_smi_instance *inst,
+	int num_transfers)
+{
+	int smics_temp;
+
+	/* Disable the peripheral: */
+	smics_temp = read_smi_reg(inst, SMICS) & ~(SMICS_ENABLE | SMICS_WRITE);
+	write_smi_reg(inst, smics_temp, SMICS);
+	while (read_smi_reg(inst, SMICS) & SMICS_ENABLE)
+		;
+
+	/* Program the transfer count: */
+	write_smi_reg(inst, num_transfers, SMIL);
+
+	/* re-enable and start: */
+	smics_temp |= SMICS_ENABLE;
+	write_smi_reg(inst, smics_temp, SMICS);
+	smics_temp |= SMICS_CLEAR;
+	/* Just to be certain: */
+	mb();
+	while (read_smi_reg(inst, SMICS) & SMICS_ACTIVE)
+		;
+	write_smi_reg(inst, smics_temp, SMICS);
+	smics_temp |= SMICS_START;
+	write_smi_reg(inst, smics_temp, SMICS);
+}
+
+/* Initiates a programmed write sequence, using data from the write FIFO.
+ * It is up to the caller to initiate a DMA transfer before calling,
+ * or use another method to keep the write FIFO topped up.
+ * SMICS_ACTIVE will go low upon completion.
+ */
+static void smi_init_programmed_write(struct bcm2835_smi_instance *inst,
+	int num_transfers)
+{
+	int smics_temp;
+
+	/* Disable the peripheral: */
+	smics_temp = read_smi_reg(inst, SMICS) & ~SMICS_ENABLE;
+	write_smi_reg(inst, smics_temp, SMICS);
+	while (read_smi_reg(inst, SMICS) & SMICS_ENABLE)
+		;
+
+	/* Program the transfer count: */
+	write_smi_reg(inst, num_transfers, SMIL);
+
+	/* setup, re-enable and start: */
+	smics_temp |= SMICS_WRITE | SMICS_ENABLE;
+	write_smi_reg(inst, smics_temp, SMICS);
+	smics_temp |= SMICS_START;
+	write_smi_reg(inst, smics_temp, SMICS);
+}
+
+/* Initiate a read and then poll FIFO for data, reading out as it appears. */
+static void smi_read_fifo(struct bcm2835_smi_instance *inst,
+	uint32_t *dest, int n_bytes)
+{
+	if (read_smi_reg(inst, SMICS) & SMICS_RXD) {
+		smi_dump_context_labelled(inst,
+			"WARNING: read FIFO not empty at start of read call.");
+		while (read_smi_reg(inst, SMICS))
+			;
+	}
+
+	/* Dispatch the read: */
+	if (inst->settings.data_width == SMI_WIDTH_8BIT)
+		smi_init_programmed_read(inst, n_bytes);
+	else if (inst->settings.data_width == SMI_WIDTH_16BIT)
+		smi_init_programmed_read(inst, n_bytes / 2);
+	else {
+		dev_err(inst->dev, "Unsupported data width for read.");
+		return;
+	}
+
+	/* Poll FIFO to keep it empty */
+	while (!(read_smi_reg(inst, SMICS) & SMICS_DONE))
+		if (read_smi_reg(inst, SMICS) & SMICS_RXD)
+			*dest++ = read_smi_reg(inst, SMID);
+
+	/* Ensure that the FIFO is emptied */
+	if (read_smi_reg(inst, SMICS) & SMICS_RXD) {
+		int fifo_count;
+
+		fifo_count = GET_BIT_FIELD(read_smi_reg(inst, SMIFD),
+			SMIFD_FCNT);
+		while (fifo_count--)
+			*dest++ = read_smi_reg(inst, SMID);
+	}
+
+	if (!(read_smi_reg(inst, SMICS) & SMICS_DONE))
+		smi_dump_context_labelled(inst,
+			"WARNING: transaction finished but done bit not set.");
+
+	if (read_smi_reg(inst, SMICS) & SMICS_RXD)
+		smi_dump_context_labelled(inst,
+			"WARNING: read FIFO not empty at end of read call.");
+
+}
+
+/* Initiate a write, and then keep the FIFO topped up. */
+static void smi_write_fifo(struct bcm2835_smi_instance *inst,
+	uint32_t *src, int n_bytes)
+{
+	int i, timeout = 0;
+
+	/* Empty FIFOs if not already so */
+	if (!(read_smi_reg(inst, SMICS) & SMICS_TXE)) {
+		smi_dump_context_labelled(inst,
+		    "WARNING: write fifo not empty at start of write call.");
+		write_smi_reg(inst, read_smi_reg(inst, SMICS) | SMICS_CLEAR,
+			SMICS);
+	}
+
+	/* Initiate the transfer */
+	if (inst->settings.data_width == SMI_WIDTH_8BIT)
+		smi_init_programmed_write(inst, n_bytes);
+	else if (inst->settings.data_width == SMI_WIDTH_16BIT)
+		smi_init_programmed_write(inst, n_bytes / 2);
+	else {
+		dev_err(inst->dev, "Unsupported data width for write.");
+		return;
+	}
+	/* Fill the FIFO: */
+	for (i = 0; i < (n_bytes - 1) / 4 + 1; ++i) {
+		while (!(read_smi_reg(inst, SMICS) & SMICS_TXD))
+			;
+		write_smi_reg(inst, *src++, SMID);
+	}
+	/* Busy wait... */
+	while (!(read_smi_reg(inst, SMICS) & SMICS_DONE) && ++timeout <
+		1000000)
+		;
+	if (timeout >= 1000000)
+		smi_dump_context_labelled(inst,
+			"Timed out on write operation!");
+	if (!(read_smi_reg(inst, SMICS) & SMICS_TXE))
+		smi_dump_context_labelled(inst,
+			"WARNING: FIFO not empty at end of write operation.");
+}
+
+/****************************************************************************
+*
+*   SMI DMA operations
+*
+***************************************************************************/
+
+/* Disable SMI and put it into the correct direction before doing DMA setup.
+   Stops spurious DREQs during setup. Peripheral is re-enabled by init_*() */
+static void smi_disable(struct bcm2835_smi_instance *inst,
+	enum dma_transfer_direction direction)
+{
+	int smics_temp = read_smi_reg(inst, SMICS) & ~SMICS_ENABLE;
+
+	if (direction == DMA_DEV_TO_MEM)
+		smics_temp &= ~SMICS_WRITE;
+	else
+		smics_temp |= SMICS_WRITE;
+	write_smi_reg(inst, smics_temp, SMICS);
+	while (read_smi_reg(inst, SMICS) & SMICS_ACTIVE)
+		;
+}
+
+static struct scatterlist *smi_scatterlist_from_buffer(
+	struct bcm2835_smi_instance *inst,
+	dma_addr_t buf,
+	size_t len,
+	struct scatterlist *sg)
+{
+	sg_init_table(sg, 1);
+	sg_dma_address(sg) = buf;
+	sg_dma_len(sg) = len;
+	return sg;
+}
+
+static void smi_dma_callback_user_copy(void *param)
+{
+	/* Notify the bottom half that a chunk is ready for user copy */
+	struct bcm2835_smi_instance *inst =
+		(struct bcm2835_smi_instance *)param;
+
+	up(&inst->bounce.callback_sem);
+}
+
+/* Creates a descriptor, assigns the given callback, and submits the
+   descriptor to dmaengine. Does not block - can queue up multiple
+   descriptors and then wait for them all to complete.
+   sg_len is the number of control blocks, NOT the number of bytes.
+   dir can be DMA_MEM_TO_DEV or DMA_DEV_TO_MEM.
+   callback can be NULL - in this case it is not called. */
+static inline struct dma_async_tx_descriptor *smi_dma_submit_sgl(
+	struct bcm2835_smi_instance *inst,
+	struct scatterlist *sgl,
+	size_t sg_len,
+	enum dma_transfer_direction dir,
+	dma_async_tx_callback callback)
+{
+	struct dma_async_tx_descriptor *desc;
+
+	desc = dmaengine_prep_slave_sg(inst->dma_chan,
+				       sgl,
+				       sg_len,
+				       dir,
+				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK |
+				       DMA_PREP_FENCE);
+	if (!desc) {
+		dev_err(inst->dev, "read_sgl: dma slave preparation failed!");
+		write_smi_reg(inst, read_smi_reg(inst, SMICS) & ~SMICS_ACTIVE,
+			SMICS);
+		while (read_smi_reg(inst, SMICS) & SMICS_ACTIVE)
+			cpu_relax();
+		write_smi_reg(inst, read_smi_reg(inst, SMICS) | SMICS_ACTIVE,
+			SMICS);
+		return NULL;
+	}
+	desc->callback = callback;
+	desc->callback_param = inst;
+	if (dmaengine_submit(desc) < 0)
+		return NULL;
+	return desc;
+}
+
+/* NB this function blocks until the transfer is complete */
+static void
+smi_dma_read_sgl(struct bcm2835_smi_instance *inst,
+	struct scatterlist *sgl, size_t sg_len, size_t n_bytes)
+{
+	struct dma_async_tx_descriptor *desc;
+
+	/* Disable SMI and set to read before dispatching DMA - if SMI is in
+	 * write mode and TX fifo is empty, it will generate a DREQ which may
+	 * cause the read DMA to complete before the SMI read command is even
+	 * dispatched! We want to dispatch DMA before SMI read so that reading
+	 * is gapless, for logic analyser.
+	 */
+
+	smi_disable(inst, DMA_DEV_TO_MEM);
+
+	desc = smi_dma_submit_sgl(inst, sgl, sg_len, DMA_DEV_TO_MEM, NULL);
+	dma_async_issue_pending(inst->dma_chan);
+
+	if (inst->settings.data_width == SMI_WIDTH_8BIT)
+		smi_init_programmed_read(inst, n_bytes);
+	else
+		smi_init_programmed_read(inst, n_bytes / 2);
+
+	if (dma_wait_for_async_tx(desc) == DMA_ERROR)
+		smi_dump_context_labelled(inst, "DMA timeout!");
+}
+
+static void
+smi_dma_write_sgl(struct bcm2835_smi_instance *inst,
+	struct scatterlist *sgl, size_t sg_len, size_t n_bytes)
+{
+	struct dma_async_tx_descriptor *desc;
+
+	if (inst->settings.data_width == SMI_WIDTH_8BIT)
+		smi_init_programmed_write(inst, n_bytes);
+	else
+		smi_init_programmed_write(inst, n_bytes / 2);
+
+	desc = smi_dma_submit_sgl(inst, sgl, sg_len, DMA_MEM_TO_DEV, NULL);
+	dma_async_issue_pending(inst->dma_chan);
+
+	if (dma_wait_for_async_tx(desc) == DMA_ERROR)
+		smi_dump_context_labelled(inst, "DMA timeout!");
+	else
+		/* Wait for SMI to finish our writes */
+		while (!(read_smi_reg(inst, SMICS) & SMICS_DONE))
+			cpu_relax();
+}
+
+ssize_t bcm2835_smi_user_dma(
+	struct bcm2835_smi_instance *inst,
+	enum dma_transfer_direction dma_dir,
+	char __user *user_ptr, size_t count,
+	struct bcm2835_smi_bounce_info **bounce)
+{
+	int chunk_no = 0, chunk_size, count_left = count;
+	struct scatterlist *sgl;
+	void (*init_trans_func)(struct bcm2835_smi_instance *, int);
+
+	spin_lock(&inst->transaction_lock);
+
+	if (dma_dir == DMA_DEV_TO_MEM)
+		init_trans_func = smi_init_programmed_read;
+	else
+		init_trans_func = smi_init_programmed_write;
+
+	smi_disable(inst, dma_dir);
+
+	sema_init(&inst->bounce.callback_sem, 0);
+	if (bounce)
+		*bounce = &inst->bounce;
+	while (count_left) {
+		chunk_size = count_left > DMA_BOUNCE_BUFFER_SIZE ?
+			DMA_BOUNCE_BUFFER_SIZE : count_left;
+		if (chunk_size == DMA_BOUNCE_BUFFER_SIZE) {
+			sgl =
+			&inst->bounce.sgl[chunk_no % DMA_BOUNCE_BUFFER_COUNT];
+		} else {
+			sgl = smi_scatterlist_from_buffer(
+				inst,
+				inst->bounce.phys[
+					chunk_no % DMA_BOUNCE_BUFFER_COUNT],
+				chunk_size,
+				&inst->buffer_sgl);
+		}
+
+		if (!smi_dma_submit_sgl(inst, sgl, 1, dma_dir,
+			smi_dma_callback_user_copy
+		)) {
+			dev_err(inst->dev, "sgl submit failed");
+			count = 0;
+			goto out;
+		}
+		count_left -= chunk_size;
+		chunk_no++;
+	}
+	dma_async_issue_pending(inst->dma_chan);
+
+	if (inst->settings.data_width == SMI_WIDTH_8BIT)
+		init_trans_func(inst, count);
+	else if (inst->settings.data_width == SMI_WIDTH_16BIT)
+		init_trans_func(inst, count / 2);
+out:
+	spin_unlock(&inst->transaction_lock);
+	return count;
+}
+EXPORT_SYMBOL(bcm2835_smi_user_dma);
+
+
+/****************************************************************************
+*
+*   High level buffer transfer functions - for use by other drivers
+*
+***************************************************************************/
+
+/* Buffer must be physically contiguous - i.e. kmalloc, not vmalloc! */
+void bcm2835_smi_write_buf(
+	struct bcm2835_smi_instance *inst,
+	const void *buf, size_t n_bytes)
+{
+	int odd_bytes = n_bytes & 0x3;
+
+	n_bytes -= odd_bytes;
+
+	spin_lock(&inst->transaction_lock);
+
+	if (n_bytes > DMA_THRESHOLD_BYTES) {
+		dma_addr_t phy_addr = dma_map_single(
+			inst->dev,
+			(void *)buf,
+			n_bytes,
+			DMA_MEM_TO_DEV);
+		struct scatterlist *sgl =
+			smi_scatterlist_from_buffer(inst, phy_addr, n_bytes,
+				&inst->buffer_sgl);
+
+		if (!sgl) {
+			smi_dump_context_labelled(inst,
+			"Error: could not create scatterlist for write!");
+			goto out;
+		}
+		smi_dma_write_sgl(inst, sgl, 1, n_bytes);
+
+		dma_unmap_single
+			(inst->dev, phy_addr, n_bytes, DMA_MEM_TO_DEV);
+	} else if (n_bytes) {
+		smi_write_fifo(inst, (uint32_t *) buf, n_bytes);
+	}
+	buf += n_bytes;
+
+	if (inst->settings.data_width == SMI_WIDTH_8BIT) {
+		while (odd_bytes--)
+			smi_write_single_word(inst, *(uint8_t *) (buf++));
+	} else {
+		while (odd_bytes >= 2) {
+			smi_write_single_word(inst, *(uint16_t *)buf);
+			buf += 2;
+			odd_bytes -= 2;
+		}
+		if (odd_bytes) {
+			/* Reading an odd number of bytes on a 16 bit bus is
+			   a user bug. It's kinder to fail early and tell them
+			   than to e.g. transparently give them the bottom byte
+			   of a 16 bit transfer. */
+			dev_err(inst->dev,
+		"WARNING: odd number of bytes specified for wide transfer.");
+			dev_err(inst->dev,
+		"At least one byte dropped as a result.");
+			dump_stack();
+		}
+	}
+out:
+	spin_unlock(&inst->transaction_lock);
+}
+EXPORT_SYMBOL(bcm2835_smi_write_buf);
+
+void bcm2835_smi_read_buf(struct bcm2835_smi_instance *inst,
+	void *buf, size_t n_bytes)
+{
+
+	/* SMI is inherently 32-bit, which causes surprising amounts of mess
+	   for bytes % 4 != 0. Easiest to avoid this mess altogether
+	   by handling remainder separately. */
+	int odd_bytes = n_bytes & 0x3;
+
+	spin_lock(&inst->transaction_lock);
+	n_bytes -= odd_bytes;
+	if (n_bytes > DMA_THRESHOLD_BYTES) {
+		dma_addr_t phy_addr = dma_map_single(inst->dev,
+						     buf, n_bytes,
+						     DMA_DEV_TO_MEM);
+		struct scatterlist *sgl = smi_scatterlist_from_buffer(
+			inst, phy_addr, n_bytes,
+			&inst->buffer_sgl);
+		if (!sgl) {
+			smi_dump_context_labelled(inst,
+			"Error: could not create scatterlist for read!");
+			goto out;
+		}
+		smi_dma_read_sgl(inst, sgl, 1, n_bytes);
+		dma_unmap_single(inst->dev, phy_addr, n_bytes, DMA_DEV_TO_MEM);
+	} else if (n_bytes) {
+		smi_read_fifo(inst, (uint32_t *)buf, n_bytes);
+	}
+	buf += n_bytes;
+
+	if (inst->settings.data_width == SMI_WIDTH_8BIT) {
+		while (odd_bytes--)
+			*((uint8_t *) (buf++)) = smi_read_single_word(inst);
+	} else {
+		while (odd_bytes >= 2) {
+			*(uint16_t *) buf = smi_read_single_word(inst);
+			buf += 2;
+			odd_bytes -= 2;
+		}
+		if (odd_bytes) {
+			dev_err(inst->dev,
+		"WARNING: odd number of bytes specified for wide transfer.");
+			dev_err(inst->dev,
+		"At least one byte dropped as a result.");
+			dump_stack();
+		}
+	}
+out:
+	spin_unlock(&inst->transaction_lock);
+}
+EXPORT_SYMBOL(bcm2835_smi_read_buf);
+
+void bcm2835_smi_set_address(struct bcm2835_smi_instance *inst,
+	unsigned int address)
+{
+	spin_lock(&inst->transaction_lock);
+	smi_set_address(inst, address);
+	spin_unlock(&inst->transaction_lock);
+}
+EXPORT_SYMBOL(bcm2835_smi_set_address);
+
+struct bcm2835_smi_instance *bcm2835_smi_get(struct device_node *node)
+{
+	struct platform_device *pdev;
+
+	if (!node)
+		return NULL;
+
+	pdev = of_find_device_by_node(node);
+	if (!pdev)
+		return NULL;
+
+	return platform_get_drvdata(pdev);
+}
+EXPORT_SYMBOL(bcm2835_smi_get);
+
+/****************************************************************************
+*
+*   bcm2835_smi_probe - called when the driver is loaded.
+*
+***************************************************************************/
+
+static int bcm2835_smi_dma_setup(struct bcm2835_smi_instance *inst)
+{
+	int i, rv = 0;
+
+	inst->dma_chan = dma_request_slave_channel(inst->dev, "rx-tx");
+
+	inst->dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	inst->dma_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	inst->dma_config.src_addr = inst->smi_regs_busaddr + SMID;
+	inst->dma_config.dst_addr = inst->dma_config.src_addr;
+	/* Direction unimportant - always overridden by prep_slave_sg */
+	inst->dma_config.direction = DMA_DEV_TO_MEM;
+	dmaengine_slave_config(inst->dma_chan, &inst->dma_config);
+	/* Alloc and map bounce buffers */
+	for (i = 0; i < DMA_BOUNCE_BUFFER_COUNT; ++i) {
+		inst->bounce.buffer[i] =
+		dmam_alloc_coherent(inst->dev, DMA_BOUNCE_BUFFER_SIZE,
+				&inst->bounce.phys[i],
+				GFP_KERNEL);
+		if (!inst->bounce.buffer[i]) {
+			dev_err(inst->dev, "Could not allocate buffer!");
+			rv = -ENOMEM;
+			break;
+		}
+		smi_scatterlist_from_buffer(
+			inst,
+			inst->bounce.phys[i],
+			DMA_BOUNCE_BUFFER_SIZE,
+			&inst->bounce.sgl[i]
+		);
+	}
+
+	return rv;
+}
+
+static int bcm2835_smi_probe(struct platform_device *pdev)
+{
+	int err;
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct resource *ioresource;
+	struct bcm2835_smi_instance *inst;
+	const __be32 *addr;
+
+	/* We require device tree support */
+	if (!node)
+		return -EINVAL;
+	/* Allocate buffers and instance data */
+	inst = devm_kzalloc(dev, sizeof(struct bcm2835_smi_instance),
+		GFP_KERNEL);
+	if (!inst)
+		return -ENOMEM;
+
+	inst->dev = dev;
+	spin_lock_init(&inst->transaction_lock);
+
+	ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	inst->smi_regs_ptr = devm_ioremap_resource(dev, ioresource);
+	if (IS_ERR(inst->smi_regs_ptr)) {
+		err = PTR_ERR(inst->smi_regs_ptr);
+		goto err;
+	}
+	addr = of_get_address(node, 0, NULL, NULL);
+	inst->smi_regs_busaddr = be32_to_cpu(*addr);
+
+	err = bcm2835_smi_dma_setup(inst);
+	if (err)
+		goto err;
+
+	/* request clock */
+	inst->clk = devm_clk_get(dev, NULL);
+	if (!inst->clk)
+		goto err;
+	clk_prepare_enable(inst->clk);
+
+	/* Finally, do peripheral setup */
+	smi_setup_regs(inst);
+
+	platform_set_drvdata(pdev, inst);
+
+	dev_info(inst->dev, "initialised");
+
+	return 0;
+err:
+	kfree(inst);
+	return err;
+}
+
+/****************************************************************************
+*
+*   bcm2835_smi_remove - called when the driver is unloaded.
+*
+***************************************************************************/
+
+static int bcm2835_smi_remove(struct platform_device *pdev)
+{
+	struct bcm2835_smi_instance *inst = platform_get_drvdata(pdev);
+	struct device *dev = inst->dev;
+
+	dmaengine_terminate_all(inst->dma_chan);
+	dma_release_channel(inst->dma_chan);
+
+	clk_disable_unprepare(inst->clk);
+
+	dev_info(dev, "SMI device removed - OK");
+	return 0;
+}
+
+/****************************************************************************
+*
+*   Register the driver with device tree
+*
+***************************************************************************/
+
+static const struct of_device_id bcm2835_smi_of_match[] = {
+	{.compatible = "brcm,bcm2835-smi",},
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, bcm2835_smi_of_match);
+
+static struct platform_driver bcm2835_smi_driver = {
+	.probe = bcm2835_smi_probe,
+	.remove = bcm2835_smi_remove,
+	.driver = {
+		   .name = DRIVER_NAME,
+		   .owner = THIS_MODULE,
+		   .of_match_table = bcm2835_smi_of_match,
+		   },
+};
+
+module_platform_driver(bcm2835_smi_driver);
+
+MODULE_ALIAS("platform:smi-bcm2835");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Device driver for BCM2835's secondary memory interface");
+MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/misc/Kconfig linux-5.10.52-v7l+/drivers/misc/Kconfig
--- linux-5.10.52-orig/drivers/misc/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/misc/Kconfig	2021-07-25 16:46:08.668245581 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:12 @
 	tristate
 	depends on INPUT
 
+config BCM2835_SMI
+	tristate "Broadcom 283x Secondary Memory Interface driver"
+	depends on ARCH_BCM2835
+	default m
+	help
+		Driver for enabling and using Broadcom's Secondary/Slow Memory Interface.
+		Appears as /dev/bcm2835_smi. For ioctl interface see drivers/misc/bcm2835_smi.h
+
 config AD525X_DPOT
 	tristate "Analog Devices Digital Potentiometers"
 	depends on (I2C || SPI) && SYSFS
diff -Nur --no-dereference linux-5.10.52-orig/drivers/misc/Makefile linux-5.10.52-v7l+/drivers/misc/Makefile
--- linux-5.10.52-orig/drivers/misc/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/misc/Makefile	2021-07-25 16:46:08.668245581 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:14 @
 obj-$(CONFIG_INTEL_MID_PTI)	+= pti.o
 obj-$(CONFIG_ATMEL_SSC)		+= atmel-ssc.o
 obj-$(CONFIG_ATMEL_TCLIB)	+= atmel_tclib.o
+obj-$(CONFIG_BCM2835_SMI)	+= bcm2835_smi.o
 obj-$(CONFIG_DUMMY_IRQ)		+= dummy-irq.o
 obj-$(CONFIG_ICS932S401)	+= ics932s401.o
 obj-$(CONFIG_LKDTM)		+= lkdtm/
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mmc/core/block.c linux-5.10.52-v7l+/drivers/mmc/core/block.c
--- linux-5.10.52-orig/drivers/mmc/core/block.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mmc/core/block.c	2021-07-25 16:46:09.438232672 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:168 @
 module_param(perdev_minors, int, 0444);
 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
 
+/*
+ * Allow quirks to be overridden for the current card
+ */
+static char *card_quirks;
+module_param(card_quirks, charp, 0644);
+MODULE_PARM_DESC(card_quirks, "Force the use of the indicated quirks (a bitfield)");
+
 static inline int mmc_blk_part_switch(struct mmc_card *card,
 				      unsigned int part_type);
 static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2908 @
 {
 	struct mmc_blk_data *md, *part_md;
 	char cap_str[10];
+	char quirk_str[24];
 
 	/*
 	 * Check that the card supports the command class(es) we need.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2916 @
 	if (!(card->csd.cmdclass & CCC_BLOCK_READ))
 		return -ENODEV;
 
-	mmc_fixup_device(card, mmc_blk_fixups);
+	if (card_quirks) {
+		unsigned long quirks;
+		if (kstrtoul(card_quirks, 0, &quirks) == 0)
+			card->quirks = (unsigned int)quirks;
+		else
+			pr_err("mmc_block: Invalid card_quirks parameter '%s'\n",
+			       card_quirks);
+	}
+	else
+		mmc_fixup_device(card, mmc_blk_fixups);
 
 	card->complete_wq = alloc_workqueue("mmc_complete",
 					WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2940 @
 
 	string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2,
 			cap_str, sizeof(cap_str));
-	pr_info("%s: %s %s %s %s\n",
+	if (card->quirks)
+		snprintf(quirk_str, sizeof(quirk_str),
+			 " (quirks 0x%08x)", card->quirks);
+	else
+		quirk_str[0] = '\0';
+	pr_info("%s: %s %s %s%s%s\n",
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-		cap_str, md->read_only ? "(ro)" : "");
+		cap_str, md->read_only ? " (ro)" : "", quirk_str);
 
 	if (mmc_blk_alloc_parts(card, md))
 		goto out;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mmc/core/core.c linux-5.10.52-v7l+/drivers/mmc/core/core.c
--- linux-5.10.52-orig/drivers/mmc/core/core.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mmc/core/core.c	2021-07-25 16:46:09.458232337 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1877 @
 
 int mmc_can_erase(struct mmc_card *card)
 {
-	if (card->csd.cmdclass & CCC_ERASE && card->erase_size)
+	if (card->csd.cmdclass & CCC_ERASE && card->erase_size &&
+	    !(card->quirks & MMC_QUIRK_ERASE_BROKEN))
 		return 1;
 	return 0;
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mmc/core/quirks.h linux-5.10.52-v7l+/drivers/mmc/core/quirks.h
--- linux-5.10.52-orig/drivers/mmc/core/quirks.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mmc/core/quirks.h	2021-07-25 16:46:09.478232001 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:102 @
 	MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
 		  MMC_QUIRK_TRIM_BROKEN),
 
+	/*
+	 *  On some Kingston SD cards, multiple erases of less than 64
+	 *  sectors can cause corruption.
+	 */
+	MMC_FIXUP("SD16G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+	MMC_FIXUP("SD32G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+	MMC_FIXUP("SD64G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN),
+
 	END_FIXUP
 };
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mmc/host/bcm2835-mmc.c linux-5.10.52-v7l+/drivers/mmc/host/bcm2835-mmc.c
--- linux-5.10.52-orig/drivers/mmc/host/bcm2835-mmc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/mmc/host/bcm2835-mmc.c	2021-07-25 16:46:09.518231331 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * BCM2835 MMC host driver.
+ *
+ * Author:      Gellert Weisz <gellert@raspberrypi.org>
+ *              Copyright 2014
+ *
+ * Based on
+ *  sdhci-bcm2708.c by Broadcom
+ *  sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
+ *  sdhci.c and sdhci-pci.c by Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sd.h>
+#include <linux/scatterlist.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/blkdev.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_dma.h>
+#include <linux/swiotlb.h>
+
+#include "sdhci.h"
+
+
+#define DRIVER_NAME "mmc-bcm2835"
+
+#define DBG(f, x...) \
+pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
+
+#ifndef CONFIG_MMC_BCM2835_DMA
+ #define FORCE_PIO
+#endif
+
+
+/* the inclusive limit in bytes under which PIO will be used instead of DMA */
+#ifdef CONFIG_MMC_BCM2835_PIO_DMA_BARRIER
+#define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_PIO_DMA_BARRIER
+#else
+#define PIO_DMA_BARRIER 00
+#endif
+
+#define MIN_FREQ 400000
+#define TIMEOUT_VAL 0xE
+#define BCM2835_SDHCI_WRITE_DELAY(f)	(((2 * 1000000) / f) + 1)
+
+
+unsigned mmc_debug;
+unsigned mmc_debug2;
+
+struct bcm2835_host {
+	spinlock_t				lock;
+
+	void __iomem			*ioaddr;
+	u32						bus_addr;
+
+	struct mmc_host			*mmc;
+
+	u32						timeout;
+
+	int						clock;	/* Current clock speed */
+	u8						pwr;	/* Current voltage */
+
+	unsigned int			max_clk;		/* Max possible freq */
+	unsigned int			timeout_clk;	/* Timeout freq (KHz) */
+	unsigned int			clk_mul;		/* Clock Muliplier value */
+
+	struct tasklet_struct	finish_tasklet;		/* Tasklet structures */
+
+	struct timer_list		timer;			/* Timer for timeouts */
+
+	struct sg_mapping_iter	sg_miter;		/* SG state for PIO */
+	unsigned int			blocks;			/* remaining PIO blocks */
+
+	int						irq;			/* Device IRQ */
+
+
+	u32						ier;			/* cached registers */
+
+	struct mmc_request		*mrq;			/* Current request */
+	struct mmc_command		*cmd;			/* Current command */
+	struct mmc_data			*data;			/* Current data request */
+	unsigned int			data_early:1;		/* Data finished before cmd */
+
+	wait_queue_head_t		buf_ready_int;		/* Waitqueue for Buffer Read Ready interrupt */
+
+	u32						shadow;
+
+	/*DMA part*/
+	struct dma_chan			*dma_chan_rxtx;		/* DMA channel for reads and writes */
+	struct dma_slave_config		dma_cfg_rx;
+	struct dma_slave_config		dma_cfg_tx;
+	struct dma_async_tx_descriptor	*tx_desc;	/* descriptor */
+
+	bool					have_dma;
+	bool					use_dma;
+	bool					wait_for_dma;
+	/*end of DMA part*/
+
+	int						max_delay;	/* maximum length of time spent waiting */
+
+	int						flags;				/* Host attributes */
+#define SDHCI_REQ_USE_DMA	(1<<2)	/* Use DMA for this req. */
+#define SDHCI_DEVICE_DEAD	(1<<3)	/* Device unresponsive */
+#define SDHCI_AUTO_CMD12	(1<<6)	/* Auto CMD12 support */
+#define SDHCI_AUTO_CMD23	(1<<7)	/* Auto CMD23 support */
+#define SDHCI_SDIO_IRQ_ENABLED	(1<<9)	/* SDIO irq enabled */
+
+	u32				overclock_50;	/* frequency to use when 50MHz is requested (in MHz) */
+	u32				max_overclock;	/* Highest reported */
+};
+
+
+static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from)
+{
+	unsigned delay;
+	lockdep_assert_held_once(&host->lock);
+	writel(val, host->ioaddr + reg);
+	udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ)));
+
+	delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf);
+	if (delay && !((1<<from) & mmc_debug2))
+		udelay(delay);
+}
+
+static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg)
+{
+	unsigned delay;
+	lockdep_assert_held_once(&host->lock);
+	writel(val, host->ioaddr + reg);
+
+	delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf);
+	if (delay)
+		udelay(delay);
+}
+
+static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg)
+{
+	lockdep_assert_held_once(&host->lock);
+	return readl(host->ioaddr + reg);
+}
+
+static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int reg)
+{
+	u32 oldval = (reg == SDHCI_COMMAND) ? host->shadow :
+		bcm2835_mmc_readl(host, reg & ~3);
+	u32 word_num = (reg >> 1) & 1;
+	u32 word_shift = word_num * 16;
+	u32 mask = 0xffff << word_shift;
+	u32 newval = (oldval & ~mask) | (val << word_shift);
+
+	if (reg == SDHCI_TRANSFER_MODE)
+		host->shadow = newval;
+	else
+		bcm2835_mmc_writel(host, newval, reg & ~3, 0);
+
+}
+
+static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg)
+{
+	u32 oldval = bcm2835_mmc_readl(host, reg & ~3);
+	u32 byte_num = reg & 3;
+	u32 byte_shift = byte_num * 8;
+	u32 mask = 0xff << byte_shift;
+	u32 newval = (oldval & ~mask) | (val << byte_shift);
+
+	bcm2835_mmc_writel(host, newval, reg & ~3, 1);
+}
+
+
+static inline u16 bcm2835_mmc_readw(struct bcm2835_host *host, int reg)
+{
+	u32 val = bcm2835_mmc_readl(host, (reg & ~3));
+	u32 word_num = (reg >> 1) & 1;
+	u32 word_shift = word_num * 16;
+	u32 word = (val >> word_shift) & 0xffff;
+
+	return word;
+}
+
+static inline u8 bcm2835_mmc_readb(struct bcm2835_host *host, int reg)
+{
+	u32 val = bcm2835_mmc_readl(host, (reg & ~3));
+	u32 byte_num = reg & 3;
+	u32 byte_shift = byte_num * 8;
+	u32 byte = (val >> byte_shift) & 0xff;
+
+	return byte;
+}
+
+static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear)
+{
+	u32 ier;
+
+	ier = bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE);
+	ier &= ~clear;
+	/* change which requests generate IRQs - makes no difference to
+	   the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */
+	bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2);
+}
+
+
+static void bcm2835_mmc_dumpregs(struct bcm2835_host *host)
+{
+	pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
+		mmc_hostname(host->mmc));
+
+	pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
+		bcm2835_mmc_readl(host, SDHCI_DMA_ADDRESS),
+		bcm2835_mmc_readw(host, SDHCI_HOST_VERSION));
+	pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
+		bcm2835_mmc_readw(host, SDHCI_BLOCK_SIZE),
+		bcm2835_mmc_readw(host, SDHCI_BLOCK_COUNT));
+	pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
+		bcm2835_mmc_readl(host, SDHCI_ARGUMENT),
+		bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE));
+	pr_debug(DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
+		bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE),
+		bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL));
+	pr_debug(DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
+		bcm2835_mmc_readb(host, SDHCI_POWER_CONTROL),
+		bcm2835_mmc_readb(host, SDHCI_BLOCK_GAP_CONTROL));
+	pr_debug(DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
+		bcm2835_mmc_readb(host, SDHCI_WAKE_UP_CONTROL),
+		bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL));
+	pr_debug(DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
+		bcm2835_mmc_readb(host, SDHCI_TIMEOUT_CONTROL),
+		bcm2835_mmc_readl(host, SDHCI_INT_STATUS));
+	pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
+		bcm2835_mmc_readl(host, SDHCI_INT_ENABLE),
+		bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE));
+	pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
+		bcm2835_mmc_readw(host, SDHCI_AUTO_CMD_STATUS),
+		bcm2835_mmc_readw(host, SDHCI_SLOT_INT_STATUS));
+	pr_debug(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
+		bcm2835_mmc_readl(host, SDHCI_CAPABILITIES),
+		bcm2835_mmc_readl(host, SDHCI_CAPABILITIES_1));
+	pr_debug(DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
+		bcm2835_mmc_readw(host, SDHCI_COMMAND),
+		bcm2835_mmc_readl(host, SDHCI_MAX_CURRENT));
+	pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
+		bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2));
+
+	pr_debug(DRIVER_NAME ": ===========================================\n");
+}
+
+
+static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask)
+{
+	unsigned long timeout;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET);
+
+	if (mask & SDHCI_RESET_ALL)
+		host->clock = 0;
+
+	/* Wait max 100 ms */
+	timeout = 100;
+
+	/* hw clears the bit when it's done */
+	while (bcm2835_mmc_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
+		if (timeout == 0) {
+			pr_err("%s: Reset 0x%x never completed.\n",
+				mmc_hostname(host->mmc), (int)mask);
+			bcm2835_mmc_dumpregs(host);
+			return;
+		}
+		timeout--;
+		spin_unlock_irqrestore(&host->lock, flags);
+		mdelay(1);
+		spin_lock_irqsave(&host->lock, flags);
+	}
+
+	if (100-timeout > 10 && 100-timeout > host->max_delay) {
+		host->max_delay = 100-timeout;
+		pr_warn("Warning: MMC controller hung for %d ms\n", host->max_delay);
+	}
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
+
+static void bcm2835_mmc_init(struct bcm2835_host *host, int soft)
+{
+	unsigned long flags;
+	if (soft)
+		bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
+	else
+		bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
+
+	host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+		    SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
+		    SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
+		    SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
+		    SDHCI_INT_RESPONSE;
+
+	spin_lock_irqsave(&host->lock, flags);
+	bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3);
+	bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3);
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (soft) {
+		/* force clock reconfiguration */
+		host->clock = 0;
+		bcm2835_mmc_set_ios(host->mmc, &host->mmc->ios);
+	}
+}
+
+
+
+static void bcm2835_mmc_finish_data(struct bcm2835_host *host);
+
+static void bcm2835_mmc_dma_complete(void *param)
+{
+	struct bcm2835_host *host = param;
+	struct dma_chan *dma_chan;
+	unsigned long flags;
+	u32 dir_data;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	host->use_dma = false;
+
+	if (host->data) {
+		dma_chan = host->dma_chan_rxtx;
+		if (host->data->flags & MMC_DATA_WRITE)
+			dir_data = DMA_TO_DEVICE;
+		else
+			dir_data = DMA_FROM_DEVICE;
+		dma_unmap_sg(dma_chan->device->dev,
+		     host->data->sg, host->data->sg_len,
+		     dir_data);
+		if (! (host->data->flags & MMC_DATA_WRITE))
+			bcm2835_mmc_finish_data(host);
+	} else if (host->wait_for_dma) {
+		host->wait_for_dma = false;
+		tasklet_schedule(&host->finish_tasklet);
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_bcm2835_mmc_read_block_pio(struct bcm2835_host *host)
+{
+	unsigned long flags;
+	size_t blksize, len, chunk;
+
+	u32 scratch = 0;
+	u8 *buf;
+
+	blksize = host->data->blksz;
+	chunk = 0;
+
+	local_irq_save(flags);
+
+	while (blksize) {
+		if (!sg_miter_next(&host->sg_miter))
+			BUG();
+
+		len = min(host->sg_miter.length, blksize);
+
+		blksize -= len;
+		host->sg_miter.consumed = len;
+
+		buf = host->sg_miter.addr;
+
+		while (len) {
+			if (chunk == 0) {
+				scratch = bcm2835_mmc_readl(host, SDHCI_BUFFER);
+				chunk = 4;
+			}
+
+			*buf = scratch & 0xFF;
+
+			buf++;
+			scratch >>= 8;
+			chunk--;
+			len--;
+		}
+	}
+
+	sg_miter_stop(&host->sg_miter);
+
+	local_irq_restore(flags);
+}
+
+static void bcm2835_bcm2835_mmc_write_block_pio(struct bcm2835_host *host)
+{
+	unsigned long flags;
+	size_t blksize, len, chunk;
+	u32 scratch;
+	u8 *buf;
+
+	blksize = host->data->blksz;
+	chunk = 0;
+	chunk = 0;
+	scratch = 0;
+
+	local_irq_save(flags);
+
+	while (blksize) {
+		if (!sg_miter_next(&host->sg_miter))
+			BUG();
+
+		len = min(host->sg_miter.length, blksize);
+
+		blksize -= len;
+		host->sg_miter.consumed = len;
+
+		buf = host->sg_miter.addr;
+
+		while (len) {
+			scratch |= (u32)*buf << (chunk * 8);
+
+			buf++;
+			chunk++;
+			len--;
+
+			if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
+				mmc_raw_writel(host, scratch, SDHCI_BUFFER);
+				chunk = 0;
+				scratch = 0;
+			}
+		}
+	}
+
+	sg_miter_stop(&host->sg_miter);
+
+	local_irq_restore(flags);
+}
+
+
+static void bcm2835_mmc_transfer_pio(struct bcm2835_host *host)
+{
+	u32 mask;
+
+	BUG_ON(!host->data);
+
+	if (host->blocks == 0)
+		return;
+
+	if (host->data->flags & MMC_DATA_READ)
+		mask = SDHCI_DATA_AVAILABLE;
+	else
+		mask = SDHCI_SPACE_AVAILABLE;
+
+	while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) {
+
+		if (host->data->flags & MMC_DATA_READ)
+			bcm2835_bcm2835_mmc_read_block_pio(host);
+		else
+			bcm2835_bcm2835_mmc_write_block_pio(host);
+
+		host->blocks--;
+
+		/* QUIRK used in sdhci.c removes the 'if' */
+		/* but it seems this is unnecessary */
+		if (host->blocks == 0)
+			break;
+
+
+	}
+}
+
+
+static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host)
+{
+	u32 len, dir_data, dir_slave;
+	struct dma_async_tx_descriptor *desc = NULL;
+	struct dma_chan *dma_chan;
+
+
+	WARN_ON(!host->data);
+
+	if (!host->data)
+		return;
+
+	if (host->blocks == 0)
+		return;
+
+	dma_chan = host->dma_chan_rxtx;
+	if (host->data->flags & MMC_DATA_READ) {
+		dir_data = DMA_FROM_DEVICE;
+		dir_slave = DMA_DEV_TO_MEM;
+	} else {
+		dir_data = DMA_TO_DEVICE;
+		dir_slave = DMA_MEM_TO_DEV;
+	}
+
+	/* The parameters have already been validated, so this will not fail */
+	(void)dmaengine_slave_config(dma_chan,
+				     (dir_data == DMA_FROM_DEVICE) ?
+				     &host->dma_cfg_rx :
+				     &host->dma_cfg_tx);
+
+	BUG_ON(!dma_chan->device);
+	BUG_ON(!dma_chan->device->dev);
+	BUG_ON(!host->data->sg);
+
+	len = dma_map_sg(dma_chan->device->dev, host->data->sg,
+			 host->data->sg_len, dir_data);
+	if (len > 0) {
+		desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg,
+					       len, dir_slave,
+					       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	} else {
+		dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
+	}
+	if (desc) {
+		unsigned long flags;
+		spin_lock_irqsave(&host->lock, flags);
+		bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL |
+						    SDHCI_INT_SPACE_AVAIL);
+		host->tx_desc = desc;
+		desc->callback = bcm2835_mmc_dma_complete;
+		desc->callback_param = host;
+		spin_unlock_irqrestore(&host->lock, flags);
+		dmaengine_submit(desc);
+		dma_async_issue_pending(dma_chan);
+	} else {
+		dma_unmap_sg(dma_chan->device->dev, host->data->sg, len, dir_data);
+	}
+
+}
+
+
+
+static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host)
+{
+	u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
+	u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
+
+	if (host->use_dma)
+		host->ier = (host->ier & ~pio_irqs) | dma_irqs;
+	else
+		host->ier = (host->ier & ~dma_irqs) | pio_irqs;
+
+	bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4);
+	bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4);
+}
+
+
+static void bcm2835_mmc_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
+{
+	u8 count;
+	struct mmc_data *data = cmd->data;
+
+	WARN_ON(host->data);
+
+	if (data || (cmd->flags & MMC_RSP_BUSY)) {
+		count = TIMEOUT_VAL;
+		bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+	}
+
+	if (!data)
+		return;
+
+	/* Sanity checks */
+	BUG_ON(data->blksz * data->blocks > 524288);
+	BUG_ON(data->blksz > host->mmc->max_blk_size);
+	BUG_ON(data->blocks > 65535);
+
+	host->data = data;
+	host->data_early = 0;
+	host->data->bytes_xfered = 0;
+
+
+	if (!(host->flags & SDHCI_REQ_USE_DMA)) {
+		int flags;
+
+		flags = SG_MITER_ATOMIC;
+		if (host->data->flags & MMC_DATA_READ)
+			flags |= SG_MITER_TO_SG;
+		else
+			flags |= SG_MITER_FROM_SG;
+		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+		host->blocks = data->blocks;
+	}
+
+	host->use_dma = host->have_dma && data->blocks > PIO_DMA_BARRIER;
+
+	bcm2835_mmc_set_transfer_irqs(host);
+
+	/* Set the DMA boundary value and block size */
+	bcm2835_mmc_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
+		data->blksz), SDHCI_BLOCK_SIZE);
+	bcm2835_mmc_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+
+	BUG_ON(!host->data);
+}
+
+static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host,
+	struct mmc_command *cmd)
+{
+	u16 mode;
+	struct mmc_data *data = cmd->data;
+
+	if (data == NULL) {
+		/* clear Auto CMD settings for no data CMDs */
+		mode = bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE);
+		bcm2835_mmc_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
+				SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
+		return;
+	}
+
+	WARN_ON(!host->data);
+
+	mode = SDHCI_TRNS_BLK_CNT_EN;
+
+	if ((mmc_op_multi(cmd->opcode) || data->blocks > 1)) {
+		mode |= SDHCI_TRNS_MULTI;
+
+		/*
+		 * If we are sending CMD23, CMD12 never gets sent
+		 * on successful completion (so no Auto-CMD12).
+		 */
+		if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
+			mode |= SDHCI_TRNS_AUTO_CMD12;
+		else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
+			mode |= SDHCI_TRNS_AUTO_CMD23;
+			bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5);
+		}
+	}
+
+	if (data->flags & MMC_DATA_READ)
+		mode |= SDHCI_TRNS_READ;
+	if (host->flags & SDHCI_REQ_USE_DMA)
+		mode |= SDHCI_TRNS_DMA;
+
+	bcm2835_mmc_writew(host, mode, SDHCI_TRANSFER_MODE);
+}
+
+void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
+{
+	int flags;
+	u32 mask;
+	unsigned long timeout;
+
+	WARN_ON(host->cmd);
+
+	/* Wait max 10 ms */
+	timeout = 1000;
+
+	mask = SDHCI_CMD_INHIBIT;
+	if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+		mask |= SDHCI_DATA_INHIBIT;
+
+	/* We shouldn't wait for data inihibit for stop commands, even
+	   though they might use busy signaling */
+	if (host->mrq->data && (cmd == host->mrq->data->stop))
+		mask &= ~SDHCI_DATA_INHIBIT;
+
+	while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) {
+		if (timeout == 0) {
+			pr_err("%s: Controller never released inhibit bit(s).\n",
+				mmc_hostname(host->mmc));
+			bcm2835_mmc_dumpregs(host);
+			cmd->error = -EIO;
+			tasklet_schedule(&host->finish_tasklet);
+			return;
+		}
+		timeout--;
+		udelay(10);
+	}
+
+	if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) {
+		host->max_delay = (1000-timeout)/100;
+		pr_warn("Warning: MMC controller hung for %d ms\n", host->max_delay);
+	}
+
+	timeout = jiffies;
+	if (!cmd->data && cmd->busy_timeout > 9000)
+		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
+	else
+		timeout += 10 * HZ;
+	mod_timer(&host->timer, timeout);
+
+	host->cmd = cmd;
+	host->use_dma = false;
+
+	bcm2835_mmc_prepare_data(host, cmd);
+
+	bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6);
+
+	bcm2835_mmc_set_transfer_mode(host, cmd);
+
+	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
+		pr_err("%s: Unsupported response type!\n",
+			mmc_hostname(host->mmc));
+		cmd->error = -EINVAL;
+		tasklet_schedule(&host->finish_tasklet);
+		return;
+	}
+
+	if (!(cmd->flags & MMC_RSP_PRESENT))
+		flags = SDHCI_CMD_RESP_NONE;
+	else if (cmd->flags & MMC_RSP_136)
+		flags = SDHCI_CMD_RESP_LONG;
+	else if (cmd->flags & MMC_RSP_BUSY)
+		flags = SDHCI_CMD_RESP_SHORT_BUSY;
+	else
+		flags = SDHCI_CMD_RESP_SHORT;
+
+	if (cmd->flags & MMC_RSP_CRC)
+		flags |= SDHCI_CMD_CRC;
+	if (cmd->flags & MMC_RSP_OPCODE)
+		flags |= SDHCI_CMD_INDEX;
+
+	if (cmd->data)
+		flags |= SDHCI_CMD_DATA;
+
+	bcm2835_mmc_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
+}
+
+
+static void bcm2835_mmc_finish_data(struct bcm2835_host *host)
+{
+	struct mmc_data *data;
+
+	BUG_ON(!host->data);
+
+	data = host->data;
+	host->data = NULL;
+
+	if (data->error)
+		data->bytes_xfered = 0;
+	else
+		data->bytes_xfered = data->blksz * data->blocks;
+
+	/*
+	 * Need to send CMD12 if -
+	 * a) open-ended multiblock transfer (no CMD23)
+	 * b) error in multiblock transfer
+	 */
+	if (data->stop &&
+	    (data->error ||
+	     !host->mrq->sbc)) {
+
+		/*
+		 * The controller needs a reset of internal state machines
+		 * upon error conditions.
+		 */
+		if (data->error) {
+			bcm2835_mmc_reset(host, SDHCI_RESET_CMD);
+			bcm2835_mmc_reset(host, SDHCI_RESET_DATA);
+		}
+
+		bcm2835_mmc_send_command(host, data->stop);
+	} else if (host->use_dma) {
+		host->wait_for_dma = true;
+	} else {
+		tasklet_schedule(&host->finish_tasklet);
+	}
+}
+
+static void bcm2835_mmc_finish_command(struct bcm2835_host *host)
+{
+	int i;
+
+	BUG_ON(host->cmd == NULL);
+
+	if (host->cmd->flags & MMC_RSP_PRESENT) {
+		if (host->cmd->flags & MMC_RSP_136) {
+			/* CRC is stripped so we need to do some shifting. */
+			for (i = 0; i < 4; i++) {
+				host->cmd->resp[i] = bcm2835_mmc_readl(host,
+					SDHCI_RESPONSE + (3-i)*4) << 8;
+				if (i != 3)
+					host->cmd->resp[i] |=
+						bcm2835_mmc_readb(host,
+						SDHCI_RESPONSE + (3-i)*4-1);
+			}
+		} else {
+			host->cmd->resp[0] = bcm2835_mmc_readl(host, SDHCI_RESPONSE);
+		}
+	}
+
+	host->cmd->error = 0;
+
+	/* Finished CMD23, now send actual command. */
+	if (host->cmd == host->mrq->sbc) {
+		host->cmd = NULL;
+		bcm2835_mmc_send_command(host, host->mrq->cmd);
+
+		if (host->mrq->cmd->data && host->use_dma) {
+			/* DMA transfer starts now, PIO starts after interrupt */
+			bcm2835_mmc_transfer_dma(host);
+		}
+	} else {
+
+		/* Processed actual command. */
+		if (host->data && host->data_early)
+			bcm2835_mmc_finish_data(host);
+
+		if (!host->cmd->data)
+			tasklet_schedule(&host->finish_tasklet);
+
+		host->cmd = NULL;
+	}
+}
+
+
+static void bcm2835_mmc_timeout_timer(struct timer_list *t)
+{
+	struct bcm2835_host *host = from_timer(host, t, timer);
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (host->mrq) {
+		pr_err("%s: Timeout waiting for hardware interrupt.\n",
+			mmc_hostname(host->mmc));
+		bcm2835_mmc_dumpregs(host);
+
+		if (host->data) {
+			host->data->error = -ETIMEDOUT;
+			bcm2835_mmc_finish_data(host);
+		} else {
+			if (host->cmd)
+				host->cmd->error = -ETIMEDOUT;
+			else
+				host->mrq->cmd->error = -ETIMEDOUT;
+
+			tasklet_schedule(&host->finish_tasklet);
+		}
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+
+static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable)
+{
+	if (!(host->flags & SDHCI_DEVICE_DEAD)) {
+		if (enable)
+			host->ier |= SDHCI_INT_CARD_INT;
+		else
+			host->ier &= ~SDHCI_INT_CARD_INT;
+
+		bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7);
+		bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7);
+	}
+}
+
+static void bcm2835_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct bcm2835_host *host = mmc_priv(mmc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (enable)
+		host->flags |= SDHCI_SDIO_IRQ_ENABLED;
+	else
+		host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
+
+	bcm2835_mmc_enable_sdio_irq_nolock(host, enable);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_mmc_cmd_irq(struct bcm2835_host *host, u32 intmask)
+{
+
+	BUG_ON(intmask == 0);
+
+	if (!host->cmd) {
+		pr_err("%s: Got command interrupt 0x%08x even "
+			"though no command operation was in progress.\n",
+			mmc_hostname(host->mmc), (unsigned)intmask);
+		bcm2835_mmc_dumpregs(host);
+		return;
+	}
+
+	if (intmask & SDHCI_INT_TIMEOUT)
+		host->cmd->error = -ETIMEDOUT;
+	else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
+			SDHCI_INT_INDEX)) {
+			host->cmd->error = -EILSEQ;
+	}
+
+	if (host->cmd->error) {
+		tasklet_schedule(&host->finish_tasklet);
+		return;
+	}
+
+	if (intmask & SDHCI_INT_RESPONSE)
+		bcm2835_mmc_finish_command(host);
+
+}
+
+static void bcm2835_mmc_data_irq(struct bcm2835_host *host, u32 intmask)
+{
+	struct dma_chan *dma_chan;
+	u32 dir_data;
+
+	BUG_ON(intmask == 0);
+
+	if (!host->data) {
+		/*
+		 * The "data complete" interrupt is also used to
+		 * indicate that a busy state has ended. See comment
+		 * above in sdhci_cmd_irq().
+		 */
+		if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+			if (intmask & SDHCI_INT_DATA_END) {
+				bcm2835_mmc_finish_command(host);
+				return;
+			}
+		}
+
+		pr_debug("%s: Got data interrupt 0x%08x even "
+			"though no data operation was in progress.\n",
+			mmc_hostname(host->mmc), (unsigned)intmask);
+		bcm2835_mmc_dumpregs(host);
+
+		return;
+	}
+
+	if (intmask & SDHCI_INT_DATA_TIMEOUT)
+		host->data->error = -ETIMEDOUT;
+	else if (intmask & SDHCI_INT_DATA_END_BIT)
+		host->data->error = -EILSEQ;
+	else if ((intmask & SDHCI_INT_DATA_CRC) &&
+		SDHCI_GET_CMD(bcm2835_mmc_readw(host, SDHCI_COMMAND))
+			!= MMC_BUS_TEST_R)
+		host->data->error = -EILSEQ;
+
+	if (host->use_dma) {
+		if  (host->data->flags & MMC_DATA_WRITE) {
+			/* IRQ handled here */
+
+			dma_chan = host->dma_chan_rxtx;
+			dir_data = DMA_TO_DEVICE;
+			dma_unmap_sg(dma_chan->device->dev,
+				 host->data->sg, host->data->sg_len,
+				 dir_data);
+
+			bcm2835_mmc_finish_data(host);
+		}
+
+	} else {
+		if (host->data->error)
+			bcm2835_mmc_finish_data(host);
+		else {
+			if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
+				bcm2835_mmc_transfer_pio(host);
+
+			if (intmask & SDHCI_INT_DATA_END) {
+				if (host->cmd) {
+					/*
+					 * Data managed to finish before the
+					 * command completed. Make sure we do
+					 * things in the proper order.
+					 */
+					host->data_early = 1;
+				} else {
+					bcm2835_mmc_finish_data(host);
+				}
+			}
+		}
+	}
+}
+
+
+static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id)
+{
+	irqreturn_t result = IRQ_NONE;
+	struct bcm2835_host *host = dev_id;
+	u32 intmask, mask, unexpected = 0;
+	int max_loops = 16;
+
+	spin_lock(&host->lock);
+
+	intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
+
+	if (!intmask || intmask == 0xffffffff) {
+		result = IRQ_NONE;
+		goto out;
+	}
+
+	do {
+		/* Clear selected interrupts. */
+		mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+				  SDHCI_INT_BUS_POWER);
+		bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8);
+
+
+		if (intmask & SDHCI_INT_CMD_MASK)
+			bcm2835_mmc_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+
+		if (intmask & SDHCI_INT_DATA_MASK)
+			bcm2835_mmc_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
+
+		if (intmask & SDHCI_INT_BUS_POWER)
+			pr_err("%s: Card is consuming too much power!\n",
+				mmc_hostname(host->mmc));
+
+		if (intmask & SDHCI_INT_CARD_INT) {
+			bcm2835_mmc_enable_sdio_irq_nolock(host, false);
+			sdio_signal_irq(host->mmc);
+		}
+
+		intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
+			     SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+			     SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
+			     SDHCI_INT_CARD_INT);
+
+		if (intmask) {
+			unexpected |= intmask;
+			bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9);
+		}
+
+		if (result == IRQ_NONE)
+			result = IRQ_HANDLED;
+
+		intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
+	} while (intmask && --max_loops);
+out:
+	spin_unlock(&host->lock);
+
+	if (unexpected) {
+		pr_err("%s: Unexpected interrupt 0x%08x.\n",
+			   mmc_hostname(host->mmc), unexpected);
+		bcm2835_mmc_dumpregs(host);
+	}
+
+	return result;
+}
+
+
+static void bcm2835_mmc_ack_sdio_irq(struct mmc_host *mmc)
+{
+	struct bcm2835_host *host = mmc_priv(mmc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
+		bcm2835_mmc_enable_sdio_irq_nolock(host, true);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+void bcm2835_mmc_set_clock(struct bcm2835_host *host, unsigned int clock)
+{
+	int div = 0; /* Initialized for compiler warning */
+	int real_div = div, clk_mul = 1;
+	u16 clk = 0;
+	unsigned long timeout;
+	unsigned int input_clock = clock;
+
+	if (host->overclock_50 && (clock == 50000000))
+		clock = host->overclock_50 * 1000000 + 999999;
+
+	host->mmc->actual_clock = 0;
+
+	bcm2835_mmc_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+	if (clock == 0)
+		return;
+
+	/* Version 3.00 divisors must be a multiple of 2. */
+	if (host->max_clk <= clock)
+		div = 1;
+	else {
+		for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
+			 div += 2) {
+			if ((host->max_clk / div) <= clock)
+				break;
+		}
+	}
+
+	real_div = div;
+	div >>= 1;
+
+	if (real_div)
+		clock = (host->max_clk * clk_mul) / real_div;
+	host->mmc->actual_clock = clock;
+
+	if ((clock > input_clock) && (clock > host->max_overclock)) {
+		pr_warn("%s: Overclocking to %dHz\n",
+			mmc_hostname(host->mmc), clock);
+		host->max_overclock = clock;
+	}
+
+	clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+	clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
+		<< SDHCI_DIVIDER_HI_SHIFT;
+	clk |= SDHCI_CLOCK_INT_EN;
+	bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+	/* Wait max 20 ms */
+	timeout = 20;
+	while (!((clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL))
+		& SDHCI_CLOCK_INT_STABLE)) {
+		if (timeout == 0) {
+			pr_err("%s: Internal clock never "
+				"stabilised.\n", mmc_hostname(host->mmc));
+			bcm2835_mmc_dumpregs(host);
+			return;
+		}
+		timeout--;
+		mdelay(1);
+	}
+
+	if (20-timeout > 10 && 20-timeout > host->max_delay) {
+		host->max_delay = 20-timeout;
+		pr_warn("Warning: MMC controller hung for %d ms\n", host->max_delay);
+	}
+
+	clk |= SDHCI_CLOCK_CARD_EN;
+	bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+}
+
+static void bcm2835_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct bcm2835_host *host;
+	unsigned long flags;
+
+	host = mmc_priv(mmc);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	WARN_ON(host->mrq != NULL);
+
+	host->mrq = mrq;
+
+	if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
+		bcm2835_mmc_send_command(host, mrq->sbc);
+	else
+		bcm2835_mmc_send_command(host, mrq->cmd);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (!(mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) && mrq->cmd->data && host->use_dma) {
+		/* DMA transfer starts now, PIO starts after interrupt */
+		bcm2835_mmc_transfer_dma(host);
+	}
+}
+
+
+static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+
+	struct bcm2835_host *host = mmc_priv(mmc);
+	unsigned long flags;
+	u8 ctrl;
+	u16 clk, ctrl_2;
+
+	pr_debug("bcm2835_mmc_set_ios: clock %d, pwr %d, bus_width %d, timing %d, vdd %d, drv_type %d\n",
+		 ios->clock, ios->power_mode, ios->bus_width,
+		 ios->timing, ios->signal_voltage, ios->drv_type);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (!ios->clock || ios->clock != host->clock) {
+		bcm2835_mmc_set_clock(host, ios->clock);
+		host->clock = ios->clock;
+	}
+
+	if (host->pwr != SDHCI_POWER_330) {
+		host->pwr = SDHCI_POWER_330;
+		bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
+	}
+
+	ctrl = bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL);
+
+	/* set bus width */
+	ctrl &= ~SDHCI_CTRL_8BITBUS;
+	if (ios->bus_width == MMC_BUS_WIDTH_4)
+		ctrl |= SDHCI_CTRL_4BITBUS;
+	else
+		ctrl &= ~SDHCI_CTRL_4BITBUS;
+
+	ctrl &= ~SDHCI_CTRL_HISPD; /* NO_HISPD_BIT */
+
+
+	bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+	/*
+	 * We only need to set Driver Strength if the
+	 * preset value enable is not set.
+	 */
+	ctrl_2 = bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2);
+	ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
+	if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
+		ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
+	else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
+		ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
+
+	bcm2835_mmc_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+	/* Reset SD Clock Enable */
+	clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL);
+	clk &= ~SDHCI_CLOCK_CARD_EN;
+	bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+	/* Re-enable SD Clock */
+	bcm2835_mmc_set_clock(host, host->clock);
+	bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+
+static struct mmc_host_ops bcm2835_ops = {
+	.request = bcm2835_mmc_request,
+	.set_ios = bcm2835_mmc_set_ios,
+	.enable_sdio_irq = bcm2835_mmc_enable_sdio_irq,
+	.ack_sdio_irq = bcm2835_mmc_ack_sdio_irq,
+};
+
+
+static void bcm2835_mmc_tasklet_finish(unsigned long param)
+{
+	struct bcm2835_host *host;
+	unsigned long flags;
+	struct mmc_request *mrq;
+
+	host = (struct bcm2835_host *)param;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	/*
+	 * If this tasklet gets rescheduled while running, it will
+	 * be run again afterwards but without any active request.
+	 */
+	if (!host->mrq) {
+		spin_unlock_irqrestore(&host->lock, flags);
+		return;
+	}
+
+	del_timer(&host->timer);
+
+	mrq = host->mrq;
+
+	/*
+	 * The controller needs a reset of internal state machines
+	 * upon error conditions.
+	 */
+	if (!(host->flags & SDHCI_DEVICE_DEAD) &&
+	    ((mrq->cmd && mrq->cmd->error) ||
+		 (mrq->data && (mrq->data->error ||
+		  (mrq->data->stop && mrq->data->stop->error))))) {
+
+		spin_unlock_irqrestore(&host->lock, flags);
+		bcm2835_mmc_reset(host, SDHCI_RESET_CMD);
+		bcm2835_mmc_reset(host, SDHCI_RESET_DATA);
+		spin_lock_irqsave(&host->lock, flags);
+	}
+
+	host->mrq = NULL;
+	host->cmd = NULL;
+	host->data = NULL;
+
+	spin_unlock_irqrestore(&host->lock, flags);
+	mmc_request_done(host->mmc, mrq);
+}
+
+
+
+static int bcm2835_mmc_add_host(struct bcm2835_host *host)
+{
+	struct mmc_host *mmc = host->mmc;
+	struct device *dev = mmc->parent;
+#ifndef FORCE_PIO
+	struct dma_slave_config cfg;
+#endif
+	int ret;
+
+	bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
+
+	host->clk_mul = 0;
+
+	if (!mmc->f_max || mmc->f_max > host->max_clk)
+		mmc->f_max = host->max_clk;
+	mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
+
+	/* SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK */
+	host->timeout_clk = mmc->f_max / 1000;
+	mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
+
+	/* host controller capabilities */
+	mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_NEEDS_POLL |
+		MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED |
+		MMC_CAP_MMC_HIGHSPEED;
+
+	mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
+	host->flags = SDHCI_AUTO_CMD23;
+
+	dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2);
+#ifdef FORCE_PIO
+	dev_info(dev, "Forcing PIO mode\n");
+	host->have_dma = false;
+#else
+	if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
+		dev_err(dev, "%s: Unable to initialise DMA channel. Falling back to PIO\n",
+			DRIVER_NAME);
+		host->have_dma = false;
+	} else {
+		dev_info(dev, "DMA channel allocated");
+
+		cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		cfg.slave_id = 11;		/* DREQ channel */
+
+		/* Validate the slave configurations */
+
+		cfg.direction = DMA_MEM_TO_DEV;
+		cfg.src_addr = 0;
+		cfg.dst_addr = host->bus_addr + SDHCI_BUFFER;
+
+		ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
+
+		if (ret == 0) {
+			host->dma_cfg_tx = cfg;
+
+			cfg.direction = DMA_DEV_TO_MEM;
+			cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
+			cfg.dst_addr = 0;
+
+			ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
+		}
+
+		if (ret == 0) {
+			host->dma_cfg_rx = cfg;
+
+			host->have_dma = true;
+		} else {
+			pr_err("%s: unable to configure DMA channel. "
+			       "Falling back to PIO\n",
+			       mmc_hostname(mmc));
+			dma_release_channel(host->dma_chan_rxtx);
+			host->dma_chan_rxtx = NULL;
+			host->have_dma = false;
+		}
+	}
+#endif
+	mmc->max_segs = 128;
+	if (swiotlb_max_segment())
+		mmc->max_req_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE;
+	else
+		mmc->max_req_size = 524288;
+	mmc->max_seg_size = mmc->max_req_size;
+	mmc->max_blk_size = 512;
+	mmc->max_blk_count =  65535;
+
+	/* report supported voltage ranges */
+	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+	tasklet_init(&host->finish_tasklet,
+		bcm2835_mmc_tasklet_finish, (unsigned long)host);
+
+	timer_setup(&host->timer, bcm2835_mmc_timeout_timer, 0);
+	init_waitqueue_head(&host->buf_ready_int);
+
+	bcm2835_mmc_init(host, 0);
+	ret = request_irq(host->irq, bcm2835_mmc_irq, IRQF_SHARED,
+				   mmc_hostname(mmc), host);
+	if (ret) {
+		dev_err(dev, "Failed to request IRQ %d: %d\n", host->irq, ret);
+		goto untasklet;
+	}
+
+	ret = mmc_add_host(mmc);
+	if (ret) {
+		dev_err(dev, "could not add MMC host\n");
+		goto free_irq;
+	}
+
+	return 0;
+
+free_irq:
+	free_irq(host->irq, host);
+untasklet:
+	tasklet_kill(&host->finish_tasklet);
+
+	return ret;
+}
+
+static int bcm2835_mmc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct clk *clk;
+	struct resource *iomem;
+	struct bcm2835_host *host;
+	struct mmc_host *mmc;
+	const __be32 *addr;
+	int ret;
+
+	mmc = mmc_alloc_host(sizeof(*host), dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	mmc->ops = &bcm2835_ops;
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	host->timeout = msecs_to_jiffies(1000);
+	spin_lock_init(&host->lock);
+
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->ioaddr = devm_ioremap_resource(dev, iomem);
+	if (IS_ERR(host->ioaddr)) {
+		ret = PTR_ERR(host->ioaddr);
+		goto err;
+	}
+
+	addr = of_get_address(node, 0, NULL, NULL);
+	if (!addr) {
+		dev_err(dev, "could not get DMA-register address\n");
+		ret = -ENODEV;
+		goto err;
+	}
+	host->bus_addr = be32_to_cpup(addr);
+	pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
+		 (unsigned long)host->ioaddr,
+		 (unsigned long)iomem->start,
+		 (unsigned long)host->bus_addr);
+
+#ifndef FORCE_PIO
+	if (node) {
+		host->dma_chan_rxtx = dma_request_slave_channel(dev, "rx-tx");
+		if (!host->dma_chan_rxtx)
+			host->dma_chan_rxtx =
+				dma_request_slave_channel(dev, "tx");
+		if (!host->dma_chan_rxtx)
+			host->dma_chan_rxtx =
+				dma_request_slave_channel(dev, "rx");
+	} else {
+		dma_cap_mask_t mask;
+
+		dma_cap_zero(mask);
+		/* we don't care about the channel, any would work */
+		dma_cap_set(DMA_SLAVE, mask);
+		host->dma_chan_rxtx = dma_request_channel(mask, NULL, NULL);
+	}
+#endif
+	clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		if (ret == -EPROBE_DEFER)
+			dev_info(dev, "could not get clk, deferring probe\n");
+		else
+			dev_err(dev, "could not get clk\n");
+		goto err;
+	}
+
+	host->max_clk = clk_get_rate(clk);
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq <= 0) {
+		dev_err(dev, "get IRQ failed\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (node) {
+		mmc_of_parse(mmc);
+
+		/* Read any custom properties */
+		of_property_read_u32(node,
+				     "brcm,overclock-50",
+				     &host->overclock_50);
+	} else {
+		mmc->caps |= MMC_CAP_4_BIT_DATA;
+	}
+
+	ret = bcm2835_mmc_add_host(host);
+	if (ret)
+		goto err;
+
+	platform_set_drvdata(pdev, host);
+
+	return 0;
+err:
+	if (host->dma_chan_rxtx)
+		dma_release_channel(host->dma_chan_rxtx);
+	mmc_free_host(mmc);
+
+	return ret;
+}
+
+static int bcm2835_mmc_remove(struct platform_device *pdev)
+{
+	struct bcm2835_host *host = platform_get_drvdata(pdev);
+	unsigned long flags;
+	int dead;
+	u32 scratch;
+
+	dead = 0;
+	scratch = bcm2835_mmc_readl(host, SDHCI_INT_STATUS);
+	if (scratch == (u32)-1)
+		dead = 1;
+
+
+	if (dead) {
+		spin_lock_irqsave(&host->lock, flags);
+
+		host->flags |= SDHCI_DEVICE_DEAD;
+
+		if (host->mrq) {
+			pr_err("%s: Controller removed during "
+				" transfer!\n", mmc_hostname(host->mmc));
+
+			host->mrq->cmd->error = -ENOMEDIUM;
+			tasklet_schedule(&host->finish_tasklet);
+		}
+
+		spin_unlock_irqrestore(&host->lock, flags);
+	}
+
+	mmc_remove_host(host->mmc);
+
+	if (!dead)
+		bcm2835_mmc_reset(host, SDHCI_RESET_ALL);
+
+	free_irq(host->irq, host);
+
+	del_timer_sync(&host->timer);
+
+	tasklet_kill(&host->finish_tasklet);
+
+	if (host->dma_chan_rxtx)
+		dma_release_channel(host->dma_chan_rxtx);
+
+	mmc_free_host(host->mmc);
+
+	return 0;
+}
+
+
+static const struct of_device_id bcm2835_mmc_match[] = {
+	{ .compatible = "brcm,bcm2835-mmc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, bcm2835_mmc_match);
+
+
+
+static struct platform_driver bcm2835_mmc_driver = {
+	.probe      = bcm2835_mmc_probe,
+	.remove     = bcm2835_mmc_remove,
+	.driver     = {
+		.name		= DRIVER_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= bcm2835_mmc_match,
+	},
+};
+module_platform_driver(bcm2835_mmc_driver);
+
+module_param(mmc_debug, uint, 0644);
+module_param(mmc_debug2, uint, 0644);
+MODULE_ALIAS("platform:mmc-bcm2835");
+MODULE_DESCRIPTION("BCM2835 SDHCI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gellert Weisz");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mmc/host/bcm2835-sdhost.c linux-5.10.52-v7l+/drivers/mmc/host/bcm2835-sdhost.c
--- linux-5.10.52-orig/drivers/mmc/host/bcm2835-sdhost.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/mmc/host/bcm2835-sdhost.c	2021-07-25 16:46:09.518231331 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * BCM2835 SD host driver.
+ *
+ * Author:      Phil Elwell <phil@raspberrypi.org>
+ *              Copyright (C) 2015-2016 Raspberry Pi (Trading) Ltd.
+ *
+ * Based on
+ *  mmc-bcm2835.c by Gellert Weisz
+ * which is, in turn, based on
+ *  sdhci-bcm2708.c by Broadcom
+ *  sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
+ *  sdhci.c and sdhci-pci.c by Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define FIFO_READ_THRESHOLD     4
+#define FIFO_WRITE_THRESHOLD    4
+#define ALLOW_CMD23_READ        1
+#define ALLOW_CMD23_WRITE       0
+#define ENABLE_LOG              1
+#define SDDATA_FIFO_PIO_BURST   8
+#define CMD_DALLY_US            1
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
+#include <linux/scatterlist.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/blkdev.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_dma.h>
+#include <linux/time.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+/* For mmc_card_blockaddr */
+#include "../core/card.h"
+
+#define DRIVER_NAME "sdhost-bcm2835"
+
+#define SDCMD  0x00 /* Command to SD card              - 16 R/W */
+#define SDARG  0x04 /* Argument to SD card             - 32 R/W */
+#define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */
+#define SDCDIV 0x0c /* Start value for clock divider   - 11 R/W */
+#define SDRSP0 0x10 /* SD card response (31:0)         - 32 R   */
+#define SDRSP1 0x14 /* SD card response (63:32)        - 32 R   */
+#define SDRSP2 0x18 /* SD card response (95:64)        - 32 R   */
+#define SDRSP3 0x1c /* SD card response (127:96)       - 32 R   */
+#define SDHSTS 0x20 /* SD host status                  - 11 R   */
+#define SDVDD  0x30 /* SD card power control           -  1 R/W */
+#define SDEDM  0x34 /* Emergency Debug Mode            - 13 R/W */
+#define SDHCFG 0x38 /* Host configuration              -  2 R/W */
+#define SDHBCT 0x3c /* Host byte count (debug)         - 32 R/W */
+#define SDDATA 0x40 /* Data to/from SD card            - 32 R/W */
+#define SDHBLC 0x50 /* Host block count (SDIO/SDHC)    -  9 R/W */
+
+#define SDCMD_NEW_FLAG                  0x8000
+#define SDCMD_FAIL_FLAG                 0x4000
+#define SDCMD_BUSYWAIT                  0x800
+#define SDCMD_NO_RESPONSE               0x400
+#define SDCMD_LONG_RESPONSE             0x200
+#define SDCMD_WRITE_CMD                 0x80
+#define SDCMD_READ_CMD                  0x40
+#define SDCMD_CMD_MASK                  0x3f
+
+#define SDCDIV_MAX_CDIV                 0x7ff
+
+#define SDHSTS_BUSY_IRPT                0x400
+#define SDHSTS_BLOCK_IRPT               0x200
+#define SDHSTS_SDIO_IRPT                0x100
+#define SDHSTS_REW_TIME_OUT             0x80
+#define SDHSTS_CMD_TIME_OUT             0x40
+#define SDHSTS_CRC16_ERROR              0x20
+#define SDHSTS_CRC7_ERROR               0x10
+#define SDHSTS_FIFO_ERROR               0x08
+/* Reserved */
+/* Reserved */
+#define SDHSTS_DATA_FLAG                0x01
+
+#define SDHSTS_TRANSFER_ERROR_MASK      (SDHSTS_CRC7_ERROR|SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR)
+#define SDHSTS_ERROR_MASK               (SDHSTS_CMD_TIME_OUT|SDHSTS_TRANSFER_ERROR_MASK)
+
+#define SDHCFG_BUSY_IRPT_EN     (1<<10)
+#define SDHCFG_BLOCK_IRPT_EN    (1<<8)
+#define SDHCFG_SDIO_IRPT_EN     (1<<5)
+#define SDHCFG_DATA_IRPT_EN     (1<<4)
+#define SDHCFG_SLOW_CARD        (1<<3)
+#define SDHCFG_WIDE_EXT_BUS     (1<<2)
+#define SDHCFG_WIDE_INT_BUS     (1<<1)
+#define SDHCFG_REL_CMD_LINE     (1<<0)
+
+#define SDEDM_FORCE_DATA_MODE   (1<<19)
+#define SDEDM_CLOCK_PULSE       (1<<20)
+#define SDEDM_BYPASS            (1<<21)
+
+#define SDEDM_WRITE_THRESHOLD_SHIFT 9
+#define SDEDM_READ_THRESHOLD_SHIFT 14
+#define SDEDM_THRESHOLD_MASK     0x1f
+
+#define SDEDM_FSM_MASK           0xf
+#define SDEDM_FSM_IDENTMODE      0x0
+#define SDEDM_FSM_DATAMODE       0x1
+#define SDEDM_FSM_READDATA       0x2
+#define SDEDM_FSM_WRITEDATA      0x3
+#define SDEDM_FSM_READWAIT       0x4
+#define SDEDM_FSM_READCRC        0x5
+#define SDEDM_FSM_WRITECRC       0x6
+#define SDEDM_FSM_WRITEWAIT1     0x7
+#define SDEDM_FSM_POWERDOWN      0x8
+#define SDEDM_FSM_POWERUP        0x9
+#define SDEDM_FSM_WRITESTART1    0xa
+#define SDEDM_FSM_WRITESTART2    0xb
+#define SDEDM_FSM_GENPULSES      0xc
+#define SDEDM_FSM_WRITEWAIT2     0xd
+#define SDEDM_FSM_STARTPOWDOWN   0xf
+
+#define SDDATA_FIFO_WORDS        16
+
+#define USE_CMD23_FLAGS          ((ALLOW_CMD23_READ * MMC_DATA_READ) | \
+				  (ALLOW_CMD23_WRITE * MMC_DATA_WRITE))
+
+#define MHZ 1000000
+
+
+struct bcm2835_host {
+	spinlock_t		lock;
+
+	void __iomem		*ioaddr;
+	phys_addr_t		bus_addr;
+
+	struct mmc_host		*mmc;
+
+	u32			pio_timeout;	/* In jiffies */
+
+	int			clock;		/* Current clock speed */
+
+	bool			slow_card;	/* Force 11-bit divisor */
+
+	unsigned int		max_clk;	/* Max possible freq */
+
+	struct tasklet_struct	finish_tasklet;	/* Tasklet structures */
+
+	struct work_struct	cmd_wait_wq;	/* Workqueue function */
+
+	struct timer_list	timer;		/* Timer for timeouts */
+
+	struct sg_mapping_iter	sg_miter;	/* SG state for PIO */
+	unsigned int		blocks;		/* remaining PIO blocks */
+
+	int			irq;		/* Device IRQ */
+
+	u32			cmd_quick_poll_retries;
+	u32			ns_per_fifo_word;
+
+	/* cached registers */
+	u32			hcfg;
+	u32			cdiv;
+
+	struct mmc_request		*mrq;			/* Current request */
+	struct mmc_command		*cmd;			/* Current command */
+	struct mmc_data			*data;			/* Current data request */
+	unsigned int			data_complete:1;	/* Data finished before cmd */
+
+	unsigned int			flush_fifo:1;		/* Drain the fifo when finishing */
+
+	unsigned int			use_busy:1;		/* Wait for busy interrupt */
+
+	unsigned int			use_sbc:1;		/* Send CMD23 */
+
+	unsigned int			debug:1;		/* Enable debug output */
+	unsigned int			firmware_sets_cdiv:1;	/* Let the firmware manage the clock */
+	unsigned int			reset_clock:1;		/* Reset the clock fore the next request */
+
+	/*DMA part*/
+	struct dma_chan			*dma_chan_rxtx;		/* DMA channel for reads and writes */
+	struct dma_chan			*dma_chan;		/* Channel in use */
+	struct dma_slave_config		dma_cfg_rx;
+	struct dma_slave_config		dma_cfg_tx;
+	struct dma_async_tx_descriptor	*dma_desc;
+	u32				dma_dir;
+	u32				drain_words;
+	struct page 			*drain_page;
+	u32				drain_offset;
+
+	bool				allow_dma;
+	bool				use_dma;
+	/*end of DMA part*/
+
+	int				max_delay;	/* maximum length of time spent waiting */
+	struct timespec64		stop_time;	/* when the last stop was issued */
+	u32				delay_after_stop; /* minimum time between stop and subsequent data transfer */
+	u32				delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
+	u32				user_overclock_50; /* User's preferred frequency to use when 50MHz is requested (in MHz) */
+	u32				overclock_50;	/* frequency to use when 50MHz is requested (in MHz) */
+	u32				overclock;	/* Current frequency if overclocked, else zero */
+	u32				pio_limit;	/* Maximum block count for PIO (0 = always DMA) */
+
+	u32				sectors;	/* Cached card size in sectors */
+};
+
+#if ENABLE_LOG
+
+struct log_entry_struct {
+	char event[4];
+	u32 timestamp;
+	u32 param1;
+	u32 param2;
+};
+
+typedef struct log_entry_struct LOG_ENTRY_T;
+
+LOG_ENTRY_T *sdhost_log_buf;
+dma_addr_t sdhost_log_addr;
+static u32 sdhost_log_idx;
+static spinlock_t log_lock;
+static void __iomem *timer_base;
+
+#define LOG_ENTRIES (256*1)
+#define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES)
+
+static void log_init(struct device *dev, u32 bus_to_phys)
+{
+	spin_lock_init(&log_lock);
+	sdhost_log_buf = dma_alloc_coherent(dev, LOG_SIZE, &sdhost_log_addr,
+					     GFP_KERNEL);
+	if (sdhost_log_buf) {
+		pr_info("sdhost: log_buf @ %p (%llx)\n",
+			sdhost_log_buf, (u64)sdhost_log_addr);
+		timer_base = ioremap(bus_to_phys + 0x7e003000, SZ_4K);
+		if (!timer_base)
+			pr_err("sdhost: failed to remap timer\n");
+	}
+	else
+		pr_err("sdhost: failed to allocate log buf\n");
+}
+
+static void log_event_impl(const char *event, u32 param1, u32 param2)
+{
+	if (sdhost_log_buf) {
+		LOG_ENTRY_T *entry;
+		unsigned long flags;
+
+		spin_lock_irqsave(&log_lock, flags);
+
+		entry = sdhost_log_buf + sdhost_log_idx;
+		memcpy(entry->event, event, 4);
+		entry->timestamp = (readl(timer_base + 4) & 0x3fffffff) +
+			(smp_processor_id()<<30);
+		entry->param1 = param1;
+		entry->param2 = param2;
+		sdhost_log_idx = (sdhost_log_idx + 1) % LOG_ENTRIES;
+
+		spin_unlock_irqrestore(&log_lock, flags);
+	}
+}
+
+static void log_dump(void)
+{
+	if (sdhost_log_buf) {
+		LOG_ENTRY_T *entry;
+		unsigned long flags;
+		int idx;
+
+		spin_lock_irqsave(&log_lock, flags);
+
+		idx = sdhost_log_idx;
+		do {
+			entry = sdhost_log_buf + idx;
+			if (entry->event[0] != '\0')
+				pr_info("[%08x] %.4s %x %x\n",
+				       entry->timestamp,
+				       entry->event,
+				       entry->param1,
+				       entry->param2);
+			idx = (idx + 1) % LOG_ENTRIES;
+		} while (idx != sdhost_log_idx);
+
+		spin_unlock_irqrestore(&log_lock, flags);
+	}
+}
+
+#define log_event(event, param1, param2) log_event_impl(event, (u32)(uintptr_t)param1, (u32)(uintptr_t)param2)
+
+#else
+
+#define log_init(x) (void)0
+#define log_event(event, param1, param2) (void)0
+#define log_dump() (void)0
+
+#endif
+
+static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg)
+{
+	writel(val, host->ioaddr + reg);
+}
+
+static inline u32 bcm2835_sdhost_read(struct bcm2835_host *host, int reg)
+{
+	return readl(host->ioaddr + reg);
+}
+
+static inline u32 bcm2835_sdhost_read_relaxed(struct bcm2835_host *host, int reg)
+{
+	return readl_relaxed(host->ioaddr + reg);
+}
+
+static void bcm2835_sdhost_dumpcmd(struct bcm2835_host *host,
+				   struct mmc_command *cmd,
+				   const char *label)
+{
+	if (cmd)
+		pr_info("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n",
+			mmc_hostname(host->mmc),
+			(cmd == host->cmd) ? '>' : ' ',
+			label, cmd->opcode, cmd->arg, cmd->flags,
+			cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3],
+			cmd->error);
+}
+
+static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host)
+{
+	if (host->mrq)
+	{
+		bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc");
+		bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd");
+		if (host->mrq->data)
+			pr_info("%s: data blocks %x blksz %x - err %d\n",
+			       mmc_hostname(host->mmc),
+			       host->mrq->data->blocks,
+			       host->mrq->data->blksz,
+			       host->mrq->data->error);
+		bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop");
+	}
+
+	pr_info("%s: =========== REGISTER DUMP ===========\n",
+		mmc_hostname(host->mmc));
+
+	pr_info("%s: SDCMD  0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDCMD));
+	pr_info("%s: SDARG  0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDARG));
+	pr_info("%s: SDTOUT 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDTOUT));
+	pr_info("%s: SDCDIV 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDCDIV));
+	pr_info("%s: SDRSP0 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDRSP0));
+	pr_info("%s: SDRSP1 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDRSP1));
+	pr_info("%s: SDRSP2 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDRSP2));
+	pr_info("%s: SDRSP3 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDRSP3));
+	pr_info("%s: SDHSTS 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDHSTS));
+	pr_info("%s: SDVDD  0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDVDD));
+	pr_info("%s: SDEDM  0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDEDM));
+	pr_info("%s: SDHCFG 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDHCFG));
+	pr_info("%s: SDHBCT 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDHBCT));
+	pr_info("%s: SDHBLC 0x%08x\n",
+		mmc_hostname(host->mmc),
+		bcm2835_sdhost_read(host, SDHBLC));
+
+	pr_info("%s: ===========================================\n",
+		mmc_hostname(host->mmc));
+}
+
+static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on)
+{
+	bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD);
+}
+
+static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host)
+{
+	u32 temp;
+
+	if (host->debug)
+		pr_info("%s: reset\n", mmc_hostname(host->mmc));
+
+	bcm2835_sdhost_set_power(host, false);
+
+	bcm2835_sdhost_write(host, 0, SDCMD);
+	bcm2835_sdhost_write(host, 0, SDARG);
+	bcm2835_sdhost_write(host, 0xf00000, SDTOUT);
+	bcm2835_sdhost_write(host, 0, SDCDIV);
+	bcm2835_sdhost_write(host, 0x7f8, SDHSTS); /* Write 1s to clear */
+	bcm2835_sdhost_write(host, 0, SDHCFG);
+	bcm2835_sdhost_write(host, 0, SDHBCT);
+	bcm2835_sdhost_write(host, 0, SDHBLC);
+
+	/* Limit fifo usage due to silicon bug */
+	temp = bcm2835_sdhost_read(host, SDEDM);
+	temp &= ~((SDEDM_THRESHOLD_MASK<<SDEDM_READ_THRESHOLD_SHIFT) |
+		  (SDEDM_THRESHOLD_MASK<<SDEDM_WRITE_THRESHOLD_SHIFT));
+	temp |= (FIFO_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
+		(FIFO_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
+	bcm2835_sdhost_write(host, temp, SDEDM);
+	mdelay(10);
+	bcm2835_sdhost_set_power(host, true);
+	mdelay(10);
+	host->clock = 0;
+	host->sectors = 0;
+	bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+	bcm2835_sdhost_write(host, SDCDIV_MAX_CDIV, SDCDIV);
+}
+
+static void bcm2835_sdhost_reset(struct mmc_host *mmc)
+{
+	struct bcm2835_host *host = mmc_priv(mmc);
+	unsigned long flags;
+	spin_lock_irqsave(&host->lock, flags);
+	log_event("RST<", 0, 0);
+
+	bcm2835_sdhost_reset_internal(host);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
+
+static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft)
+{
+	pr_debug("bcm2835_sdhost_init(%d)\n", soft);
+
+	/* Set interrupt enables */
+	host->hcfg = SDHCFG_BUSY_IRPT_EN;
+
+	bcm2835_sdhost_reset_internal(host);
+
+	if (soft) {
+		/* force clock reconfiguration */
+		host->clock = 0;
+		bcm2835_sdhost_set_ios(host->mmc, &host->mmc->ios);
+	}
+}
+
+static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host)
+{
+	int timediff;
+	u32 alternate_idle;
+	u32 edm;
+
+	alternate_idle = (host->mrq->data->flags & MMC_DATA_READ) ?
+		SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1;
+
+	edm = bcm2835_sdhost_read(host, SDEDM);
+
+	log_event("WTC<", edm, 0);
+
+	timediff = 0;
+
+	while (1) {
+		u32 fsm = edm & SDEDM_FSM_MASK;
+		if ((fsm == SDEDM_FSM_IDENTMODE) ||
+		    (fsm == SDEDM_FSM_DATAMODE))
+			break;
+		if (fsm == alternate_idle) {
+			bcm2835_sdhost_write(host,
+					     edm | SDEDM_FORCE_DATA_MODE,
+					     SDEDM);
+			break;
+		}
+
+		timediff++;
+		if (timediff == 100000) {
+			pr_err("%s: wait_transfer_complete - still waiting after %d retries\n",
+			       mmc_hostname(host->mmc),
+			       timediff);
+			log_dump();
+			bcm2835_sdhost_dumpregs(host);
+			host->mrq->data->error = -ETIMEDOUT;
+			log_event("WTC!", edm, 0);
+			return;
+		}
+		cpu_relax();
+		edm = bcm2835_sdhost_read(host, SDEDM);
+	}
+	log_event("WTC>", edm, 0);
+}
+
+static void bcm2835_sdhost_finish_data(struct bcm2835_host *host);
+
+static void bcm2835_sdhost_dma_complete(void *param)
+{
+	struct bcm2835_host *host = param;
+	struct mmc_data *data = host->data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	log_event("DMA<", host->data, bcm2835_sdhost_read(host, SDHSTS));
+	log_event("DMA ", bcm2835_sdhost_read(host, SDCMD),
+		  bcm2835_sdhost_read(host, SDEDM));
+
+	if (host->dma_chan) {
+		dma_unmap_sg(host->dma_chan->device->dev,
+			     data->sg, data->sg_len,
+			     host->dma_dir);
+
+		host->dma_chan = NULL;
+	}
+
+	if (host->drain_words) {
+		void *page;
+		u32 *buf;
+
+		if (host->drain_offset & PAGE_MASK) {
+			host->drain_page += host->drain_offset >> PAGE_SHIFT;
+			host->drain_offset &= ~PAGE_MASK;
+		}
+
+		page = kmap_atomic(host->drain_page);
+		buf = page + host->drain_offset;
+
+		while (host->drain_words) {
+			u32 edm = bcm2835_sdhost_read(host, SDEDM);
+			if ((edm >> 4) & 0x1f)
+				*(buf++) = bcm2835_sdhost_read(host,
+							       SDDATA);
+			host->drain_words--;
+		}
+
+		kunmap_atomic(page);
+	}
+
+	bcm2835_sdhost_finish_data(host);
+
+	log_event("DMA>", host->data, 0);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host)
+{
+	unsigned long flags;
+	size_t blksize, len;
+	u32 *buf;
+	unsigned long wait_max;
+
+	blksize = host->data->blksz;
+
+	wait_max = jiffies + msecs_to_jiffies(host->pio_timeout);
+
+	local_irq_save(flags);
+
+	while (blksize) {
+		int copy_words;
+		u32 hsts = 0;
+
+		if (!sg_miter_next(&host->sg_miter)) {
+			host->data->error = -EINVAL;
+			break;
+		}
+
+		len = min(host->sg_miter.length, blksize);
+		if (len % 4) {
+			host->data->error = -EINVAL;
+			break;
+		}
+
+		blksize -= len;
+		host->sg_miter.consumed = len;
+
+		buf = (u32 *)host->sg_miter.addr;
+
+		copy_words = len/4;
+
+		while (copy_words) {
+			int burst_words, words;
+			u32 edm;
+
+			burst_words = SDDATA_FIFO_PIO_BURST;
+			if (burst_words > copy_words)
+				burst_words = copy_words;
+			edm = bcm2835_sdhost_read(host, SDEDM);
+			words = ((edm >> 4) & 0x1f);
+
+			if (words < burst_words) {
+				int fsm_state = (edm & SDEDM_FSM_MASK);
+				if ((fsm_state != SDEDM_FSM_READDATA) &&
+				    (fsm_state != SDEDM_FSM_READWAIT) &&
+				    (fsm_state != SDEDM_FSM_READCRC)) {
+					hsts = bcm2835_sdhost_read(host,
+								   SDHSTS);
+					pr_info("%s: fsm %x, hsts %x\n",
+					       mmc_hostname(host->mmc),
+					       fsm_state, hsts);
+					if (hsts & SDHSTS_ERROR_MASK)
+						break;
+				}
+
+				if (time_after(jiffies, wait_max)) {
+					pr_err("%s: PIO read timeout - EDM %x\n",
+					       mmc_hostname(host->mmc),
+					       edm);
+					hsts = SDHSTS_REW_TIME_OUT;
+					break;
+				}
+				ndelay((burst_words - words) *
+				       host->ns_per_fifo_word);
+				continue;
+			} else if (words > copy_words) {
+				words = copy_words;
+			}
+
+			copy_words -= words;
+
+			while (words) {
+				*(buf++) = bcm2835_sdhost_read(host, SDDATA);
+				words--;
+			}
+		}
+
+		if (hsts & SDHSTS_ERROR_MASK)
+			break;
+	}
+
+	sg_miter_stop(&host->sg_miter);
+
+	local_irq_restore(flags);
+}
+
+static void bcm2835_sdhost_write_block_pio(struct bcm2835_host *host)
+{
+	unsigned long flags;
+	size_t blksize, len;
+	u32 *buf;
+	unsigned long wait_max;
+
+	blksize = host->data->blksz;
+
+	wait_max = jiffies + msecs_to_jiffies(host->pio_timeout);
+
+	local_irq_save(flags);
+
+	while (blksize) {
+		int copy_words;
+		u32 hsts = 0;
+
+		if (!sg_miter_next(&host->sg_miter)) {
+			host->data->error = -EINVAL;
+			break;
+		}
+
+		len = min(host->sg_miter.length, blksize);
+		if (len % 4) {
+			host->data->error = -EINVAL;
+			break;
+		}
+
+		blksize -= len;
+		host->sg_miter.consumed = len;
+
+		buf = (u32 *)host->sg_miter.addr;
+
+		copy_words = len/4;
+
+		while (copy_words) {
+			int burst_words, words;
+			u32 edm;
+
+			burst_words = SDDATA_FIFO_PIO_BURST;
+			if (burst_words > copy_words)
+				burst_words = copy_words;
+			edm = bcm2835_sdhost_read(host, SDEDM);
+			words = SDDATA_FIFO_WORDS - ((edm >> 4) & 0x1f);
+
+			if (words < burst_words) {
+				int fsm_state = (edm & SDEDM_FSM_MASK);
+				if ((fsm_state != SDEDM_FSM_WRITEDATA) &&
+				    (fsm_state != SDEDM_FSM_WRITESTART1) &&
+				    (fsm_state != SDEDM_FSM_WRITESTART2)) {
+					hsts = bcm2835_sdhost_read(host,
+								   SDHSTS);
+					pr_info("%s: fsm %x, hsts %x\n",
+					       mmc_hostname(host->mmc),
+					       fsm_state, hsts);
+					if (hsts & SDHSTS_ERROR_MASK)
+						break;
+				}
+
+				if (time_after(jiffies, wait_max)) {
+					pr_err("%s: PIO write timeout - EDM %x\n",
+					       mmc_hostname(host->mmc),
+					       edm);
+					hsts = SDHSTS_REW_TIME_OUT;
+					break;
+				}
+				ndelay((burst_words - words) *
+				       host->ns_per_fifo_word);
+				continue;
+			} else if (words > copy_words) {
+				words = copy_words;
+			}
+
+			copy_words -= words;
+
+			while (words) {
+				bcm2835_sdhost_write(host, *(buf++), SDDATA);
+				words--;
+			}
+		}
+
+		if (hsts & SDHSTS_ERROR_MASK)
+			break;
+	}
+
+	sg_miter_stop(&host->sg_miter);
+
+	local_irq_restore(flags);
+}
+
+static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host)
+{
+	u32 sdhsts;
+	bool is_read;
+	BUG_ON(!host->data);
+	log_event("XFP<", host->data, host->blocks);
+
+	is_read = (host->data->flags & MMC_DATA_READ) != 0;
+	if (is_read)
+		bcm2835_sdhost_read_block_pio(host);
+	else
+		bcm2835_sdhost_write_block_pio(host);
+
+	sdhsts = bcm2835_sdhost_read(host, SDHSTS);
+	if (sdhsts & (SDHSTS_CRC16_ERROR |
+		      SDHSTS_CRC7_ERROR |
+		      SDHSTS_FIFO_ERROR)) {
+		pr_err("%s: %s transfer error - HSTS %x\n",
+		       mmc_hostname(host->mmc),
+		       is_read ? "read" : "write",
+		       sdhsts);
+		host->data->error = -EILSEQ;
+	} else if ((sdhsts & (SDHSTS_CMD_TIME_OUT |
+			      SDHSTS_REW_TIME_OUT))) {
+		pr_err("%s: %s timeout error - HSTS %x\n",
+		       mmc_hostname(host->mmc),
+		       is_read ? "read" : "write",
+		       sdhsts);
+		host->data->error = -ETIMEDOUT;
+	}
+	log_event("XFP>", host->data, host->blocks);
+}
+
+static void bcm2835_sdhost_prepare_dma(struct bcm2835_host *host,
+	struct mmc_data *data)
+{
+	int len, dir_data, dir_slave;
+	struct dma_async_tx_descriptor *desc = NULL;
+	struct dma_chan *dma_chan;
+
+	log_event("PRD<", data, 0);
+	pr_debug("bcm2835_sdhost_prepare_dma()\n");
+
+	dma_chan = host->dma_chan_rxtx;
+	if (data->flags & MMC_DATA_READ) {
+		dir_data = DMA_FROM_DEVICE;
+		dir_slave = DMA_DEV_TO_MEM;
+	} else {
+		dir_data = DMA_TO_DEVICE;
+		dir_slave = DMA_MEM_TO_DEV;
+	}
+	log_event("PRD1", dma_chan, 0);
+
+	BUG_ON(!dma_chan->device);
+	BUG_ON(!dma_chan->device->dev);
+	BUG_ON(!data->sg);
+
+	/* The block doesn't manage the FIFO DREQs properly for multi-block
+	   transfers, so don't attempt to DMA the final few words.
+	   Unfortunately this requires the final sg entry to be trimmed.
+	   N.B. This code demands that the overspill is contained in
+	   a single sg entry.
+	*/
+
+	host->drain_words = 0;
+	if ((data->blocks > 1) && (dir_data == DMA_FROM_DEVICE)) {
+		struct scatterlist *sg;
+		u32 len;
+		int i;
+
+		len = min((u32)(FIFO_READ_THRESHOLD - 1) * 4,
+			  (u32)data->blocks * data->blksz);
+
+		for_each_sg(data->sg, sg, data->sg_len, i) {
+			if (sg_is_last(sg)) {
+				BUG_ON(sg->length < len);
+				sg->length -= len;
+				host->drain_page = sg_page(sg);
+				host->drain_offset = sg->offset + sg->length;
+			}
+		}
+		host->drain_words = len/4;
+	}
+
+	/* The parameters have already been validated, so this will not fail */
+	(void)dmaengine_slave_config(dma_chan,
+				     (dir_data == DMA_FROM_DEVICE) ?
+				     &host->dma_cfg_rx :
+				     &host->dma_cfg_tx);
+
+	len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
+			 dir_data);
+
+	log_event("PRD2", len, 0);
+	if (len > 0)
+		desc = dmaengine_prep_slave_sg(dma_chan, data->sg,
+					       len, dir_slave,
+					       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	log_event("PRD3", desc, 0);
+
+	if (desc) {
+		desc->callback = bcm2835_sdhost_dma_complete;
+		desc->callback_param = host;
+		host->dma_desc = desc;
+		host->dma_chan = dma_chan;
+		host->dma_dir = dir_data;
+	}
+	log_event("PDM>", data, 0);
+}
+
+static void bcm2835_sdhost_start_dma(struct bcm2835_host *host)
+{
+	log_event("SDMA", host->data, host->dma_chan);
+	dmaengine_submit(host->dma_desc);
+	dma_async_issue_pending(host->dma_chan);
+}
+
+static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host)
+{
+	u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN |
+		SDHCFG_BUSY_IRPT_EN;
+	if (host->dma_desc)
+		host->hcfg = (host->hcfg & ~all_irqs) |
+			SDHCFG_BUSY_IRPT_EN;
+	else
+		host->hcfg = (host->hcfg & ~all_irqs) |
+			SDHCFG_DATA_IRPT_EN |
+			SDHCFG_BUSY_IRPT_EN;
+
+	bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+}
+
+static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
+{
+	struct mmc_data *data = cmd->data;
+
+	WARN_ON(host->data);
+
+	host->data = data;
+	if (!data)
+		return;
+
+	/* Sanity checks */
+	BUG_ON(data->blksz * data->blocks > 524288);
+	BUG_ON(data->blksz > host->mmc->max_blk_size);
+	BUG_ON(data->blocks > 65535);
+
+	host->data_complete = 0;
+	host->flush_fifo = 0;
+	host->data->bytes_xfered = 0;
+
+	if (!host->sectors && host->mmc->card) {
+		struct mmc_card *card = host->mmc->card;
+		if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+			/*
+			 * The EXT_CSD sector count is in number of 512 byte
+			 * sectors.
+			 */
+			host->sectors = card->ext_csd.sectors;
+		} else {
+			/*
+			 * The CSD capacity field is in units of read_blkbits.
+			 * set_capacity takes units of 512 bytes.
+			 */
+			host->sectors = card->csd.capacity <<
+				(card->csd.read_blkbits - 9);
+		}
+	}
+
+	if (!host->dma_desc) {
+		/* Use PIO */
+		int flags = SG_MITER_ATOMIC;
+
+		if (data->flags & MMC_DATA_READ)
+			flags |= SG_MITER_TO_SG;
+		else
+			flags |= SG_MITER_FROM_SG;
+		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+		host->blocks = data->blocks;
+	}
+
+	bcm2835_sdhost_set_transfer_irqs(host);
+
+	bcm2835_sdhost_write(host, data->blksz, SDHBCT);
+	bcm2835_sdhost_write(host, data->blocks, SDHBLC);
+
+	BUG_ON(!host->data);
+}
+
+bool bcm2835_sdhost_send_command(struct bcm2835_host *host,
+				 struct mmc_command *cmd)
+{
+	u32 sdcmd, sdhsts;
+	unsigned long timeout;
+	int delay;
+
+	WARN_ON(host->cmd);
+	log_event("CMD<", cmd->opcode, cmd->arg);
+
+	if (cmd->data)
+		pr_debug("%s: send_command %d 0x%x "
+			 "(flags 0x%x) - %s %d*%d\n",
+			 mmc_hostname(host->mmc),
+			 cmd->opcode, cmd->arg, cmd->flags,
+			 (cmd->data->flags & MMC_DATA_READ) ?
+			 "read" : "write", cmd->data->blocks,
+			 cmd->data->blksz);
+	else
+		pr_debug("%s: send_command %d 0x%x (flags 0x%x)\n",
+			 mmc_hostname(host->mmc),
+			 cmd->opcode, cmd->arg, cmd->flags);
+
+	/* Wait max 100 ms */
+	timeout = 10000;
+
+	while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) {
+		if (timeout == 0) {
+			pr_warn("%s: previous command never completed.\n",
+				mmc_hostname(host->mmc));
+			if (host->debug)
+				bcm2835_sdhost_dumpregs(host);
+			cmd->error = -EILSEQ;
+			tasklet_schedule(&host->finish_tasklet);
+			return false;
+		}
+		timeout--;
+		udelay(10);
+	}
+
+	delay = (10000 - timeout)/100;
+	if (delay > host->max_delay) {
+		host->max_delay = delay;
+		pr_warn("%s: controller hung for %d ms\n",
+			   mmc_hostname(host->mmc),
+			   host->max_delay);
+	}
+
+	timeout = jiffies;
+	if (!cmd->data && cmd->busy_timeout > 9000)
+		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
+	else
+		timeout += 10 * HZ;
+	mod_timer(&host->timer, timeout);
+
+	host->cmd = cmd;
+
+	/* Clear any error flags */
+	sdhsts = bcm2835_sdhost_read(host, SDHSTS);
+	if (sdhsts & SDHSTS_ERROR_MASK)
+		bcm2835_sdhost_write(host, sdhsts, SDHSTS);
+
+	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
+		pr_err("%s: unsupported response type!\n",
+			mmc_hostname(host->mmc));
+		cmd->error = -EINVAL;
+		tasklet_schedule(&host->finish_tasklet);
+		return false;
+	}
+
+	bcm2835_sdhost_prepare_data(host, cmd);
+
+	bcm2835_sdhost_write(host, cmd->arg, SDARG);
+
+	sdcmd = cmd->opcode & SDCMD_CMD_MASK;
+
+	host->use_busy = 0;
+	if (!(cmd->flags & MMC_RSP_PRESENT)) {
+		sdcmd |= SDCMD_NO_RESPONSE;
+	} else {
+		if (cmd->flags & MMC_RSP_136)
+			sdcmd |= SDCMD_LONG_RESPONSE;
+		if (cmd->flags & MMC_RSP_BUSY) {
+			sdcmd |= SDCMD_BUSYWAIT;
+			host->use_busy = 1;
+		}
+	}
+
+	if (cmd->data) {
+		log_event("CMDD", cmd->data->blocks, cmd->data->blksz);
+		if (host->delay_after_this_stop) {
+			struct timespec64 now;
+			int time_since_stop;
+
+			ktime_get_real_ts64(&now);
+			time_since_stop = now.tv_sec - host->stop_time.tv_sec;
+			if (time_since_stop < 2) {
+				/* Possibly less than one second */
+				time_since_stop = time_since_stop * 1000000 +
+					(now.tv_nsec - host->stop_time.tv_nsec)/1000;
+				if (time_since_stop <
+				    host->delay_after_this_stop)
+					udelay(host->delay_after_this_stop -
+					       time_since_stop);
+			}
+		}
+
+		host->delay_after_this_stop = host->delay_after_stop;
+		if ((cmd->data->flags & MMC_DATA_READ) && !host->use_sbc) {
+			/* See if read crosses one of the hazardous sectors */
+			u32 first_blk, last_blk;
+
+			/* Intentionally include the following sector because
+			   without CMD23/SBC the read may run on. */
+			first_blk = host->mrq->cmd->arg;
+			last_blk = first_blk + cmd->data->blocks;
+
+			if (((last_blk >= (host->sectors - 64)) &&
+			     (first_blk <= (host->sectors - 64))) ||
+			    ((last_blk >= (host->sectors - 32)) &&
+			     (first_blk <= (host->sectors - 32)))) {
+				host->delay_after_this_stop =
+					max(250u, host->delay_after_stop);
+			}
+		}
+
+		if (cmd->data->flags & MMC_DATA_WRITE)
+			sdcmd |= SDCMD_WRITE_CMD;
+		if (cmd->data->flags & MMC_DATA_READ)
+			sdcmd |= SDCMD_READ_CMD;
+	}
+
+	bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD);
+
+	return true;
+}
+
+static void bcm2835_sdhost_finish_command(struct bcm2835_host *host,
+					  unsigned long *irq_flags);
+static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host);
+
+static void bcm2835_sdhost_finish_data(struct bcm2835_host *host)
+{
+	struct mmc_data *data;
+
+	data = host->data;
+	BUG_ON(!data);
+
+	log_event("FDA<", host->mrq, host->cmd);
+	pr_debug("finish_data(error %d, stop %d, sbc %d)\n",
+	       data->error, data->stop ? 1 : 0,
+	       host->mrq->sbc ? 1 : 0);
+
+	host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN);
+	bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+
+	data->bytes_xfered = data->error ? 0 : (data->blksz * data->blocks);
+
+	host->data_complete = 1;
+
+	if (host->cmd) {
+		/*
+		 * Data managed to finish before the
+		 * command completed. Make sure we do
+		 * things in the proper order.
+		 */
+		pr_debug("Finished early - HSTS %x\n",
+			 bcm2835_sdhost_read(host, SDHSTS));
+	}
+	else
+		bcm2835_sdhost_transfer_complete(host);
+	log_event("FDA>", host->mrq, host->cmd);
+}
+
+static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host)
+{
+	struct mmc_data *data;
+
+	BUG_ON(host->cmd);
+	BUG_ON(!host->data);
+	BUG_ON(!host->data_complete);
+
+	data = host->data;
+	host->data = NULL;
+
+	log_event("TCM<", data, data->error);
+	pr_debug("transfer_complete(error %d, stop %d)\n",
+	       data->error, data->stop ? 1 : 0);
+
+	/*
+	 * Need to send CMD12 if -
+	 * a) open-ended multiblock transfer (no CMD23)
+	 * b) error in multiblock transfer
+	 */
+	if (host->mrq->stop && (data->error || !host->use_sbc)) {
+		if (bcm2835_sdhost_send_command(host, host->mrq->stop)) {
+			/* No busy, so poll for completion */
+			if (!host->use_busy)
+				bcm2835_sdhost_finish_command(host, NULL);
+
+			if (host->delay_after_this_stop)
+				ktime_get_real_ts64(&host->stop_time);
+		}
+	} else {
+		bcm2835_sdhost_wait_transfer_complete(host);
+		tasklet_schedule(&host->finish_tasklet);
+	}
+	log_event("TCM>", data, 0);
+}
+
+/* If irq_flags is valid, the caller is in a thread context and is allowed
+   to sleep */
+static void bcm2835_sdhost_finish_command(struct bcm2835_host *host,
+					  unsigned long *irq_flags)
+{
+	u32 sdcmd;
+	u32 retries;
+#ifdef DEBUG
+	struct timespec64 before, after;
+	int timediff = 0;
+#endif
+
+	log_event("FCM<", host->mrq, host->cmd);
+	pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD));
+
+	BUG_ON(!host->cmd || !host->mrq);
+
+	/* Poll quickly at first */
+
+	retries = host->cmd_quick_poll_retries;
+	if (!retries) {
+		/* Work out how many polls take 1us by timing 10us */
+		struct timespec64 start, now;
+		int us_diff;
+
+		retries = 1;
+		do {
+			int i;
+
+			retries *= 2;
+
+			ktime_get_real_ts64(&start);
+
+			for (i = 0; i < retries; i++) {
+				cpu_relax();
+				sdcmd = bcm2835_sdhost_read(host, SDCMD);
+			}
+
+			ktime_get_real_ts64(&now);
+			us_diff = (now.tv_sec - start.tv_sec) * 1000000 +
+				(now.tv_nsec - start.tv_nsec)/1000;
+		} while (us_diff < 10);
+
+		host->cmd_quick_poll_retries = ((retries * us_diff + 9)*CMD_DALLY_US)/10 + 1;
+		retries = 1; // We've already waited long enough this time
+	}
+
+	for (sdcmd = bcm2835_sdhost_read(host, SDCMD);
+	     (sdcmd & SDCMD_NEW_FLAG) && retries;
+	     retries--) {
+		cpu_relax();
+		sdcmd = bcm2835_sdhost_read(host, SDCMD);
+	}
+
+	if (!retries) {
+		unsigned long wait_max;
+
+		if (!irq_flags) {
+			/* Schedule the work */
+			log_event("CWWQ", 0, 0);
+			schedule_work(&host->cmd_wait_wq);
+			return;
+		}
+
+		/* Wait max 100 ms */
+		wait_max = jiffies + msecs_to_jiffies(100);
+		while (time_before(jiffies, wait_max)) {
+			spin_unlock_irqrestore(&host->lock, *irq_flags);
+			usleep_range(1, 10);
+			spin_lock_irqsave(&host->lock, *irq_flags);
+			sdcmd = bcm2835_sdhost_read(host, SDCMD);
+			if (!(sdcmd & SDCMD_NEW_FLAG))
+				break;
+		}
+	}
+
+	/* Check for errors */
+	if (sdcmd & SDCMD_NEW_FLAG) {
+		if (host->debug) {
+			pr_err("%s: command %d never completed.\n",
+			       mmc_hostname(host->mmc), host->cmd->opcode);
+			bcm2835_sdhost_dumpregs(host);
+		}
+		host->cmd->error = -EILSEQ;
+		tasklet_schedule(&host->finish_tasklet);
+		return;
+	} else if (sdcmd & SDCMD_FAIL_FLAG) {
+		u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
+
+		/* Clear the errors */
+		bcm2835_sdhost_write(host, SDHSTS_ERROR_MASK, SDHSTS);
+
+		if (host->debug)
+			pr_info("%s: error detected - CMD %x, HSTS %03x, EDM %x\n",
+				mmc_hostname(host->mmc), sdcmd, sdhsts,
+				bcm2835_sdhost_read(host, SDEDM));
+
+		if ((sdhsts & SDHSTS_CRC7_ERROR) &&
+		    (host->cmd->opcode == 1)) {
+			if (host->debug)
+				pr_info("%s: ignoring CRC7 error for CMD1\n",
+					mmc_hostname(host->mmc));
+		} else {
+			u32 edm, fsm;
+
+			if (sdhsts & SDHSTS_CMD_TIME_OUT) {
+				if (host->debug)
+					pr_warn("%s: command %d timeout\n",
+					       mmc_hostname(host->mmc),
+					       host->cmd->opcode);
+				host->cmd->error = -ETIMEDOUT;
+			} else {
+				pr_warn("%s: unexpected command %d error\n",
+				       mmc_hostname(host->mmc),
+				       host->cmd->opcode);
+				host->cmd->error = -EILSEQ;
+			}
+
+			edm = readl(host->ioaddr + SDEDM);
+			fsm = edm & SDEDM_FSM_MASK;
+			if (fsm == SDEDM_FSM_READWAIT ||
+			    fsm == SDEDM_FSM_WRITESTART1)
+				writel(edm | SDEDM_FORCE_DATA_MODE,
+				       host->ioaddr + SDEDM);
+			tasklet_schedule(&host->finish_tasklet);
+			return;
+		}
+	}
+
+	if (host->cmd->flags & MMC_RSP_PRESENT) {
+		if (host->cmd->flags & MMC_RSP_136) {
+			int i;
+			for (i = 0; i < 4; i++)
+				host->cmd->resp[3 - i] = bcm2835_sdhost_read(host, SDRSP0 + i*4);
+			pr_debug("%s: finish_command %08x %08x %08x %08x\n",
+				 mmc_hostname(host->mmc),
+				 host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]);
+			log_event("RSP ", host->cmd->resp[0], host->cmd->resp[1]);
+		} else {
+			host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0);
+			pr_debug("%s: finish_command %08x\n",
+				 mmc_hostname(host->mmc),
+				 host->cmd->resp[0]);
+			log_event("RSP ", host->cmd->resp[0], 0);
+		}
+	}
+
+	if (host->cmd == host->mrq->sbc) {
+		/* Finished CMD23, now send actual command. */
+		host->cmd = NULL;
+		if (bcm2835_sdhost_send_command(host, host->mrq->cmd)) {
+			if (host->data && host->dma_desc)
+				/* DMA transfer starts now, PIO starts after irq */
+				bcm2835_sdhost_start_dma(host);
+
+			if (!host->use_busy)
+				bcm2835_sdhost_finish_command(host, NULL);
+		}
+	} else if (host->cmd == host->mrq->stop) {
+		/* Finished CMD12 */
+		tasklet_schedule(&host->finish_tasklet);
+	} else {
+		/* Processed actual command. */
+		host->cmd = NULL;
+		if (!host->data)
+			tasklet_schedule(&host->finish_tasklet);
+		else if (host->data_complete)
+			bcm2835_sdhost_transfer_complete(host);
+	}
+	log_event("FCM>", host->mrq, host->cmd);
+}
+
+static void bcm2835_sdhost_timeout(struct timer_list *t)
+{
+	struct bcm2835_host *host = from_timer(host, t, timer);
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	log_event("TIM<", 0, 0);
+
+	if (host->mrq) {
+		pr_err("%s: timeout waiting for hardware interrupt.\n",
+			mmc_hostname(host->mmc));
+		log_dump();
+		bcm2835_sdhost_dumpregs(host);
+
+		if (host->data) {
+			host->data->error = -ETIMEDOUT;
+			bcm2835_sdhost_finish_data(host);
+		} else {
+			if (host->cmd)
+				host->cmd->error = -ETIMEDOUT;
+			else
+				host->mrq->cmd->error = -ETIMEDOUT;
+
+			pr_debug("timeout_timer tasklet_schedule\n");
+			tasklet_schedule(&host->finish_tasklet);
+		}
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask)
+{
+	log_event("IRQB", host->cmd, intmask);
+	if (!host->cmd) {
+		pr_err("%s: got command busy interrupt 0x%08x even "
+			"though no command operation was in progress.\n",
+			mmc_hostname(host->mmc), (unsigned)intmask);
+		bcm2835_sdhost_dumpregs(host);
+		return;
+	}
+
+	if (!host->use_busy) {
+		pr_err("%s: got command busy interrupt 0x%08x even "
+			"though not expecting one.\n",
+			mmc_hostname(host->mmc), (unsigned)intmask);
+		bcm2835_sdhost_dumpregs(host);
+		return;
+	}
+	host->use_busy = 0;
+
+	if (intmask & SDHSTS_ERROR_MASK)
+	{
+		pr_err("sdhost_busy_irq: intmask %x, data %p\n", intmask, host->mrq->data);
+		if (intmask & SDHSTS_CRC7_ERROR)
+			host->cmd->error = -EILSEQ;
+		else if (intmask & (SDHSTS_CRC16_ERROR |
+				    SDHSTS_FIFO_ERROR)) {
+			if (host->mrq->data)
+				host->mrq->data->error = -EILSEQ;
+			else
+				host->cmd->error = -EILSEQ;
+		} else if (intmask & SDHSTS_REW_TIME_OUT) {
+			if (host->mrq->data)
+				host->mrq->data->error = -ETIMEDOUT;
+			else
+				host->cmd->error = -ETIMEDOUT;
+		} else if (intmask & SDHSTS_CMD_TIME_OUT)
+			host->cmd->error = -ETIMEDOUT;
+
+		if (host->debug) {
+			log_dump();
+			bcm2835_sdhost_dumpregs(host);
+		}
+	}
+	else
+		bcm2835_sdhost_finish_command(host, NULL);
+}
+
+static void bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask)
+{
+	/* There are no dedicated data/space available interrupt
+	   status bits, so it is necessary to use the single shared
+	   data/space available FIFO status bits. It is therefore not
+	   an error to get here when there is no data transfer in
+	   progress. */
+	log_event("IRQD", host->data, intmask);
+	if (!host->data)
+		return;
+
+	if (intmask & (SDHSTS_CRC16_ERROR |
+		       SDHSTS_FIFO_ERROR |
+		       SDHSTS_REW_TIME_OUT)) {
+		if (intmask & (SDHSTS_CRC16_ERROR |
+			       SDHSTS_FIFO_ERROR))
+			host->data->error = -EILSEQ;
+		else
+			host->data->error = -ETIMEDOUT;
+
+		if (host->debug) {
+			log_dump();
+			bcm2835_sdhost_dumpregs(host);
+		}
+	}
+
+	if (host->data->error) {
+		bcm2835_sdhost_finish_data(host);
+	} else if (host->data->flags & MMC_DATA_WRITE) {
+		/* Use the block interrupt for writes after the first block */
+		host->hcfg &= ~(SDHCFG_DATA_IRPT_EN);
+		host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
+		bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+		bcm2835_sdhost_transfer_pio(host);
+	} else {
+		bcm2835_sdhost_transfer_pio(host);
+		host->blocks--;
+		if ((host->blocks == 0) || host->data->error)
+			bcm2835_sdhost_finish_data(host);
+	}
+}
+
+static void bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask)
+{
+	log_event("IRQK", host->data, intmask);
+	if (!host->data) {
+		pr_err("%s: got block interrupt 0x%08x even "
+			"though no data operation was in progress.\n",
+			mmc_hostname(host->mmc), (unsigned)intmask);
+		bcm2835_sdhost_dumpregs(host);
+		return;
+	}
+
+	if (intmask & (SDHSTS_CRC16_ERROR |
+		       SDHSTS_FIFO_ERROR |
+		       SDHSTS_REW_TIME_OUT)) {
+		if (intmask & (SDHSTS_CRC16_ERROR |
+			       SDHSTS_FIFO_ERROR))
+			host->data->error = -EILSEQ;
+		else
+			host->data->error = -ETIMEDOUT;
+
+		if (host->debug) {
+			log_dump();
+			bcm2835_sdhost_dumpregs(host);
+		}
+	}
+
+	if (!host->dma_desc) {
+		BUG_ON(!host->blocks);
+		if (host->data->error || (--host->blocks == 0)) {
+			bcm2835_sdhost_finish_data(host);
+		} else {
+			bcm2835_sdhost_transfer_pio(host);
+		}
+	} else if (host->data->flags & MMC_DATA_WRITE) {
+		bcm2835_sdhost_finish_data(host);
+	}
+}
+
+static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id)
+{
+	irqreturn_t result = IRQ_NONE;
+	struct bcm2835_host *host = dev_id;
+	u32 intmask;
+
+	spin_lock(&host->lock);
+
+	intmask = bcm2835_sdhost_read(host, SDHSTS);
+	log_event("IRQ<", intmask, 0);
+
+	bcm2835_sdhost_write(host,
+			     SDHSTS_BUSY_IRPT |
+			     SDHSTS_BLOCK_IRPT |
+			     SDHSTS_SDIO_IRPT |
+			     SDHSTS_DATA_FLAG,
+			     SDHSTS);
+
+	if (intmask & SDHSTS_BLOCK_IRPT) {
+		bcm2835_sdhost_block_irq(host, intmask);
+		result = IRQ_HANDLED;
+	}
+
+	if (intmask & SDHSTS_BUSY_IRPT) {
+		bcm2835_sdhost_busy_irq(host, intmask);
+		result = IRQ_HANDLED;
+	}
+
+	/* There is no true data interrupt status bit, so it is
+	   necessary to qualify the data flag with the interrupt
+	   enable bit */
+	if ((intmask & SDHSTS_DATA_FLAG) &&
+	    (host->hcfg & SDHCFG_DATA_IRPT_EN)) {
+		bcm2835_sdhost_data_irq(host, intmask);
+		result = IRQ_HANDLED;
+	}
+
+	log_event("IRQ>", bcm2835_sdhost_read(host, SDHSTS), 0);
+	spin_unlock(&host->lock);
+
+	return result;
+}
+
+void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
+{
+	int div = 0; /* Initialized for compiler warning */
+	unsigned int input_clock = clock;
+	unsigned long flags;
+
+	if (host->debug)
+		pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
+
+	if (host->overclock_50 && (clock == 50*MHZ))
+		clock = host->overclock_50 * MHZ + (MHZ - 1);
+
+	/* The SDCDIV register has 11 bits, and holds (div - 2).
+	   But in data mode the max is 50MHz wihout a minimum, and only the
+	   bottom 3 bits are used. Since the switch over is automatic (unless
+	   we have marked the card as slow...), chosen values have to make
+	   sense in both modes.
+	   Ident mode must be 100-400KHz, so can range check the requested
+	   clock. CMD15 must be used to return to data mode, so this can be
+	   monitored.
+
+	   clock 250MHz -> 0->125MHz, 1->83.3MHz, 2->62.5MHz, 3->50.0MHz
+                           4->41.7MHz, 5->35.7MHz, 6->31.3MHz, 7->27.8MHz
+
+			 623->400KHz/27.8MHz
+			 reset value (507)->491159/50MHz
+
+	   BUT, the 3-bit clock divisor in data mode is too small if the
+	   core clock is higher than 250MHz, so instead use the SLOW_CARD
+	   configuration bit to force the use of the ident clock divisor
+	   at all times.
+	*/
+
+	host->mmc->actual_clock = 0;
+
+	if (host->firmware_sets_cdiv) {
+		u32 msg[3] = { clock, 0, 0 };
+
+		rpi_firmware_property(rpi_firmware_get(NULL),
+				      RPI_FIRMWARE_SET_SDHOST_CLOCK,
+				      &msg, sizeof(msg));
+
+		clock = max(msg[1], msg[2]);
+		spin_lock_irqsave(&host->lock, flags);
+	} else {
+		spin_lock_irqsave(&host->lock, flags);
+		if (clock < 100000) {
+			/* Can't stop the clock, but make it as slow as
+			 * possible to show willing
+			 */
+			host->cdiv = SDCDIV_MAX_CDIV;
+			bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+			spin_unlock_irqrestore(&host->lock, flags);
+			return;
+		}
+
+		div = host->max_clk / clock;
+		if (div < 2)
+			div = 2;
+		if ((host->max_clk / div) > clock)
+			div++;
+		div -= 2;
+
+		if (div > SDCDIV_MAX_CDIV)
+			div = SDCDIV_MAX_CDIV;
+
+		clock = host->max_clk / (div + 2);
+
+		host->cdiv = div;
+		bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
+
+		if (host->debug)
+			pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x "
+				"(actual clock %d)\n",
+				mmc_hostname(host->mmc), input_clock,
+				host->max_clk, host->cdiv,
+				clock);
+	}
+
+	/* Calibrate some delays */
+
+	host->ns_per_fifo_word = (1000000000/clock) *
+		((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
+
+	if (input_clock == 50 * MHZ) {
+		if (clock > input_clock) {
+			/* Save the closest value, to make it easier
+			   to reduce in the event of error */
+			host->overclock_50 = (clock/MHZ);
+
+			if (clock != host->overclock) {
+				pr_info("%s: overclocking to %dHz\n",
+					mmc_hostname(host->mmc), clock);
+				host->overclock = clock;
+			}
+		} else if (host->overclock) {
+			host->overclock = 0;
+			if (clock == 50 * MHZ)
+				pr_warn("%s: cancelling overclock\n",
+					mmc_hostname(host->mmc));
+		}
+	} else if (input_clock == 0) {
+		/* Reset the preferred overclock when the clock is stopped.
+		 * This always happens during initialisation. */
+		host->overclock_50 = host->user_overclock_50;
+		host->overclock = 0;
+	}
+
+	/* Set the timeout to 500ms */
+	bcm2835_sdhost_write(host, clock/2, SDTOUT);
+
+	host->mmc->actual_clock = clock;
+	host->clock = input_clock;
+	host->reset_clock = 0;
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct bcm2835_host *host;
+	unsigned long flags;
+	u32 edm, fsm;
+
+	host = mmc_priv(mmc);
+
+	if (host->debug) {
+		struct mmc_command *cmd = mrq->cmd;
+		BUG_ON(!cmd);
+		if (cmd->data)
+			pr_info("%s: cmd %d 0x%x (flags 0x%x) - %s %d*%d\n",
+				mmc_hostname(mmc),
+				cmd->opcode, cmd->arg, cmd->flags,
+				(cmd->data->flags & MMC_DATA_READ) ?
+				"read" : "write", cmd->data->blocks,
+				cmd->data->blksz);
+		else
+			pr_info("%s: cmd %d 0x%x (flags 0x%x)\n",
+				mmc_hostname(mmc),
+				cmd->opcode, cmd->arg, cmd->flags);
+	}
+
+	/* Reset the error statuses in case this is a retry */
+	if (mrq->sbc)
+		mrq->sbc->error = 0;
+	if (mrq->cmd)
+		mrq->cmd->error = 0;
+	if (mrq->data)
+		mrq->data->error = 0;
+	if (mrq->stop)
+		mrq->stop->error = 0;
+
+	if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
+		pr_err("%s: unsupported block size (%d bytes)\n",
+		       mmc_hostname(mmc), mrq->data->blksz);
+		mrq->cmd->error = -EINVAL;
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
+	if (host->use_dma && mrq->data &&
+	    (mrq->data->blocks > host->pio_limit))
+		bcm2835_sdhost_prepare_dma(host, mrq->data);
+
+	if (host->reset_clock)
+	    bcm2835_sdhost_set_clock(host, host->clock);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	WARN_ON(host->mrq != NULL);
+	host->mrq = mrq;
+
+	edm = bcm2835_sdhost_read(host, SDEDM);
+	fsm = edm & SDEDM_FSM_MASK;
+
+	log_event("REQ<", mrq, edm);
+	if ((fsm != SDEDM_FSM_IDENTMODE) &&
+	    (fsm != SDEDM_FSM_DATAMODE)) {
+		log_event("REQ!", mrq, edm);
+		if (host->debug) {
+			pr_warn("%s: previous command (%d) not complete (EDM %x)\n",
+			       mmc_hostname(host->mmc),
+			       bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK,
+			       edm);
+			log_dump();
+			bcm2835_sdhost_dumpregs(host);
+		}
+		mrq->cmd->error = -EILSEQ;
+		tasklet_schedule(&host->finish_tasklet);
+		spin_unlock_irqrestore(&host->lock, flags);
+		return;
+	}
+
+	host->use_sbc = !!mrq->sbc &&
+		(host->mrq->data->flags & USE_CMD23_FLAGS);
+	if (host->use_sbc) {
+		if (bcm2835_sdhost_send_command(host, mrq->sbc)) {
+			if (!host->use_busy)
+				bcm2835_sdhost_finish_command(host, &flags);
+		}
+	} else if (bcm2835_sdhost_send_command(host, mrq->cmd)) {
+		if (host->data && host->dma_desc)
+			/* DMA transfer starts now, PIO starts after irq */
+			bcm2835_sdhost_start_dma(host);
+
+		if (!host->use_busy)
+			bcm2835_sdhost_finish_command(host, &flags);
+	}
+
+	log_event("CMD ", mrq->cmd->opcode,
+		   mrq->data ? (u32)mrq->data->blksz : 0);
+
+	log_event("REQ>", mrq, 0);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+
+	struct bcm2835_host *host = mmc_priv(mmc);
+	unsigned long flags;
+
+	if (host->debug)
+		pr_info("%s: ios clock %d, pwr %d, bus_width %d, "
+			"timing %d, vdd %d, drv_type %d\n",
+			mmc_hostname(mmc),
+			ios->clock, ios->power_mode, ios->bus_width,
+			ios->timing, ios->signal_voltage, ios->drv_type);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	log_event("IOS<", ios->clock, 0);
+
+	/* set bus width */
+	host->hcfg &= ~SDHCFG_WIDE_EXT_BUS;
+	if (ios->bus_width == MMC_BUS_WIDTH_4)
+		host->hcfg |= SDHCFG_WIDE_EXT_BUS;
+
+	host->hcfg |= SDHCFG_WIDE_INT_BUS;
+
+	/* Disable clever clock switching, to cope with fast core clocks */
+	host->hcfg |= SDHCFG_SLOW_CARD;
+
+	bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (!ios->clock || ios->clock != host->clock)
+		bcm2835_sdhost_set_clock(host, ios->clock);
+}
+
+static struct mmc_host_ops bcm2835_sdhost_ops = {
+	.request = bcm2835_sdhost_request,
+	.set_ios = bcm2835_sdhost_set_ios,
+	.hw_reset = bcm2835_sdhost_reset,
+};
+
+static void bcm2835_sdhost_cmd_wait_work(struct work_struct *work)
+{
+	struct bcm2835_host *host;
+	unsigned long flags;
+
+	host = container_of(work, struct bcm2835_host, cmd_wait_wq);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	log_event("CWK<", host->cmd, host->mrq);
+
+	/*
+	 * If this tasklet gets rescheduled while running, it will
+	 * be run again afterwards but without any active request.
+	 */
+	if (!host->mrq) {
+		spin_unlock_irqrestore(&host->lock, flags);
+		return;
+	}
+
+	bcm2835_sdhost_finish_command(host, &flags);
+
+	log_event("CWK>", host->cmd, 0);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void bcm2835_sdhost_tasklet_finish(unsigned long param)
+{
+	struct bcm2835_host *host;
+	unsigned long flags;
+	struct mmc_request *mrq;
+	struct dma_chan *terminate_chan = NULL;
+
+	host = (struct bcm2835_host *)param;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	log_event("TSK<", host->mrq, 0);
+	/*
+	 * If this tasklet gets rescheduled while running, it will
+	 * be run again afterwards but without any active request.
+	 */
+	if (!host->mrq) {
+		spin_unlock_irqrestore(&host->lock, flags);
+		return;
+	}
+
+	del_timer(&host->timer);
+
+	mrq = host->mrq;
+
+	/* Drop the overclock after any data corruption, or after any
+	 * error while overclocked. Ignore errors for status commands,
+	 * as they are likely when a card is ejected. */
+	if (host->overclock) {
+		if ((mrq->cmd && mrq->cmd->error &&
+		     (mrq->cmd->opcode != MMC_SEND_STATUS)) ||
+		    (mrq->data && mrq->data->error) ||
+		    (mrq->stop && mrq->stop->error) ||
+		    (mrq->sbc && mrq->sbc->error)) {
+			host->overclock_50--;
+			pr_warn("%s: reducing overclock due to errors\n",
+				mmc_hostname(host->mmc));
+			host->reset_clock = 1;
+			mrq->cmd->error = -ETIMEDOUT;
+			mrq->cmd->retries = 1;
+		}
+	}
+
+	host->mrq = NULL;
+	host->cmd = NULL;
+	host->data = NULL;
+
+	host->dma_desc = NULL;
+	terminate_chan = host->dma_chan;
+	host->dma_chan = NULL;
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (terminate_chan)
+	{
+		int err = dmaengine_terminate_all(terminate_chan);
+		if (err)
+			pr_err("%s: failed to terminate DMA (%d)\n",
+			       mmc_hostname(host->mmc), err);
+	}
+
+	/* The SDHOST block doesn't report any errors for a disconnected
+	   interface. All cards and SDIO devices should report some supported
+	   voltage range, so a zero response to SEND_OP_COND, IO_SEND_OP_COND
+	   or APP_SEND_OP_COND can be treated as an error. */
+	if (((mrq->cmd->opcode == MMC_SEND_OP_COND) ||
+	     (mrq->cmd->opcode == SD_IO_SEND_OP_COND) ||
+	     (mrq->cmd->opcode == SD_APP_OP_COND)) &&
+	    (mrq->cmd->error == 0) &&
+	    (mrq->cmd->resp[0] == 0)) {
+		mrq->cmd->error = -ETIMEDOUT;
+		if (host->debug)
+			pr_info("%s: faking timeout due to zero OCR\n",
+				mmc_hostname(host->mmc));
+	}
+
+	mmc_request_done(host->mmc, mrq);
+	log_event("TSK>", mrq, 0);
+}
+
+int bcm2835_sdhost_add_host(struct bcm2835_host *host)
+{
+	struct mmc_host *mmc;
+	struct dma_slave_config cfg;
+	char pio_limit_string[20];
+	int ret;
+
+	mmc = host->mmc;
+
+	if (!mmc->f_max || mmc->f_max > host->max_clk)
+		mmc->f_max = host->max_clk;
+	mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV;
+
+	mmc->max_busy_timeout =  (~(unsigned int)0)/(mmc->f_max/1000);
+
+	pr_debug("f_max %d, f_min %d, max_busy_timeout %d\n",
+		 mmc->f_max, mmc->f_min, mmc->max_busy_timeout);
+
+	/* host controller capabilities */
+	mmc->caps |=
+		MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
+		MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET |
+		((ALLOW_CMD23_READ|ALLOW_CMD23_WRITE) * MMC_CAP_CMD23);
+
+	spin_lock_init(&host->lock);
+
+	if (host->allow_dma) {
+		if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
+			pr_err("%s: unable to initialise DMA channel. "
+			       "Falling back to PIO\n",
+			       mmc_hostname(mmc));
+			host->use_dma = false;
+		} else {
+			cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+			cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+			cfg.slave_id = 13;		/* DREQ channel */
+
+			/* Validate the slave configurations */
+
+			cfg.direction = DMA_MEM_TO_DEV;
+			cfg.src_addr = 0;
+			cfg.dst_addr = host->bus_addr + SDDATA;
+
+			ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
+
+			if (ret == 0) {
+				host->dma_cfg_tx = cfg;
+
+				cfg.direction = DMA_DEV_TO_MEM;
+				cfg.src_addr = host->bus_addr + SDDATA;
+				cfg.dst_addr = 0;
+
+				ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
+			}
+
+			if (ret == 0) {
+				host->dma_cfg_rx = cfg;
+
+				host->use_dma = true;
+			} else {
+				pr_err("%s: unable to configure DMA channel. "
+				       "Falling back to PIO\n",
+				       mmc_hostname(mmc));
+				dma_release_channel(host->dma_chan_rxtx);
+				host->dma_chan_rxtx = NULL;
+				host->use_dma = false;
+			}
+		}
+	} else {
+		host->use_dma = false;
+	}
+
+	mmc->max_segs = 128;
+	mmc->max_req_size = 524288;
+	mmc->max_seg_size = mmc->max_req_size;
+	mmc->max_blk_size = 512;
+	mmc->max_blk_count =  65535;
+
+	/* report supported voltage ranges */
+	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+	tasklet_init(&host->finish_tasklet,
+		bcm2835_sdhost_tasklet_finish, (unsigned long)host);
+
+	INIT_WORK(&host->cmd_wait_wq, bcm2835_sdhost_cmd_wait_work);
+
+	timer_setup(&host->timer, bcm2835_sdhost_timeout, 0);
+
+	bcm2835_sdhost_init(host, 0);
+
+	ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/,
+				  mmc_hostname(mmc), host);
+	if (ret) {
+		pr_err("%s: failed to request IRQ %d: %d\n",
+		       mmc_hostname(mmc), host->irq, ret);
+		goto untasklet;
+	}
+
+	mmc_add_host(mmc);
+
+	pio_limit_string[0] = '\0';
+	if (host->use_dma && (host->pio_limit > 0))
+		sprintf(pio_limit_string, " (>%d)", host->pio_limit);
+	pr_info("%s: %s loaded - DMA %s%s\n",
+		mmc_hostname(mmc), DRIVER_NAME,
+		host->use_dma ? "enabled" : "disabled",
+		pio_limit_string);
+
+	return 0;
+
+untasklet:
+	tasklet_kill(&host->finish_tasklet);
+
+	return ret;
+}
+
+static int bcm2835_sdhost_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct clk *clk;
+	struct resource *iomem;
+	struct bcm2835_host *host;
+	struct mmc_host *mmc;
+	const __be32 *addr;
+	u32 msg[3];
+	int na;
+	int ret;
+
+	pr_debug("bcm2835_sdhost_probe\n");
+	mmc = mmc_alloc_host(sizeof(*host), dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	mmc->ops = &bcm2835_sdhost_ops;
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	host->pio_timeout = msecs_to_jiffies(500);
+	host->pio_limit = 1;
+	host->max_delay = 1; /* Warn if over 1ms */
+	host->allow_dma = 1;
+	spin_lock_init(&host->lock);
+
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->ioaddr = devm_ioremap_resource(dev, iomem);
+	if (IS_ERR(host->ioaddr)) {
+		ret = PTR_ERR(host->ioaddr);
+		goto err;
+	}
+
+	na = of_n_addr_cells(node);
+	addr = of_get_address(node, 0, NULL, NULL);
+	if (!addr) {
+		dev_err(dev, "could not get DMA-register address\n");
+		return -ENODEV;
+	}
+	host->bus_addr = (phys_addr_t)of_read_number(addr, na);
+	pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
+		 (unsigned long)host->ioaddr,
+		 (unsigned long)iomem->start,
+		 (unsigned long)host->bus_addr);
+
+	if (node) {
+		/* Read any custom properties */
+		of_property_read_u32(node,
+				     "brcm,delay-after-stop",
+				     &host->delay_after_stop);
+		of_property_read_u32(node,
+				     "brcm,overclock-50",
+				     &host->user_overclock_50);
+		of_property_read_u32(node,
+				     "brcm,pio-limit",
+				     &host->pio_limit);
+		host->allow_dma =
+			!of_property_read_bool(node, "brcm,force-pio");
+		host->debug = of_property_read_bool(node, "brcm,debug");
+	}
+
+	host->dma_chan = NULL;
+	host->dma_desc = NULL;
+
+	/* Formally recognise the other way of disabling DMA */
+	if (host->pio_limit == 0x7fffffff)
+		host->allow_dma = false;
+
+	if (host->allow_dma) {
+		if (node) {
+			host->dma_chan_rxtx =
+				dma_request_slave_channel(dev, "rx-tx");
+			if (!host->dma_chan_rxtx)
+				host->dma_chan_rxtx =
+					dma_request_slave_channel(dev, "tx");
+			if (!host->dma_chan_rxtx)
+				host->dma_chan_rxtx =
+					dma_request_slave_channel(dev, "rx");
+		} else {
+			dma_cap_mask_t mask;
+
+			dma_cap_zero(mask);
+			/* we don't care about the channel, any would work */
+			dma_cap_set(DMA_SLAVE, mask);
+			host->dma_chan_rxtx =
+				dma_request_channel(mask, NULL, NULL);
+		}
+	}
+
+	clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		if (ret == -EPROBE_DEFER)
+			dev_info(dev, "could not get clk, deferring probe\n");
+		else
+			dev_err(dev, "could not get clk\n");
+		goto err;
+	}
+
+	host->max_clk = clk_get_rate(clk);
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq <= 0) {
+		dev_err(dev, "get IRQ failed\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	pr_debug(" - max_clk %lx, irq %d\n",
+		 (unsigned long)host->max_clk,
+		 (int)host->irq);
+
+	log_init(dev, iomem->start - host->bus_addr);
+
+	if (node)
+		mmc_of_parse(mmc);
+	else
+		mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+	msg[0] = 0;
+	msg[1] = ~0;
+	msg[2] = ~0;
+
+	rpi_firmware_property(rpi_firmware_get(NULL),
+			      RPI_FIRMWARE_SET_SDHOST_CLOCK,
+			      &msg, sizeof(msg));
+
+	host->firmware_sets_cdiv = (msg[1] != ~0);
+
+	ret = bcm2835_sdhost_add_host(host);
+	if (ret)
+		goto err;
+
+	platform_set_drvdata(pdev, host);
+
+	pr_debug("bcm2835_sdhost_probe -> OK\n");
+
+	return 0;
+
+err:
+	pr_debug("bcm2835_sdhost_probe -> err %d\n", ret);
+	if (host->dma_chan_rxtx)
+		dma_release_channel(host->dma_chan_rxtx);
+	mmc_free_host(mmc);
+
+	return ret;
+}
+
+static int bcm2835_sdhost_remove(struct platform_device *pdev)
+{
+	struct bcm2835_host *host = platform_get_drvdata(pdev);
+
+	pr_debug("bcm2835_sdhost_remove\n");
+
+	mmc_remove_host(host->mmc);
+
+	bcm2835_sdhost_set_power(host, false);
+
+	free_irq(host->irq, host);
+
+	del_timer_sync(&host->timer);
+
+	tasklet_kill(&host->finish_tasklet);
+	if (host->dma_chan_rxtx)
+		dma_release_channel(host->dma_chan_rxtx);
+	mmc_free_host(host->mmc);
+	platform_set_drvdata(pdev, NULL);
+
+	pr_debug("bcm2835_sdhost_remove - OK\n");
+	return 0;
+}
+
+static const struct of_device_id bcm2835_sdhost_match[] = {
+	{ .compatible = "brcm,bcm2835-sdhost" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match);
+
+static struct platform_driver bcm2835_sdhost_driver = {
+	.probe      = bcm2835_sdhost_probe,
+	.remove     = bcm2835_sdhost_remove,
+	.driver     = {
+		.name		= DRIVER_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= bcm2835_sdhost_match,
+	},
+};
+module_platform_driver(bcm2835_sdhost_driver);
+
+MODULE_ALIAS("platform:sdhost-bcm2835");
+MODULE_DESCRIPTION("BCM2835 SDHost driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Phil Elwell");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mmc/host/Kconfig linux-5.10.52-v7l+/drivers/mmc/host/Kconfig
--- linux-5.10.52-orig/drivers/mmc/host/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mmc/host/Kconfig	2021-07-25 16:46:09.498231666 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:8 @
 
 comment "MMC/SD/SDIO Host Controller Drivers"
 
+config MMC_BCM2835_MMC
+	tristate "MMC support on BCM2835"
+	depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
+	help
+	  This selects the MMC Interface on BCM2835.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
+config MMC_BCM2835_DMA
+	bool "DMA support on BCM2835 Arasan controller"
+	depends on MMC_BCM2835_MMC
+	help
+	  Enable DMA support on the Arasan SDHCI controller in Broadcom 2708
+	  based chips.
+
+	  If unsure, say N.
+
+config MMC_BCM2835_PIO_DMA_BARRIER
+	int "Block count limit for PIO transfers"
+	depends on MMC_BCM2835_MMC && MMC_BCM2835_DMA
+	range 0 256
+	default 2
+	help
+	  The inclusive limit in bytes under which PIO will be used instead of DMA
+
+	  If unsure, say 2 here.
+
+config MMC_BCM2835_SDHOST
+	tristate "Support for the SDHost controller on BCM2708/9"
+	depends on ARCH_BCM2835
+	help
+	  This selects the SDHost controller on BCM2835/6.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_DEBUG
 	bool "MMC host drivers debugging"
 	depends on MMC != n
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mmc/host/Makefile linux-5.10.52-v7l+/drivers/mmc/host/Makefile
--- linux-5.10.52-orig/drivers/mmc/host/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mmc/host/Makefile	2021-07-25 16:46:09.498231666 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:27 @
 obj-$(CONFIG_MMC_SDHCI_MILBEAUT)	+= sdhci-milbeaut.o
 obj-$(CONFIG_MMC_SDHCI_SPEAR)	+= sdhci-spear.o
 obj-$(CONFIG_MMC_SDHCI_AM654)	+= sdhci_am654.o
+obj-$(CONFIG_MMC_BCM2835_MMC)	+= bcm2835-mmc.o
+obj-$(CONFIG_MMC_BCM2835_SDHOST)	+= bcm2835-sdhost.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
 obj-$(CONFIG_MMC_ALCOR)	+= alcor.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mmc/host/sdhci.c linux-5.10.52-v7l+/drivers/mmc/host/sdhci.c
--- linux-5.10.52-orig/drivers/mmc/host/sdhci.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mmc/host/sdhci.c	2021-07-25 16:46:09.678228648 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:44 @
 	pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
 
 #define SDHCI_DUMP(f, x...) \
-	pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
+	pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
 
 #define MAX_TUNING_LOOP 40
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3129 @
 	spin_lock_irqsave(&host->lock, flags);
 
 	if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
-		pr_err("%s: Timeout waiting for hardware cmd interrupt.\n",
+		pr_debug("%s: Timeout waiting for hardware cmd interrupt.\n",
 		       mmc_hostname(host->mmc));
 		sdhci_dumpregs(host);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3151 @
 
 	if (host->data || host->data_cmd ||
 	    (host->cmd && sdhci_data_line_cmd(host->cmd))) {
-		pr_err("%s: Timeout waiting for hardware interrupt.\n",
+		pr_debug("%s: Timeout waiting for hardware interrupt.\n",
 		       mmc_hostname(host->mmc));
 		sdhci_dumpregs(host);
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/mmc/host/sdhci-iproc.c linux-5.10.52-v7l+/drivers/mmc/host/sdhci-iproc.c
--- linux-5.10.52-orig/drivers/mmc/host/sdhci-iproc.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/mmc/host/sdhci-iproc.c	2021-07-25 16:46:09.618229654 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:176 @
 		return pltfm_host->clock;
 }
 
+static void sdhci_iproc_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 const struct sdhci_ops sdhci_iproc_ops = {
 	.set_clock = sdhci_set_clock,
 	.get_max_clock = sdhci_iproc_get_max_clock,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:204 @
 	.write_b = sdhci_iproc_writeb,
 	.set_clock = sdhci_set_clock,
 	.get_max_clock = sdhci_iproc_get_max_clock,
+	.set_power = sdhci_iproc_set_power,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
 	.set_uhs_signaling = sdhci_set_uhs_signaling,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/ethernet/broadcom/genet/bcmgenet.c linux-5.10.52-v7l+/drivers/net/ethernet/broadcom/genet/bcmgenet.c
--- linux-5.10.52-orig/drivers/net/ethernet/broadcom/genet/bcmgenet.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/ethernet/broadcom/genet/bcmgenet.c	2021-07-25 16:46:11.398199812 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:70 @
 
 /* Forward declarations */
 static void bcmgenet_set_rx_mode(struct net_device *dev);
+static bool skip_umac_reset = false;
+module_param(skip_umac_reset, bool, 0444);
+MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step");
 
 static inline void bcmgenet_writel(u32 value, void __iomem *offset)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2431 @
 	bcmgenet_rbuf_ctrl_set(priv, 0);
 	udelay(10);
 
+	if (skip_umac_reset) {
+		pr_warn("Skipping UMAC reset\n");
+		return;
+	}
+
 	/* issue soft reset and disable MAC while updating its registers */
 	bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD);
 	udelay(2);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2605 @
 
 	bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
 	bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
-	bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
+	bcmgenet_tdma_ring_writel(priv, index, 10, DMA_MBUF_DONE_THRESH);
 	/* Disable rate control for now */
 	bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
 				  TDMA_FLOW_PERIOD);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3246 @
 }
 
 /* Returns a reusable dma control register value */
-static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv)
+static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv, bool flush_rx)
 {
 	u32 reg;
 	u32 dma_ctrl;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3265 @
 	udelay(10);
 	bcmgenet_umac_writel(priv, 0, UMAC_TX_FLUSH);
 
+	if (flush_rx) {
+	    reg = bcmgenet_rbuf_ctrl_get(priv);
+	    bcmgenet_rbuf_ctrl_set(priv, reg | BIT(0));
+	    udelay(10);
+	    bcmgenet_rbuf_ctrl_set(priv, reg);
+	    udelay(10);
+	}
+
 	return dma_ctrl;
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3343 @
 		bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
 	}
 
-	/* Disable RX/TX DMA and flush TX queues */
-	dma_ctrl = bcmgenet_dma_disable(priv);
+	/* Disable RX/TX DMA and flush TX and RX queues */
+	dma_ctrl = bcmgenet_dma_disable(priv, true);
 
 	/* Reinitialize TDMA and RDMA and SW housekeeping */
 	ret = bcmgenet_init_dma(priv);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4077 @
 	netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
 
 	/* Set default coalescing parameters */
-	for (i = 0; i < priv->hw_params->rx_queues; i++)
+	for (i = 0; i < priv->hw_params->rx_queues; i++) {
 		priv->rx_rings[i].rx_max_coalesced_frames = 1;
+		priv->rx_rings[i].rx_coalesce_usecs = 50;
+	}
 	priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1;
+	priv->rx_rings[DESC_INDEX].rx_coalesce_usecs = 50;
 
 	/* libphy will determine the link state */
 	netif_carrier_off(dev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4205 @
 	}
 
 	/* Disable RX/TX DMA and flush TX queues */
-	dma_ctrl = bcmgenet_dma_disable(priv);
+	dma_ctrl = bcmgenet_dma_disable(priv, false);
 
 	/* Reinitialize TDMA and RDMA and SW housekeeping */
 	ret = bcmgenet_init_dma(priv);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/ethernet/broadcom/genet/bcmgenet.h linux-5.10.52-v7l+/drivers/net/ethernet/broadcom/genet/bcmgenet.h
--- linux-5.10.52-orig/drivers/net/ethernet/broadcom/genet/bcmgenet.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/ethernet/broadcom/genet/bcmgenet.h	2021-07-25 16:46:11.398199812 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:32 @
 #define ENET_PAD		8
 #define ENET_MAX_MTU_SIZE	(ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
 				 ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
-#define DMA_MAX_BURST_LENGTH    0x10
+#define DMA_MAX_BURST_LENGTH    0x08
 
 /* misc. configuration */
 #define MAX_NUM_OF_FS_RULES		16
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/ethernet/broadcom/genet/bcmmii.c linux-5.10.52-v7l+/drivers/net/ethernet/broadcom/genet/bcmmii.c
--- linux-5.10.52-orig/drivers/net/ethernet/broadcom/genet/bcmmii.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/ethernet/broadcom/genet/bcmmii.c	2021-07-25 16:46:11.398199812 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:296 @
 	/* Communicate the integrated PHY revision */
 	if (priv->internal_phy)
 		phy_flags = priv->gphy_rev;
+	else
+		phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE;
 
 	/* Initialize link state variables that bcmgenet_mii_setup() uses */
 	priv->old_link = -1;
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/phy/broadcom.c linux-5.10.52-v7l+/drivers/net/phy/broadcom.c
--- linux-5.10.52-orig/drivers/net/phy/broadcom.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/phy/broadcom.c	2021-07-25 16:46:15.808125878 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:85 @
 	return 0;
 }
 
+static int bcm54213pe_config_init(struct phy_device *phydev)
+{
+	return bcm54210e_config_init(phydev);
+}
+
 static int bcm54612e_config_init(struct phy_device *phydev)
 {
 	int reg;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:260 @
 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 &&
-	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811)
+	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811 &&
+	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54213PE)
 		return;
 
 	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:322 @
 static int bcm54xx_config_init(struct phy_device *phydev)
 {
 	int reg, err, val;
+	u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT,
+			   BCM_LED_MULTICOLOR_LINK};
+	struct device_node *np = phydev->mdio.dev.of_node;
 
 	reg = phy_read(phydev, MII_BCM54XX_ECR);
 	if (reg < 0)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:362 @
 	case PHY_ID_BCM54612E:
 		err = bcm54612e_config_init(phydev);
 		break;
+	case PHY_ID_BCM54213PE:
+		err = bcm54213pe_config_init(phydev);
+		break;
 	case PHY_ID_BCM54616S:
 		err = bcm54616s_config_init(phydev);
 		break;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:383 @
 
 	bcm54xx_phydsp_config(phydev);
 
-	/* Encode link speed into LED1 and LED3 pair (green/amber).
-	 * Also flash these two LEDs on activity. This means configuring
-	 * them for MULTICOLOR and encoding link/activity into them.
-	 */
+	of_property_read_u32_array(np, "led-modes", led_modes, 2);
+
 	val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
 		BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
 	bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
 
 	val = BCM_LED_MULTICOLOR_IN_PHASE |
-		BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
-		BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
+		BCM5482_SHD_LEDS1_LED1(led_modes[0]) |
+		BCM5482_SHD_LEDS1_LED3(led_modes[1]);
 	bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
 
 	return 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:775 @
 	.config_intr	= bcm_phy_config_intr,
 }, {
 	.phy_id		= PHY_ID_BCM54210E,
-	.phy_id_mask	= 0xfffffff0,
+	.phy_id_mask	= 0xffffffff,
 	.name		= "Broadcom BCM54210E",
 	/* PHY_GBIT_FEATURES */
 	.config_init	= bcm54xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
 	.config_intr	= bcm_phy_config_intr,
 }, {
+	.phy_id		= PHY_ID_BCM54213PE,
+	.phy_id_mask	= 0xffffffff,
+	.name		= "Broadcom BCM54213PE",
+	/* PHY_GBIT_FEATURES */
+	.config_init	= bcm54xx_config_init,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
+}, {
 	.phy_id		= PHY_ID_BCM5461,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5461",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:944 @
 static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
 	{ PHY_ID_BCM5411, 0xfffffff0 },
 	{ PHY_ID_BCM5421, 0xfffffff0 },
-	{ PHY_ID_BCM54210E, 0xfffffff0 },
+	{ PHY_ID_BCM54210E, 0xffffffff },
+	{ PHY_ID_BCM54213PE, 0xffffffff },
 	{ PHY_ID_BCM5461, 0xfffffff0 },
 	{ PHY_ID_BCM54612E, 0xfffffff0 },
 	{ PHY_ID_BCM54616S, 0xfffffff0 },
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/phy/microchip.c linux-5.10.52-v7l+/drivers/net/phy/microchip.c
--- linux-5.10.52-orig/drivers/net/phy/microchip.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/phy/microchip.c	2021-07-25 16:46:15.848125208 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:220 @
 	struct device *dev = &phydev->mdio.dev;
 	struct lan88xx_priv *priv;
 	u32 led_modes[4];
+	u32 downshift_after = 0;
 	int len;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:250 @
 		return -EINVAL;
 	}
 
+	if (!of_property_read_u32(dev->of_node,
+				  "microchip,downshift-after",
+				  &downshift_after)) {
+		u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK;
+		u32 val= LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+
+		switch (downshift_after) {
+		case 2:	val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2;
+			break;
+		case 3:	val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3;
+			break;
+		case 4:	val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4;
+			break;
+		case 5:	val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5;
+			break;
+		case 0: // Disable completely
+			mask = LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+			val = 0;
+			break;
+		default:
+			return -EINVAL;
+		}
+		(void)phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
+				       mask, val);
+	}
+
 	/* these values can be used to identify internal PHY */
 	priv->chip_id = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_ID);
 	priv->chip_rev = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_REV);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/usb/lan78xx.c linux-5.10.52-v7l+/drivers/net/usb/lan78xx.c
--- linux-5.10.52-orig/drivers/net/usb/lan78xx.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/usb/lan78xx.c	2021-07-25 16:46:16.018122357 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:428 @
 module_param(msg_level, int, 0);
 MODULE_PARM_DESC(msg_level, "Override default message level");
 
+/* TSO seems to be having some issue with Selective Acknowledge (SACK) that
+ * results in lost data never being retransmitted.
+ * Disable it by default now, but adds a module parameter to enable it for
+ * debug purposes (the full cause is not currently understood).
+ */
+static bool enable_tso;
+module_param(enable_tso, bool, 0644);
+MODULE_PARM_DESC(enable_tso, "Enables TCP segmentation offload");
+
+#define INT_URB_MICROFRAMES_PER_MS	8
+static int int_urb_interval_ms = 8;
+module_param(int_urb_interval_ms, int, 0);
+MODULE_PARM_DESC(int_urb_interval_ms, "Override usb interrupt urb interval");
+
 static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
 {
 	u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1184 @
 	if (unlikely(ret < 0))
 		return -EIO;
 
+	/* Acknowledge any pending PHY interrupt, lest it be the last */
+	phy_read(phydev, LAN88XX_INT_STS);
+
 	phy_read_status(phydev);
 
 	if (!phydev->link && dev->link_on) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2178 @
 	mii_adv_to_linkmode_adv_t(fc, mii_adv);
 	linkmode_or(phydev->advertising, fc, phydev->advertising);
 
+	if (of_property_read_bool(phydev->mdio.dev.of_node,
+				  "microchip,eee-enabled")) {
+		struct ethtool_eee edata;
+		memset(&edata, 0, sizeof(edata));
+		edata.cmd = ETHTOOL_SEEE;
+		edata.advertised = ADVERTISED_1000baseT_Full |
+				   ADVERTISED_100baseT_Full;
+		edata.eee_enabled = true;
+		edata.tx_lpi_enabled = true;
+		if (of_property_read_u32(dev->udev->dev.of_node,
+					 "microchip,tx-lpi-timer",
+					 &edata.tx_lpi_timer))
+			edata.tx_lpi_timer = 600; /* non-aggressive */
+		(void)lan78xx_set_eee(dev->net, &edata);
+	}
+
 	if (phydev->mdio.dev.of_node) {
 		u32 reg;
 		int len;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2489 @
 	int ret = 0;
 	unsigned long timeout;
 	u8 sig;
+	bool has_eeprom;
+	bool has_otp;
+
+	has_eeprom = !lan78xx_read_eeprom(dev, 0, 0, NULL);
+	has_otp = !lan78xx_read_otp(dev, 0, 0, NULL);
 
 	ret = lan78xx_read_reg(dev, HW_CFG, &buf);
 	buf |= HW_CFG_LRST_;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2547 @
 
 	ret = lan78xx_read_reg(dev, HW_CFG, &buf);
 	buf |= HW_CFG_MEF_;
+	/* If no valid EEPROM and no valid OTP, enable the LEDs by default */
+	if (!has_eeprom && !has_otp)
+	    buf |= HW_CFG_LED0_EN_ | HW_CFG_LED1_EN_;
 	ret = lan78xx_write_reg(dev, HW_CFG, buf);
 
 	ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2605 @
 			buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
 		}
 	}
+	/* If no valid EEPROM and no valid OTP, enable AUTO negotiation */
+	if (!has_eeprom && !has_otp)
+	    buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
 	ret = lan78xx_write_reg(dev, MAC_CR, buf);
 
 	ret = lan78xx_read_reg(dev, MAC_TX, &buf);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2937 @
 	if (DEFAULT_RX_CSUM_ENABLE)
 		dev->net->features |= NETIF_F_RXCSUM;
 
-	if (DEFAULT_TSO_CSUM_ENABLE)
-		dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG;
+	if (DEFAULT_TSO_CSUM_ENABLE) {
+		dev->net->features |= NETIF_F_SG;
+		/* Use module parameter to control TCP segmentation offload as
+		 * it appears to cause issues.
+		 */
+		if (enable_tso)
+			dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6;
+	}
 
 	if (DEFAULT_VLAN_RX_OFFLOAD)
 		dev->net->features |= NETIF_F_HW_VLAN_CTAG_RX;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3167 @
 	size_t size = dev->rx_urb_size;
 	int ret = 0;
 
-	skb = netdev_alloc_skb_ip_align(dev->net, size);
+	skb = netdev_alloc_skb(dev->net, size);
 	if (!skb) {
 		usb_free_urb(urb);
 		return -ENOMEM;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3771 @
 	netdev->max_mtu = MAX_SINGLE_PACKET_SIZE;
 	netif_set_gso_max_size(netdev, MAX_SINGLE_PACKET_SIZE - MAX_HEADER);
 
-	period = ep_intr->desc.bInterval;
+	if (int_urb_interval_ms <= 0)
+		period = ep_intr->desc.bInterval;
+	else
+		period = int_urb_interval_ms * INT_URB_MICROFRAMES_PER_MS;
+
+	netif_notice(dev, probe, netdev, "int urb period %d\n", period);
+
 	maxp = usb_maxpacket(dev->udev, dev->pipe_intr, 0);
 	buf = kmalloc(maxp, GFP_KERNEL);
 	if (buf) {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/usb/Makefile linux-5.10.52-v7l+/drivers/net/usb/Makefile
--- linux-5.10.52-orig/drivers/net/usb/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/usb/Makefile	2021-07-25 16:46:15.958123363 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:16 @
 obj-$(CONFIG_USB_NET_AX8817X)	+= asix.o
 asix-y := asix_devices.o asix_common.o ax88172a.o
 obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
-obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
+obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o r8153_ecm.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
 obj-$(CONFIG_USB_NET_SR9700)	+= sr9700.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/usb/r8152.c linux-5.10.52-v7l+/drivers/net/usb/r8152.c
--- linux-5.10.52-orig/drivers/net/usb/r8152.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/usb/r8152.c	2021-07-25 16:46:16.038122022 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:29 @
 #include <linux/acpi.h>
 #include <linux/firmware.h>
 #include <crypto/hash.h>
+#include <linux/usb/r8152.h>
 
 /* Information for net-next */
-#define NETNEXT_VERSION		"11"
+#define NETNEXT_VERSION		"12"
 
 /* Information for net */
 #define NET_VERSION		"11"
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:46 @
 
 #define PLA_IDR			0xc000
 #define PLA_RCR			0xc010
+#define PLA_RCR1		0xc012
 #define PLA_RMS			0xc016
 #define PLA_RXFIFO_CTRL0	0xc0a0
+#define PLA_RXFIFO_FULL		0xc0a2
 #define PLA_RXFIFO_CTRL1	0xc0a4
+#define PLA_RX_FIFO_FULL	0xc0a6
 #define PLA_RXFIFO_CTRL2	0xc0a8
+#define PLA_RX_FIFO_EMPTY	0xc0aa
 #define PLA_DMY_REG0		0xc0b0
 #define PLA_FMC			0xc0b4
 #define PLA_CFG_WOL		0xc0b6
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:70 @
 #define PLA_MACDBG_PRE		0xd38c	/* RTL_VER_04 only */
 #define PLA_MACDBG_POST		0xd38e	/* RTL_VER_04 only */
 #define PLA_EXTRA_STATUS	0xd398
+#define PLA_GPHY_CTRL		0xd3ae
+#define PLA_POL_GPIO_CTRL	0xdc6a
 #define PLA_EFUSE_DATA		0xdd00
 #define PLA_EFUSE_CMD		0xdd02
 #define PLA_LEDSEL		0xdd90
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:81 @
 #define PLA_LWAKE_CTRL_REG	0xe007
 #define PLA_GPHY_INTR_IMR	0xe022
 #define PLA_EEE_CR		0xe040
+#define PLA_EEE_TXTWSYS		0xe04c
+#define PLA_EEE_TXTWSYS_2P5G	0xe058
 #define PLA_EEEP_CR		0xe080
 #define PLA_MAC_PWR_CTRL	0xe0c0
 #define PLA_MAC_PWR_CTRL2	0xe0ca
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:93 @
 #define PLA_TCR1		0xe612
 #define PLA_MTPS		0xe615
 #define PLA_TXFIFO_CTRL		0xe618
+#define PLA_TXFIFO_FULL		0xe61a
 #define PLA_RSTTALLY		0xe800
 #define PLA_CR			0xe813
 #define PLA_CRWECR		0xe81c
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:110 @
 #define PLA_SFF_STS_7		0xe8de
 #define PLA_PHYSTATUS		0xe908
 #define PLA_CONFIG6		0xe90a /* CONFIG6 */
+#define PLA_USB_CFG		0xe952
 #define PLA_BP_BA		0xfc26
 #define PLA_BP_0		0xfc28
 #define PLA_BP_1		0xfc2a
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:125 @
 #define USB_USB2PHY		0xb41e
 #define USB_SSPHYLINK1		0xb426
 #define USB_SSPHYLINK2		0xb428
+#define USB_L1_CTRL		0xb45e
 #define USB_U2P3_CTRL		0xb460
 #define USB_CSR_DUMMY1		0xb464
 #define USB_CSR_DUMMY2		0xb466
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:136 @
 #define USB_FW_FIX_EN0		0xcfca
 #define USB_FW_FIX_EN1		0xcfcc
 #define USB_LPM_CONFIG		0xcfd8
+#define USB_ECM_OPTION		0xcfee
 #define USB_CSTMR		0xcfef	/* RTL8153A */
+#define USB_MISC_2		0xcfff
+#define USB_ECM_OP		0xd26b
+#define USB_GPHY_CTRL		0xd284
+#define USB_SPEED_OPTION	0xd32a
 #define USB_FW_CTRL		0xd334	/* RTL8153B */
 #define USB_FC_TIMER		0xd340
 #define USB_USB_CTRL		0xd406
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:155 @
 #define USB_RX_EXTRA_AGGR_TMR	0xd432	/* RTL8153B */
 #define USB_TX_DMA		0xd434
 #define USB_UPT_RXDMA_OWN	0xd437
+#define USB_UPHY3_MDCMDIO	0xd480
 #define USB_TOLERANCE		0xd490
 #define USB_LPM_CTRL		0xd41a
 #define USB_BMU_RESET		0xd4b0
+#define USB_BMU_CONFIG		0xd4b4
 #define USB_U1U2_TIMER		0xd4da
 #define USB_FW_TASK		0xd4e8	/* RTL8153B */
+#define USB_RX_AGGR_NUM		0xd4ee
 #define USB_UPS_CTRL		0xd800
 #define USB_POWER_CUT		0xd80a
 #define USB_MISC_0		0xd81a
 #define USB_MISC_1		0xd81f
 #define USB_AFE_CTRL2		0xd824
+#define USB_UPHY_XTAL		0xd826
 #define USB_UPS_CFG		0xd842
 #define USB_UPS_FLAGS		0xd848
 #define USB_WDT1_CTRL		0xe404
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:211 @
 #define OCP_EEE_ABLE		0xa5c4
 #define OCP_EEE_ADV		0xa5d0
 #define OCP_EEE_LPABLE		0xa5d2
+#define OCP_10GBT_CTRL		0xa5d4
+#define OCP_10GBT_STAT		0xa5d6
+#define OCP_EEE_ADV2		0xa6d4
 #define OCP_PHY_STATE		0xa708		/* nway state for 8153 */
 #define OCP_PHY_PATCH_STAT	0xb800
 #define OCP_PHY_PATCH_CMD	0xb820
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:225 @
 /* SRAM Register */
 #define SRAM_GREEN_CFG		0x8011
 #define SRAM_LPF_CFG		0x8012
+#define SRAM_GPHY_FW_VER	0x801e
 #define SRAM_10M_AMP1		0x8080
 #define SRAM_10M_AMP2		0x8082
 #define SRAM_IMPEDANCE		0x8084
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:237 @
 #define RCR_AM			0x00000004
 #define RCR_AB			0x00000008
 #define RCR_ACPT_ALL		(RCR_AAP | RCR_APM | RCR_AM | RCR_AB)
+#define SLOT_EN			BIT(11)
+
+/* PLA_RCR1 */
+#define OUTER_VLAN		BIT(7)
+#define INNER_VLAN		BIT(6)
 
 /* PLA_RXFIFO_CTRL0 */
 #define RXFIFO_THR1_NORMAL	0x00080002
 #define RXFIFO_THR1_OOB		0x01800003
 
+/* PLA_RXFIFO_FULL */
+#define RXFIFO_FULL_MASK	0xfff
+
 /* PLA_RXFIFO_CTRL1 */
 #define RXFIFO_THR2_FULL	0x00000060
 #define RXFIFO_THR2_HIGH	0x00000038
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:284 @
 
 /* PLA_TCR1 */
 #define VERSION_MASK		0x7cf0
+#define IFG_MASK		(BIT(3) | BIT(9) | BIT(8))
+#define IFG_144NS		BIT(9)
+#define IFG_96NS		(BIT(9) | BIT(8))
 
 /* PLA_MTPS */
 #define MTPS_JUMBO		(12 * 1024 / 64)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:320 @
 #define MCU_BORW_EN		0x4000
 
 /* PLA_CPCR */
+#define FLOW_CTRL_EN		BIT(0)
 #define CPCR_RX_VLAN		0x0040
 
 /* PLA_CFG_WOL */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:346 @
 /* PLA_CONFIG6 */
 #define LANWAKE_CLR_EN		BIT(0)
 
+/* PLA_USB_CFG */
+#define EN_XG_LIP		BIT(1)
+#define EN_G_LIP		BIT(2)
+
 /* PLA_CONFIG5 */
 #define BWF_EN			0x0040
 #define MWF_EN			0x0020
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:373 @
 /* PLA_MAC_PWR_CTRL2 */
 #define EEE_SPDWN_RATIO		0x8007
 #define MAC_CLK_SPDWN_EN	BIT(15)
+#define EEE_SPDWN_RATIO_MASK	0xff
 
 /* PLA_MAC_PWR_CTRL3 */
 #define PLA_MCU_SPDWN_EN	BIT(14)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:386 @
 #define PWRSAVE_SPDWN_EN	0x1000
 #define RXDV_SPDWN_EN		0x0800
 #define TX10MIDLE_EN		0x0100
+#define IDLE_SPDWN_EN		BIT(6)
 #define TP100_SPDWN_EN		0x0020
 #define TP500_SPDWN_EN		0x0010
 #define TP1000_SPDWN_EN		0x0008
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:427 @
 #define LINK_CHANGE_FLAG	BIT(8)
 #define POLL_LINK_CHG		BIT(0)
 
+/* PLA_GPHY_CTRL */
+#define GPHY_FLASH		BIT(1)
+
+/* PLA_POL_GPIO_CTRL */
+#define DACK_DET_EN		BIT(15)
+#define POL_GPHY_PATCH		BIT(4)
+
 /* USB_USB2PHY */
 #define USB2PHY_SUSPEND		0x0001
 #define USB2PHY_L1		0x0002
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:482 @
 #define BMU_RESET_EP_IN		0x01
 #define BMU_RESET_EP_OUT	0x02
 
+/* USB_BMU_CONFIG */
+#define ACT_ODMA		BIT(1)
+
 /* USB_UPT_RXDMA_OWN */
 #define OWN_UPDATE		BIT(0)
 #define OWN_CLEAR		BIT(1)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:492 @
 /* USB_FW_TASK */
 #define FC_PATCH_TASK		BIT(1)
 
+/* USB_RX_AGGR_NUM */
+#define RX_AGGR_NUM_MASK	0x1ff
+
 /* USB_UPS_CTRL */
 #define POWER_CUT		0x0100
 
 /* USB_PM_CTRL_STATUS */
 #define RESUME_INDICATE		0x0001
 
+/* USB_ECM_OPTION */
+#define BYPASS_MAC_RESET	BIT(5)
+
 /* USB_CSTMR */
 #define FORCE_SUPER		BIT(0)
 
+/* USB_MISC_2 */
+#define UPS_FORCE_PWR_DOWN	BIT(0)
+
+/* USB_ECM_OP */
+#define	EN_ALL_SPEED		BIT(0)
+
+/* USB_GPHY_CTRL */
+#define GPHY_PATCH_DONE		BIT(2)
+#define BYPASS_FLASH		BIT(5)
+#define BACKUP_RESTRORE		BIT(6)
+
+/* USB_SPEED_OPTION */
+#define RG_PWRDN_EN		BIT(8)
+#define ALL_SPEED_OFF		BIT(9)
+
 /* USB_FW_CTRL */
 #define FLOW_CTRL_PATCH_OPT	BIT(1)
+#define AUTO_SPEEDUP		BIT(3)
+#define FLOW_CTRL_PATCH_2	BIT(8)
 
 /* USB_FC_TIMER */
 #define CTRL_TIMER_EN		BIT(15)
 
 /* USB_USB_CTRL */
+#define CDC_ECM_EN		BIT(3)
 #define RX_AGG_DISABLE		0x0010
 #define RX_ZERO_EN		0x0080
 
 /* USB_U2P3_CTRL */
 #define U2P3_ENABLE		0x0001
+#define RX_DETECT8		BIT(3)
 
 /* USB_POWER_CUT */
 #define PWR_EN			0x0001
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:573 @
 #define SEN_VAL_NORMAL		0xa000
 #define SEL_RXIDLE		0x0100
 
+/* USB_UPHY_XTAL */
+#define OOBS_POLLING		BIT(8)
+
 /* USB_UPS_CFG */
 #define SAW_CNT_1MS_MASK	0x0fff
+#define MID_REVERSE		BIT(5)	/* RTL8156A */
 
 /* USB_UPS_FLAGS */
 #define UPS_FLAGS_R_TUNE		BIT(0)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:586 @
 #define UPS_FLAGS_250M_CKDIV		BIT(2)
 #define UPS_FLAGS_EN_ALDPS		BIT(3)
 #define UPS_FLAGS_CTAP_SHORT_DIS	BIT(4)
+#define UPS_FLAGS_SPEED_MASK		(0xf << 16)
 #define ups_flags_speed(x)		((x) << 16)
 #define UPS_FLAGS_EN_EEE		BIT(20)
 #define UPS_FLAGS_EN_500M_EEE		BIT(21)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:607 @
 	FORCE_10M_FULL,
 	FORCE_100M_HALF,
 	FORCE_100M_FULL,
+	FORCE_1000M_FULL,
+	NWAY_2500M_FULL,
 };
 
 /* OCP_ALDPS_CONFIG */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:673 @
 #define EN_10M_CLKDIV		BIT(11)
 #define EN_10M_BGOFF		0x0080
 
+/* OCP_10GBT_CTRL */
+#define RTL_ADV2_5G_F_R		BIT(5)	/* Advertise 2.5GBASE-T fast-retrain */
+
 /* OCP_PHY_STATE */
 #define TXDIS_STATE		0x01
 #define ABD_STATE		0x02
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:695 @
 #define EN_EMI_L		0x0040
 
 /* OCP_SYSCLK_CFG */
-#define clk_div_expo(x)		(min(x, 5) << 8)
+#define sysclk_div_expo(x)	(min(x, 5) << 8)
+#define clk_div_expo(x)		(min(x, 5) << 4)
 
 /* SRAM_GREEN_CFG */
 #define GREEN_ETH_EN		BIT(15)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:727 @
 #define BP4_SUPER_ONLY		0x1578	/* RTL_VER_04 only */
 
 enum rtl_register_content {
+	_2500bps	= BIT(10),
+	_1250bps	= BIT(9),
+	_500bps		= BIT(8),
+	_tx_flow	= BIT(6),
+	_rx_flow	= BIT(5),
 	_1000bps	= 0x10,
 	_100bps		= 0x08,
 	_10bps		= 0x04,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:739 @
 	FULL_DUP	= 0x01,
 };
 
+#define is_speed_2500(_speed)	(((_speed) & (_2500bps | LINK_STATUS)) == (_2500bps | LINK_STATUS))
+#define is_flow_control(_speed)	(((_speed) & (_tx_flow | _rx_flow)) == (_tx_flow | _rx_flow))
+
 #define RTL8152_MAX_TX		4
 #define RTL8152_MAX_RX		10
 #define INTBUFSIZE		2
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:753 @
 
 #define INTR_LINK		0x0004
 
-#define RTL8152_REQT_READ	0xc0
-#define RTL8152_REQT_WRITE	0x40
-#define RTL8152_REQ_GET_REGS	0x05
-#define RTL8152_REQ_SET_REGS	0x05
-
-#define BYTE_EN_DWORD		0xff
-#define BYTE_EN_WORD		0x33
-#define BYTE_EN_BYTE		0x11
-#define BYTE_EN_SIX_BYTES	0x3f
-#define BYTE_EN_START_MASK	0x0f
-#define BYTE_EN_END_MASK	0xf0
-
-#define RTL8153_MAX_PACKET	9216 /* 9K */
-#define RTL8153_MAX_MTU		(RTL8153_MAX_PACKET - VLAN_ETH_HLEN - \
-				 ETH_FCS_LEN)
 #define RTL8152_RMS		(VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
 #define RTL8153_RMS		RTL8153_MAX_PACKET
 #define RTL8152_TX_TIMEOUT	(5 * HZ)
-#define RTL8152_NAPI_WEIGHT	64
-#define rx_reserved_size(x)	((x) + VLAN_ETH_HLEN + ETH_FCS_LEN + \
-				 sizeof(struct rx_desc) + RX_ALIGN)
+#define mtu_to_size(m)		((m) + VLAN_ETH_HLEN + ETH_FCS_LEN)
+#define size_to_mtu(s)		((s) - VLAN_ETH_HLEN - ETH_FCS_LEN)
+#define rx_reserved_size(x)	(mtu_to_size(x) + sizeof(struct rx_desc) + RX_ALIGN)
 
 /* rtl8152 flags */
 enum rtl8152_flags {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:774 @
 	LENOVO_MACPASSTHRU,
 };
 
-/* Define these values to match your device */
-#define VENDOR_ID_REALTEK		0x0bda
-#define VENDOR_ID_MICROSOFT		0x045e
-#define VENDOR_ID_SAMSUNG		0x04e8
-#define VENDOR_ID_LENOVO		0x17ef
-#define VENDOR_ID_LINKSYS		0x13b1
-#define VENDOR_ID_NVIDIA		0x0955
-#define VENDOR_ID_TPLINK		0x2357
-
 #define DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2	0x3082
 #define DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2		0xa387
 
-#define MCU_TYPE_PLA			0x0100
-#define MCU_TYPE_USB			0x0000
-
 struct tally_counter {
 	__le64	tx_packets;
 	__le64	rx_packets;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:888 @
 		bool (*in_nway)(struct r8152 *tp);
 		void (*hw_phy_cfg)(struct r8152 *tp);
 		void (*autosuspend_en)(struct r8152 *tp, bool enable);
+		void (*change_mtu)(struct r8152 *tp);
 	} rtl_ops;
 
 	struct ups_info {
+		u32 r_tune:1;
 		u32 _10m_ckdiv:1;
 		u32 _250m_ckdiv:1;
 		u32 aldps:1;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:934 @
 	u32 rx_buf_sz;
 	u32 rx_copybreak;
 	u32 rx_pending;
+	u32 fc_pause_on, fc_pause_off;
 
+	u32 support_2500full:1;
 	u16 ocp_base;
 	u16 speed;
 	u16 eee_adv;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:971 @
 	struct fw_block blocks[];
 } __packed;
 
+enum rtl8152_fw_flags {
+	FW_FLAGS_USB = 0,
+	FW_FLAGS_PLA,
+	FW_FLAGS_START,
+	FW_FLAGS_STOP,
+	FW_FLAGS_NC,
+	FW_FLAGS_NC1,
+	FW_FLAGS_NC2,
+	FW_FLAGS_UC2,
+	FW_FLAGS_UC,
+	FW_FLAGS_SPEED_UP,
+	FW_FLAGS_VER,
+};
+
+enum rtl8152_fw_fixup_cmd {
+	FW_FIXUP_AND = 0,
+	FW_FIXUP_OR,
+	FW_FIXUP_NOT,
+	FW_FIXUP_XOR,
+};
+
+struct fw_phy_set {
+	__le16 addr;
+	__le16 data;
+} __packed;
+
+struct fw_phy_speed_up {
+	struct fw_block blk_hdr;
+	__le16 fw_offset;
+	__le16 version;
+	__le16 fw_reg;
+	__le16 reserved;
+	char info[];
+} __packed;
+
+struct fw_phy_ver {
+	struct fw_block blk_hdr;
+	struct fw_phy_set ver;
+	__le32 reserved;
+} __packed;
+
+struct fw_phy_fixup {
+	struct fw_block blk_hdr;
+	struct fw_phy_set setting;
+	__le16 bit_cmd;
+	__le16 reserved;
+} __packed;
+
+struct fw_phy_union {
+	struct fw_block blk_hdr;
+	__le16 fw_offset;
+	__le16 fw_reg;
+	struct fw_phy_set pre_set[2];
+	struct fw_phy_set bp[8];
+	struct fw_phy_set bp_en;
+	u8 pre_num;
+	u8 bp_num;
+	char info[];
+} __packed;
+
 /**
  * struct fw_mac - a firmware block used by RTL_FW_PLA and RTL_FW_USB.
  *	The layout of the firmware block is:
  *	<struct fw_mac> + <info> + <firmware data>.
+ * @blk_hdr: firmware descriptor (type, length)
  * @fw_offset: offset of the firmware binary data. The start address of
  *	the data would be the address of struct fw_mac + @fw_offset.
  * @fw_reg: the register to load the firmware. Depends on chip.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1049 @
  * @bp_num: the break point number which needs to be set for this firmware.
  *	Depends on the firmware.
  * @bp: break points. Depends on firmware.
+ * @reserved: reserved space (unused)
  * @fw_ver_reg: the register to store the fw version.
  * @fw_ver_data: the firmware version of the current type.
  * @info: additional information for debugging, and is followed by the
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1075 @
 /**
  * struct fw_phy_patch_key - a firmware block used by RTL_FW_PHY_START.
  *	This is used to set patch key when loading the firmware of PHY.
+ * @blk_hdr: firmware descriptor (type, length)
  * @key_reg: the register to write the patch key.
  * @key_data: patch key.
+ * @reserved: reserved space (unused)
  */
 struct fw_phy_patch_key {
 	struct fw_block blk_hdr;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1091 @
  * struct fw_phy_nc - a firmware block used by RTL_FW_PHY_NC.
  *	The layout of the firmware block is:
  *	<struct fw_phy_nc> + <info> + <firmware data>.
+ * @blk_hdr: firmware descriptor (type, length)
  * @fw_offset: offset of the firmware binary data. The start address of
  *	the data would be the address of struct fw_phy_nc + @fw_offset.
  * @fw_reg: the register to load the firmware. Depends on chip.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1100 @
  * @patch_en_addr: the register of enabling patch mode. Depends on chip.
  * @patch_en_value: patch mode enabled mask. Depends on the firmware.
  * @mode_reg: the regitster of switching the mode.
- * @mod_pre: the mode needing to be set before loading the firmware.
- * @mod_post: the mode to be set when finishing to load the firmware.
+ * @mode_pre: the mode needing to be set before loading the firmware.
+ * @mode_post: the mode to be set when finishing to load the firmware.
+ * @reserved: reserved space (unused)
  * @bp_start: the start register of break points. Depends on chip.
  * @bp_num: the break point number which needs to be set for this firmware.
  *	Depends on the firmware.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1135 @
 	RTL_FW_PHY_START,
 	RTL_FW_PHY_STOP,
 	RTL_FW_PHY_NC,
+	RTL_FW_PHY_FIXUP,
+	RTL_FW_PHY_UNION_NC,
+	RTL_FW_PHY_UNION_NC1,
+	RTL_FW_PHY_UNION_NC2,
+	RTL_FW_PHY_UNION_UC2,
+	RTL_FW_PHY_UNION_UC,
+	RTL_FW_PHY_UNION_MISC,
+	RTL_FW_PHY_SPEED_UP,
+	RTL_FW_PHY_VER,
 };
 
 enum rtl_version {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1157 @
 	RTL_VER_07,
 	RTL_VER_08,
 	RTL_VER_09,
+
+	RTL_TEST_01,
+	RTL_VER_10,
+	RTL_VER_11,
+	RTL_VER_12,
+	RTL_VER_13,
+	RTL_VER_14,
+	RTL_VER_15,
+
 	RTL_VER_MAX
 };
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1181 @
 #define RTL_ADVERTISED_100_FULL			BIT(3)
 #define RTL_ADVERTISED_1000_HALF		BIT(4)
 #define RTL_ADVERTISED_1000_FULL		BIT(5)
+#define RTL_ADVERTISED_2500_FULL		BIT(6)
 
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
  * The RTL chips use a 64 element hash table based on the Ethernet CRC.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1189 @
 static const int multicast_filter_limit = 32;
 static unsigned int agg_buf_sz = 16384;
 
-#define RTL_LIMITED_TSO_SIZE	(agg_buf_sz - sizeof(struct tx_desc) - \
-				 VLAN_ETH_HLEN - ETH_FCS_LEN)
+#define RTL_LIMITED_TSO_SIZE	(size_to_mtu(agg_buf_sz) - sizeof(struct tx_desc))
 
 static
 int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1549 @
 static int
 r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
 
+static int
+rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
+		  u32 advertising);
+
 static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
 {
 	struct r8152 *tp = netdev_priv(netdev);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2575 @
 	} while (res == 0);
 }
 
-static void bottom_half(unsigned long data)
+static void bottom_half(struct tasklet_struct *t)
 {
-	struct r8152 *tp;
-
-	tp = (struct r8152 *)data;
+	struct r8152 *tp = from_tasklet(tp, t, tx_tl);
 
 	if (test_bit(RTL8152_UNPLUG, &tp->flags))
 		return;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2775 @
 
 static void r8152b_reset_packet_filter(struct r8152 *tp)
 {
-	u32	ocp_data;
+	u32 ocp_data;
 
 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC);
 	ocp_data &= ~FMC_FCR_MCU_EN;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2786 @
 
 static void rtl8152_nic_reset(struct r8152 *tp)
 {
-	int	i;
+	u32 ocp_data;
+	int i;
 
-	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST);
+	switch (tp->version) {
+	case RTL_TEST_01:
+	case RTL_VER_10:
+	case RTL_VER_11:
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
+		ocp_data &= ~CR_TE;
+		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_RESET);
+		ocp_data &= ~BMU_RESET_EP_IN;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+		ocp_data |= CDC_ECM_EN;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
+		ocp_data &= ~CR_RE;
+		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_RESET);
+		ocp_data |= BMU_RESET_EP_IN;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+		ocp_data &= ~CDC_ECM_EN;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+		break;
 
-	for (i = 0; i < 1000; i++) {
-		if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST))
-			break;
-		usleep_range(100, 400);
+	default:
+		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST);
+
+		for (i = 0; i < 1000; i++) {
+			if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST))
+				break;
+			usleep_range(100, 400);
+		}
+		break;
 	}
 }
 
 static void set_tx_qlen(struct r8152 *tp)
 {
-	struct net_device *netdev = tp->netdev;
-
-	tp->tx_qlen = agg_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN +
-				    sizeof(struct tx_desc));
+	tp->tx_qlen = agg_buf_sz / (mtu_to_size(tp->netdev->mtu) + sizeof(struct tx_desc));
 }
 
-static inline u8 rtl8152_get_speed(struct r8152 *tp)
+static inline u16 rtl8152_get_speed(struct r8152 *tp)
 {
-	return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
+	return ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
 }
 
-static void rtl_set_eee_plus(struct r8152 *tp)
+static void rtl_eee_plus_en(struct r8152 *tp, bool enable)
 {
 	u32 ocp_data;
-	u8 speed;
 
-	speed = rtl8152_get_speed(tp);
-	if (speed & _10bps) {
-		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
+	if (enable)
 		ocp_data |= EEEP_CR_EEEP_TX;
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
-	} else {
-		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
+	else
 		ocp_data &= ~EEEP_CR_EEEP_TX;
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
-	}
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
+}
+
+static void rtl_set_eee_plus(struct r8152 *tp)
+{
+	if (rtl8152_get_speed(tp) & _10bps)
+		rtl_eee_plus_en(tp, true);
+	else
+		rtl_eee_plus_en(tp, false);
 }
 
 static void rxdy_gated_en(struct r8152 *tp, bool enable)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2955 @
 	return 0;
 }
 
+static void rtl_set_ifg(struct r8152 *tp, u16 speed)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1);
+	ocp_data &= ~IFG_MASK;
+	if ((speed & (_10bps | _100bps)) && !(speed & FULL_DUP)) {
+		ocp_data |= IFG_144NS;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR1, ocp_data);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
+		ocp_data &= ~TX10MIDLE_EN;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
+	} else {
+		ocp_data |= IFG_96NS;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR1, ocp_data);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
+		ocp_data |= TX10MIDLE_EN;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
+	}
+}
+
 static inline void r8153b_rx_agg_chg_indicate(struct r8152 *tp)
 {
 	ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2997 @
 	switch (tp->version) {
 	case RTL_VER_08:
 	case RTL_VER_09:
+	case RTL_VER_14:
 		r8153b_rx_agg_chg_indicate(tp);
 		break;
 	default:
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3035 @
 
 	case RTL_VER_08:
 	case RTL_VER_09:
+	case RTL_VER_14:
 		/* The RTL8153B uses USB_RX_EXTRA_AGGR_TMR for rx timeout
 		 * primarily. For USB_RX_EARLY_TIMEOUT, we fix it to 128ns.
 		 */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3045 @
 			       ocp_data);
 		break;
 
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_15:
+		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT,
+			       640 / 8);
+		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR,
+			       ocp_data);
+		r8153b_rx_agg_chg_indicate(tp);
+		break;
+
 	default:
 		break;
 	}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3076 @
 		break;
 	case RTL_VER_08:
 	case RTL_VER_09:
+	case RTL_VER_14:
+		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
+			       ocp_data / 8);
+		break;
+	case RTL_TEST_01:
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_15:
 		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
 			       ocp_data / 8);
+		r8153b_rx_agg_chg_indicate(tp);
 		break;
 	default:
 		WARN_ON_ONCE(1);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3098 @
 
 static int rtl8153_enable(struct r8152 *tp)
 {
+	u32 ocp_data;
+
 	if (test_bit(RTL8152_UNPLUG, &tp->flags))
 		return -ENODEV;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3108 @
 	r8153_set_rx_early_timeout(tp);
 	r8153_set_rx_early_size(tp);
 
-	if (tp->version == RTL_VER_09) {
-		u32 ocp_data;
+	rtl_set_ifg(tp, rtl8152_get_speed(tp));
 
+	switch (tp->version) {
+	case RTL_VER_09:
+	case RTL_VER_14:
 		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
 		ocp_data &= ~FC_PATCH_TASK;
 		ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
 		usleep_range(1000, 2000);
 		ocp_data |= FC_PATCH_TASK;
 		ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
+		break;
+	default:
+		break;
 	}
 
 	return rtl_enable(tp);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3186 @
 {
 	u32 ocp_data;
 
-	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
-	if (enable)
-		ocp_data |= CPCR_RX_VLAN;
-	else
-		ocp_data &= ~CPCR_RX_VLAN;
-	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
+	switch (tp->version) {
+	case RTL_VER_01:
+	case RTL_VER_02:
+	case RTL_VER_03:
+	case RTL_VER_04:
+	case RTL_VER_05:
+	case RTL_VER_06:
+	case RTL_VER_07:
+	case RTL_VER_08:
+	case RTL_VER_09:
+	case RTL_VER_14:
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
+		if (enable)
+			ocp_data |= CPCR_RX_VLAN;
+		else
+			ocp_data &= ~CPCR_RX_VLAN;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
+		break;
+
+	case RTL_TEST_01:
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_15:
+	default:
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RCR1);
+		if (enable)
+			ocp_data |= OUTER_VLAN | INNER_VLAN;
+		else
+			ocp_data &= ~(OUTER_VLAN | INNER_VLAN);
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_RCR1, ocp_data);
+		break;
+	}
 }
 
 static int rtl8152_set_features(struct net_device *dev,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3312 @
 		device_set_wakeup_enable(&tp->udev->dev, false);
 }
 
+static void r8153_mac_clk_speed_down(struct r8152 *tp, bool enable)
+{
+	u32 ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2);
+
+	/* MAC clock speed down */
+	if (enable)
+		ocp_data |= MAC_CLK_SPDWN_EN;
+	else
+		ocp_data &= ~MAC_CLK_SPDWN_EN;
+
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
+}
+
+static void r8156_mac_clk_spd(struct r8152 *tp, bool enable)
+{
+	u32 ocp_data;
+
+	/* MAC clock speed down */
+	if (enable) {
+		/* aldps_spdwn_ratio, tp10_spdwn_ratio */
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL,
+			       0x0403);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2);
+		ocp_data &= ~EEE_SPDWN_RATIO_MASK;
+		ocp_data |= MAC_CLK_SPDWN_EN | 0x03; /* eee_spdwn_ratio */
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
+	} else {
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2);
+		ocp_data &= ~MAC_CLK_SPDWN_EN;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
+	}
+}
+
 static void r8153_u1u2en(struct r8152 *tp, bool enable)
 {
 	u8 u1u2[8];
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3405 @
 	if (tp->ups_info.eee_cmod_lv)
 		ups_flags |= UPS_FLAGS_EEE_CMOD_LV_EN;
 
+	if (tp->ups_info.r_tune)
+		ups_flags |= UPS_FLAGS_R_TUNE;
+
 	if (tp->ups_info._10m_ckdiv)
 		ups_flags |= UPS_FLAGS_EN_10M_CKDIV;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3458 @
 	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPS_FLAGS, ups_flags);
 }
 
-static void r8153b_green_en(struct r8152 *tp, bool enable)
+static void r8156_ups_flags(struct r8152 *tp)
+{
+	u32 ups_flags = 0;
+
+	if (tp->ups_info.green)
+		ups_flags |= UPS_FLAGS_EN_GREEN;
+
+	if (tp->ups_info.aldps)
+		ups_flags |= UPS_FLAGS_EN_ALDPS;
+
+	if (tp->ups_info.eee)
+		ups_flags |= UPS_FLAGS_EN_EEE;
+
+	if (tp->ups_info.flow_control)
+		ups_flags |= UPS_FLAGS_EN_FLOW_CTR;
+
+	if (tp->ups_info.eee_ckdiv)
+		ups_flags |= UPS_FLAGS_EN_EEE_CKDIV;
+
+	if (tp->ups_info._10m_ckdiv)
+		ups_flags |= UPS_FLAGS_EN_10M_CKDIV;
+
+	if (tp->ups_info.eee_plloff_100)
+		ups_flags |= UPS_FLAGS_EEE_PLLOFF_100;
+
+	if (tp->ups_info.eee_plloff_giga)
+		ups_flags |= UPS_FLAGS_EEE_PLLOFF_GIGA;
+
+	if (tp->ups_info._250m_ckdiv)
+		ups_flags |= UPS_FLAGS_250M_CKDIV;
+
+	switch (tp->ups_info.speed_duplex) {
+	case FORCE_10M_HALF:
+		ups_flags |= ups_flags_speed(0);
+		break;
+	case FORCE_10M_FULL:
+		ups_flags |= ups_flags_speed(1);
+		break;
+	case FORCE_100M_HALF:
+		ups_flags |= ups_flags_speed(2);
+		break;
+	case FORCE_100M_FULL:
+		ups_flags |= ups_flags_speed(3);
+		break;
+	case NWAY_10M_HALF:
+		ups_flags |= ups_flags_speed(4);
+		break;
+	case NWAY_10M_FULL:
+		ups_flags |= ups_flags_speed(5);
+		break;
+	case NWAY_100M_HALF:
+		ups_flags |= ups_flags_speed(6);
+		break;
+	case NWAY_100M_FULL:
+		ups_flags |= ups_flags_speed(7);
+		break;
+	case NWAY_1000M_FULL:
+		ups_flags |= ups_flags_speed(8);
+		break;
+	case NWAY_2500M_FULL:
+		ups_flags |= ups_flags_speed(9);
+		break;
+	default:
+		break;
+	}
+
+	switch (tp->ups_info.lite_mode) {
+	case 1:
+		ups_flags |= 0 << 5;
+		break;
+	case 2:
+		ups_flags |= 2 << 5;
+		break;
+	case 0:
+	default:
+		ups_flags |= 1 << 5;
+		break;
+	}
+
+	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPS_FLAGS, ups_flags);
+}
+
+static void rtl_green_en(struct r8152 *tp, bool enable)
 {
 	u16 data;
 
+	data = sram_read(tp, SRAM_GREEN_CFG);
+	if (enable)
+		data |= GREEN_ETH_EN;
+	else
+		data &= ~GREEN_ETH_EN;
+	sram_write(tp, SRAM_GREEN_CFG, data);
+
+	tp->ups_info.green = enable;
+}
+
+static void r8153b_green_en(struct r8152 *tp, bool enable)
+{
 	if (enable) {
 		sram_write(tp, 0x8045, 0);	/* 10M abiq&ldvbias */
 		sram_write(tp, 0x804d, 0x1222);	/* 100M short abiq&ldvbias */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3566 @
 		sram_write(tp, 0x805d, 0x2444);	/* 1000M short abiq&ldvbias */
 	}
 
-	data = sram_read(tp, SRAM_GREEN_CFG);
-	data |= GREEN_ETH_EN;
-	sram_write(tp, SRAM_GREEN_CFG, data);
-
-	tp->ups_info.green = enable;
+	rtl_green_en(tp, true);
 }
 
 static u16 r8153_phy_status(struct r8152 *tp, u16 desired)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3603 @
 		ocp_data |= UPS_EN | USP_PREWAKE | PHASE2_EN;
 		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
 
-		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xcfff);
-		ocp_data |= BIT(0);
-		ocp_write_byte(tp, MCU_TYPE_USB, 0xcfff, ocp_data);
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
+		ocp_data |= UPS_FORCE_PWR_DOWN;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
 	} else {
-		u16 data;
+		ocp_data &= ~(UPS_EN | USP_PREWAKE);
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
+		ocp_data &= ~UPS_FORCE_PWR_DOWN;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
+
+		if (ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0) & PCUT_STATUS) {
+			int i;
+
+			for (i = 0; i < 500; i++) {
+				if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
+				    AUTOLOAD_DONE)
+					break;
+				msleep(20);
+			}
+
+			tp->rtl_ops.hw_phy_cfg(tp);
+
+			rtl8152_set_speed(tp, tp->autoneg, tp->speed,
+					  tp->duplex, tp->advertising);
+		}
+	}
+}
 
+static void r8153c_ups_en(struct r8152 *tp, bool enable)
+{
+	u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_POWER_CUT);
+
+	if (enable) {
+		r8153b_ups_flags(tp);
+
+		ocp_data |= UPS_EN | USP_PREWAKE | PHASE2_EN;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
+		ocp_data |= UPS_FORCE_PWR_DOWN;
+		ocp_data &= ~BIT(7);
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
+	} else {
 		ocp_data &= ~(UPS_EN | USP_PREWAKE);
 		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
 
-		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xcfff);
-		ocp_data &= ~BIT(0);
-		ocp_write_byte(tp, MCU_TYPE_USB, 0xcfff, ocp_data);
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
+		ocp_data &= ~UPS_FORCE_PWR_DOWN;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
+
+		if (ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0) & PCUT_STATUS) {
+			int i;
+
+			for (i = 0; i < 500; i++) {
+				if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
+				    AUTOLOAD_DONE)
+					break;
+				msleep(20);
+			}
 
-		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
-		ocp_data &= ~PCUT_STATUS;
-		ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
+			tp->rtl_ops.hw_phy_cfg(tp);
+
+			rtl8152_set_speed(tp, tp->autoneg, tp->speed,
+					  tp->duplex, tp->advertising);
+		}
 
-		data = r8153_phy_status(tp, 0);
+		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
 
-		switch (data) {
-		case PHY_STAT_PWRDN:
-		case PHY_STAT_EXT_INIT:
-			r8153b_green_en(tp,
-					test_bit(GREEN_ETHERNET, &tp->flags));
-
-			data = r8152_mdio_read(tp, MII_BMCR);
-			data &= ~BMCR_PDOWN;
-			data |= BMCR_RESET;
-			r8152_mdio_write(tp, MII_BMCR, data);
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
+		ocp_data |= BIT(8);
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
 
-			data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
-			fallthrough;
+		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+	}
+}
+
+static void r8156_ups_en(struct r8152 *tp, bool enable)
+{
+	u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_POWER_CUT);
+
+	if (enable) {
+		r8156_ups_flags(tp);
+
+		ocp_data |= UPS_EN | USP_PREWAKE | PHASE2_EN;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
+		ocp_data |= UPS_FORCE_PWR_DOWN;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
 
+		switch (tp->version) {
+		case RTL_VER_13:
+		case RTL_VER_15:
+			ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL);
+			ocp_data &= ~OOBS_POLLING;
+			ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data);
+			break;
 		default:
-			if (data != PHY_STAT_LAN_ON)
-				netif_warn(tp, link, tp->netdev,
-					   "PHY not ready");
 			break;
 		}
+	} else {
+		ocp_data &= ~(UPS_EN | USP_PREWAKE);
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
+		ocp_data &= ~UPS_FORCE_PWR_DOWN;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
+
+		if (ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0) & PCUT_STATUS) {
+			tp->rtl_ops.hw_phy_cfg(tp);
+
+			rtl8152_set_speed(tp, tp->autoneg, tp->speed,
+					  tp->duplex, tp->advertising);
+		}
 	}
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3845 @
 		r8153b_ups_en(tp, false);
 		r8153_queue_wake(tp, false);
 		rtl_runtime_suspend_enable(tp, false);
-		if (tp->udev->speed != USB_SPEED_HIGH)
+		if (tp->udev->speed >= USB_SPEED_SUPER)
+			r8153b_u1u2en(tp, true);
+	}
+}
+
+static void rtl8153c_runtime_enable(struct r8152 *tp, bool enable)
+{
+	if (enable) {
+		r8153_queue_wake(tp, true);
+		r8153b_u1u2en(tp, false);
+		r8153_u2p3en(tp, false);
+		rtl_runtime_suspend_enable(tp, true);
+		r8153c_ups_en(tp, true);
+	} else {
+		r8153c_ups_en(tp, false);
+		r8153_queue_wake(tp, false);
+		rtl_runtime_suspend_enable(tp, false);
+		r8153b_u1u2en(tp, true);
+	}
+}
+
+static void rtl8156_runtime_enable(struct r8152 *tp, bool enable)
+{
+	if (enable) {
+		r8153_queue_wake(tp, true);
+		r8153b_u1u2en(tp, false);
+		r8153_u2p3en(tp, false);
+		rtl_runtime_suspend_enable(tp, true);
+	} else {
+		r8153_queue_wake(tp, false);
+		rtl_runtime_suspend_enable(tp, false);
+		r8153_u2p3en(tp, true);
+		if (tp->udev->speed >= USB_SPEED_SUPER)
 			r8153b_u1u2en(tp, true);
 	}
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3902 @
 
 	case RTL_VER_08:
 	case RTL_VER_09:
+	case RTL_TEST_01:
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_14:
+	case RTL_VER_15:
+	default:
 		/* The bit 0 ~ 7 are relative with teredo settings. They are
 		 * W1C (write 1 to clear), so set all 1 to disable it.
 		 */
 		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, 0xff);
 		break;
-
-	default:
-		break;
 	}
 
 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3949 @
 		break;
 	case RTL_VER_08:
 	case RTL_VER_09:
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_14:
+	case RTL_VER_15:
 	default:
 		if (type == MCU_TYPE_USB) {
 			ocp_write_byte(tp, MCU_TYPE_USB, USB_BP2_EN, 0);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3987 @
 	ocp_write_word(tp, type, PLA_BP_BA, 0);
 }
 
-static int r8153_patch_request(struct r8152 *tp, bool request)
+static int rtl_phy_patch_request(struct r8152 *tp, bool request, bool wait)
 {
-	u16 data;
+	u16 data, check;
 	int i;
 
 	data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD);
-	if (request)
+	if (request) {
 		data |= PATCH_REQUEST;
-	else
+		check = 0;
+	} else {
 		data &= ~PATCH_REQUEST;
+		check = PATCH_READY;
+	}
 	ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data);
 
-	for (i = 0; request && i < 5000; i++) {
+	for (i = 0; wait && i < 5000; i++) {
+		u32 ocp_data;
+
 		usleep_range(1000, 2000);
-		if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)
+		ocp_data = ocp_reg_read(tp, OCP_PHY_PATCH_STAT);
+		if ((ocp_data & PATCH_READY) ^ check)
 			break;
 	}
 
-	if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) {
-		netif_err(tp, drv, tp->netdev, "patch request fail\n");
-		r8153_patch_request(tp, false);
+	if (request && wait &&
+	    !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) {
+		dev_err(&tp->intf->dev, "PHY patch request fail\n");
+		rtl_phy_patch_request(tp, false, false);
 		return -ETIME;
 	} else {
 		return 0;
 	}
 }
 
-static int r8153_pre_ram_code(struct r8152 *tp, u16 key_addr, u16 patch_key)
+static void rtl_patch_key_set(struct r8152 *tp, u16 key_addr, u16 patch_key)
 {
-	if (r8153_patch_request(tp, true)) {
-		dev_err(&tp->intf->dev, "patch request fail\n");
-		return -ETIME;
-	}
+	if (patch_key && key_addr) {
+		sram_write(tp, key_addr, patch_key);
+		sram_write(tp, SRAM_PHY_LOCK, PHY_PATCH_LOCK);
+	} else if (key_addr) {
+		u16 data;
 
-	sram_write(tp, key_addr, patch_key);
-	sram_write(tp, SRAM_PHY_LOCK, PHY_PATCH_LOCK);
+		sram_write(tp, 0x0000, 0x0000);
 
-	return 0;
+		data = ocp_reg_read(tp, OCP_PHY_LOCK);
+		data &= ~PATCH_LOCK;
+		ocp_reg_write(tp, OCP_PHY_LOCK, data);
+
+		sram_write(tp, key_addr, 0x0000);
+	} else {
+		WARN_ON_ONCE(1);
+	}
 }
 
-static int r8153_post_ram_code(struct r8152 *tp, u16 key_addr)
+static int
+rtl_pre_ram_code(struct r8152 *tp, u16 key_addr, u16 patch_key, bool wait)
 {
-	u16 data;
+	if (rtl_phy_patch_request(tp, true, wait))
+		return -ETIME;
 
-	sram_write(tp, 0x0000, 0x0000);
+	rtl_patch_key_set(tp, key_addr, patch_key);
 
-	data = ocp_reg_read(tp, OCP_PHY_LOCK);
-	data &= ~PATCH_LOCK;
-	ocp_reg_write(tp, OCP_PHY_LOCK, data);
+	return 0;
+}
 
-	sram_write(tp, key_addr, 0x0000);
+static int rtl_post_ram_code(struct r8152 *tp, u16 key_addr, bool wait)
+{
+	rtl_patch_key_set(tp, key_addr, 0);
 
-	r8153_patch_request(tp, false);
+	rtl_phy_patch_request(tp, false, wait);
 
 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base);
 
 	return 0;
 }
 
+static bool rtl8152_is_fw_phy_speed_up_ok(struct r8152 *tp, struct fw_phy_speed_up *phy)
+{
+	u16 fw_offset;
+	u32 length;
+	bool rc = false;
+
+	switch (tp->version) {
+	case RTL_VER_01:
+	case RTL_VER_02:
+	case RTL_VER_03:
+	case RTL_VER_04:
+	case RTL_VER_05:
+	case RTL_VER_06:
+	case RTL_VER_07:
+	case RTL_VER_08:
+	case RTL_VER_09:
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_14:
+		goto out;
+	case RTL_VER_13:
+	case RTL_VER_15:
+	default:
+		break;
+	}
+
+	fw_offset = __le16_to_cpu(phy->fw_offset);
+	length = __le32_to_cpu(phy->blk_hdr.length);
+	if (fw_offset < sizeof(*phy) || length <= fw_offset) {
+		dev_err(&tp->intf->dev, "invalid fw_offset\n");
+		goto out;
+	}
+
+	length -= fw_offset;
+	if (length & 3) {
+		dev_err(&tp->intf->dev, "invalid block length\n");
+		goto out;
+	}
+
+	if (__le16_to_cpu(phy->fw_reg) != 0x9A00) {
+		dev_err(&tp->intf->dev, "invalid register to load firmware\n");
+		goto out;
+	}
+
+	rc = true;
+out:
+	return rc;
+}
+
+static bool rtl8152_is_fw_phy_ver_ok(struct r8152 *tp, struct fw_phy_ver *ver)
+{
+	bool rc = false;
+
+	switch (tp->version) {
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_15:
+		break;
+	default:
+		goto out;
+	}
+
+	if (__le32_to_cpu(ver->blk_hdr.length) != sizeof(*ver)) {
+		dev_err(&tp->intf->dev, "invalid block length\n");
+		goto out;
+	}
+
+	if (__le16_to_cpu(ver->ver.addr) != SRAM_GPHY_FW_VER) {
+		dev_err(&tp->intf->dev, "invalid phy ver addr\n");
+		goto out;
+	}
+
+	rc = true;
+out:
+	return rc;
+}
+
+static bool rtl8152_is_fw_phy_fixup_ok(struct r8152 *tp, struct fw_phy_fixup *fix)
+{
+	bool rc = false;
+
+	switch (tp->version) {
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_15:
+		break;
+	default:
+		goto out;
+	}
+
+	if (__le32_to_cpu(fix->blk_hdr.length) != sizeof(*fix)) {
+		dev_err(&tp->intf->dev, "invalid block length\n");
+		goto out;
+	}
+
+	if (__le16_to_cpu(fix->setting.addr) != OCP_PHY_PATCH_CMD ||
+	    __le16_to_cpu(fix->setting.data) != BIT(7)) {
+		dev_err(&tp->intf->dev, "invalid phy fixup\n");
+		goto out;
+	}
+
+	rc = true;
+out:
+	return rc;
+}
+
+static bool rtl8152_is_fw_phy_union_ok(struct r8152 *tp, struct fw_phy_union *phy)
+{
+	u16 fw_offset;
+	u32 length;
+	bool rc = false;
+
+	switch (tp->version) {
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_15:
+		break;
+	default:
+		goto out;
+	}
+
+	fw_offset = __le16_to_cpu(phy->fw_offset);
+	length = __le32_to_cpu(phy->blk_hdr.length);
+	if (fw_offset < sizeof(*phy) || length <= fw_offset) {
+		dev_err(&tp->intf->dev, "invalid fw_offset\n");
+		goto out;
+	}
+
+	length -= fw_offset;
+	if (length & 1) {
+		dev_err(&tp->intf->dev, "invalid block length\n");
+		goto out;
+	}
+
+	if (phy->pre_num > 2) {
+		dev_err(&tp->intf->dev, "invalid pre_num %d\n", phy->pre_num);
+		goto out;
+	}
+
+	if (phy->bp_num > 8) {
+		dev_err(&tp->intf->dev, "invalid bp_num %d\n", phy->bp_num);
+		goto out;
+	}
+
+	rc = true;
+out:
+	return rc;
+}
+
 static bool rtl8152_is_fw_phy_nc_ok(struct r8152 *tp, struct fw_phy_nc *phy)
 {
 	u32 length;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4320 @
 		case RTL_VER_06:
 		case RTL_VER_08:
 		case RTL_VER_09:
+		case RTL_VER_11:
+		case RTL_VER_12:
+		case RTL_VER_13:
+		case RTL_VER_14:
+		case RTL_VER_15:
 			fw_reg = 0xf800;
 			bp_ba_addr = PLA_BP_BA;
 			bp_en_addr = PLA_BP_EN;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4348 @
 			break;
 		case RTL_VER_08:
 		case RTL_VER_09:
+		case RTL_VER_11:
+		case RTL_VER_12:
+		case RTL_VER_13:
+		case RTL_VER_14:
+		case RTL_VER_15:
 			fw_reg = 0xe600;
 			bp_ba_addr = USB_BP_BA;
 			bp_en_addr = USB_BP2_EN;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4480 @
 {
 	const struct firmware *fw = rtl_fw->fw;
 	struct fw_header *fw_hdr = (struct fw_header *)fw->data;
-	struct fw_mac *pla = NULL, *usb = NULL;
-	struct fw_phy_patch_key *start = NULL;
-	struct fw_phy_nc *phy_nc = NULL;
-	struct fw_block *stop = NULL;
+	unsigned long fw_flags = 0;
 	long ret = -EFAULT;
 	int i;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4509 @
 				goto fail;
 			goto fw_end;
 		case RTL_FW_PLA:
-			if (pla) {
+			if (test_bit(FW_FLAGS_PLA, &fw_flags)) {
 				dev_err(&tp->intf->dev,
 					"multiple PLA firmware encountered");
 				goto fail;
 			}
 
-			pla = (struct fw_mac *)block;
-			if (!rtl8152_is_fw_mac_ok(tp, pla)) {
+			if (!rtl8152_is_fw_mac_ok(tp, (struct fw_mac *)block)) {
 				dev_err(&tp->intf->dev,
 					"check PLA firmware failed\n");
 				goto fail;
 			}
+			__set_bit(FW_FLAGS_PLA, &fw_flags);
 			break;
 		case RTL_FW_USB:
-			if (usb) {
+			if (test_bit(FW_FLAGS_USB, &fw_flags)) {
 				dev_err(&tp->intf->dev,
 					"multiple USB firmware encountered");
 				goto fail;
 			}
 
-			usb = (struct fw_mac *)block;
-			if (!rtl8152_is_fw_mac_ok(tp, usb)) {
+			if (!rtl8152_is_fw_mac_ok(tp, (struct fw_mac *)block)) {
 				dev_err(&tp->intf->dev,
 					"check USB firmware failed\n");
 				goto fail;
 			}
+			__set_bit(FW_FLAGS_USB, &fw_flags);
 			break;
 		case RTL_FW_PHY_START:
-			if (start || phy_nc || stop) {
+			if (test_bit(FW_FLAGS_START, &fw_flags) ||
+			    test_bit(FW_FLAGS_NC, &fw_flags) ||
+			    test_bit(FW_FLAGS_NC1, &fw_flags) ||
+			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
 				dev_err(&tp->intf->dev,
 					"check PHY_START fail\n");
 				goto fail;
 			}
 
-			if (__le32_to_cpu(block->length) != sizeof(*start)) {
+			if (__le32_to_cpu(block->length) != sizeof(struct fw_phy_patch_key)) {
 				dev_err(&tp->intf->dev,
 					"Invalid length for PHY_START\n");
 				goto fail;
 			}
-
-			start = (struct fw_phy_patch_key *)block;
+			__set_bit(FW_FLAGS_START, &fw_flags);
 			break;
 		case RTL_FW_PHY_STOP:
-			if (stop || !start) {
+			if (test_bit(FW_FLAGS_STOP, &fw_flags) ||
+			    !test_bit(FW_FLAGS_START, &fw_flags)) {
 				dev_err(&tp->intf->dev,
 					"Check PHY_STOP fail\n");
 				goto fail;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4569 @
 					"Invalid length for PHY_STOP\n");
 				goto fail;
 			}
-
-			stop = block;
+			__set_bit(FW_FLAGS_STOP, &fw_flags);
 			break;
 		case RTL_FW_PHY_NC:
-			if (!start || stop) {
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
 				dev_err(&tp->intf->dev,
 					"check PHY_NC fail\n");
 				goto fail;
 			}
 
-			if (phy_nc) {
+			if (test_bit(FW_FLAGS_NC, &fw_flags)) {
 				dev_err(&tp->intf->dev,
 					"multiple PHY NC encountered\n");
 				goto fail;
 			}
 
-			phy_nc = (struct fw_phy_nc *)block;
-			if (!rtl8152_is_fw_phy_nc_ok(tp, phy_nc)) {
+			if (!rtl8152_is_fw_phy_nc_ok(tp, (struct fw_phy_nc *)block)) {
 				dev_err(&tp->intf->dev,
 					"check PHY NC firmware failed\n");
 				goto fail;
 			}
+			__set_bit(FW_FLAGS_NC, &fw_flags);
+			break;
+		case RTL_FW_PHY_UNION_NC:
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
+			    test_bit(FW_FLAGS_NC1, &fw_flags) ||
+			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
+				dev_err(&tp->intf->dev, "PHY_UNION_NC out of order\n");
+				goto fail;
+			}
+
+			if (test_bit(FW_FLAGS_NC, &fw_flags)) {
+				dev_err(&tp->intf->dev, "multiple PHY_UNION_NC encountered\n");
+				goto fail;
+			}
+
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
+				dev_err(&tp->intf->dev, "check PHY_UNION_NC failed\n");
+				goto fail;
+			}
+			__set_bit(FW_FLAGS_NC, &fw_flags);
+			break;
+		case RTL_FW_PHY_UNION_NC1:
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
+			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
+				dev_err(&tp->intf->dev, "PHY_UNION_NC1 out of order\n");
+				goto fail;
+			}
+
+			if (test_bit(FW_FLAGS_NC1, &fw_flags)) {
+				dev_err(&tp->intf->dev, "multiple PHY NC1 encountered\n");
+				goto fail;
+			}
+
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
+				dev_err(&tp->intf->dev, "check PHY_UNION_NC1 failed\n");
+				goto fail;
+			}
+			__set_bit(FW_FLAGS_NC1, &fw_flags);
+			break;
+		case RTL_FW_PHY_UNION_NC2:
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
+				dev_err(&tp->intf->dev, "PHY_UNION_NC2 out of order\n");
+				goto fail;
+			}
 
+			if (test_bit(FW_FLAGS_NC2, &fw_flags)) {
+				dev_err(&tp->intf->dev, "multiple PHY NC2 encountered\n");
+				goto fail;
+			}
+
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
+				dev_err(&tp->intf->dev, "check PHY_UNION_NC2 failed\n");
+				goto fail;
+			}
+			__set_bit(FW_FLAGS_NC2, &fw_flags);
+			break;
+		case RTL_FW_PHY_UNION_UC2:
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
+				dev_err(&tp->intf->dev, "PHY_UNION_UC2 out of order\n");
+				goto fail;
+			}
+
+			if (test_bit(FW_FLAGS_UC2, &fw_flags)) {
+				dev_err(&tp->intf->dev, "multiple PHY UC2 encountered\n");
+				goto fail;
+			}
+
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
+				dev_err(&tp->intf->dev, "check PHY_UNION_UC2 failed\n");
+				goto fail;
+			}
+			__set_bit(FW_FLAGS_UC2, &fw_flags);
+			break;
+		case RTL_FW_PHY_UNION_UC:
+			if (!test_bit(FW_FLAGS_START, &fw_flags) ||
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
+				dev_err(&tp->intf->dev, "PHY_UNION_UC out of order\n");
+				goto fail;
+			}
+
+			if (test_bit(FW_FLAGS_UC, &fw_flags)) {
+				dev_err(&tp->intf->dev, "multiple PHY UC encountered\n");
+				goto fail;
+			}
+
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
+				dev_err(&tp->intf->dev, "check PHY_UNION_UC failed\n");
+				goto fail;
+			}
+			__set_bit(FW_FLAGS_UC, &fw_flags);
+			break;
+		case RTL_FW_PHY_UNION_MISC:
+			if (!rtl8152_is_fw_phy_union_ok(tp, (struct fw_phy_union *)block)) {
+				dev_err(&tp->intf->dev, "check RTL_FW_PHY_UNION_MISC failed\n");
+				goto fail;
+			}
+			break;
+		case RTL_FW_PHY_FIXUP:
+			if (!rtl8152_is_fw_phy_fixup_ok(tp, (struct fw_phy_fixup *)block)) {
+				dev_err(&tp->intf->dev, "check PHY fixup failed\n");
+				goto fail;
+			}
+			break;
+		case RTL_FW_PHY_SPEED_UP:
+			if (test_bit(FW_FLAGS_SPEED_UP, &fw_flags)) {
+				dev_err(&tp->intf->dev, "multiple PHY firmware encountered");
+				goto fail;
+			}
+
+			if (!rtl8152_is_fw_phy_speed_up_ok(tp, (struct fw_phy_speed_up *)block)) {
+				dev_err(&tp->intf->dev, "check PHY speed up failed\n");
+				goto fail;
+			}
+			__set_bit(FW_FLAGS_SPEED_UP, &fw_flags);
+			break;
+		case RTL_FW_PHY_VER:
+			if (test_bit(FW_FLAGS_START, &fw_flags) ||
+			    test_bit(FW_FLAGS_NC, &fw_flags) ||
+			    test_bit(FW_FLAGS_NC1, &fw_flags) ||
+			    test_bit(FW_FLAGS_NC2, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC2, &fw_flags) ||
+			    test_bit(FW_FLAGS_UC, &fw_flags) ||
+			    test_bit(FW_FLAGS_STOP, &fw_flags)) {
+				dev_err(&tp->intf->dev, "Invalid order to set PHY version\n");
+				goto fail;
+			}
+
+			if (test_bit(FW_FLAGS_VER, &fw_flags)) {
+				dev_err(&tp->intf->dev, "multiple PHY version encountered");
+				goto fail;
+			}
+
+			if (!rtl8152_is_fw_phy_ver_ok(tp, (struct fw_phy_ver *)block)) {
+				dev_err(&tp->intf->dev, "check PHY version failed\n");
+				goto fail;
+			}
+			__set_bit(FW_FLAGS_VER, &fw_flags);
 			break;
 		default:
 			dev_warn(&tp->intf->dev, "Unknown type %u is found\n",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4750 @
 	}
 
 fw_end:
-	if ((phy_nc || start) && !stop) {
+	if (test_bit(FW_FLAGS_START, &fw_flags) && !test_bit(FW_FLAGS_STOP, &fw_flags)) {
 		dev_err(&tp->intf->dev, "without PHY_STOP\n");
 		goto fail;
 	}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4760 @
 	return ret;
 }
 
+static void rtl_ram_code_speed_up(struct r8152 *tp, struct fw_phy_speed_up *phy, bool wait)
+{
+	u32 len;
+	u8 *data;
+
+	if (sram_read(tp, SRAM_GPHY_FW_VER) >= __le16_to_cpu(phy->version)) {
+		dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
+		return;
+	}
+
+	len = __le32_to_cpu(phy->blk_hdr.length);
+	len -= __le16_to_cpu(phy->fw_offset);
+	data = (u8 *)phy + __le16_to_cpu(phy->fw_offset);
+
+	if (rtl_phy_patch_request(tp, true, wait))
+		return;
+
+	while (len) {
+		u32 ocp_data, size;
+		int i;
+
+		if (len < 2048)
+			size = len;
+		else
+			size = 2048;
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL);
+		ocp_data |= GPHY_PATCH_DONE | BACKUP_RESTRORE;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL, ocp_data);
+
+		generic_ocp_write(tp, __le16_to_cpu(phy->fw_reg), 0xff, size, data, MCU_TYPE_USB);
+
+		data += size;
+		len -= size;
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL);
+		ocp_data |= POL_GPHY_PATCH;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL, ocp_data);
+
+		for (i = 0; i < 1000; i++) {
+			if (!(ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL) & POL_GPHY_PATCH))
+				break;
+		}
+
+		if (i == 1000) {
+			dev_err(&tp->intf->dev, "ram code speedup mode timeout\n");
+			return;
+		}
+	}
+
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base);
+	rtl_phy_patch_request(tp, false, wait);
+
+	if (sram_read(tp, SRAM_GPHY_FW_VER) == __le16_to_cpu(phy->version))
+		dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info);
+	else
+		dev_err(&tp->intf->dev, "ram code speedup mode fail\n");
+}
+
+static int rtl8152_fw_phy_ver(struct r8152 *tp, struct fw_phy_ver *phy_ver)
+{
+	u16 ver_addr, ver;
+
+	ver_addr = __le16_to_cpu(phy_ver->ver.addr);
+	ver = __le16_to_cpu(phy_ver->ver.data);
+
+	if (sram_read(tp, ver_addr) >= ver) {
+		dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
+		return 0;
+	}
+
+	sram_write(tp, ver_addr, ver);
+
+	dev_dbg(&tp->intf->dev, "PHY firmware version %x\n", ver);
+
+	return ver;
+}
+
+static void rtl8152_fw_phy_fixup(struct r8152 *tp, struct fw_phy_fixup *fix)
+{
+	u16 addr, data;
+
+	addr = __le16_to_cpu(fix->setting.addr);
+	data = ocp_reg_read(tp, addr);
+
+	switch (__le16_to_cpu(fix->bit_cmd)) {
+	case FW_FIXUP_AND:
+		data &= __le16_to_cpu(fix->setting.data);
+		break;
+	case FW_FIXUP_OR:
+		data |= __le16_to_cpu(fix->setting.data);
+		break;
+	case FW_FIXUP_NOT:
+		data &= ~__le16_to_cpu(fix->setting.data);
+		break;
+	case FW_FIXUP_XOR:
+		data ^= __le16_to_cpu(fix->setting.data);
+		break;
+	default:
+		return;
+	}
+
+	ocp_reg_write(tp, addr, data);
+
+	dev_dbg(&tp->intf->dev, "applied ocp %x %x\n", addr, data);
+}
+
+static void rtl8152_fw_phy_union_apply(struct r8152 *tp, struct fw_phy_union *phy)
+{
+	__le16 *data;
+	u32 length;
+	int i, num;
+
+	num = phy->pre_num;
+	for (i = 0; i < num; i++)
+		sram_write(tp, __le16_to_cpu(phy->pre_set[i].addr),
+			   __le16_to_cpu(phy->pre_set[i].data));
+
+	length = __le32_to_cpu(phy->blk_hdr.length);
+	length -= __le16_to_cpu(phy->fw_offset);
+	num = length / 2;
+	data = (__le16 *)((u8 *)phy + __le16_to_cpu(phy->fw_offset));
+
+	ocp_reg_write(tp, OCP_SRAM_ADDR, __le16_to_cpu(phy->fw_reg));
+	for (i = 0; i < num; i++)
+		ocp_reg_write(tp, OCP_SRAM_DATA, __le16_to_cpu(data[i]));
+
+	num = phy->bp_num;
+	for (i = 0; i < num; i++)
+		sram_write(tp, __le16_to_cpu(phy->bp[i].addr), __le16_to_cpu(phy->bp[i].data));
+
+	if (phy->bp_num && phy->bp_en.addr)
+		sram_write(tp, __le16_to_cpu(phy->bp_en.addr), __le16_to_cpu(phy->bp_en.data));
+
+	dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info);
+}
+
 static void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy)
 {
 	u16 mode_reg, bp_index;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4950 @
 		return;
 	}
 
+	fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg);
+	if (fw_ver_reg && ocp_read_byte(tp, MCU_TYPE_USB, fw_ver_reg) >= mac->fw_ver_data) {
+		dev_dbg(&tp->intf->dev, "%s firmware has been the newest\n", type ? "PLA" : "USB");
+		return;
+	}
+
 	rtl_clear_bp(tp, type);
 
 	/* Enable backup/restore of MACDBG. This is required after clearing PLA
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4991 @
 		ocp_write_word(tp, type, bp_en_addr,
 			       __le16_to_cpu(mac->bp_en_value));
 
-	fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg);
 	if (fw_ver_reg)
 		ocp_write_byte(tp, MCU_TYPE_USB, fw_ver_reg,
 			       mac->fw_ver_data);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4998 @
 	dev_dbg(&tp->intf->dev, "successfully applied %s\n", mac->info);
 }
 
-static void rtl8152_apply_firmware(struct r8152 *tp)
+static void rtl8152_apply_firmware(struct r8152 *tp, bool power_cut)
 {
 	struct rtl_fw *rtl_fw = &tp->rtl_fw;
 	const struct firmware *fw;
 	struct fw_header *fw_hdr;
 	struct fw_phy_patch_key *key;
 	u16 key_addr = 0;
-	int i;
+	int i, patch_phy = 1;
 
 	if (IS_ERR_OR_NULL(rtl_fw->fw))
 		return;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5027 @
 			rtl8152_fw_mac_apply(tp, (struct fw_mac *)block);
 			break;
 		case RTL_FW_PHY_START:
+			if (!patch_phy)
+				break;
 			key = (struct fw_phy_patch_key *)block;
 			key_addr = __le16_to_cpu(key->key_reg);
-			r8153_pre_ram_code(tp, key_addr,
-					   __le16_to_cpu(key->key_data));
+			rtl_pre_ram_code(tp, key_addr, __le16_to_cpu(key->key_data), !power_cut);
 			break;
 		case RTL_FW_PHY_STOP:
+			if (!patch_phy)
+				break;
 			WARN_ON(!key_addr);
-			r8153_post_ram_code(tp, key_addr);
+			rtl_post_ram_code(tp, key_addr, !power_cut);
 			break;
 		case RTL_FW_PHY_NC:
 			rtl8152_fw_phy_nc_apply(tp, (struct fw_phy_nc *)block);
 			break;
+		case RTL_FW_PHY_VER:
+			patch_phy = rtl8152_fw_phy_ver(tp, (struct fw_phy_ver *)block);
+			break;
+		case RTL_FW_PHY_UNION_NC:
+		case RTL_FW_PHY_UNION_NC1:
+		case RTL_FW_PHY_UNION_NC2:
+		case RTL_FW_PHY_UNION_UC2:
+		case RTL_FW_PHY_UNION_UC:
+		case RTL_FW_PHY_UNION_MISC:
+			if (patch_phy)
+				rtl8152_fw_phy_union_apply(tp, (struct fw_phy_union *)block);
+			break;
+		case RTL_FW_PHY_FIXUP:
+			if (patch_phy)
+				rtl8152_fw_phy_fixup(tp, (struct fw_phy_fixup *)block);
+			break;
+		case RTL_FW_PHY_SPEED_UP:
+			rtl_ram_code_speed_up(tp, (struct fw_phy_speed_up *)block, !power_cut);
+			break;
 		default:
 			break;
 		}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5207 @
 	tp->ups_info.eee = enable;
 }
 
+static void r8156_eee_en(struct r8152 *tp, bool enable)
+{
+	u16 config;
+
+	r8153_eee_en(tp, enable);
+
+	config = ocp_reg_read(tp, OCP_EEE_ADV2);
+
+	if (enable)
+		config |= MDIO_EEE_2_5GT;
+	else
+		config &= ~MDIO_EEE_2_5GT;
+
+	ocp_reg_write(tp, OCP_EEE_ADV2, config);
+}
+
 static void rtl_eee_enable(struct r8152 *tp, bool enable)
 {
 	switch (tp->version) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5244 @
 	case RTL_VER_06:
 	case RTL_VER_08:
 	case RTL_VER_09:
+	case RTL_VER_14:
 		if (enable) {
 			r8153_eee_en(tp, true);
 			ocp_reg_write(tp, OCP_EEE_ADV, tp->eee_adv);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5253 @
 			ocp_reg_write(tp, OCP_EEE_ADV, 0);
 		}
 		break;
+	case RTL_VER_10:
+	case RTL_VER_11:
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_15:
+		if (enable) {
+			r8156_eee_en(tp, true);
+			ocp_reg_write(tp, OCP_EEE_ADV, tp->eee_adv);
+		} else {
+			r8156_eee_en(tp, false);
+			ocp_reg_write(tp, OCP_EEE_ADV, 0);
+		}
+		break;
 	default:
 		break;
 	}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5291 @
 
 static void r8152b_hw_phy_cfg(struct r8152 *tp)
 {
-	rtl8152_apply_firmware(tp);
+	rtl8152_apply_firmware(tp, false);
 	rtl_eee_enable(tp, tp->eee_en);
 	r8152_aldps_en(tp, true);
 	r8152b_enable_fc(tp);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5312 @
 	}
 }
 
+static void r8156b_wait_loading_flash(struct r8152 *tp)
+{
+	if ((ocp_read_word(tp, MCU_TYPE_PLA, PLA_GPHY_CTRL) & GPHY_FLASH) &&
+	    !(ocp_read_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL) & BYPASS_FLASH)) {
+		int i;
+
+		for (i = 0; i < 100; i++) {
+			if (ocp_read_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL) & GPHY_PATCH_DONE)
+				break;
+			usleep_range(1000, 2000);
+		}
+	}
+}
+
 static void r8152b_exit_oob(struct r8152 *tp)
 {
 	u32 ocp_data;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5376 @
 	}
 
 	/* TX share fifo free credit full threshold */
-	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL);
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2);
 
 	ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
 	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5553 @
 	return 0;
 }
 
+static int r8153c_post_firmware_1(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_CTRL);
+	ocp_data |= FLOW_CTRL_PATCH_2;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_CTRL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
+	ocp_data |= FC_PATCH_TASK;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
+
+	return 0;
+}
+
+static int r8156a_post_firmware_1(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1);
+	ocp_data |= FW_IP_RESET_EN;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data);
+
+	/* Modify U3PHY parameter for compatibility issue */
+	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPHY3_MDCMDIO, 0x4026840e);
+	ocp_write_dword(tp, MCU_TYPE_USB, USB_UPHY3_MDCMDIO, 0x4001acc9);
+
+	return 0;
+}
+
 static void r8153_aldps_en(struct r8152 *tp, bool enable)
 {
 	u16 data;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5617 @
 	/* disable EEE before updating the PHY parameters */
 	rtl_eee_enable(tp, false);
 
-	rtl8152_apply_firmware(tp);
+	rtl8152_apply_firmware(tp, false);
 
 	if (tp->version == RTL_VER_03) {
 		data = ocp_reg_read(tp, OCP_EEE_CFG);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5685 @
 	u32 ocp_data;
 	u16 data;
 
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+	if (ocp_data & PCUT_STATUS) {
+		ocp_data &= ~PCUT_STATUS;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
+	}
+
 	/* disable ALDPS before updating the PHY parameters */
 	r8153_aldps_en(tp, false);
 
 	/* disable EEE before updating the PHY parameters */
 	rtl_eee_enable(tp, false);
 
-	rtl8152_apply_firmware(tp);
+	/* U1/U2/L1 idle timer. 500 us */
+	ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
+
+	data = r8153_phy_status(tp, 0);
+
+	switch (data) {
+	case PHY_STAT_PWRDN:
+	case PHY_STAT_EXT_INIT:
+		rtl8152_apply_firmware(tp, true);
+
+		data = r8152_mdio_read(tp, MII_BMCR);
+		data &= ~BMCR_PDOWN;
+		r8152_mdio_write(tp, MII_BMCR, data);
+		break;
+	case PHY_STAT_LAN_ON:
+	default:
+		rtl8152_apply_firmware(tp, false);
+		break;
+	}
 
 	r8153b_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags));
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5756 @
 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
 
 	/* Advnace EEE */
-	if (!r8153_patch_request(tp, true)) {
+	if (!rtl_phy_patch_request(tp, true, true)) {
 		data = ocp_reg_read(tp, OCP_POWER_CFG);
 		data |= EEE_CLKDIV_EN;
 		ocp_reg_write(tp, OCP_POWER_CFG, data);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5773 @
 		ocp_reg_write(tp, OCP_SYSCLK_CFG, clk_div_expo(5));
 		tp->ups_info._250m_ckdiv = true;
 
-		r8153_patch_request(tp, false);
+		rtl_phy_patch_request(tp, false, true);
 	}
 
 	if (tp->eee_en)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5785 @
 	set_bit(PHY_RESET, &tp->flags);
 }
 
+static void r8153c_hw_phy_cfg(struct r8152 *tp)
+{
+	r8153b_hw_phy_cfg(tp);
+
+	tp->ups_info.r_tune = true;
+}
+
+static void rtl8153_change_mtu(struct r8152 *tp)
+{
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, mtu_to_size(tp->netdev->mtu));
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO);
+}
+
 static void r8153_first_init(struct r8152 *tp)
 {
 	u32 ocp_data;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5830 @
 
 	rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX);
 
-	ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
-	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data);
-	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO);
+	rtl8153_change_mtu(tp);
 
 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
 	ocp_data |= TCR0_AUTO_FIFO;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5865 @
 
 	wait_oob_link_list_ready(tp);
 
-	ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
-	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, mtu_to_size(tp->netdev->mtu));
 
 	switch (tp->version) {
 	case RTL_VER_03:
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5879 @
 
 	case RTL_VER_08:
 	case RTL_VER_09:
+	case RTL_VER_14:
 		/* Clear teredo wake event. bit[15:8] is the teredo wakeup
 		 * type. Set it to zero. bits[7:0] are the W1C bits about
 		 * the events. Set them to all 1 to clear them.
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:5916 @
 	r8153_aldps_en(tp, true);
 }
 
+static int rtl8156_enable(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 speed;
+
+	if (test_bit(RTL8152_UNPLUG, &tp->flags))
+		return -ENODEV;
+
+	set_tx_qlen(tp);
+	rtl_set_eee_plus(tp);
+	r8153_set_rx_early_timeout(tp);
+	r8153_set_rx_early_size(tp);
+
+	speed = rtl8152_get_speed(tp);
+	rtl_set_ifg(tp, speed);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
+	if (speed & _2500bps)
+		ocp_data &= ~IDLE_SPDWN_EN;
+	else
+		ocp_data |= IDLE_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
+
+	if (speed & _1000bps)
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS, 0x11);
+	else if (speed & _500bps)
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS, 0x3d);
+
+	if (tp->udev->speed == USB_SPEED_HIGH) {
+		/* USB 0xb45e[3:0] l1_nyet_hird */
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_L1_CTRL);
+		ocp_data &= ~0xf;
+		if (is_flow_control(speed))
+			ocp_data |= 0xf;
+		else
+			ocp_data |= 0x1;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_L1_CTRL, ocp_data);
+	}
+
+	return rtl_enable(tp);
+}
+
+static int rtl8156b_enable(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 speed;
+
+	if (test_bit(RTL8152_UNPLUG, &tp->flags))
+		return -ENODEV;
+
+	set_tx_qlen(tp);
+	rtl_set_eee_plus(tp);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_RX_AGGR_NUM);
+	ocp_data &= ~RX_AGGR_NUM_MASK;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_RX_AGGR_NUM, ocp_data);
+
+	r8153_set_rx_early_timeout(tp);
+	r8153_set_rx_early_size(tp);
+
+	speed = rtl8152_get_speed(tp);
+	rtl_set_ifg(tp, speed);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
+	if (speed & _2500bps)
+		ocp_data &= ~IDLE_SPDWN_EN;
+	else
+		ocp_data |= IDLE_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
+
+	if (tp->udev->speed == USB_SPEED_HIGH) {
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_L1_CTRL);
+		ocp_data &= ~0xf;
+		if (is_flow_control(speed))
+			ocp_data |= 0xf;
+		else
+			ocp_data |= 0x1;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_L1_CTRL, ocp_data);
+	}
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
+	ocp_data &= ~FC_PATCH_TASK;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
+	usleep_range(1000, 2000);
+	ocp_data |= FC_PATCH_TASK;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
+
+	return rtl_enable(tp);
+}
+
 static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
 			     u32 advertising)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6054 @
 
 		tp->mii.force_media = 1;
 	} else {
-		u16 anar, tmp1;
+		u16 orig, new1;
 		u32 support;
 
 		support = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL |
 			  RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL;
 
-		if (tp->mii.supports_gmii)
+		if (tp->mii.supports_gmii) {
 			support |= RTL_ADVERTISED_1000_FULL;
 
+			if (tp->support_2500full)
+				support |= RTL_ADVERTISED_2500_FULL;
+		}
+
 		if (!(advertising & support))
 			return -EINVAL;
 
-		anar = r8152_mdio_read(tp, MII_ADVERTISE);
-		tmp1 = anar & ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
+		orig = r8152_mdio_read(tp, MII_ADVERTISE);
+		new1 = orig & ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
 				ADVERTISE_100HALF | ADVERTISE_100FULL);
 		if (advertising & RTL_ADVERTISED_10_HALF) {
-			tmp1 |= ADVERTISE_10HALF;
+			new1 |= ADVERTISE_10HALF;
 			tp->ups_info.speed_duplex = NWAY_10M_HALF;
 		}
 		if (advertising & RTL_ADVERTISED_10_FULL) {
-			tmp1 |= ADVERTISE_10FULL;
+			new1 |= ADVERTISE_10FULL;
 			tp->ups_info.speed_duplex = NWAY_10M_FULL;
 		}
 
 		if (advertising & RTL_ADVERTISED_100_HALF) {
-			tmp1 |= ADVERTISE_100HALF;
+			new1 |= ADVERTISE_100HALF;
 			tp->ups_info.speed_duplex = NWAY_100M_HALF;
 		}
 		if (advertising & RTL_ADVERTISED_100_FULL) {
-			tmp1 |= ADVERTISE_100FULL;
+			new1 |= ADVERTISE_100FULL;
 			tp->ups_info.speed_duplex = NWAY_100M_FULL;
 		}
 
-		if (anar != tmp1) {
-			r8152_mdio_write(tp, MII_ADVERTISE, tmp1);
-			tp->mii.advertising = tmp1;
+		if (orig != new1) {
+			r8152_mdio_write(tp, MII_ADVERTISE, new1);
+			tp->mii.advertising = new1;
 		}
 
 		if (tp->mii.supports_gmii) {
-			u16 gbcr;
-
-			gbcr = r8152_mdio_read(tp, MII_CTRL1000);
-			tmp1 = gbcr & ~(ADVERTISE_1000FULL |
+			orig = r8152_mdio_read(tp, MII_CTRL1000);
+			new1 = orig & ~(ADVERTISE_1000FULL |
 					ADVERTISE_1000HALF);
 
 			if (advertising & RTL_ADVERTISED_1000_FULL) {
-				tmp1 |= ADVERTISE_1000FULL;
+				new1 |= ADVERTISE_1000FULL;
 				tp->ups_info.speed_duplex = NWAY_1000M_FULL;
 			}
 
-			if (gbcr != tmp1)
-				r8152_mdio_write(tp, MII_CTRL1000, tmp1);
+			if (orig != new1)
+				r8152_mdio_write(tp, MII_CTRL1000, new1);
+		}
+
+		if (tp->support_2500full) {
+			orig = ocp_reg_read(tp, OCP_10GBT_CTRL);
+			new1 = orig & ~MDIO_AN_10GBT_CTRL_ADV2_5G;
+
+			if (advertising & RTL_ADVERTISED_2500_FULL) {
+				new1 |= MDIO_AN_10GBT_CTRL_ADV2_5G;
+				tp->ups_info.speed_duplex = NWAY_2500M_FULL;
+			}
+
+			if (orig != new1)
+				ocp_reg_write(tp, OCP_10GBT_CTRL, new1);
 		}
 
 		bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6251 @
 
 	r8153_aldps_en(tp, true);
 
-	if (tp->udev->speed != USB_SPEED_HIGH)
+	if (tp->udev->speed >= USB_SPEED_SUPER)
 		r8153b_u1u2en(tp, true);
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6276 @
 	r8153_aldps_en(tp, true);
 }
 
+static void rtl8153c_change_mtu(struct r8152 *tp)
+{
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, mtu_to_size(tp->netdev->mtu));
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, 10 * 1024 / 64);
+
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, 512 / 64);
+
+	/* Adjust the tx fifo free credit full threshold, otherwise
+	 * the fifo would be too small to send a jumbo frame packet.
+	 */
+	if (tp->netdev->mtu < 8000)
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL, 2048 / 8);
+	else
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL, 900 / 8);
+}
+
+static void rtl8153c_up(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	if (test_bit(RTL8152_UNPLUG, &tp->flags))
+		return;
+
+	r8153b_u1u2en(tp, false);
+	r8153_u2p3en(tp, false);
+	r8153_aldps_en(tp, false);
+
+	rxdy_gated_en(tp, true);
+	r8153_teredo_off(tp);
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data &= ~RCR_ACPT_ALL;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+	rtl8152_nic_reset(tp);
+	rtl_reset_bmu(tp);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data &= ~NOW_IS_OOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+	ocp_data &= ~MCU_BORW_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+	wait_oob_link_list_ready(tp);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+	ocp_data |= RE_INIT_LL;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+	wait_oob_link_list_ready(tp);
+
+	rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX);
+
+	rtl8153c_change_mtu(tp);
+
+	rtl8152_nic_reset(tp);
+
+	/* rx share fifo credit full threshold */
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, 0x02);
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL, 0x08);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL);
+
+	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_B);
+
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
+	ocp_data |= BIT(8);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
+
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
+	ocp_data &= ~PLA_MCU_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
+
+	r8153_aldps_en(tp, true);
+	r8153b_u1u2en(tp, true);
+}
+
+static inline u32 fc_pause_on_auto(struct r8152 *tp)
+{
+	return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 6 * 1024);
+}
+
+static inline u32 fc_pause_off_auto(struct r8152 *tp)
+{
+	return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 14 * 1024);
+}
+
+static void r8156_fc_parameter(struct r8152 *tp)
+{
+	u32 pause_on = tp->fc_pause_on ? tp->fc_pause_on : fc_pause_on_auto(tp);
+	u32 pause_off = tp->fc_pause_off ? tp->fc_pause_off : fc_pause_off_auto(tp);
+
+	switch (tp->version) {
+	case RTL_VER_10:
+	case RTL_VER_11:
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, pause_on / 8);
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, pause_off / 8);
+		break;
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_15:
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, pause_on / 16);
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, pause_off / 16);
+		break;
+	default:
+		break;
+	}
+}
+
+static void rtl8156_change_mtu(struct r8152 *tp)
+{
+	u32 rx_max_size = mtu_to_size(tp->netdev->mtu);
+
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, rx_max_size);
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO);
+	r8156_fc_parameter(tp);
+
+	/* TX share fifo free credit full threshold */
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, 512 / 64);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL,
+		       ALIGN(rx_max_size + sizeof(struct tx_desc), 1024) / 16);
+}
+
+static void rtl8156_up(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	if (test_bit(RTL8152_UNPLUG, &tp->flags))
+		return;
+
+	r8153b_u1u2en(tp, false);
+	r8153_u2p3en(tp, false);
+	r8153_aldps_en(tp, false);
+
+	rxdy_gated_en(tp, true);
+	r8153_teredo_off(tp);
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data &= ~RCR_ACPT_ALL;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+	rtl8152_nic_reset(tp);
+	rtl_reset_bmu(tp);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data &= ~NOW_IS_OOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+	ocp_data &= ~MCU_BORW_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+	rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX);
+
+	rtl8156_change_mtu(tp);
+
+	switch (tp->version) {
+	case RTL_TEST_01:
+	case RTL_VER_10:
+	case RTL_VER_11:
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_CONFIG);
+		ocp_data |= ACT_ODMA;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_CONFIG, ocp_data);
+		break;
+	default:
+		break;
+	}
+
+	/* share FIFO settings */
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL);
+	ocp_data &= ~RXFIFO_FULL_MASK;
+	ocp_data |= 0x08;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
+	ocp_data &= ~PLA_MCU_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION);
+	ocp_data &= ~(RG_PWRDN_EN | ALL_SPEED_OFF);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION, ocp_data);
+
+	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, 0x00600400);
+
+	if (tp->saved_wolopts != __rtl_get_wol(tp)) {
+		netif_warn(tp, ifup, tp->netdev, "wol setting is changed\n");
+		__rtl_set_wol(tp, tp->saved_wolopts);
+	}
+
+	r8153_aldps_en(tp, true);
+	r8153_u2p3en(tp, true);
+
+	if (tp->udev->speed >= USB_SPEED_SUPER)
+		r8153b_u1u2en(tp, true);
+}
+
+static void rtl8156_down(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
+		rtl_drop_queued_tx(tp);
+		return;
+	}
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
+	ocp_data |= PLA_MCU_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
+
+	r8153b_u1u2en(tp, false);
+	r8153_u2p3en(tp, false);
+	r8153b_power_cut_en(tp, false);
+	r8153_aldps_en(tp, false);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data &= ~NOW_IS_OOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	rtl_disable(tp);
+	rtl_reset_bmu(tp);
+
+	/* Clear teredo wake event. bit[15:8] is the teredo wakeup
+	 * type. Set it to zero. bits[7:0] are the W1C bits about
+	 * the events. Set them to all 1 to clear them.
+	 */
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_WAKE_BASE, 0x00ff);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data |= NOW_IS_OOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	rtl_rx_vlan_en(tp, true);
+	rxdy_gated_en(tp, false);
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+	r8153_aldps_en(tp, true);
+}
+
 static bool rtl8152_in_nway(struct r8152 *tp)
 {
 	u16 nway_state;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6553 @
 {
 	struct net_device *netdev = tp->netdev;
 	struct napi_struct *napi = &tp->napi;
-	u8 speed;
+	u16 speed;
 
 	speed = rtl8152_get_speed(tp);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6566 @
 			rtl_start_rx(tp);
 			clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
 			_rtl8152_set_rx_mode(netdev);
-			napi_enable(&tp->napi);
+			napi_enable(napi);
 			netif_wake_queue(netdev);
 			netif_info(tp, link, netdev, "carrier on\n");
 		} else if (netif_queue_stopped(netdev) &&
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:6927 @
 
 	ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001);
 
-	/* MAC clock speed down */
-	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0);
-	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0);
-	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0);
-	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0);
-
 	r8153_power_cut_en(tp, false);
 	rtl_runtime_suspend_enable(tp, false);
+	r8153_mac_clk_speed_down(tp, false);
 	r8153_u1u2en(tp, true);
 	usb_enable_lpm(tp->udev);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:7001 @
 	/* MSC timer = 0xfff * 8ms = 32760 ms */
 	ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
 
-	/* U1/U2/L1 idle timer. 500 us */
-	ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
-
 	r8153b_power_cut_en(tp, false);
 	r8153b_ups_en(tp, false);
 	r8153_queue_wake(tp, false);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:7014 @
 	ocp_data |= POLL_LINK_CHG;
 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
 
-	if (tp->udev->speed != USB_SPEED_HIGH)
+	if (tp->udev->speed >= USB_SPEED_SUPER)
 		r8153b_u1u2en(tp, true);
+
 	usb_enable_lpm(tp->udev);
 
 	/* MAC clock speed down */
-	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2);
-	ocp_data |= MAC_CLK_SPDWN_EN;
-	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
+	r8153_mac_clk_speed_down(tp, true);
 
 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
 	ocp_data &= ~PLA_MCU_SPDWN_EN;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:7047 @
 	tp->coalesce = 15000;	/* 15 us */
 }
 
+static void r8153c_init(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 data;
+	int i;
+
+	if (test_bit(RTL8152_UNPLUG, &tp->flags))
+		return;
+
+	r8153b_u1u2en(tp, false);
+
+	/* Disable spi_en */
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
+	ocp_data &= ~BIT(3);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data);
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, 0xcbf0);
+	ocp_data |= BIT(1);
+	ocp_write_word(tp, MCU_TYPE_USB, 0xcbf0, ocp_data);
+
+	for (i = 0; i < 500; i++) {
+		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
+		    AUTOLOAD_DONE)
+			break;
+
+		msleep(20);
+		if (test_bit(RTL8152_UNPLUG, &tp->flags))
+			return;
+	}
+
+	data = r8153_phy_status(tp, 0);
+
+	data = r8152_mdio_read(tp, MII_BMCR);
+	if (data & BMCR_PDOWN) {
+		data &= ~BMCR_PDOWN;
+		r8152_mdio_write(tp, MII_BMCR, data);
+	}
+
+	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
+
+	r8153_u2p3en(tp, false);
+
+	/* MSC timer = 0xfff * 8ms = 32760 ms */
+	ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
+
+	r8153b_power_cut_en(tp, false);
+	r8153c_ups_en(tp, false);
+	r8153_queue_wake(tp, false);
+	rtl_runtime_suspend_enable(tp, false);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
+	if (rtl8152_get_speed(tp) & LINK_STATUS)
+		ocp_data |= CUR_LINK_OK;
+	else
+		ocp_data &= ~CUR_LINK_OK;
+
+	ocp_data |= POLL_LINK_CHG;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
+
+	r8153b_u1u2en(tp, true);
+
+	usb_enable_lpm(tp->udev);
+
+	/* MAC clock speed down */
+	r8153_mac_clk_speed_down(tp, true);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_2);
+	ocp_data &= ~BIT(7);
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_MISC_2, ocp_data);
+
+	set_bit(GREEN_ETHERNET, &tp->flags);
+
+	/* rx aggregation */
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+
+	rtl_tally_reset(tp);
+
+	tp->coalesce = 15000;	/* 15 us */
+}
+
+static void r8156_hw_phy_cfg(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+	if (ocp_data & PCUT_STATUS) {
+		ocp_data &= ~PCUT_STATUS;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
+	}
+
+	data = r8153_phy_status(tp, 0);
+	switch (data) {
+	case PHY_STAT_EXT_INIT:
+		rtl8152_apply_firmware(tp, true);
+
+		data = ocp_reg_read(tp, 0xa468);
+		data &= ~(BIT(3) | BIT(1));
+		ocp_reg_write(tp, 0xa468, data);
+		break;
+	case PHY_STAT_LAN_ON:
+	case PHY_STAT_PWRDN:
+	default:
+		rtl8152_apply_firmware(tp, false);
+		break;
+	}
+
+	/* disable ALDPS before updating the PHY parameters */
+	r8153_aldps_en(tp, false);
+
+	/* disable EEE before updating the PHY parameters */
+	rtl_eee_enable(tp, false);
+
+	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
+	WARN_ON_ONCE(data != PHY_STAT_LAN_ON);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
+	ocp_data |= PFM_PWM_SWITCH;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
+
+	switch (tp->version) {
+	case RTL_VER_10:
+		data = ocp_reg_read(tp, 0xad40);
+		data &= ~0x3ff;
+		data |= BIT(7) | BIT(2);
+		ocp_reg_write(tp, 0xad40, data);
+
+		data = ocp_reg_read(tp, 0xad4e);
+		data |= BIT(4);
+		ocp_reg_write(tp, 0xad4e, data);
+		data = ocp_reg_read(tp, 0xad16);
+		data &= ~0x3ff;
+		data |= 0x6;
+		ocp_reg_write(tp, 0xad16, data);
+		data = ocp_reg_read(tp, 0xad32);
+		data &= ~0x3f;
+		data |= 6;
+		ocp_reg_write(tp, 0xad32, data);
+		data = ocp_reg_read(tp, 0xac08);
+		data &= ~(BIT(12) | BIT(8));
+		ocp_reg_write(tp, 0xac08, data);
+		data = ocp_reg_read(tp, 0xac8a);
+		data |= BIT(12) | BIT(13) | BIT(14);
+		data &= ~BIT(15);
+		ocp_reg_write(tp, 0xac8a, data);
+		data = ocp_reg_read(tp, 0xad18);
+		data |= BIT(10);
+		ocp_reg_write(tp, 0xad18, data);
+		data = ocp_reg_read(tp, 0xad1a);
+		data |= 0x3ff;
+		ocp_reg_write(tp, 0xad1a, data);
+		data = ocp_reg_read(tp, 0xad1c);
+		data |= 0x3ff;
+		ocp_reg_write(tp, 0xad1c, data);
+
+		data = sram_read(tp, 0x80ea);
+		data &= ~0xff00;
+		data |= 0xc400;
+		sram_write(tp, 0x80ea, data);
+		data = sram_read(tp, 0x80eb);
+		data &= ~0x0700;
+		data |= 0x0300;
+		sram_write(tp, 0x80eb, data);
+		data = sram_read(tp, 0x80f8);
+		data &= ~0xff00;
+		data |= 0x1c00;
+		sram_write(tp, 0x80f8, data);
+		data = sram_read(tp, 0x80f1);
+		data &= ~0xff00;
+		data |= 0x3000;
+		sram_write(tp, 0x80f1, data);
+
+		data = sram_read(tp, 0x80fe);
+		data &= ~0xff00;
+		data |= 0xa500;
+		sram_write(tp, 0x80fe, data);
+		data = sram_read(tp, 0x8102);
+		data &= ~0xff00;
+		data |= 0x5000;
+		sram_write(tp, 0x8102, data);
+		data = sram_read(tp, 0x8015);
+		data &= ~0xff00;
+		data |= 0x3300;
+		sram_write(tp, 0x8015, data);
+		data = sram_read(tp, 0x8100);
+		data &= ~0xff00;
+		data |= 0x7000;
+		sram_write(tp, 0x8100, data);
+		data = sram_read(tp, 0x8014);
+		data &= ~0xff00;
+		data |= 0xf000;
+		sram_write(tp, 0x8014, data);
+		data = sram_read(tp, 0x8016);
+		data &= ~0xff00;
+		data |= 0x6500;
+		sram_write(tp, 0x8016, data);
+		data = sram_read(tp, 0x80dc);
+		data &= ~0xff00;
+		data |= 0xed00;
+		sram_write(tp, 0x80dc, data);
+		data = sram_read(tp, 0x80df);
+		data |= BIT(8);
+		sram_write(tp, 0x80df, data);
+		data = sram_read(tp, 0x80e1);
+		data &= ~BIT(8);
+		sram_write(tp, 0x80e1, data);
+
+		data = ocp_reg_read(tp, 0xbf06);
+		data &= ~0x003f;
+		data |= 0x0038;
+		ocp_reg_write(tp, 0xbf06, data);
+
+		sram_write(tp, 0x819f, 0xddb6);
+
+		ocp_reg_write(tp, 0xbc34, 0x5555);
+		data = ocp_reg_read(tp, 0xbf0a);
+		data &= ~0x0e00;
+		data |= 0x0a00;
+		ocp_reg_write(tp, 0xbf0a, data);
+
+		data = ocp_reg_read(tp, 0xbd2c);
+		data &= ~BIT(13);
+		ocp_reg_write(tp, 0xbd2c, data);
+		break;
+	case RTL_VER_11:
+		data = ocp_reg_read(tp, 0xad16);
+		data |= 0x3ff;
+		ocp_reg_write(tp, 0xad16, data);
+		data = ocp_reg_read(tp, 0xad32);
+		data &= ~0x3f;
+		data |= 6;
+		ocp_reg_write(tp, 0xad32, data);
+		data = ocp_reg_read(tp, 0xac08);
+		data &= ~(BIT(12) | BIT(8));
+		ocp_reg_write(tp, 0xac08, data);
+		data = ocp_reg_read(tp, 0xacc0);
+		data &= ~0x3;
+		data |= BIT(1);
+		ocp_reg_write(tp, 0xacc0, data);
+		data = ocp_reg_read(tp, 0xad40);
+		data &= ~0xe7;
+		data |= BIT(6) | BIT(2);
+		ocp_reg_write(tp, 0xad40, data);
+		data = ocp_reg_read(tp, 0xac14);
+		data &= ~BIT(7);
+		ocp_reg_write(tp, 0xac14, data);
+		data = ocp_reg_read(tp, 0xac80);
+		data &= ~(BIT(8) | BIT(9));
+		ocp_reg_write(tp, 0xac80, data);
+		data = ocp_reg_read(tp, 0xac5e);
+		data &= ~0x7;
+		data |= BIT(1);
+		ocp_reg_write(tp, 0xac5e, data);
+		ocp_reg_write(tp, 0xad4c, 0x00a8);
+		ocp_reg_write(tp, 0xac5c, 0x01ff);
+		data = ocp_reg_read(tp, 0xac8a);
+		data &= ~0xf0;
+		data |= BIT(4) | BIT(5);
+		ocp_reg_write(tp, 0xac8a, data);
+		ocp_reg_write(tp, 0xb87c, 0x8157);
+		data = ocp_reg_read(tp, 0xb87e);
+		data &= ~0xff00;
+		data |= 0x0500;
+		ocp_reg_write(tp, 0xb87e, data);
+		ocp_reg_write(tp, 0xb87c, 0x8159);
+		data = ocp_reg_read(tp, 0xb87e);
+		data &= ~0xff00;
+		data |= 0x0700;
+		ocp_reg_write(tp, 0xb87e, data);
+
+		/* AAGC */
+		ocp_reg_write(tp, 0xb87c, 0x80a2);
+		ocp_reg_write(tp, 0xb87e, 0x0153);
+		ocp_reg_write(tp, 0xb87c, 0x809c);
+		ocp_reg_write(tp, 0xb87e, 0x0153);
+
+		/* EEE parameter */
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS_2P5G, 0x0056);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_USB_CFG);
+		ocp_data |= EN_XG_LIP | EN_G_LIP;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_USB_CFG, ocp_data);
+
+		sram_write(tp, 0x8257, 0x020f); /*  XG PLL */
+		sram_write(tp, 0x80ea, 0x7843); /* GIGA Master */
+
+		if (rtl_phy_patch_request(tp, true, true))
+			return;
+
+		/* Advance EEE */
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
+		ocp_data |= EEE_SPDWN_EN;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
+
+		data = ocp_reg_read(tp, OCP_DOWN_SPEED);
+		data &= ~(EN_EEE_100 | EN_EEE_1000);
+		data |= EN_10M_CLKDIV;
+		ocp_reg_write(tp, OCP_DOWN_SPEED, data);
+		tp->ups_info._10m_ckdiv = true;
+		tp->ups_info.eee_plloff_100 = false;
+		tp->ups_info.eee_plloff_giga = false;
+
+		data = ocp_reg_read(tp, OCP_POWER_CFG);
+		data &= ~EEE_CLKDIV_EN;
+		ocp_reg_write(tp, OCP_POWER_CFG, data);
+		tp->ups_info.eee_ckdiv = false;
+
+		ocp_reg_write(tp, OCP_SYSCLK_CFG, 0);
+		ocp_reg_write(tp, OCP_SYSCLK_CFG, sysclk_div_expo(5));
+		tp->ups_info._250m_ckdiv = false;
+
+		rtl_phy_patch_request(tp, false, true);
+
+		/* enable ADC Ibias Cal */
+		data = ocp_reg_read(tp, 0xd068);
+		data |= BIT(13);
+		ocp_reg_write(tp, 0xd068, data);
+
+		/* enable Thermal Sensor */
+		data = sram_read(tp, 0x81a2);
+		data &= ~BIT(8);
+		sram_write(tp, 0x81a2, data);
+		data = ocp_reg_read(tp, 0xb54c);
+		data &= ~0xff00;
+		data |= 0xdb00;
+		ocp_reg_write(tp, 0xb54c, data);
+
+		/* Nway 2.5G Lite */
+		data = ocp_reg_read(tp, 0xa454);
+		data &= ~BIT(0);
+		ocp_reg_write(tp, 0xa454, data);
+
+		/* CS DSP solution */
+		data = ocp_reg_read(tp, OCP_10GBT_CTRL);
+		data |= RTL_ADV2_5G_F_R;
+		ocp_reg_write(tp, OCP_10GBT_CTRL, data);
+		data = ocp_reg_read(tp, 0xad4e);
+		data &= ~BIT(4);
+		ocp_reg_write(tp, 0xad4e, data);
+		data = ocp_reg_read(tp, 0xa86a);
+		data &= ~BIT(0);
+		ocp_reg_write(tp, 0xa86a, data);
+
+		/* MDI SWAP */
+		if ((ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CFG) & MID_REVERSE) &&
+		    (ocp_reg_read(tp, 0xd068) & BIT(1))) {
+			u16 swap_a, swap_b;
+
+			data = ocp_reg_read(tp, 0xd068);
+			data &= ~0x1f;
+			data |= 0x1; /* p0 */
+			ocp_reg_write(tp, 0xd068, data);
+			swap_a = ocp_reg_read(tp, 0xd06a);
+			data &= ~0x18;
+			data |= 0x18; /* p3 */
+			ocp_reg_write(tp, 0xd068, data);
+			swap_b = ocp_reg_read(tp, 0xd06a);
+			data &= ~0x18; /* p0 */
+			ocp_reg_write(tp, 0xd068, data);
+			ocp_reg_write(tp, 0xd06a,
+				      (swap_a & ~0x7ff) | (swap_b & 0x7ff));
+			data |= 0x18; /* p3 */
+			ocp_reg_write(tp, 0xd068, data);
+			ocp_reg_write(tp, 0xd06a,
+				      (swap_b & ~0x7ff) | (swap_a & 0x7ff));
+			data &= ~0x18;
+			data |= 0x08; /* p1 */
+			ocp_reg_write(tp, 0xd068, data);
+			swap_a = ocp_reg_read(tp, 0xd06a);
+			data &= ~0x18;
+			data |= 0x10; /* p2 */
+			ocp_reg_write(tp, 0xd068, data);
+			swap_b = ocp_reg_read(tp, 0xd06a);
+			data &= ~0x18;
+			data |= 0x08; /* p1 */
+			ocp_reg_write(tp, 0xd068, data);
+			ocp_reg_write(tp, 0xd06a,
+				      (swap_a & ~0x7ff) | (swap_b & 0x7ff));
+			data &= ~0x18;
+			data |= 0x10; /* p2 */
+			ocp_reg_write(tp, 0xd068, data);
+			ocp_reg_write(tp, 0xd06a,
+				      (swap_b & ~0x7ff) | (swap_a & 0x7ff));
+			swap_a = ocp_reg_read(tp, 0xbd5a);
+			swap_b = ocp_reg_read(tp, 0xbd5c);
+			ocp_reg_write(tp, 0xbd5a, (swap_a & ~0x1f1f) |
+				      ((swap_b & 0x1f) << 8) |
+				      ((swap_b >> 8) & 0x1f));
+			ocp_reg_write(tp, 0xbd5c, (swap_b & ~0x1f1f) |
+				      ((swap_a & 0x1f) << 8) |
+				      ((swap_a >> 8) & 0x1f));
+			swap_a = ocp_reg_read(tp, 0xbc18);
+			swap_b = ocp_reg_read(tp, 0xbc1a);
+			ocp_reg_write(tp, 0xbc18, (swap_a & ~0x1f1f) |
+				      ((swap_b & 0x1f) << 8) |
+				      ((swap_b >> 8) & 0x1f));
+			ocp_reg_write(tp, 0xbc1a, (swap_b & ~0x1f1f) |
+				      ((swap_a & 0x1f) << 8) |
+				      ((swap_a >> 8) & 0x1f));
+		}
+		break;
+	default:
+		break;
+	}
+
+	rtl_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags));
+
+	data = ocp_reg_read(tp, 0xa428);
+	data &= ~BIT(9);
+	ocp_reg_write(tp, 0xa428, data);
+	data = ocp_reg_read(tp, 0xa5ea);
+	data &= ~BIT(0);
+	ocp_reg_write(tp, 0xa5ea, data);
+	tp->ups_info.lite_mode = 0;
+
+	if (tp->eee_en)
+		rtl_eee_enable(tp, true);
+
+	r8153_aldps_en(tp, true);
+	r8152b_enable_fc(tp);
+	r8153_u2p3en(tp, true);
+
+	set_bit(PHY_RESET, &tp->flags);
+}
+
+static void r8156b_hw_phy_cfg(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 data;
+
+	switch (tp->version) {
+	case RTL_VER_12:
+		ocp_reg_write(tp, 0xbf86, 0x9000);
+		data = ocp_reg_read(tp, 0xc402);
+		data |= BIT(10);
+		ocp_reg_write(tp, 0xc402, data);
+		data &= ~BIT(10);
+		ocp_reg_write(tp, 0xc402, data);
+		ocp_reg_write(tp, 0xbd86, 0x1010);
+		ocp_reg_write(tp, 0xbd88, 0x1010);
+		data = ocp_reg_read(tp, 0xbd4e);
+		data &= ~(BIT(10) | BIT(11));
+		data |= BIT(11);
+		ocp_reg_write(tp, 0xbd4e, data);
+		data = ocp_reg_read(tp, 0xbf46);
+		data &= ~0xf00;
+		data |= 0x700;
+		ocp_reg_write(tp, 0xbf46, data);
+		break;
+	case RTL_VER_13:
+	case RTL_VER_15:
+		r8156b_wait_loading_flash(tp);
+		break;
+	default:
+		break;
+	}
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+	if (ocp_data & PCUT_STATUS) {
+		ocp_data &= ~PCUT_STATUS;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
+	}
+
+	data = r8153_phy_status(tp, 0);
+	switch (data) {
+	case PHY_STAT_EXT_INIT:
+		rtl8152_apply_firmware(tp, true);
+
+		data = ocp_reg_read(tp, 0xa466);
+		data &= ~BIT(0);
+		ocp_reg_write(tp, 0xa466, data);
+
+		data = ocp_reg_read(tp, 0xa468);
+		data &= ~(BIT(3) | BIT(1));
+		ocp_reg_write(tp, 0xa468, data);
+		break;
+	case PHY_STAT_LAN_ON:
+	case PHY_STAT_PWRDN:
+	default:
+		rtl8152_apply_firmware(tp, false);
+		break;
+	}
+
+	data = r8152_mdio_read(tp, MII_BMCR);
+	if (data & BMCR_PDOWN) {
+		data &= ~BMCR_PDOWN;
+		r8152_mdio_write(tp, MII_BMCR, data);
+	}
+
+	/* disable ALDPS before updating the PHY parameters */
+	r8153_aldps_en(tp, false);
+
+	/* disable EEE before updating the PHY parameters */
+	rtl_eee_enable(tp, false);
+
+	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
+	WARN_ON_ONCE(data != PHY_STAT_LAN_ON);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
+	ocp_data |= PFM_PWM_SWITCH;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
+
+	switch (tp->version) {
+	case RTL_VER_12:
+		data = ocp_reg_read(tp, 0xbc08);
+		data |= BIT(3) | BIT(2);
+		ocp_reg_write(tp, 0xbc08, data);
+
+		data = sram_read(tp, 0x8fff);
+		data &= ~0xff00;
+		data |= 0x0400;
+		sram_write(tp, 0x8fff, data);
+
+		data = ocp_reg_read(tp, 0xacda);
+		data |= 0xff00;
+		ocp_reg_write(tp, 0xacda, data);
+		data = ocp_reg_read(tp, 0xacde);
+		data |= 0xf000;
+		ocp_reg_write(tp, 0xacde, data);
+		ocp_reg_write(tp, 0xac8c, 0x0ffc);
+		ocp_reg_write(tp, 0xac46, 0xb7b4);
+		ocp_reg_write(tp, 0xac50, 0x0fbc);
+		ocp_reg_write(tp, 0xac3c, 0x9240);
+		ocp_reg_write(tp, 0xac4e, 0x0db4);
+		ocp_reg_write(tp, 0xacc6, 0x0707);
+		ocp_reg_write(tp, 0xacc8, 0xa0d3);
+		ocp_reg_write(tp, 0xad08, 0x0007);
+
+		ocp_reg_write(tp, 0xb87c, 0x8560);
+		ocp_reg_write(tp, 0xb87e, 0x19cc);
+		ocp_reg_write(tp, 0xb87c, 0x8562);
+		ocp_reg_write(tp, 0xb87e, 0x19cc);
+		ocp_reg_write(tp, 0xb87c, 0x8564);
+		ocp_reg_write(tp, 0xb87e, 0x19cc);
+		ocp_reg_write(tp, 0xb87c, 0x8566);
+		ocp_reg_write(tp, 0xb87e, 0x147d);
+		ocp_reg_write(tp, 0xb87c, 0x8568);
+		ocp_reg_write(tp, 0xb87e, 0x147d);
+		ocp_reg_write(tp, 0xb87c, 0x856a);
+		ocp_reg_write(tp, 0xb87e, 0x147d);
+		ocp_reg_write(tp, 0xb87c, 0x8ffe);
+		ocp_reg_write(tp, 0xb87e, 0x0907);
+		ocp_reg_write(tp, 0xb87c, 0x80d6);
+		ocp_reg_write(tp, 0xb87e, 0x2801);
+		ocp_reg_write(tp, 0xb87c, 0x80f2);
+		ocp_reg_write(tp, 0xb87e, 0x2801);
+		ocp_reg_write(tp, 0xb87c, 0x80f4);
+		ocp_reg_write(tp, 0xb87e, 0x6077);
+		ocp_reg_write(tp, 0xb506, 0x01e7);
+
+		ocp_reg_write(tp, 0xb87c, 0x8013);
+		ocp_reg_write(tp, 0xb87e, 0x0700);
+		ocp_reg_write(tp, 0xb87c, 0x8fb9);
+		ocp_reg_write(tp, 0xb87e, 0x2801);
+		ocp_reg_write(tp, 0xb87c, 0x8fba);
+		ocp_reg_write(tp, 0xb87e, 0x0100);
+		ocp_reg_write(tp, 0xb87c, 0x8fbc);
+		ocp_reg_write(tp, 0xb87e, 0x1900);
+		ocp_reg_write(tp, 0xb87c, 0x8fbe);
+		ocp_reg_write(tp, 0xb87e, 0xe100);
+		ocp_reg_write(tp, 0xb87c, 0x8fc0);
+		ocp_reg_write(tp, 0xb87e, 0x0800);
+		ocp_reg_write(tp, 0xb87c, 0x8fc2);
+		ocp_reg_write(tp, 0xb87e, 0xe500);
+		ocp_reg_write(tp, 0xb87c, 0x8fc4);
+		ocp_reg_write(tp, 0xb87e, 0x0f00);
+		ocp_reg_write(tp, 0xb87c, 0x8fc6);
+		ocp_reg_write(tp, 0xb87e, 0xf100);
+		ocp_reg_write(tp, 0xb87c, 0x8fc8);
+		ocp_reg_write(tp, 0xb87e, 0x0400);
+		ocp_reg_write(tp, 0xb87c, 0x8fca);
+		ocp_reg_write(tp, 0xb87e, 0xf300);
+		ocp_reg_write(tp, 0xb87c, 0x8fcc);
+		ocp_reg_write(tp, 0xb87e, 0xfd00);
+		ocp_reg_write(tp, 0xb87c, 0x8fce);
+		ocp_reg_write(tp, 0xb87e, 0xff00);
+		ocp_reg_write(tp, 0xb87c, 0x8fd0);
+		ocp_reg_write(tp, 0xb87e, 0xfb00);
+		ocp_reg_write(tp, 0xb87c, 0x8fd2);
+		ocp_reg_write(tp, 0xb87e, 0x0100);
+		ocp_reg_write(tp, 0xb87c, 0x8fd4);
+		ocp_reg_write(tp, 0xb87e, 0xf400);
+		ocp_reg_write(tp, 0xb87c, 0x8fd6);
+		ocp_reg_write(tp, 0xb87e, 0xff00);
+		ocp_reg_write(tp, 0xb87c, 0x8fd8);
+		ocp_reg_write(tp, 0xb87e, 0xf600);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_USB_CFG);
+		ocp_data |= EN_XG_LIP | EN_G_LIP;
+		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_USB_CFG, ocp_data);
+		ocp_reg_write(tp, 0xb87c, 0x813d);
+		ocp_reg_write(tp, 0xb87e, 0x390e);
+		ocp_reg_write(tp, 0xb87c, 0x814f);
+		ocp_reg_write(tp, 0xb87e, 0x790e);
+		ocp_reg_write(tp, 0xb87c, 0x80b0);
+		ocp_reg_write(tp, 0xb87e, 0x0f31);
+		data = ocp_reg_read(tp, 0xbf4c);
+		data |= BIT(1);
+		ocp_reg_write(tp, 0xbf4c, data);
+		data = ocp_reg_read(tp, 0xbcca);
+		data |= BIT(9) | BIT(8);
+		ocp_reg_write(tp, 0xbcca, data);
+		ocp_reg_write(tp, 0xb87c, 0x8141);
+		ocp_reg_write(tp, 0xb87e, 0x320e);
+		ocp_reg_write(tp, 0xb87c, 0x8153);
+		ocp_reg_write(tp, 0xb87e, 0x720e);
+		ocp_reg_write(tp, 0xb87c, 0x8529);
+		ocp_reg_write(tp, 0xb87e, 0x050e);
+		data = ocp_reg_read(tp, OCP_EEE_CFG);
+		data &= ~CTAP_SHORT_EN;
+		ocp_reg_write(tp, OCP_EEE_CFG, data);
+
+		sram_write(tp, 0x816c, 0xc4a0);
+		sram_write(tp, 0x8170, 0xc4a0);
+		sram_write(tp, 0x8174, 0x04a0);
+		sram_write(tp, 0x8178, 0x04a0);
+		sram_write(tp, 0x817c, 0x0719);
+		sram_write(tp, 0x8ff4, 0x0400);
+		sram_write(tp, 0x8ff1, 0x0404);
+
+		ocp_reg_write(tp, 0xbf4a, 0x001b);
+		ocp_reg_write(tp, 0xb87c, 0x8033);
+		ocp_reg_write(tp, 0xb87e, 0x7c13);
+		ocp_reg_write(tp, 0xb87c, 0x8037);
+		ocp_reg_write(tp, 0xb87e, 0x7c13);
+		ocp_reg_write(tp, 0xb87c, 0x803b);
+		ocp_reg_write(tp, 0xb87e, 0xfc32);
+		ocp_reg_write(tp, 0xb87c, 0x803f);
+		ocp_reg_write(tp, 0xb87e, 0x7c13);
+		ocp_reg_write(tp, 0xb87c, 0x8043);
+		ocp_reg_write(tp, 0xb87e, 0x7c13);
+		ocp_reg_write(tp, 0xb87c, 0x8047);
+		ocp_reg_write(tp, 0xb87e, 0x7c13);
+
+		ocp_reg_write(tp, 0xb87c, 0x8145);
+		ocp_reg_write(tp, 0xb87e, 0x370e);
+		ocp_reg_write(tp, 0xb87c, 0x8157);
+		ocp_reg_write(tp, 0xb87e, 0x770e);
+		ocp_reg_write(tp, 0xb87c, 0x8169);
+		ocp_reg_write(tp, 0xb87e, 0x0d0a);
+		ocp_reg_write(tp, 0xb87c, 0x817b);
+		ocp_reg_write(tp, 0xb87e, 0x1d0a);
+
+		data = sram_read(tp, 0x8217);
+		data &= ~0xff00;
+		data |= 0x5000;
+		sram_write(tp, 0x8217, data);
+		data = sram_read(tp, 0x821a);
+		data &= ~0xff00;
+		data |= 0x5000;
+		sram_write(tp, 0x821a, data);
+		sram_write(tp, 0x80da, 0x0403);
+		data = sram_read(tp, 0x80dc);
+		data &= ~0xff00;
+		data |= 0x1000;
+		sram_write(tp, 0x80dc, data);
+		sram_write(tp, 0x80b3, 0x0384);
+		sram_write(tp, 0x80b7, 0x2007);
+		data = sram_read(tp, 0x80ba);
+		data &= ~0xff00;
+		data |= 0x6c00;
+		sram_write(tp, 0x80ba, data);
+		sram_write(tp, 0x80b5, 0xf009);
+		data = sram_read(tp, 0x80bd);
+		data &= ~0xff00;
+		data |= 0x9f00;
+		sram_write(tp, 0x80bd, data);
+		sram_write(tp, 0x80c7, 0xf083);
+		sram_write(tp, 0x80dd, 0x03f0);
+		data = sram_read(tp, 0x80df);
+		data &= ~0xff00;
+		data |= 0x1000;
+		sram_write(tp, 0x80df, data);
+		sram_write(tp, 0x80cb, 0x2007);
+		data = sram_read(tp, 0x80ce);
+		data &= ~0xff00;
+		data |= 0x6c00;
+		sram_write(tp, 0x80ce, data);
+		sram_write(tp, 0x80c9, 0x8009);
+		data = sram_read(tp, 0x80d1);
+		data &= ~0xff00;
+		data |= 0x8000;
+		sram_write(tp, 0x80d1, data);
+		sram_write(tp, 0x80a3, 0x200a);
+		sram_write(tp, 0x80a5, 0xf0ad);
+		sram_write(tp, 0x809f, 0x6073);
+		sram_write(tp, 0x80a1, 0x000b);
+		data = sram_read(tp, 0x80a9);
+		data &= ~0xff00;
+		data |= 0xc000;
+		sram_write(tp, 0x80a9, data);
+
+		if (rtl_phy_patch_request(tp, true, true))
+			return;
+
+		data = ocp_reg_read(tp, 0xb896);
+		data &= ~BIT(0);
+		ocp_reg_write(tp, 0xb896, data);
+		data = ocp_reg_read(tp, 0xb892);
+		data &= ~0xff00;
+		ocp_reg_write(tp, 0xb892, data);
+		ocp_reg_write(tp, 0xb88e, 0xc23e);
+		ocp_reg_write(tp, 0xb890, 0x0000);
+		ocp_reg_write(tp, 0xb88e, 0xc240);
+		ocp_reg_write(tp, 0xb890, 0x0103);
+		ocp_reg_write(tp, 0xb88e, 0xc242);
+		ocp_reg_write(tp, 0xb890, 0x0507);
+		ocp_reg_write(tp, 0xb88e, 0xc244);
+		ocp_reg_write(tp, 0xb890, 0x090b);
+		ocp_reg_write(tp, 0xb88e, 0xc246);
+		ocp_reg_write(tp, 0xb890, 0x0c0e);
+		ocp_reg_write(tp, 0xb88e, 0xc248);
+		ocp_reg_write(tp, 0xb890, 0x1012);
+		ocp_reg_write(tp, 0xb88e, 0xc24a);
+		ocp_reg_write(tp, 0xb890, 0x1416);
+		data = ocp_reg_read(tp, 0xb896);
+		data |= BIT(0);
+		ocp_reg_write(tp, 0xb896, data);
+
+		rtl_phy_patch_request(tp, false, true);
+
+		data = ocp_reg_read(tp, 0xa86a);
+		data |= BIT(0);
+		ocp_reg_write(tp, 0xa86a, data);
+		data = ocp_reg_read(tp, 0xa6f0);
+		data |= BIT(0);
+		ocp_reg_write(tp, 0xa6f0, data);
+
+		ocp_reg_write(tp, 0xbfa0, 0xd70d);
+		ocp_reg_write(tp, 0xbfa2, 0x4100);
+		ocp_reg_write(tp, 0xbfa4, 0xe868);
+		ocp_reg_write(tp, 0xbfa6, 0xdc59);
+		ocp_reg_write(tp, 0xb54c, 0x3c18);
+		data = ocp_reg_read(tp, 0xbfa4);
+		data &= ~BIT(5);
+		ocp_reg_write(tp, 0xbfa4, data);
+		data = sram_read(tp, 0x817d);
+		data |= BIT(12);
+		sram_write(tp, 0x817d, data);
+		break;
+	case RTL_VER_13:
+		/* 2.5G INRX */
+		data = ocp_reg_read(tp, 0xac46);
+		data &= ~0x00f0;
+		data |= 0x0090;
+		ocp_reg_write(tp, 0xac46, data);
+		data = ocp_reg_read(tp, 0xad30);
+		data &= ~0x0003;
+		data |= 0x0001;
+		ocp_reg_write(tp, 0xad30, data);
+		fallthrough;
+	case RTL_VER_15:
+		/* EEE parameter */
+		ocp_reg_write(tp, 0xb87c, 0x80f5);
+		ocp_reg_write(tp, 0xb87e, 0x760e);
+		ocp_reg_write(tp, 0xb87c, 0x8107);
+		ocp_reg_write(tp, 0xb87e, 0x360e);
+		ocp_reg_write(tp, 0xb87c, 0x8551);
+		data = ocp_reg_read(tp, 0xb87e);
+		data &= ~0xff00;
+		data |= 0x0800;
+		ocp_reg_write(tp, 0xb87e, data);
+
+		/* ADC_PGA parameter */
+		data = ocp_reg_read(tp, 0xbf00);
+		data &= ~0xe000;
+		data |= 0xa000;
+		ocp_reg_write(tp, 0xbf00, data);
+		data = ocp_reg_read(tp, 0xbf46);
+		data &= ~0x0f00;
+		data |= 0x0300;
+		ocp_reg_write(tp, 0xbf46, data);
+
+		/* Green Table-PGA, 1G full viterbi */
+		sram_write(tp, 0x8044, 0x2417);
+		sram_write(tp, 0x804a, 0x2417);
+		sram_write(tp, 0x8050, 0x2417);
+		sram_write(tp, 0x8056, 0x2417);
+		sram_write(tp, 0x805c, 0x2417);
+		sram_write(tp, 0x8062, 0x2417);
+		sram_write(tp, 0x8068, 0x2417);
+		sram_write(tp, 0x806e, 0x2417);
+		sram_write(tp, 0x8074, 0x2417);
+		sram_write(tp, 0x807a, 0x2417);
+
+		/* XG PLL */
+		data = ocp_reg_read(tp, 0xbf84);
+		data &= ~0xe000;
+		data |= 0xa000;
+		ocp_reg_write(tp, 0xbf84, data);
+		break;
+	default:
+		break;
+	}
+
+	if (rtl_phy_patch_request(tp, true, true))
+		return;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4);
+	ocp_data |= EEE_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, ocp_data);
+
+	data = ocp_reg_read(tp, OCP_DOWN_SPEED);
+	data &= ~(EN_EEE_100 | EN_EEE_1000);
+	data |= EN_10M_CLKDIV;
+	ocp_reg_write(tp, OCP_DOWN_SPEED, data);
+	tp->ups_info._10m_ckdiv = true;
+	tp->ups_info.eee_plloff_100 = false;
+	tp->ups_info.eee_plloff_giga = false;
+
+	data = ocp_reg_read(tp, OCP_POWER_CFG);
+	data &= ~EEE_CLKDIV_EN;
+	ocp_reg_write(tp, OCP_POWER_CFG, data);
+	tp->ups_info.eee_ckdiv = false;
+
+	rtl_phy_patch_request(tp, false, true);
+
+	rtl_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags));
+
+	data = ocp_reg_read(tp, 0xa428);
+	data &= ~BIT(9);
+	ocp_reg_write(tp, 0xa428, data);
+	data = ocp_reg_read(tp, 0xa5ea);
+	data &= ~BIT(0);
+	ocp_reg_write(tp, 0xa5ea, data);
+	tp->ups_info.lite_mode = 0;
+
+	if (tp->eee_en)
+		rtl_eee_enable(tp, true);
+
+	r8153_aldps_en(tp, true);
+	r8152b_enable_fc(tp);
+	r8153_u2p3en(tp, true);
+
+	set_bit(PHY_RESET, &tp->flags);
+}
+
+static void r8156_init(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 data;
+	int i;
+
+	if (test_bit(RTL8152_UNPLUG, &tp->flags))
+		return;
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_ECM_OP);
+	ocp_data &= ~EN_ALL_SPEED;
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_ECM_OP, ocp_data);
+
+	ocp_write_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION, 0);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_ECM_OPTION);
+	ocp_data |= BYPASS_MAC_RESET;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_ECM_OPTION, ocp_data);
+
+	r8153b_u1u2en(tp, false);
+
+	for (i = 0; i < 500; i++) {
+		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
+		    AUTOLOAD_DONE)
+			break;
+
+		msleep(20);
+		if (test_bit(RTL8152_UNPLUG, &tp->flags))
+			return;
+	}
+
+	data = r8153_phy_status(tp, 0);
+	if (data == PHY_STAT_EXT_INIT) {
+		data = ocp_reg_read(tp, 0xa468);
+		data &= ~(BIT(3) | BIT(1));
+		ocp_reg_write(tp, 0xa468, data);
+	}
+
+	data = r8152_mdio_read(tp, MII_BMCR);
+	if (data & BMCR_PDOWN) {
+		data &= ~BMCR_PDOWN;
+		r8152_mdio_write(tp, MII_BMCR, data);
+	}
+
+	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
+	WARN_ON_ONCE(data != PHY_STAT_LAN_ON);
+
+	r8153_u2p3en(tp, false);
+
+	/* MSC timer = 0xfff * 8ms = 32760 ms */
+	ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
+
+	/* U1/U2/L1 idle timer. 500 us */
+	ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
+
+	r8153b_power_cut_en(tp, false);
+	r8156_ups_en(tp, false);
+	r8153_queue_wake(tp, false);
+	rtl_runtime_suspend_enable(tp, false);
+
+	if (tp->udev->speed >= USB_SPEED_SUPER)
+		r8153b_u1u2en(tp, true);
+
+	usb_enable_lpm(tp->udev);
+
+	r8156_mac_clk_spd(tp, true);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
+	ocp_data &= ~PLA_MCU_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
+	if (rtl8152_get_speed(tp) & LINK_STATUS)
+		ocp_data |= CUR_LINK_OK;
+	else
+		ocp_data &= ~CUR_LINK_OK;
+	ocp_data |= POLL_LINK_CHG;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
+
+	set_bit(GREEN_ETHERNET, &tp->flags);
+
+	/* rx aggregation */
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_BMU_CONFIG);
+	ocp_data |= ACT_ODMA;
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_CONFIG, ocp_data);
+
+	rtl_tally_reset(tp);
+
+	tp->coalesce = 15000;	/* 15 us */
+}
+
+static void r8156b_init(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 data;
+	int i;
+
+	if (test_bit(RTL8152_UNPLUG, &tp->flags))
+		return;
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_ECM_OP);
+	ocp_data &= ~EN_ALL_SPEED;
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_ECM_OP, ocp_data);
+
+	ocp_write_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION, 0);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_ECM_OPTION);
+	ocp_data |= BYPASS_MAC_RESET;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_ECM_OPTION, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
+	ocp_data |= RX_DETECT8;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
+
+	r8153b_u1u2en(tp, false);
+
+	switch (tp->version) {
+	case RTL_VER_13:
+	case RTL_VER_15:
+		r8156b_wait_loading_flash(tp);
+		break;
+	default:
+		break;
+	}
+
+	for (i = 0; i < 500; i++) {
+		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
+		    AUTOLOAD_DONE)
+			break;
+
+		msleep(20);
+		if (test_bit(RTL8152_UNPLUG, &tp->flags))
+			return;
+	}
+
+	data = r8153_phy_status(tp, 0);
+	if (data == PHY_STAT_EXT_INIT) {
+		data = ocp_reg_read(tp, 0xa468);
+		data &= ~(BIT(3) | BIT(1));
+		ocp_reg_write(tp, 0xa468, data);
+
+		data = ocp_reg_read(tp, 0xa466);
+		data &= ~BIT(0);
+		ocp_reg_write(tp, 0xa466, data);
+	}
+
+	data = r8152_mdio_read(tp, MII_BMCR);
+	if (data & BMCR_PDOWN) {
+		data &= ~BMCR_PDOWN;
+		r8152_mdio_write(tp, MII_BMCR, data);
+	}
+
+	data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
+
+	r8153_u2p3en(tp, false);
+
+	/* MSC timer = 0xfff * 8ms = 32760 ms */
+	ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
+
+	/* U1/U2/L1 idle timer. 500 us */
+	ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
+
+	r8153b_power_cut_en(tp, false);
+	r8156_ups_en(tp, false);
+	r8153_queue_wake(tp, false);
+	rtl_runtime_suspend_enable(tp, false);
+
+	if (tp->udev->speed >= USB_SPEED_SUPER)
+		r8153b_u1u2en(tp, true);
+
+	usb_enable_lpm(tp->udev);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data &= ~SLOT_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
+	ocp_data |= FLOW_CTRL_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
+
+	/* enable fc timer and set timer to 600 ms. */
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FC_TIMER,
+		       CTRL_TIMER_EN | (600 / 8));
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_CTRL);
+	if (!(ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL) & DACK_DET_EN))
+		ocp_data |= FLOW_CTRL_PATCH_2;
+	ocp_data &= ~AUTO_SPEEDUP;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_CTRL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK);
+	ocp_data |= FC_PATCH_TASK;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data);
+
+	r8156_mac_clk_spd(tp, true);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
+	ocp_data &= ~PLA_MCU_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
+	if (rtl8152_get_speed(tp) & LINK_STATUS)
+		ocp_data |= CUR_LINK_OK;
+	else
+		ocp_data &= ~CUR_LINK_OK;
+	ocp_data |= POLL_LINK_CHG;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
+
+	set_bit(GREEN_ETHERNET, &tp->flags);
+
+	/* rx aggregation */
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+
+	rtl_tally_reset(tp);
+
+	tp->coalesce = 15000;	/* 15 us */
+}
+
+static bool rtl_vendor_mode(struct usb_interface *intf)
+{
+	struct usb_host_interface *alt = intf->cur_altsetting;
+	struct usb_device *udev;
+	struct usb_host_config *c;
+	int i, num_configs;
+
+	if (alt->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC)
+		return true;
+
+	/* The vendor mode is not always config #1, so to find it out. */
+	udev = interface_to_usbdev(intf);
+	c = udev->config;
+	num_configs = udev->descriptor.bNumConfigurations;
+	for (i = 0; i < num_configs; (i++, c++)) {
+		struct usb_interface_descriptor	*desc = NULL;
+
+		if (c->desc.bNumInterfaces > 0)
+			desc = &c->intf_cache[0]->altsetting->desc;
+		else
+			continue;
+
+		if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
+			usb_driver_set_configuration(udev, c->desc.bConfigurationValue);
+			break;
+		}
+	}
+
+	WARN_ON_ONCE(i == num_configs);
+
+	return false;
+}
+
 static int rtl8152_pre_reset(struct usb_interface *intf)
 {
 	struct r8152 *tp = usb_get_intfdata(intf);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:8293 @
 	struct net_device *netdev = tp->netdev;
 	int ret = 0;
 
+	if (!tp->rtl_ops.autosuspend_en)
+		return -EBUSY;
+
 	set_bit(SELECTIVE_SUSPEND, &tp->flags);
 	smp_mb__after_atomic();
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:8506 @
 
 	mii_ethtool_get_link_ksettings(&tp->mii, cmd);
 
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+			 cmd->link_modes.supported, tp->support_2500full);
+
+	if (tp->support_2500full) {
+		linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+				 cmd->link_modes.advertising,
+				 ocp_reg_read(tp, OCP_10GBT_CTRL) & MDIO_AN_10GBT_CTRL_ADV2_5G);
+
+		linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+				 cmd->link_modes.lp_advertising,
+				 ocp_reg_read(tp, OCP_10GBT_STAT) & MDIO_AN_10GBT_STAT_LP2_5G);
+
+		if (is_speed_2500(rtl8152_get_speed(tp)))
+			cmd->base.speed = SPEED_2500;
+	}
+
 	mutex_unlock(&tp->control);
 
 	usb_autopm_put_interface(tp->intf);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:8565 @
 		     cmd->link_modes.advertising))
 		advertising |= RTL_ADVERTISED_1000_FULL;
 
+	if (test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+		     cmd->link_modes.advertising))
+		advertising |= RTL_ADVERTISED_2500_FULL;
+
 	mutex_lock(&tp->control);
 
 	ret = rtl8152_set_speed(tp, cmd->base.autoneg, cmd->base.speed,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:8715 @
 	struct r8152 *tp = netdev_priv(net);
 	int ret;
 
+	if (!tp->rtl_ops.eee_get) {
+		ret = -EOPNOTSUPP;
+		goto out;
+	}
+
 	ret = usb_autopm_get_interface(tp->intf);
 	if (ret < 0)
 		goto out;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:8742 @
 	struct r8152 *tp = netdev_priv(net);
 	int ret;
 
+	if (!tp->rtl_ops.eee_set) {
+		ret = -EOPNOTSUPP;
+		goto out;
+	}
+
 	ret = usb_autopm_get_interface(tp->intf);
 	if (ret < 0)
 		goto out;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9027 @
 	dev->mtu = new_mtu;
 
 	if (netif_running(dev)) {
-		u32 rms = new_mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
+		if (tp->rtl_ops.change_mtu)
+			tp->rtl_ops.change_mtu(tp);
 
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, rms);
-
-		if (netif_carrier_ok(dev))
-			r8153_set_rx_early_size(tp);
+		if (netif_carrier_ok(dev)) {
+			netif_stop_queue(dev);
+			napi_disable(&tp->napi);
+			tasklet_disable(&tp->tx_tl);
+			tp->rtl_ops.disable(tp);
+			tp->rtl_ops.enable(tp);
+			rtl_start_rx(tp);
+			tasklet_enable(&tp->tx_tl);
+			napi_enable(&tp->napi);
+			rtl8152_set_rx_mode(dev);
+			netif_wake_queue(dev);
+		}
 	}
 
 	mutex_unlock(&tp->control);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9130 @
 		ops->in_nway		= rtl8153_in_nway;
 		ops->hw_phy_cfg		= r8153_hw_phy_cfg;
 		ops->autosuspend_en	= rtl8153_runtime_enable;
+		ops->change_mtu		= rtl8153_change_mtu;
 		if (tp->udev->speed < USB_SPEED_SUPER)
 			tp->rx_buf_sz	= 16 * 1024;
 		else
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9152 @
 		ops->in_nway		= rtl8153_in_nway;
 		ops->hw_phy_cfg		= r8153b_hw_phy_cfg;
 		ops->autosuspend_en	= rtl8153b_runtime_enable;
+		ops->change_mtu		= rtl8153_change_mtu;
+		tp->rx_buf_sz		= 32 * 1024;
+		tp->eee_en		= true;
+		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
+		break;
+
+	case RTL_VER_11:
+		tp->eee_en		= true;
+		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
+		fallthrough;
+	case RTL_VER_10:
+		ops->init		= r8156_init;
+		ops->enable		= rtl8156_enable;
+		ops->disable		= rtl8153_disable;
+		ops->up			= rtl8156_up;
+		ops->down		= rtl8156_down;
+		ops->unload		= rtl8153_unload;
+		ops->eee_get		= r8153_get_eee;
+		ops->eee_set		= r8152_set_eee;
+		ops->in_nway		= rtl8153_in_nway;
+		ops->hw_phy_cfg		= r8156_hw_phy_cfg;
+		ops->autosuspend_en	= rtl8156_runtime_enable;
+		ops->change_mtu		= rtl8156_change_mtu;
+		tp->rx_buf_sz		= 48 * 1024;
+		tp->support_2500full	= 1;
+		break;
+
+	case RTL_VER_12:
+	case RTL_VER_13:
+		tp->support_2500full	= 1;
+		fallthrough;
+	case RTL_VER_15:
+		tp->eee_en		= true;
+		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
+		ops->init		= r8156b_init;
+		ops->enable		= rtl8156b_enable;
+		ops->disable		= rtl8153_disable;
+		ops->up			= rtl8156_up;
+		ops->down		= rtl8156_down;
+		ops->unload		= rtl8153_unload;
+		ops->eee_get		= r8153_get_eee;
+		ops->eee_set		= r8152_set_eee;
+		ops->in_nway		= rtl8153_in_nway;
+		ops->hw_phy_cfg		= r8156b_hw_phy_cfg;
+		ops->autosuspend_en	= rtl8156_runtime_enable;
+		ops->change_mtu		= rtl8156_change_mtu;
+		tp->rx_buf_sz		= 48 * 1024;
+		break;
+
+	case RTL_VER_14:
+		ops->init		= r8153c_init;
+		ops->enable		= rtl8153_enable;
+		ops->disable		= rtl8153_disable;
+		ops->up			= rtl8153c_up;
+		ops->down		= rtl8153b_down;
+		ops->unload		= rtl8153_unload;
+		ops->eee_get		= r8153_get_eee;
+		ops->eee_set		= r8152_set_eee;
+		ops->in_nway		= rtl8153_in_nway;
+		ops->hw_phy_cfg		= r8153c_hw_phy_cfg;
+		ops->autosuspend_en	= rtl8153c_runtime_enable;
+		ops->change_mtu		= rtl8153c_change_mtu;
 		tp->rx_buf_sz		= 32 * 1024;
 		tp->eee_en		= true;
 		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9221 @
 
 	default:
 		ret = -ENODEV;
-		netif_err(tp, probe, tp->netdev, "Unknown Device\n");
+		dev_err(&tp->intf->dev, "Unknown Device\n");
 		break;
 	}
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9232 @
 #define FIRMWARE_8153A_3	"rtl_nic/rtl8153a-3.fw"
 #define FIRMWARE_8153A_4	"rtl_nic/rtl8153a-4.fw"
 #define FIRMWARE_8153B_2	"rtl_nic/rtl8153b-2.fw"
+#define FIRMWARE_8153C_1	"rtl_nic/rtl8153c-1.fw"
+#define FIRMWARE_8156A_2	"rtl_nic/rtl8156a-2.fw"
+#define FIRMWARE_8156B_2	"rtl_nic/rtl8156b-2.fw"
 
 MODULE_FIRMWARE(FIRMWARE_8153A_2);
 MODULE_FIRMWARE(FIRMWARE_8153A_3);
 MODULE_FIRMWARE(FIRMWARE_8153A_4);
 MODULE_FIRMWARE(FIRMWARE_8153B_2);
+MODULE_FIRMWARE(FIRMWARE_8153C_1);
+MODULE_FIRMWARE(FIRMWARE_8156A_2);
+MODULE_FIRMWARE(FIRMWARE_8156B_2);
 
 static int rtl_fw_init(struct r8152 *tp)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9268 @
 		rtl_fw->pre_fw		= r8153b_pre_firmware_1;
 		rtl_fw->post_fw		= r8153b_post_firmware_1;
 		break;
+	case RTL_VER_11:
+		rtl_fw->fw_name		= FIRMWARE_8156A_2;
+		rtl_fw->post_fw		= r8156a_post_firmware_1;
+		break;
+	case RTL_VER_13:
+	case RTL_VER_15:
+		rtl_fw->fw_name		= FIRMWARE_8156B_2;
+		break;
+	case RTL_VER_14:
+		rtl_fw->fw_name		= FIRMWARE_8153C_1;
+		rtl_fw->pre_fw		= r8153b_pre_firmware_1;
+		rtl_fw->post_fw		= r8153c_post_firmware_1;
+		break;
 	default:
 		break;
 	}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9288 @
 	return 0;
 }
 
-static u8 rtl_get_version(struct usb_interface *intf)
+u8 rtl8152_get_version(struct usb_interface *intf)
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	u32 ocp_data = 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9336 @
 	case 0x6010:
 		version = RTL_VER_09;
 		break;
+	case 0x7010:
+		version = RTL_TEST_01;
+		break;
+	case 0x7020:
+		version = RTL_VER_10;
+		break;
+	case 0x7030:
+		version = RTL_VER_11;
+		break;
+	case 0x7400:
+		version = RTL_VER_12;
+		break;
+	case 0x7410:
+		version = RTL_VER_13;
+		break;
+	case 0x6400:
+		version = RTL_VER_14;
+		break;
+	case 0x7420:
+		version = RTL_VER_15;
+		break;
 	default:
 		version = RTL_VER_UNKNOWN;
 		dev_info(&intf->dev, "Unknown version 0x%04x\n", ocp_data);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9367 @
 
 	return version;
 }
+EXPORT_SYMBOL_GPL(rtl8152_get_version);
 
 static int rtl8152_probe(struct usb_interface *intf,
 			 const struct usb_device_id *id)
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
-	u8 version = rtl_get_version(intf);
+	u8 version = rtl8152_get_version(intf);
 	struct r8152 *tp;
 	struct net_device *netdev;
 	int ret;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9381 @
 	if (version == RTL_VER_UNKNOWN)
 		return -ENODEV;
 
-	if (udev->actconfig->desc.bConfigurationValue != 1) {
-		usb_driver_set_configuration(udev, 1);
+	if (!rtl_vendor_mode(intf))
 		return -ENODEV;
-	}
 
 	if (intf->cur_altsetting->desc.bNumEndpoints < 3)
 		return -ENODEV;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9423 @
 	mutex_init(&tp->control);
 	INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
 	INIT_DELAYED_WORK(&tp->hw_phy_work, rtl_hw_phy_work_func_t);
-	tasklet_init(&tp->tx_tl, bottom_half, (unsigned long)tp);
+	tasklet_setup(&tp->tx_tl, bottom_half);
 	tasklet_disable(&tp->tx_tl);
 
 	netdev->netdev_ops = &rtl8152_netdev_ops;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9467 @
 	/* MTU range: 68 - 1500 or 9194 */
 	netdev->min_mtu = ETH_MIN_MTU;
 	switch (tp->version) {
+	case RTL_VER_03:
+	case RTL_VER_04:
+	case RTL_VER_05:
+	case RTL_VER_06:
+	case RTL_VER_08:
+	case RTL_VER_09:
+	case RTL_VER_14:
+		netdev->max_mtu = size_to_mtu(9 * 1024);
+		break;
+	case RTL_VER_10:
+	case RTL_VER_11:
+		netdev->max_mtu = size_to_mtu(15 * 1024);
+		break;
+	case RTL_VER_12:
+	case RTL_VER_13:
+	case RTL_VER_15:
+		netdev->max_mtu = size_to_mtu(16 * 1024);
+		break;
 	case RTL_VER_01:
 	case RTL_VER_02:
-		netdev->max_mtu = ETH_DATA_LEN;
-		break;
+	case RTL_VER_07:
 	default:
-		netdev->max_mtu = RTL8153_MAX_MTU;
+		netdev->max_mtu = ETH_DATA_LEN;
 		break;
 	}
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9505 @
 	tp->advertising = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL |
 			  RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL;
 	if (tp->mii.supports_gmii) {
-		tp->speed = SPEED_1000;
+		if (tp->support_2500full &&
+		    tp->udev->speed >= USB_SPEED_SUPER) {
+			tp->speed = SPEED_2500;
+			tp->advertising |= RTL_ADVERTISED_2500_FULL;
+		} else {
+			tp->speed = SPEED_1000;
+		}
 		tp->advertising |= RTL_ADVERTISED_1000_FULL;
 	}
 	tp->duplex = DUPLEX_FULL;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9535 @
 	set_ethernet_addr(tp);
 
 	usb_set_intfdata(intf, tp);
-	netif_napi_add(netdev, &tp->napi, r8152_poll, RTL8152_NAPI_WEIGHT);
+
+	if (tp->support_2500full)
+		netif_napi_add(netdev, &tp->napi, r8152_poll, 256);
+	else
+		netif_napi_add(netdev, &tp->napi, r8152_poll, 64);
 
 	ret = register_netdev(netdev);
 	if (ret != 0) {
-		netif_err(tp, probe, netdev, "couldn't register the device\n");
+		dev_err(&intf->dev, "couldn't register the device\n");
 		goto out1;
 	}
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9575 @
 		unregister_netdev(tp->netdev);
 		tasklet_kill(&tp->tx_tl);
 		cancel_delayed_work_sync(&tp->hw_phy_work);
-		tp->rtl_ops.unload(tp);
+		if (tp->rtl_ops.unload)
+			tp->rtl_ops.unload(tp);
 		rtl8152_release_firmware(tp);
 		free_netdev(tp->netdev);
 	}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9596 @
 	.idProduct = (prod), \
 	.bInterfaceClass = USB_CLASS_COMM, \
 	.bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
+	.bInterfaceProtocol = USB_CDC_PROTO_NONE \
+}, \
+{ \
+	.match_flags = USB_DEVICE_ID_MATCH_INT_INFO | \
+		       USB_DEVICE_ID_MATCH_DEVICE, \
+	.idVendor = (vend), \
+	.idProduct = (prod), \
+	.bInterfaceClass = USB_CLASS_COMM, \
+	.bInterfaceSubClass = USB_CDC_SUBCLASS_NCM, \
 	.bInterfaceProtocol = USB_CDC_PROTO_NONE
 
 /* table of devices that work with this driver */
 static const struct usb_device_id rtl8152_table[] = {
+	/* Realtek */
 	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8050)},
+	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8053)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},
+	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8155)},
+	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8156)},
+
+	/* Microsoft */
 	{REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927)},
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/usb/r8153_ecm.c linux-5.10.52-v7l+/drivers/net/usb/r8153_ecm.c
--- linux-5.10.52-orig/drivers/net/usb/r8153_ecm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/net/usb/r8153_ecm.c	2021-07-25 16:46:16.038122022 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+#include <linux/usb/r8152.h>
+
+#define OCP_BASE		0xe86c
+
+static int pla_read_word(struct usbnet *dev, u16 index)
+{
+	u16 byen = BYTE_EN_WORD;
+	u8 shift = index & 2;
+	__le32 tmp;
+	int ret;
+
+	if (shift)
+		byen <<= shift;
+
+	index &= ~3;
+
+	ret = usbnet_read_cmd(dev, RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, index,
+			      MCU_TYPE_PLA | byen, &tmp, sizeof(tmp));
+	if (ret < 0)
+		goto out;
+
+	ret = __le32_to_cpu(tmp);
+	ret >>= (shift * 8);
+	ret &= 0xffff;
+
+out:
+	return ret;
+}
+
+static int pla_write_word(struct usbnet *dev, u16 index, u32 data)
+{
+	u32 mask = 0xffff;
+	u16 byen = BYTE_EN_WORD;
+	u8 shift = index & 2;
+	__le32 tmp;
+	int ret;
+
+	data &= mask;
+
+	if (shift) {
+		byen <<= shift;
+		mask <<= (shift * 8);
+		data <<= (shift * 8);
+	}
+
+	index &= ~3;
+
+	ret = usbnet_read_cmd(dev, RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, index,
+			      MCU_TYPE_PLA | byen, &tmp, sizeof(tmp));
+
+	if (ret < 0)
+		goto out;
+
+	data |= __le32_to_cpu(tmp) & ~mask;
+	tmp = __cpu_to_le32(data);
+
+	ret = usbnet_write_cmd(dev, RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, index,
+			       MCU_TYPE_PLA | byen, &tmp, sizeof(tmp));
+
+out:
+	return ret;
+}
+
+static int r8153_ecm_mdio_read(struct net_device *netdev, int phy_id, int reg)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	int ret;
+
+	ret = pla_write_word(dev, OCP_BASE, 0xa000);
+	if (ret < 0)
+		goto out;
+
+	ret = pla_read_word(dev, 0xb400 + reg * 2);
+
+out:
+	return ret;
+}
+
+static void r8153_ecm_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	int ret;
+
+	ret = pla_write_word(dev, OCP_BASE, 0xa000);
+	if (ret < 0)
+		return;
+
+	ret = pla_write_word(dev, 0xb400 + reg * 2, val);
+}
+
+static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int status;
+
+	status = usbnet_cdc_bind(dev, intf);
+	if (status < 0)
+		return status;
+
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = r8153_ecm_mdio_read;
+	dev->mii.mdio_write = r8153_ecm_mdio_write;
+	dev->mii.reg_num_mask = 0x1f;
+	dev->mii.supports_gmii = 1;
+
+	return status;
+}
+
+static const struct driver_info r8153_info = {
+	.description =	"RTL8153 ECM Device",
+	.flags =	FLAG_ETHER,
+	.bind =		r8153_bind,
+	.unbind =	usbnet_cdc_unbind,
+	.status =	usbnet_cdc_status,
+	.manage_power =	usbnet_manage_power,
+};
+
+static const struct usb_device_id products[] = {
+{
+	USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID_REALTEK, 0x8153, USB_CLASS_COMM,
+				      USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+	.driver_info = (unsigned long)&r8153_info,
+},
+
+	{ },		/* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static int rtl8153_ecm_probe(struct usb_interface *intf,
+			     const struct usb_device_id *id)
+{
+#if IS_REACHABLE(CONFIG_USB_RTL8152)
+	if (rtl8152_get_version(intf))
+		return -ENODEV;
+#endif
+
+	return usbnet_probe(intf, id);
+}
+
+static struct usb_driver r8153_ecm_driver = {
+	.name =		"r8153_ecm",
+	.id_table =	products,
+	.probe =	rtl8153_ecm_probe,
+	.disconnect =	usbnet_disconnect,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
+	.reset_resume =	usbnet_resume,
+	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(r8153_ecm_driver);
+
+MODULE_AUTHOR("Hayes Wang");
+MODULE_DESCRIPTION("Realtek USB ECM device");
+MODULE_LICENSE("GPL");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/usb/smsc95xx.c linux-5.10.52-v7l+/drivers/net/usb/smsc95xx.c
--- linux-5.10.52-orig/drivers/net/usb/smsc95xx.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/usb/smsc95xx.c	2021-07-25 16:46:16.058121687 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:53 @
 #define SUSPEND_SUSPEND3		(0x08)
 #define SUSPEND_ALLMODES		(SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
 					 SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
+#define MAC_ADDR_LEN                    (6)
 
 struct smsc95xx_priv {
 	u32 mac_cr;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:71 @
 module_param(turbo_mode, bool, 0644);
 MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
 
+static bool truesize_mode = false;
+module_param(truesize_mode, bool, 0644);
+MODULE_PARM_DESC(truesize_mode, "Report larger truesize value");
+
+static int packetsize = 2560;
+module_param(packetsize, int, 0644);
+MODULE_PARM_DESC(packetsize, "Override the RX URB packet size");
+
+static char *macaddr = ":";
+module_param(macaddr, charp, 0);
+MODULE_PARM_DESC(macaddr, "MAC address");
+
 static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
 					    u32 *data, int in_pm)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:769 @
 	return phy_mii_ioctl(netdev->phydev, rq, cmd);
 }
 
+/* Check the macaddr module parameter for a MAC address */
+static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac)
+{
+       int i, j, got_num, num;
+       u8 mtbl[MAC_ADDR_LEN];
+
+       if (macaddr[0] == ':')
+               return 0;
+
+       i = 0;
+       j = 0;
+       num = 0;
+       got_num = 0;
+       while (j < MAC_ADDR_LEN) {
+               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 == MAC_ADDR_LEN) {
+               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]);
+               for (i = 0; i < MAC_ADDR_LEN; i++)
+                       dev_mac[i] = mtbl[i];
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
 static void smsc95xx_init_mac_address(struct usbnet *dev)
 {
 	/* maybe the boot loader passed the MAC address in devicetree */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:838 @
 		}
 	}
 
+	/* Check module parameters */
+	if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
+		return;
+
 	/* no useful static MAC address found. generate a random one */
 	eth_hw_addr_random(dev->net);
 	netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n");
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:968 @
 
 	if (!turbo_mode) {
 		burst_cap = 0;
-		dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
+		dev->rx_urb_size = packetsize ? packetsize : MAX_SINGLE_PACKET_SIZE;
 	} else if (dev->udev->speed == USB_SPEED_HIGH) {
-		burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
-		dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
+		dev->rx_urb_size = packetsize ? packetsize : DEFAULT_HS_BURST_CAP_SIZE;
+		burst_cap = dev->rx_urb_size / HS_USB_PKT_SIZE;
 	} else {
-		burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
-		dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
+		dev->rx_urb_size = packetsize ? packetsize : DEFAULT_FS_BURST_CAP_SIZE;
+		burst_cap = dev->rx_urb_size / FS_USB_PKT_SIZE;
 	}
 
 	netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n",
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1894 @
 				if (dev->net->features & NETIF_F_RXCSUM)
 					smsc95xx_rx_csum_offload(skb);
 				skb_trim(skb, skb->len - 4); /* remove fcs */
-				skb->truesize = size + sizeof(struct sk_buff);
+				if (truesize_mode)
+					skb->truesize = size + sizeof(struct sk_buff);
 
 				return 1;
 			}
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1913 @
 			if (dev->net->features & NETIF_F_RXCSUM)
 				smsc95xx_rx_csum_offload(ax_skb);
 			skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
-			ax_skb->truesize = size + sizeof(struct sk_buff);
+			if (truesize_mode)
+				ax_skb->truesize = size + sizeof(struct sk_buff);
 
 			usbnet_skb_return(dev, ax_skb);
 		}
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
--- linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h	2021-07-25 16:46:16.948106766 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:81 @
 	size_t (*get_ramsize)(struct device *dev);
 	int (*get_memdump)(struct device *dev, void *data, size_t len);
 	int (*get_fwname)(struct device *dev, const char *ext,
-			  unsigned char *fw_name);
+			  unsigned char *fw_name, bool board_specific);
 	void (*debugfs_create)(struct device *dev);
 	int (*reset)(struct device *dev);
 };
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:226 @
 int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext,
 			 unsigned char *fw_name)
 {
-	return bus->ops->get_fwname(bus->dev, ext, fw_name);
+	return bus->ops->get_fwname(bus->dev, ext, fw_name, false);
+}
+
+static inline
+int brcmf_bus_get_board_fwname(struct brcmf_bus *bus, const char *ext,
+			       unsigned char *fw_name)
+{
+	return bus->ops->get_fwname(bus->dev, ext, fw_name, true);
 }
 
 static inline
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
--- linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c	2021-07-25 16:46:16.958106598 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:12 @
 #include <linux/etherdevice.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
+#include <linux/ctype.h>
 #include <net/cfg80211.h>
 #include <net/netlink.h>
 #include <uapi/linux/if_arp.h>
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2944 @
 		brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
 		pm = PM_OFF;
 	}
-	brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
+	brcmf_info("power save %s\n", (pm ? "enabled" : "disabled"));
 
 	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
 	if (err) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2954 @
 			bphy_err(drvr, "error (%d)\n", err);
 	}
 
+	timeout = 2000; /* 2000ms - the maximum */
 	err = brcmf_fil_iovar_int_set(ifp, "pm2_sleep_ret",
 				min_t(u32, timeout, BRCMF_PS_MAX_TIMEOUT_MS));
 	if (err)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:7361 @
 	struct brcmfmac_pd_cc *country_codes;
 	struct brcmfmac_pd_cc_entry *cc;
 	s32 found_index;
+	char ccode[BRCMF_COUNTRY_BUF_SZ];
+	int rev;
 	int i;
 
+	memcpy(ccode, alpha2, sizeof(ccode));
+	rev = -1;
+
 	country_codes = drvr->settings->country_codes;
 	if (!country_codes) {
-		brcmf_dbg(TRACE, "No country codes configured for device\n");
-		return -EINVAL;
+		brcmf_dbg(TRACE, "No country codes configured for device"
+				 " - use requested value\n");
+		goto use_input_value;
 	}
 
 	if ((alpha2[0] == ccreq->country_abbrev[0]) &&
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:7396 @
 		brcmf_dbg(TRACE, "No country code match found\n");
 		return -EINVAL;
 	}
-	memset(ccreq, 0, sizeof(*ccreq));
-	ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
-	memcpy(ccreq->ccode, country_codes->table[found_index].cc,
+	rev = country_codes->table[found_index].rev;
+	memcpy(ccode, country_codes->table[found_index].cc,
 	       BRCMF_COUNTRY_BUF_SZ);
+
+use_input_value:
+	memset(ccreq, 0, sizeof(*ccreq));
+	ccreq->rev = cpu_to_le32(rev);
+	memcpy(ccreq->ccode, ccode, sizeof(ccode));
 	ccreq->country_abbrev[0] = alpha2[0];
 	ccreq->country_abbrev[1] = alpha2[1];
 	ccreq->country_abbrev[2] = 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:7418 @
 	struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
 	struct brcmf_pub *drvr = cfg->pub;
 	struct brcmf_fil_country_le ccreq;
+	char *alpha2;
 	s32 err;
 	int i;
 
-	/* The country code gets set to "00" by default at boot, ignore */
-	if (req->alpha2[0] == '0' && req->alpha2[1] == '0')
+	err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
+	if (err) {
+		bphy_err(drvr, "Country code iovar returned err = %d\n", err);
 		return;
+	}
+
+	/* The country code gets set to "00" by default at boot - substitute
+	 * any saved ccode from the nvram file unless there is a valid code
+	 * already set.
+	 */
+	alpha2 = req->alpha2;
+	if (alpha2[0] == '0' && alpha2[1] == '0') {
+		extern char saved_ccode[2];
+
+		if ((isupper(ccreq.country_abbrev[0]) &&
+		     isupper(ccreq.country_abbrev[1])) ||
+		    !saved_ccode[0])
+			return;
+		alpha2 = saved_ccode;
+		pr_debug("brcmfmac: substituting saved ccode %c%c\n",
+			 alpha2[0], alpha2[1]);
+	}
 
 	/* ignore non-ISO3166 country codes */
 	for (i = 0; i < 2; i++)
-		if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
+		if (alpha2[i] < 'A' || alpha2[i] > 'Z') {
 			bphy_err(drvr, "not an ISO3166 code (0x%02x 0x%02x)\n",
-				 req->alpha2[0], req->alpha2[1]);
+				 alpha2[0], alpha2[1]);
 			return;
 		}
 
 	brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
-		  req->alpha2[0], req->alpha2[1]);
-
-	err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
-	if (err) {
-		bphy_err(drvr, "Country code iovar returned err = %d\n", err);
-		return;
-	}
+		  alpha2[0], alpha2[1]);
 
-	err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
+	err = brcmf_translate_country_code(ifp->drvr, alpha2, &ccreq);
 	if (err)
 		return;
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
--- linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c	2021-07-25 16:46:16.978106263 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:137 @
 	brcmf_dbg(TRACE, "Enter\n");
 
 	memset(clm_name, 0, sizeof(clm_name));
-	err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name);
+	err = brcmf_bus_get_board_fwname(bus, ".clm_blob", clm_name);
 	if (err) {
 		bphy_err(drvr, "get CLM blob file name failed (%d)\n", err);
 		return err;
 	}
 
-	err = firmware_request_nowarn(&clm, clm_name, bus->dev);
+	if (clm_name[0])
+		err = firmware_request_nowarn(&clm, clm_name, bus->dev);
+	if (err || !clm_name[0]) {
+		err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name);
+		if (err) {
+			bphy_err(drvr, "get CLM blob file name failed (%d)\n", err);
+			return err;
+		}
+
+		err = firmware_request_nowarn(&clm, clm_name, bus->dev);
+	}
 	if (err) {
 		brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
 			   err);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
--- linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c	2021-07-25 16:46:16.978106263 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:13 @
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/bcm47xx_nvram.h>
+#include <linux/ctype.h>
 
 #include "debug.h"
 #include "firmware.h"
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:34 @
 	END
 };
 
+char saved_ccode[2] = {};
+
 /**
  * struct nvram_parser - internal info for parser.
  *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:551 @
 			goto fail;
 	}
 
-	if (data)
+	if (data) {
+		char *ccode = strnstr((char *)data, "ccode=", data_len);
+		/* Ensure this is a whole token */
+		if (ccode && ((void *)ccode == (void *)data || isspace(ccode[-1]))) {
+			/* Comment out the line */
+			ccode[0] = '#';
+			ccode += 6;
+			if (isupper(ccode[0]) && isupper(ccode[1]) &&
+			    isspace(ccode[2])) {
+				pr_debug("brcmfmac: intercepting ccode=%c%c\n",
+					 ccode[0], ccode[1]);
+				saved_ccode[0] = ccode[0];
+				saved_ccode[1] = ccode[1];
+			}
+		};
+
 		nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,
 					     fwctx->req->domain_nr,
 					     fwctx->req->bus_nr);
+	}
 
 	if (free_bcm47xx_nvram)
 		bcm47xx_nvram_release_contents(data);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:635 @
 		strlcat(alt_path, fwctx->req->board_type, BRCMF_FW_NAME_LEN);
 		strlcat(alt_path, ".txt", BRCMF_FW_NAME_LEN);
 
-		ret = request_firmware(fw, alt_path, fwctx->dev);
+		ret = firmware_request_nowarn(fw, alt_path, fwctx->dev);
 		if (ret == 0)
 			return ret;
 	}
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
--- linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c	2021-07-25 16:46:16.998105928 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1403 @
 }
 
 static
-int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name,
+			  bool board_specific)
 {
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_fw_request *fwreq;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1412 @
 		{ ext, fw_name },
 	};
 
+	if (board_specific) {
+		fw_name[0] = 0;
+		return 0;
+	}
 	fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
 				       brcmf_pcie_fwnames,
 				       ARRAY_SIZE(brcmf_pcie_fwnames),
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
--- linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c	2021-07-25 16:46:16.998105928 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:614 @
 BRCMF_FW_DEF(4330, "brcmfmac4330-sdio");
 BRCMF_FW_DEF(4334, "brcmfmac4334-sdio");
 BRCMF_FW_DEF(43340, "brcmfmac43340-sdio");
+BRCMF_FW_DEF(43341, "brcmfmac43341-sdio");
 BRCMF_FW_DEF(4335, "brcmfmac4335-sdio");
 BRCMF_FW_DEF(43362, "brcmfmac43362-sdio");
 BRCMF_FW_DEF(4339, "brcmfmac4339-sdio");
 BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio");
 /* Note the names are not postfixed with a1 for backward compatibility */
 BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio");
+BRCMF_FW_DEF(43436, "brcmfmac43436-sdio");
 BRCMF_FW_DEF(43455, "brcmfmac43455-sdio");
 BRCMF_FW_DEF(43456, "brcmfmac43456-sdio");
 BRCMF_FW_DEF(4354, "brcmfmac4354-sdio");
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:639 @
 	BRCMF_FW_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330),
 	BRCMF_FW_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334),
 	BRCMF_FW_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340),
-	BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340),
+	BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43341),
 	BRCMF_FW_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335),
 	BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362),
 	BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339),
 	BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0),
-	BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1),
+	BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFA, 43430A1),
+	BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000004, 43436),
 	BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0x00000200, 43456),
 	BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455),
 	BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4120 @
 }
 
 static
-int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name,
+			  bool board_specific)
 {
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 	struct brcmf_fw_request *fwreq;
+	u8 board_ext[BRCMF_FW_NAME_LEN];
 	struct brcmf_fw_name fwnames[] = {
 		{ ext, fw_name },
 	};
 
+	if (board_specific) {
+		strlcpy(board_ext, ".", BRCMF_FW_NAME_LEN);
+		strlcat(board_ext, sdiodev->settings->board_type,
+			BRCMF_FW_NAME_LEN);
+		strlcat(board_ext, ext, BRCMF_FW_NAME_LEN);
+		fwnames[0].extension = board_ext;
+	}
 	fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
 				       brcmf_sdio_fwnames,
 				       ARRAY_SIZE(brcmf_sdio_fwnames),
diff -Nur --no-dereference linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
--- linux-5.10.52-orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c	2021-07-25 16:46:16.998105928 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1158 @
 }
 
 static
-int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name,
+			 bool board_specific)
 {
 	struct brcmf_bus *bus = dev_get_drvdata(dev);
 	struct brcmf_fw_request *fwreq;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1167 @
 		{ ext, fw_name },
 	};
 
+	if (board_specific) {
+		fw_name[0] = 0;
+		return 0;
+	}
 	fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev,
 				       brcmf_usb_fwnames,
 				       ARRAY_SIZE(brcmf_usb_fwnames),
diff -Nur --no-dereference linux-5.10.52-orig/drivers/nvmem/Kconfig linux-5.10.52-v7l+/drivers/nvmem/Kconfig
--- linux-5.10.52-orig/drivers/nvmem/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/nvmem/Kconfig	2021-07-25 16:46:19.268067871 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:273 @
 	  This driver can also be built as a module. If so, the module
 	  will be called nvmem-sprd-efuse.
 
+config NVMEM_RMEM
+	tristate "Reserved Memory Based Driver Support"
+	help
+	  This drivers maps reserved memory into an nvmem device. It might be
+	  useful to expose information left by firmware in memory.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called nvmem-rmem.
 endif
diff -Nur --no-dereference linux-5.10.52-orig/drivers/nvmem/Makefile linux-5.10.52-v7l+/drivers/nvmem/Makefile
--- linux-5.10.52-orig/drivers/nvmem/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/nvmem/Makefile	2021-07-25 16:46:19.268067871 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:58 @
 nvmem_zynqmp_nvmem-y		:= zynqmp_nvmem.o
 obj-$(CONFIG_SPRD_EFUSE)	+= nvmem_sprd_efuse.o
 nvmem_sprd_efuse-y		:= sprd-efuse.o
+obj-$(CONFIG_NVMEM_RMEM) 	+= nvmem-rmem.o
+nvmem-rmem-y			:= rmem.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/nvmem/rmem.c linux-5.10.52-v7l+/drivers/nvmem/rmem.c
--- linux-5.10.52-orig/drivers/nvmem/rmem.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/nvmem/rmem.c	2021-07-25 16:46:19.288067536 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+
+struct rmem {
+	struct device *dev;
+	struct nvmem_device *nvmem;
+	struct reserved_mem *mem;
+
+	phys_addr_t size;
+};
+
+static int rmem_read(void *context, unsigned int offset,
+		     void *val, size_t bytes)
+{
+	struct rmem *priv = context;
+	size_t available = priv->mem->size;
+	loff_t off = offset;
+	void *addr;
+	int count;
+
+	/*
+	 * Only map the reserved memory at this point to avoid potential rogue
+	 * kernel threads inadvertently modifying it. Based on the current
+	 * uses-cases for this driver, the performance hit isn't a concern.
+	 * Nor is likely to be, given the nature of the subsystem. Most nvmem
+	 * devices operate over slow buses to begin with.
+	 *
+	 * An alternative would be setting the memory as RO, set_memory_ro(),
+	 * but as of Dec 2020 this isn't possible on arm64.
+	 */
+	addr = memremap(priv->mem->base, available, MEMREMAP_WB);
+	if (IS_ERR(addr)) {
+		dev_err(priv->dev, "Failed to remap memory region\n");
+		return PTR_ERR(addr);
+	}
+
+	count = memory_read_from_buffer(val, bytes, &off, addr, available);
+
+	memunmap(addr);
+
+	return count;
+}
+
+static int rmem_probe(struct platform_device *pdev)
+{
+	struct nvmem_config config = { };
+	struct device *dev = &pdev->dev;
+	struct reserved_mem *mem;
+	struct rmem *priv;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	priv->dev = dev;
+
+	mem = of_reserved_mem_lookup(dev->of_node);
+	if (!mem) {
+		dev_err(dev, "Failed to lookup reserved memory\n");
+		return -EINVAL;
+	}
+	priv->mem = mem;
+
+	config.dev = dev;
+	config.priv = priv;
+	config.name = "rmem";
+	config.size = mem->size;
+	config.reg_read = rmem_read;
+
+	return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
+}
+
+static const struct of_device_id rmem_match[] = {
+	{ .compatible = "nvmem-rmem", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, rmem_match);
+
+static struct platform_driver rmem_driver = {
+	.probe = rmem_probe,
+	.driver = {
+		.name = "rmem",
+		.of_match_table = rmem_match,
+	},
+};
+module_platform_driver(rmem_driver);
+
+MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>");
+MODULE_DESCRIPTION("Reserved Memory Based nvmem Driver");
+MODULE_LICENSE("GPL");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/of/configfs.c linux-5.10.52-v7l+/drivers/of/configfs.c
--- linux-5.10.52-orig/drivers/of/configfs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/of/configfs.c	2021-07-25 16:46:19.308067200 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * Configfs entries for device-tree
+ *
+ * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/ctype.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/configfs.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/limits.h>
+#include <linux/file.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/sizes.h>
+
+#include "of_private.h"
+
+struct cfs_overlay_item {
+	struct config_item	item;
+
+	char			path[PATH_MAX];
+
+	const struct firmware	*fw;
+	struct device_node	*overlay;
+	int			ov_id;
+
+	void			*dtbo;
+	int			dtbo_size;
+};
+
+static inline struct cfs_overlay_item *to_cfs_overlay_item(
+		struct config_item *item)
+{
+	return item ? container_of(item, struct cfs_overlay_item, item) : NULL;
+}
+
+static ssize_t cfs_overlay_item_path_show(struct config_item *item,
+		char *page)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+	return sprintf(page, "%s\n", overlay->path);
+}
+
+static ssize_t cfs_overlay_item_path_store(struct config_item *item,
+		const char *page, size_t count)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+	const char *p = page;
+	char *s;
+	int err;
+
+	/* if it's set do not allow changes */
+	if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
+		return -EPERM;
+
+	/* copy to path buffer (and make sure it's always zero terminated */
+	count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p);
+	overlay->path[sizeof(overlay->path) - 1] = '\0';
+
+	/* strip trailing newlines */
+	s = overlay->path + strlen(overlay->path);
+	while (s > overlay->path && *--s == '\n')
+		*s = '\0';
+
+	pr_debug("%s: path is '%s'\n", __func__, overlay->path);
+
+	err = request_firmware(&overlay->fw, overlay->path, NULL);
+	if (err != 0)
+		goto out_err;
+
+	err = of_overlay_fdt_apply((void *)overlay->fw->data,
+				   (u32)overlay->fw->size, &overlay->ov_id);
+	if (err != 0)
+		goto out_err;
+
+	return count;
+
+out_err:
+
+	release_firmware(overlay->fw);
+	overlay->fw = NULL;
+
+	overlay->path[0] = '\0';
+	return err;
+}
+
+static ssize_t cfs_overlay_item_status_show(struct config_item *item,
+		char *page)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+	return sprintf(page, "%s\n",
+			overlay->ov_id > 0 ? "applied" : "unapplied");
+}
+
+CONFIGFS_ATTR(cfs_overlay_item_, path);
+CONFIGFS_ATTR_RO(cfs_overlay_item_, status);
+
+static struct configfs_attribute *cfs_overlay_attrs[] = {
+	&cfs_overlay_item_attr_path,
+	&cfs_overlay_item_attr_status,
+	NULL,
+};
+
+ssize_t cfs_overlay_item_dtbo_read(struct config_item *item,
+		void *buf, size_t max_count)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+	pr_debug("%s: buf=%p max_count=%zu\n", __func__,
+			buf, max_count);
+
+	if (overlay->dtbo == NULL)
+		return 0;
+
+	/* copy if buffer provided */
+	if (buf != NULL) {
+		/* the buffer must be large enough */
+		if (overlay->dtbo_size > max_count)
+			return -ENOSPC;
+
+		memcpy(buf, overlay->dtbo, overlay->dtbo_size);
+	}
+
+	return overlay->dtbo_size;
+}
+
+ssize_t cfs_overlay_item_dtbo_write(struct config_item *item,
+		const void *buf, size_t count)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+	int err;
+
+	/* if it's set do not allow changes */
+	if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
+		return -EPERM;
+
+	/* copy the contents */
+	overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
+	if (overlay->dtbo == NULL)
+		return -ENOMEM;
+
+	overlay->dtbo_size = count;
+
+	err = of_overlay_fdt_apply(overlay->dtbo, overlay->dtbo_size,
+				   &overlay->ov_id);
+	if (err != 0)
+		goto out_err;
+
+	return count;
+
+out_err:
+	kfree(overlay->dtbo);
+	overlay->dtbo = NULL;
+	overlay->dtbo_size = 0;
+	overlay->ov_id = 0;
+
+	return err;
+}
+
+CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M);
+
+static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = {
+	&cfs_overlay_item_attr_dtbo,
+	NULL,
+};
+
+static void cfs_overlay_release(struct config_item *item)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+	if (overlay->ov_id > 0)
+		of_overlay_remove(&overlay->ov_id);
+	if (overlay->fw)
+		release_firmware(overlay->fw);
+	/* kfree with NULL is safe */
+	kfree(overlay->dtbo);
+	kfree(overlay);
+}
+
+static struct configfs_item_operations cfs_overlay_item_ops = {
+	.release	= cfs_overlay_release,
+};
+
+static struct config_item_type cfs_overlay_type = {
+	.ct_item_ops	= &cfs_overlay_item_ops,
+	.ct_attrs	= cfs_overlay_attrs,
+	.ct_bin_attrs	= cfs_overlay_bin_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_item *cfs_overlay_group_make_item(
+		struct config_group *group, const char *name)
+{
+	struct cfs_overlay_item *overlay;
+
+	overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
+	if (!overlay)
+		return ERR_PTR(-ENOMEM);
+
+	config_item_init_type_name(&overlay->item, name, &cfs_overlay_type);
+	return &overlay->item;
+}
+
+static void cfs_overlay_group_drop_item(struct config_group *group,
+		struct config_item *item)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+	config_item_put(&overlay->item);
+}
+
+static struct configfs_group_operations overlays_ops = {
+	.make_item	= cfs_overlay_group_make_item,
+	.drop_item	= cfs_overlay_group_drop_item,
+};
+
+static struct config_item_type overlays_type = {
+	.ct_group_ops   = &overlays_ops,
+	.ct_owner       = THIS_MODULE,
+};
+
+static struct configfs_group_operations of_cfs_ops = {
+	/* empty - we don't allow anything to be created */
+};
+
+static struct config_item_type of_cfs_type = {
+	.ct_group_ops   = &of_cfs_ops,
+	.ct_owner       = THIS_MODULE,
+};
+
+struct config_group of_cfs_overlay_group;
+
+static struct configfs_subsystem of_cfs_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_namebuf = "device-tree",
+			.ci_type = &of_cfs_type,
+		},
+	},
+	.su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex),
+};
+
+static int __init of_cfs_init(void)
+{
+	int ret;
+
+	pr_info("%s\n", __func__);
+
+	config_group_init(&of_cfs_subsys.su_group);
+	config_group_init_type_name(&of_cfs_overlay_group, "overlays",
+			&overlays_type);
+	configfs_add_default_group(&of_cfs_overlay_group,
+			&of_cfs_subsys.su_group);
+
+	ret = configfs_register_subsystem(&of_cfs_subsys);
+	if (ret != 0) {
+		pr_err("%s: failed to register subsys\n", __func__);
+		goto out;
+	}
+	pr_info("%s: OK\n", __func__);
+out:
+	return ret;
+}
+late_initcall(of_cfs_init);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/of/Kconfig linux-5.10.52-v7l+/drivers/of/Kconfig
--- linux-5.10.52-orig/drivers/of/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/of/Kconfig	2021-07-25 16:46:19.288067536 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:103 @
 	# arches should select this if DMA is coherent by default for OF devices
 	bool
 
+config OF_CONFIGFS
+	bool "Device Tree Overlay ConfigFS interface"
+	select CONFIGFS_FS
+	select OF_OVERLAY
+	help
+	  Enable a simple user-space driven DT overlay interface.
+
 endif # OF
diff -Nur --no-dereference linux-5.10.52-orig/drivers/of/Makefile linux-5.10.52-v7l+/drivers/of/Makefile
--- linux-5.10.52-orig/drivers/of/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/of/Makefile	2021-07-25 16:46:19.288067536 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
 # SPDX-License-Identifier: GPL-2.0
 obj-y = base.o device.o platform.o property.o
 obj-$(CONFIG_OF_KOBJ) += kobj.o
+obj-$(CONFIG_OF_CONFIGFS) += configfs.o
 obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
 obj-$(CONFIG_OF_FLATTREE) += fdt.o
 obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/of/overlay.c linux-5.10.52-v7l+/drivers/of/overlay.c
--- linux-5.10.52-orig/drivers/of/overlay.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/of/overlay.c	2021-07-25 16:46:19.308067200 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:248 @
 	if (!target_path)
 		return NULL;
 	target_path_len = strlen(target_path);
+	if (!strcmp(target_path, "/"))
+		target_path_len = 0;
 
 	new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
 	if (!new_prop)
diff -Nur --no-dereference linux-5.10.52-orig/drivers/of/platform.c linux-5.10.52-v7l+/drivers/of/platform.c
--- linux-5.10.52-orig/drivers/of/platform.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/of/platform.c	2021-07-25 16:46:19.308067200 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:514 @
 	{ .compatible = "qcom,rmtfs-mem" },
 	{ .compatible = "qcom,cmd-db" },
 	{ .compatible = "ramoops" },
+	{ .compatible = "nvmem-rmem" },
 	{}
 };
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/pci/controller/pcie-brcmstb.c linux-5.10.52-v7l+/drivers/pci/controller/pcie-brcmstb.c
--- linux-5.10.52-orig/drivers/pci/controller/pcie-brcmstb.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/pci/controller/pcie-brcmstb.c	2021-07-25 16:46:19.448064853 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:117 @
 		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_CLKREQ_DEBUG_ENABLE_MASK	0x2
-#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK		0x08000000
+#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK	BIT(1)
+#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK		BIT(21)
+#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK		BIT(27)
 
 
 #define PCIE_INTR2_CPU_BASE		0x4300
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:280 @
 	struct clk		*clk;
 	struct device_node	*np;
 	bool			ssc;
+	bool			l1ss;
 	int			gen;
 	u64			msi_target_addr;
 	struct brcm_msi		*msi;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:466 @
 
 static struct msi_domain_info brcm_msi_domain_info = {
 	/* Multi MSI is supported by the controller, but not by this driver */
-	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+		   MSI_FLAG_PCI_MSIX),
 	.chip	= &brcm_msi_irq_chip,
 };
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:875 @
 
 	/* Reset the bridge */
 	pcie->bridge_sw_init_set(pcie, 1);
+	pcie->perst_set(pcie, 1);
+
 	usleep_range(100, 200);
 
 	/* Take the bridge out of reset */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1033 @
 		PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK);
 	writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1);
 
-	/*
-	 * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
-	 * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1.
-	 */
 	tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
-	tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
+	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;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1272 @
 	pcie->gen = (ret < 0) ? 0 : ret;
 
 	pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc");
+	pcie->l1ss = of_property_read_bool(np, "brcm,enable-l1ss");
 
 	ret = clk_prepare_enable(pcie->clk);
 	if (ret) {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/perf/Kconfig linux-5.10.52-v7l+/drivers/perf/Kconfig
--- linux-5.10.52-orig/drivers/perf/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/perf/Kconfig	2021-07-25 16:46:19.668061165 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:133 @
 	  Extension, which provides periodic sampling of operations in
 	  the CPU pipeline and reports this via the perf AUX interface.
 
+config RPI_AXIPERF
+        depends on ARCH_BCM2835
+        tristate "RaspberryPi AXI Performance monitors"
+        default n
+        help
+          Say y if you want to use Raspberry Pi AXI performance monitors, m if
+          you want to build it as a module.
+
 source "drivers/perf/hisilicon/Kconfig"
 
 endmenu
diff -Nur --no-dereference linux-5.10.52-orig/drivers/perf/Makefile linux-5.10.52-v7l+/drivers/perf/Makefile
--- linux-5.10.52-orig/drivers/perf/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/perf/Makefile	2021-07-25 16:46:19.668061165 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:16 @
 obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o
 obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
 obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o
+obj-$(CONFIG_RPI_AXIPERF) += raspberrypi_axi_monitor.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/perf/raspberrypi_axi_monitor.c linux-5.10.52-v7l+/drivers/perf/raspberrypi_axi_monitor.c
--- linux-5.10.52-orig/drivers/perf/raspberrypi_axi_monitor.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/perf/raspberrypi_axi_monitor.c	2021-07-25 16:46:19.698060662 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/*
+ * raspberrypi_axi_monitor.c
+ *
+ * Author: james.hughes@raspberrypi.org
+ *
+ * Raspberry Pi AXI performance counters.
+ *
+ * Copyright (C) 2017 Raspberry Pi Trading Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/devcoredump.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define NUM_MONITORS 2
+#define NUM_BUS_WATCHERS_PER_MONITOR 3
+
+#define SYSTEM_MONITOR 0
+#define VPU_MONITOR 1
+
+#define MAX_BUSES 16
+#define DEFAULT_SAMPLE_TIME 100
+
+#define NUM_BUS_WATCHER_RESULTS 9
+
+struct bus_watcher_data {
+	union	{
+		u32 results[NUM_BUS_WATCHER_RESULTS];
+		struct {
+			u32 atrans;
+			u32 atwait;
+			u32 amax;
+			u32 wtrans;
+			u32 wtwait;
+			u32 wmax;
+			u32 rtrans;
+			u32 rtwait;
+			u32 rmax;
+		};
+	};
+};
+
+
+struct rpi_axiperf {
+	struct platform_device *dev;
+	struct dentry *root_folder;
+
+	struct task_struct *monitor_thread;
+	struct mutex lock;
+
+	struct rpi_firmware *firmware;
+
+	/* Sample time spent on for each bus */
+	int sample_time;
+
+	/* Now storage for the per monitor settings and the resulting
+	 * performance figures
+	 */
+	struct {
+		/* Bit field of buses we want to monitor */
+		int bus_enabled;
+		/* Bit field of buses to filter by */
+		int bus_filter;
+		/* The current buses being monitored on this monitor */
+		int current_bus[NUM_BUS_WATCHERS_PER_MONITOR];
+		/* The last bus monitored on this monitor */
+		int last_monitored;
+
+		/* Set true if this mailbox must use the mailbox interface
+		 * rather than access registers directly.
+		 */
+		int use_mailbox_interface;
+
+		/* Current result values */
+		struct bus_watcher_data results[MAX_BUSES];
+
+		struct dentry *debugfs_entry;
+		void __iomem *base_address;
+
+	}  monitor[NUM_MONITORS];
+
+};
+
+static struct rpi_axiperf *state;
+
+/* Two monitors, System and VPU, each with the following register sets.
+ * Each monitor can only monitor one bus at a time, so we time share them,
+ * giving each bus 100ms (default, settable via debugfs) of time on its
+ * associated monitor
+ * Record results from the three Bus watchers per monitor and push to the sysfs
+ */
+
+/* general registers */
+const int GEN_CTRL;
+
+const int GEN_CTL_ENABLE_BIT	= BIT(0);
+const int GEN_CTL_RESET_BIT	= BIT(1);
+
+/* Bus watcher registers */
+const int BW_PITCH		= 0x40;
+
+const int BW0_CTRL		= 0x40;
+const int BW1_CTRL		= 0x80;
+const int BW2_CTRL		= 0xc0;
+
+const int BW_ATRANS_OFFSET	= 0x04;
+const int BW_ATWAIT_OFFSET	= 0x08;
+const int BW_AMAX_OFFSET	= 0x0c;
+const int BW_WTRANS_OFFSET	= 0x10;
+const int BW_WTWAIT_OFFSET	= 0x14;
+const int BW_WMAX_OFFSET	= 0x18;
+const int BW_RTRANS_OFFSET	= 0x1c;
+const int BW_RTWAIT_OFFSET	= 0x20;
+const int BW_RMAX_OFFSET	= 0x24;
+
+const int BW_CTRL_RESET_BIT	= BIT(31);
+const int BW_CTRL_ENABLE_BIT	= BIT(30);
+const int BW_CTRL_ENABLE_ID_FILTER_BIT	= BIT(29);
+const int BW_CTRL_LIMIT_HALT_BIT	= BIT(28);
+
+const int BW_CTRL_SOURCE_SHIFT	= 8;
+const int BW_CTRL_SOURCE_MASK	= GENMASK(12, 8); // 5 bits
+const int BW_CTRL_BUS_WATCH_SHIFT;
+const int BW_CTRL_BUS_WATCH_MASK = GENMASK(5, 0); // 6 bits
+const int BW_CTRL_BUS_FILTER_SHIFT = 8;
+
+const static char *bus_filter_strings[] = {
+	"",
+	"CORE0_V",
+	"ICACHE0",
+	"DCACHE0",
+	"CORE1_V",
+	"ICACHE1",
+	"DCACHE1",
+	"L2_MAIN",
+	"HOST_PORT",
+	"HOST_PORT2",
+	"HVS",
+	"ISP",
+	"VIDEO_DCT",
+	"VIDEO_SD2AXI",
+	"CAM0",
+	"CAM1",
+	"DMA0",
+	"DMA1",
+	"DMA2_VPU",
+	"JPEG",
+	"VIDEO_CME",
+	"TRANSPOSER",
+	"VIDEO_FME",
+	"CCP2TX",
+	"USB",
+	"V3D0",
+	"V3D1",
+	"V3D2",
+	"AVE",
+	"DEBUG",
+	"CPU",
+	"M30"
+};
+
+const int num_bus_filters = ARRAY_SIZE(bus_filter_strings);
+
+const static char *system_bus_string[] = {
+	"DMA_L2",
+	"TRANS",
+	"JPEG",
+	"SYSTEM_UC",
+	"DMA_UC",
+	"SYSTEM_L2",
+	"CCP2TX",
+	"MPHI_RX",
+	"MPHI_TX",
+	"HVS",
+	"H264",
+	"ISP",
+	"V3D",
+	"PERIPHERAL",
+	"CPU_UC",
+	"CPU_L2"
+};
+
+const int num_system_buses = ARRAY_SIZE(system_bus_string);
+
+const static char *vpu_bus_string[] = {
+	"VPU1_D_L2",
+	"VPU0_D_L2",
+	"VPU1_I_L2",
+	"VPU0_I_L2",
+	"SYSTEM_L2",
+	"L2_FLUSH",
+	"DMA_L2",
+	"VPU1_D_UC",
+	"VPU0_D_UC",
+	"VPU1_I_UC",
+	"VPU0_I_UC",
+	"SYSTEM_UC",
+	"L2_OUT",
+	"DMA_UC",
+	"SDRAM",
+	"L2_IN"
+};
+
+const int num_vpu_buses = ARRAY_SIZE(vpu_bus_string);
+
+const static char *monitor_name[] = {
+	"System",
+	"VPU"
+};
+
+static inline void write_reg(int monitor, int reg, u32 value)
+{
+	writel(value, state->monitor[monitor].base_address + reg);
+}
+
+static inline u32 read_reg(int monitor, u32 reg)
+{
+	return readl(state->monitor[monitor].base_address + reg);
+}
+
+static void read_bus_watcher(int monitor, int watcher, u32 *results)
+{
+	if (state->monitor[monitor].use_mailbox_interface) {
+		/* We have 9 results, plus the overheads of start address and
+		 * length So 11 u32 to define
+		 */
+		u32 tmp[11];
+		int err;
+
+		tmp[0] = (u32)(uintptr_t)(state->monitor[monitor].base_address + watcher
+				+ BW_ATRANS_OFFSET);
+		tmp[1] = NUM_BUS_WATCHER_RESULTS;
+
+		err = rpi_firmware_property(state->firmware,
+					    RPI_FIRMWARE_GET_PERIPH_REG,
+					    tmp, sizeof(tmp));
+
+		if (err < 0 || tmp[1] != NUM_BUS_WATCHER_RESULTS)
+			dev_err_once(&state->dev->dev,
+				     "Failed to read bus watcher");
+		else
+			memcpy(results, &tmp[2],
+			       NUM_BUS_WATCHER_RESULTS * sizeof(u32));
+	} else {
+		int i;
+		void __iomem *addr = state->monitor[monitor].base_address
+				+ watcher + BW_ATRANS_OFFSET;
+		for (i = 0; i < NUM_BUS_WATCHER_RESULTS; i++, addr += 4)
+			*results++ = readl(addr);
+	}
+}
+
+static void set_monitor_control(int monitor, u32 set)
+{
+	if (state->monitor[monitor].use_mailbox_interface) {
+		u32 tmp[3] = {(u32)(uintptr_t)(state->monitor[monitor].base_address +
+				GEN_CTRL), 1, set};
+		int err = rpi_firmware_property(state->firmware,
+						RPI_FIRMWARE_SET_PERIPH_REG,
+						tmp, sizeof(tmp));
+
+		if (err < 0 || tmp[1] != 1)
+			dev_err_once(&state->dev->dev,
+				"Failed to set monitor control");
+	} else
+		write_reg(monitor, GEN_CTRL, set);
+}
+
+static void set_bus_watcher_control(int monitor, int watcher, u32 set)
+{
+	if (state->monitor[monitor].use_mailbox_interface) {
+		u32 tmp[3] = {(u32)(uintptr_t)(state->monitor[monitor].base_address +
+				    watcher), 1, set};
+		int err = rpi_firmware_property(state->firmware,
+						RPI_FIRMWARE_SET_PERIPH_REG,
+						tmp, sizeof(tmp));
+		if (err < 0 || tmp[1] != 1)
+			dev_err_once(&state->dev->dev,
+				"Failed to set bus watcher control");
+	} else
+		write_reg(monitor, watcher, set);
+}
+
+static void monitor(struct rpi_axiperf *state)
+{
+	int monitor, num_buses[NUM_MONITORS];
+
+	mutex_lock(&state->lock);
+
+	for (monitor = 0; monitor < NUM_MONITORS; monitor++) {
+		typeof(state->monitor[0]) *mon = &(state->monitor[monitor]);
+
+		/* Anything enabled? */
+		if (mon->bus_enabled == 0) {
+			/* No, disable all monitoring for this monitor */
+			set_monitor_control(monitor, GEN_CTL_RESET_BIT);
+		} else {
+			int i;
+
+			/* Find out how many busses we want to monitor, and
+			 * spread our 3 actual monitors over them
+			 */
+			num_buses[monitor] = hweight32(mon->bus_enabled);
+			num_buses[monitor] = min(num_buses[monitor],
+						 NUM_BUS_WATCHERS_PER_MONITOR);
+
+			for (i = 0; i < num_buses[monitor]; i++) {
+				int bus_control;
+
+				do {
+					mon->last_monitored++;
+					mon->last_monitored &= 0xf;
+				} while ((mon->bus_enabled &
+					 (1 << mon->last_monitored)) == 0);
+
+				mon->current_bus[i] = mon->last_monitored;
+
+				/* Reset the counters */
+				set_bus_watcher_control(monitor,
+							BW0_CTRL +
+							i*BW_PITCH,
+							BW_CTRL_RESET_BIT);
+
+				bus_control = BW_CTRL_ENABLE_BIT |
+						mon->current_bus[i];
+
+				if (mon->bus_filter) {
+					bus_control |=
+						BW_CTRL_ENABLE_ID_FILTER_BIT;
+					bus_control |=
+						((mon->bus_filter & 0x1f)
+						<< BW_CTRL_BUS_FILTER_SHIFT);
+				}
+
+				// Start capture
+				set_bus_watcher_control(monitor,
+							BW0_CTRL + i*BW_PITCH,
+							bus_control);
+			}
+		}
+
+		/* start monitoring */
+		set_monitor_control(monitor, GEN_CTL_ENABLE_BIT);
+	}
+
+	mutex_unlock(&state->lock);
+
+	msleep(state->sample_time);
+
+	/* Now read the results */
+
+	mutex_lock(&state->lock);
+	for (monitor = 0; monitor < NUM_MONITORS; monitor++) {
+		typeof(state->monitor[0]) *mon = &(state->monitor[monitor]);
+
+		/* Anything enabled? */
+		if (mon->bus_enabled == 0) {
+			/* No, disable all monitoring for this monitor */
+			set_monitor_control(monitor, 0);
+		} else {
+			int i;
+
+			for (i = 0; i < num_buses[monitor]; i++) {
+				int bus = mon->current_bus[i];
+
+				read_bus_watcher(monitor,
+					BW0_CTRL + i*BW_PITCH,
+					(u32 *)&mon->results[bus].results);
+			}
+		}
+	}
+	mutex_unlock(&state->lock);
+}
+
+static int monitor_thread(void *data)
+{
+	struct rpi_axiperf *state  = data;
+
+	while (1) {
+		monitor(state);
+
+		if (kthread_should_stop())
+			return 0;
+	}
+	return 0;
+}
+
+static ssize_t myreader(struct file *fp, char __user *user_buffer,
+			size_t count, loff_t *position)
+{
+#define INIT_BUFF_SIZE 2048
+
+	int i;
+	int idx = (int)(uintptr_t)(fp->private_data);
+	int num_buses, cnt;
+	char *string_buffer;
+	int buff_size = INIT_BUFF_SIZE;
+	char *p;
+	typeof(state->monitor[0]) *mon = &(state->monitor[idx]);
+
+	if (idx < 0 || idx > NUM_MONITORS)
+		idx = 0;
+
+	num_buses = idx == SYSTEM_MONITOR ? num_system_buses : num_vpu_buses;
+
+	string_buffer = kmalloc(buff_size, GFP_KERNEL);
+
+	if (!string_buffer) {
+		dev_err(&state->dev->dev,
+				"Failed temporary string allocation\n");
+		return 0;
+	}
+
+	p = string_buffer;
+
+	mutex_lock(&state->lock);
+
+	if (mon->bus_filter) {
+		int filt = min(mon->bus_filter & 0x1f, num_bus_filters);
+
+		cnt = snprintf(p, buff_size,
+			       "\nMonitoring transactions from %s only\n",
+			       bus_filter_strings[filt]);
+		p += cnt;
+		buff_size -= cnt;
+	}
+
+	cnt = snprintf(p, buff_size, "     Bus   |    Atrans    Atwait      AMax    Wtrans    Wtwait      WMax    Rtrans    Rtwait      RMax\n"
+				     "======================================================================================================\n");
+
+	if (cnt >= buff_size)
+		goto done;
+
+	p += cnt;
+	buff_size -= cnt;
+
+	for (i = 0; i < num_buses; i++) {
+		if (mon->bus_enabled & (1 << i)) {
+#define DIVIDER (1024)
+			typeof(mon->results[0]) *res = &(mon->results[i]);
+
+			cnt = snprintf(p, buff_size,
+					"%10s | %8uK %8uK %8uK %8uK %8uK %8uK %8uK %8uK %8uK\n",
+					idx == SYSTEM_MONITOR ?
+						system_bus_string[i] :
+						vpu_bus_string[i],
+					res->atrans/DIVIDER,
+					res->atwait/DIVIDER,
+					res->amax/DIVIDER,
+					res->wtrans/DIVIDER,
+					res->wtwait/DIVIDER,
+					res->wmax/DIVIDER,
+					res->rtrans/DIVIDER,
+					res->rtwait/DIVIDER,
+					res->rmax/DIVIDER
+					);
+			if (cnt >= buff_size)
+				goto done;
+
+			p += cnt;
+			buff_size -= cnt;
+		}
+	}
+
+	mutex_unlock(&state->lock);
+
+done:
+
+	/* did the last string entry exceeed our buffer size? ie out of string
+	 * buffer space. Null terminate, use what we have.
+	 */
+	if (cnt >= buff_size) {
+		buff_size = 0;
+		string_buffer[INIT_BUFF_SIZE] = 0;
+	}
+
+	cnt = simple_read_from_buffer(user_buffer, count, position,
+				      string_buffer,
+				      INIT_BUFF_SIZE - buff_size);
+
+	kfree(string_buffer);
+
+	return cnt;
+}
+
+static ssize_t mywriter(struct file *fp, const char __user *user_buffer,
+			size_t count, loff_t *position)
+{
+	int idx = (int)(uintptr_t)(fp->private_data);
+
+	if (idx < 0 || idx > NUM_MONITORS)
+		idx = 0;
+
+	/* At the moment, this does nothing, but in the future it could be
+	 * used to reset counters etc
+	 */
+	return count;
+}
+
+static const struct file_operations fops_debug = {
+	.read = myreader,
+	.write = mywriter,
+	.open = simple_open
+};
+
+static int rpi_axiperf_probe(struct platform_device *pdev)
+{
+	int ret = 0, i;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *fw_node;
+
+	state = kzalloc(sizeof(struct rpi_axiperf), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	/* Get the firmware handle for future rpi-firmware-xxx calls */
+	fw_node = of_parse_phandle(np, "firmware", 0);
+	if (!fw_node) {
+		dev_err(dev, "Missing firmware node\n");
+		return -ENOENT;
+	}
+
+	state->firmware = rpi_firmware_get(fw_node);
+	if (!state->firmware)
+		return -EPROBE_DEFER;
+
+	/* Special case for the VPU monitor, we must use the mailbox interface
+	 * as it is not accessible from the ARM address space.
+	 */
+	state->monitor[VPU_MONITOR].use_mailbox_interface = 1;
+	state->monitor[SYSTEM_MONITOR].use_mailbox_interface = 0;
+
+	for (i = 0; i < NUM_MONITORS; i++) {
+		if (state->monitor[i].use_mailbox_interface) {
+			 of_property_read_u32_index(np, "reg", i*2,
+				(u32 *)(&state->monitor[i].base_address));
+		} else {
+			struct resource *resource =
+				platform_get_resource(pdev, IORESOURCE_MEM, i);
+
+			state->monitor[i].base_address =
+				devm_ioremap_resource(&pdev->dev, resource);
+		}
+
+		if (IS_ERR(state->monitor[i].base_address))
+			return PTR_ERR(state->monitor[i].base_address);
+
+		/* Enable all buses by default */
+		state->monitor[i].bus_enabled = 0xffff;
+	}
+
+	state->dev = pdev;
+	platform_set_drvdata(pdev, state);
+
+	state->sample_time = DEFAULT_SAMPLE_TIME;
+
+	/* Set up all the debugfs stuff */
+	state->root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+	for (i = 0; i < NUM_MONITORS; i++) {
+		state->monitor[i].debugfs_entry =
+			debugfs_create_dir(monitor_name[i], state->root_folder);
+		if (IS_ERR(state->monitor[i].debugfs_entry))
+			state->monitor[i].debugfs_entry = NULL;
+
+		debugfs_create_file("data", 0444,
+				    state->monitor[i].debugfs_entry,
+				    (void *)(uintptr_t)i, &fops_debug);
+		debugfs_create_u32("enable", 0644,
+				   state->monitor[i].debugfs_entry,
+				   &state->monitor[i].bus_enabled);
+		debugfs_create_u32("filter", 0644,
+				   state->monitor[i].debugfs_entry,
+				   &state->monitor[i].bus_filter);
+		debugfs_create_u32("sample_time", 0644,
+				   state->monitor[i].debugfs_entry,
+				   &state->sample_time);
+	}
+
+	mutex_init(&state->lock);
+
+	state->monitor_thread = kthread_run(monitor_thread, state,
+					    "rpi-axiperfmon");
+
+	return ret;
+
+}
+
+static int rpi_axiperf_remove(struct platform_device *dev)
+{
+	int ret = 0;
+
+	kthread_stop(state->monitor_thread);
+
+	debugfs_remove_recursive(state->root_folder);
+	state->root_folder = NULL;
+
+	return ret;
+}
+
+static const struct of_device_id rpi_axiperf_match[] = {
+	{
+		.compatible = "brcm,bcm2835-axiperf",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rpi_axiperf_match);
+
+static struct platform_driver rpi_axiperf_driver  = {
+	.probe =	rpi_axiperf_probe,
+	.remove =	rpi_axiperf_remove,
+	.driver = {
+		.name   = "rpi-bcm2835-axiperf",
+		.of_match_table = of_match_ptr(rpi_axiperf_match),
+	},
+};
+
+module_platform_driver(rpi_axiperf_driver);
+
+/* Module information */
+MODULE_AUTHOR("James Hughes <james.hughes@raspberrypi.org>");
+MODULE_DESCRIPTION("RPI AXI Performance monitor driver");
+MODULE_LICENSE("GPL");
+
diff -Nur --no-dereference linux-5.10.52-orig/drivers/pinctrl/bcm/pinctrl-bcm2835.c linux-5.10.52-v7l+/drivers/pinctrl/bcm/pinctrl-bcm2835.c
--- linux-5.10.52-orig/drivers/pinctrl/bcm/pinctrl-bcm2835.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/pinctrl/bcm/pinctrl-bcm2835.c	2021-07-25 16:46:19.858057980 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:365 @
 	.get = bcm2835_gpio_get,
 	.set = bcm2835_gpio_set,
 	.set_config = gpiochip_generic_config,
-	.base = -1,
+	.base = 0,
 	.ngpio = BCM2835_NUM_GPIOS,
 	.can_sleep = false,
 };
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:381 @
 	.get = bcm2835_gpio_get,
 	.set = bcm2835_gpio_set,
 	.set_config = gpiochip_generic_config,
-	.base = -1,
+	.base = 0,
 	.ngpio = BCM2711_NUM_GPIOS,
 	.can_sleep = false,
 };
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1247 @
 		raw_spin_lock_init(&pc->irq_lock[i]);
 	}
 
+	pc->pctl_desc = *pdata->pctl_desc;
+	pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
+	if (IS_ERR(pc->pctl_dev)) {
+		gpiochip_remove(&pc->gpio_chip);
+		return PTR_ERR(pc->pctl_dev);
+	}
+
+	pc->gpio_range = *pdata->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);
+
 	girq = &pc->gpio_chip.irq;
 	girq->chip = &bcm2835_gpio_irq_chip;
 	girq->parent_handler = bcm2835_gpio_irq_handler;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1266 @
 	girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
 				     sizeof(*girq->parents),
 				     GFP_KERNEL);
-	if (!girq->parents)
+	if (!girq->parents) {
+		pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
 		return -ENOMEM;
+	}
 
 	if (is_7211) {
 		pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1291 @
 		char *name;
 
 		girq->parents[i] = irq_of_parse_and_map(np, i);
-		if (!is_7211)
+		if (!is_7211) {
+			if (!girq->parents[i]) {
+				girq->num_parents = i;
+				break;
+			}
 			continue;
-
+		}
 		/* Skip over the all banks interrupts */
 		pc->wake_irq[i] = irq_of_parse_and_map(np, i +
 						       BCM2835_NUM_IRQS + 1);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1321 @
 	girq->default_type = IRQ_TYPE_NONE;
 	girq->handler = handle_level_irq;
 
-	err = gpiochip_add_data(&pc->gpio_chip, pc);
+	err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
 	if (err) {
 		dev_err(dev, "could not add GPIO chip\n");
+		pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
 		return err;
 	}
 
-	pc->pctl_desc = *pdata->pctl_desc;
-	pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
-	if (IS_ERR(pc->pctl_dev)) {
-		gpiochip_remove(&pc->gpio_chip);
-		return PTR_ERR(pc->pctl_dev);
-	}
-
-	pc->gpio_range = *pdata->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;
 }
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/power/reset/gpio-poweroff.c linux-5.10.52-v7l+/drivers/power/reset/gpio-poweroff.c
--- linux-5.10.52-orig/drivers/power/reset/gpio-poweroff.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/power/reset/gpio-poweroff.c	2021-07-25 16:46:20.758042891 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:27 @
 static u32 timeout = DEFAULT_TIMEOUT_MS;
 static u32 active_delay = 100;
 static u32 inactive_delay = 100;
+static void (*old_power_off)(void);
 
 static void gpio_poweroff_do_poweroff(void)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:47 @
 	/* give it some time */
 	mdelay(timeout);
 
+	if (old_power_off)
+		old_power_off();
+
 	WARN_ON(1);
 }
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:57 @
 {
 	bool input = false;
 	enum gpiod_flags flags;
+	bool force = false;
+	bool export = false;
 
 	/* If a pm_power_off function has already been added, leave it alone */
-	if (pm_power_off != NULL) {
+	force = of_property_read_bool(pdev->dev.of_node, "force");
+	if (!force && (pm_power_off != NULL)) {
 		dev_err(&pdev->dev,
 			"%s: pm_power_off function already registered\n",
 		       __func__);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:84 @
 	if (IS_ERR(reset_gpio))
 		return PTR_ERR(reset_gpio);
 
+	export = of_property_read_bool(pdev->dev.of_node, "export");
+	if (export) {
+		gpiod_export(reset_gpio, false);
+		gpiod_export_link(&pdev->dev, "poweroff-gpio", reset_gpio);
+	}
+
+	old_power_off = pm_power_off;
 	pm_power_off = &gpio_poweroff_do_poweroff;
 	return 0;
 }
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:98 @
 static int gpio_poweroff_remove(struct platform_device *pdev)
 {
 	if (pm_power_off == &gpio_poweroff_do_poweroff)
-		pm_power_off = NULL;
+		pm_power_off = old_power_off;
+
+	gpiod_unexport(reset_gpio);
 
 	return 0;
 }
diff -Nur --no-dereference linux-5.10.52-orig/drivers/power/supply/Kconfig linux-5.10.52-v7l+/drivers/power/supply/Kconfig
--- linux-5.10.52-orig/drivers/power/supply/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/power/supply/Kconfig	2021-07-25 16:46:20.768042723 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:31 @
 	  Say 'Y' here if you want power supplies to
 	  have hwmon sysfs interface too.
 
+config RPI_POE_POWER
+	tristate "Raspberry Pi PoE+ HAT power supply driver"
+	depends on RASPBERRYPI_FIRMWARE
+	help
+	  Say Y here to enable support for Raspberry Pi PoE+ (Power over Ethernet
+	  Plus) HAT current measurement.
 
 config PDA_POWER
 	tristate "Generic PDA/phone power driver"
diff -Nur --no-dereference linux-5.10.52-orig/drivers/power/supply/Makefile linux-5.10.52-v7l+/drivers/power/supply/Makefile
--- linux-5.10.52-orig/drivers/power/supply/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/power/supply/Makefile	2021-07-25 16:46:20.768042723 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:12 @
 obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o
 obj-$(CONFIG_GENERIC_ADC_BATTERY)	+= generic-adc-battery.o
 
+obj-$(CONFIG_RPI_POE_POWER)	+= rpi_poe_power.o
 obj-$(CONFIG_PDA_POWER)		+= pda_power.o
 obj-$(CONFIG_APM_POWER)		+= apm_power.o
 obj-$(CONFIG_AXP20X_POWER)	+= axp20x_usb_power.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/power/supply/rpi_poe_power.c linux-5.10.52-v7l+/drivers/power/supply/rpi_poe_power.c
--- linux-5.10.52-orig/drivers/power/supply/rpi_poe_power.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/power/supply/rpi_poe_power.c	2021-07-25 16:46:20.858041215 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rpi-poe-power.c - Raspberry Pi PoE+ HAT power supply driver.
+ *
+ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
+ * Based on axp20x_ac_power.c by Quentin Schulz <quentin.schulz@free-electrons.com>
+ *
+ * Author: Serge Schneider <serge@raspberrypi.org>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define RPI_POE_ADC_REG			0x2
+#define RPI_POE_FLAG_REG		0x4
+
+#define RPI_POE_FLAG_AT			BIT(0)
+#define RPI_POE_FLAG_OC			BIT(1)
+
+#define RPI_POE_CURRENT_AF_MAX	(2500 * 1000)
+#define RPI_POE_CURRENT_AT_MAX	(5000 * 1000)
+
+#define DRVNAME "rpi-poe-power-supply"
+
+struct rpi_poe_power_supply_ctx {
+	struct power_supply *supply;
+	struct rpi_firmware *fw;
+};
+
+struct fw_tag_data_s {
+	u32 reg;
+	u32 val;
+	u32 ret;
+};
+
+static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val)
+{
+	struct fw_tag_data_s fw_tag_data = {
+		.reg = reg,
+		.val = *val
+	};
+	int ret;
+
+	ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POE_HAT_VAL,
+				    &fw_tag_data, sizeof(fw_tag_data));
+	if (ret)
+		return ret;
+	else if (fw_tag_data.ret)
+		return -EIO;
+	return 0;
+}
+
+static int read_reg(struct rpi_firmware *fw, u32 reg, u32 *val)
+{
+	struct fw_tag_data_s fw_tag_data = {
+		.reg = reg,
+		.val = *val
+	};
+	int ret;
+
+	ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_POE_HAT_VAL,
+				    &fw_tag_data, sizeof(fw_tag_data));
+	if (ret)
+		return ret;
+	else if (fw_tag_data.ret)
+		return -EIO;
+
+	*val = fw_tag_data.val;
+	return 0;
+}
+
+static int rpi_poe_power_supply_get_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					union power_supply_propval *r_val)
+{
+	struct rpi_poe_power_supply_ctx *ctx = power_supply_get_drvdata(psy);
+	int ret;
+	unsigned int val = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_HEALTH:
+		ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
+		if (ret)
+			return ret;
+
+		if (val & RPI_POE_FLAG_OC) {
+			r_val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+			val = RPI_POE_FLAG_OC;
+			ret = write_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
+			if (ret)
+				return ret;
+			return 0;
+		}
+
+		r_val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		return 0;
+
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
+		if (ret)
+			return ret;
+
+		r_val->intval = (val > 5);
+		return 0;
+
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		val = 50;
+		ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
+		if (ret)
+			return ret;
+		val = (val * 3300)/9821;
+		r_val->intval = val * 1000;
+		return 0;
+
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
+		if (ret)
+			return ret;
+		val = (val * 3300)/9821;
+		r_val->intval = val * 1000;
+		return 0;
+
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
+		if (ret)
+			return ret;
+
+		if (val & RPI_POE_FLAG_AT) {
+			r_val->intval = RPI_POE_CURRENT_AT_MAX;
+			return 0;
+		}
+		r_val->intval = RPI_POE_CURRENT_AF_MAX;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static enum power_supply_property rpi_poe_power_supply_properties[] = {
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static const struct power_supply_desc rpi_poe_power_supply_desc = {
+	.name = "rpi-poe",
+	.type = POWER_SUPPLY_TYPE_MAINS,
+	.properties = rpi_poe_power_supply_properties,
+	.num_properties = ARRAY_SIZE(rpi_poe_power_supply_properties),
+	.get_property = rpi_poe_power_supply_get_property,
+};
+
+static int rpi_poe_power_supply_probe(struct platform_device *pdev)
+{
+	struct power_supply_config psy_cfg = {};
+	struct rpi_poe_power_supply_ctx *ctx;
+	struct device_node *fw_node;
+	u32 revision;
+
+	if (!of_device_is_available(pdev->dev.of_node))
+		return -ENODEV;
+
+	fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
+	if (!fw_node) {
+		dev_err(&pdev->dev, "Missing firmware node\n");
+		return -ENOENT;
+	}
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->fw = rpi_firmware_get(fw_node);
+	if (!ctx->fw)
+		return -EPROBE_DEFER;
+	if (rpi_firmware_property(ctx->fw,
+			RPI_FIRMWARE_GET_FIRMWARE_REVISION,
+			&revision, sizeof(revision))) {
+		dev_err(&pdev->dev, "Failed to get firmware revision\n");
+		return -ENOENT;
+	}
+	if (revision < 0x60af72e8) {
+		dev_err(&pdev->dev, "Unsupported firmware\n");
+		return -ENOENT;
+	}
+	platform_set_drvdata(pdev, ctx);
+
+	psy_cfg.of_node = pdev->dev.of_node;
+	psy_cfg.drv_data = ctx;
+
+	ctx->supply = devm_power_supply_register(&pdev->dev,
+						   &rpi_poe_power_supply_desc,
+						   &psy_cfg);
+	if (IS_ERR(ctx->supply))
+		return PTR_ERR(ctx->supply);
+
+	return 0;
+}
+
+static const struct of_device_id of_rpi_poe_power_supply_match[] = {
+	{ .compatible = "raspberrypi,rpi-poe-power-supply", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_rpi_poe_power_supply_match);
+
+static struct platform_driver rpi_poe_power_supply_driver = {
+	.probe = rpi_poe_power_supply_probe,
+	.driver = {
+		.name = DRVNAME,
+		.of_match_table = of_rpi_poe_power_supply_match
+	},
+};
+
+module_platform_driver(rpi_poe_power_supply_driver);
+
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_DESCRIPTION("Raspberry Pi PoE+ HAT power supply driver");
+MODULE_LICENSE("GPL");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/pps/clients/pps-gpio.c linux-5.10.52-v7l+/drivers/pps/clients/pps-gpio.c
--- linux-5.10.52-orig/drivers/pps/clients/pps-gpio.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/pps/clients/pps-gpio.c	2021-07-25 16:46:20.888040712 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:148 @
 
 	if (of_property_read_bool(np, "assert-falling-edge"))
 		data->assert_falling_edge = true;
+        if (of_property_read_bool(np, "capture-clear"))
+                data->capture_clear = true;
 	return 0;
 }
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/rtc/rtc-pcf2123.c linux-5.10.52-v7l+/drivers/rtc/rtc-pcf2123.c
--- linux-5.10.52-orig/drivers/rtc/rtc-pcf2123.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/rtc/rtc-pcf2123.c	2021-07-25 16:46:21.348033000 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:468 @
 MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>");
 MODULE_DESCRIPTION("NXP PCF2123 RTC driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:rtc-pcf2123");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/rtc/rtc-pcf8523.c linux-5.10.52-v7l+/drivers/rtc/rtc-pcf8523.c
--- linux-5.10.52-orig/drivers/rtc/rtc-pcf8523.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/rtc/rtc-pcf8523.c	2021-07-25 16:46:21.348033000 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:208 @
 	if (err < 0)
 		return err;
 
-	if (regs[0] & REG_SECONDS_OS)
-		return -EINVAL;
+	if (regs[0] & REG_SECONDS_OS) {
+		/*
+		 * If the oscillator was stopped, try to clear the flag. Upon
+		 * power-up the flag is always set, but if we cannot clear it
+		 * the oscillator isn't running properly for some reason. The
+		 * sensible thing therefore is to return an error, signalling
+		 * that the clock cannot be assumed to be correct.
+		 */
+
+		regs[0] &= ~REG_SECONDS_OS;
+
+		err = pcf8523_write(client, REG_SECONDS, regs[0]);
+		if (err < 0)
+			return err;
+
+		err = pcf8523_read(client, REG_SECONDS, &regs[0]);
+		if (err < 0)
+			return err;
+
+		if (regs[0] & REG_SECONDS_OS)
+			return -EAGAIN;
+	}
 
 	tm->tm_sec = bcd2bin(regs[0] & 0x7f);
 	tm->tm_min = bcd2bin(regs[1] & 0x7f);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:265 @
 		return err;
 
 	regs[0] = REG_SECONDS;
-	/* This will purposely overwrite REG_SECONDS_OS */
 	regs[1] = bin2bcd(tm->tm_sec);
 	regs[2] = bin2bcd(tm->tm_min);
 	regs[3] = bin2bcd(tm->tm_hour);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/rtc/rtc-rv3028.c linux-5.10.52-v7l+/drivers/rtc/rtc-rv3028.c
--- linux-5.10.52-orig/drivers/rtc/rtc-rv3028.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/rtc/rtc-rv3028.c	2021-07-25 16:46:21.378032497 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:83 @
 
 #define RV3028_BACKUP_TCE		BIT(5)
 #define RV3028_BACKUP_TCR_MASK		GENMASK(1,0)
+#define RV3028_BACKUP_BSM_MASK		0x0C
 
 #define OFFSET_STEP_PPT			953674
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:793 @
 	struct rv3028_data *rv3028;
 	int ret, status;
 	u32 ohms;
+	u8 bsm;
 	struct nvmem_config nvmem_cfg = {
 		.name = "rv3028_nvram",
 		.word_size = 1,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:865 @
 	if (ret)
 		return ret;
 
+	/* setup backup switchover mode */
+	if (!device_property_read_u8(&client->dev, "backup-switchover-mode",
+				     &bsm))  {
+		if (bsm <= 3) {
+			ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP,
+				RV3028_BACKUP_BSM_MASK,
+				(bsm & 0x03) << 2);
+
+			if (ret)
+				return ret;
+		} else {
+			dev_warn(&client->dev, "invalid backup switchover mode value\n");
+		}
+	}
+
 	/* setup trickle charger */
 	if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
 				      &ohms)) {
diff -Nur --no-dereference linux-5.10.52-orig/drivers/soc/bcm/bcm2835-power.c linux-5.10.52-v7l+/drivers/soc/bcm/bcm2835-power.c
--- linux-5.10.52-orig/drivers/soc/bcm/bcm2835-power.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/soc/bcm/bcm2835-power.c	2021-07-25 16:46:24.297983543 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:146 @
 	/* AXI Async bridge registers. */
 	void __iomem		*asb;
 
+	bool is_2711;
+
 	struct genpd_onecell_data pd_xlate;
 	struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
 	struct reset_controller_dev reset;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:197 @
 {
 	struct bcm2835_power *power = pd->power;
 
+	/* 2711 has no power domains above the reset controller. */
+	if (power->is_2711)
+		return 0;
+
 	/* Enable functional isolation */
 	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:222 @
 	int inrush;
 	bool powok;
 
+	/* 2711 has no power domains above the reset controller. */
+	if (power->is_2711)
+		return 0;
+
 	/* If it was already powered on by the fw, leave it that way. */
 	if (PM_READ(pm_reg) & PM_POWUP)
 		return 0;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:640 @
 	power->base = pm->base;
 	power->asb = pm->asb;
 
+	/* 2711 hack: the new RPiVid ASB took over V3D, which is our
+	 * only consumer of this driver so far.  The old ASB seems to
+	 * still be present with ISP and H264 bits but no V3D, but I
+	 * don't know if that's real or not.  The V3D is in the same
+	 * place in the new ASB as the old one, so just poke the new
+	 * one for now.
+	 */
+	if (pm->rpivid_asb) {
+		power->asb = pm->rpivid_asb;
+		power->is_2711 = true;
+	}
+
 	id = ASB_READ(ASB_AXI_BRDG_ID);
 	if (id != 0x62726467 /* "BRDG" */) {
 		dev_err(dev, "ASB register ID returned 0x%08x\n", id);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/soc/bcm/Kconfig linux-5.10.52-v7l+/drivers/soc/bcm/Kconfig
--- linux-5.10.52-orig/drivers/soc/bcm/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/soc/bcm/Kconfig	2021-07-25 16:46:24.297983543 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:20 @
 	bool "Raspberry Pi power domain driver"
 	depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
 	depends on RASPBERRYPI_FIRMWARE=y
+	depends on PM
 	select PM_GENERIC_DOMAINS if PM
 	help
 	  This enables support for the RPi power domains which can be enabled
diff -Nur --no-dereference linux-5.10.52-orig/drivers/spi/spi-bcm2835.c linux-5.10.52-v7l+/drivers/spi/spi-bcm2835.c
--- linux-5.10.52-orig/drivers/spi/spi-bcm2835.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/spi/spi-bcm2835.c	2021-07-25 16:46:24.537979519 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:31 @
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/machine.h> /* FIXME: using chip internals */
 #include <linux/gpio/driver.h> /* FIXME: using chip internals */
+#include <linux/of_gpio.h>
 #include <linux/of_irq.h>
 #include <linux/spi/spi.h>
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:381 @
 	if (bs->tx_len && cs & BCM2835_SPI_CS_DONE)
 		bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
 
+	/* check if we got interrupt enabled */
+	if (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_INTR))
+		return IRQ_NONE;
+
 	/* Read as many bytes as possible from FIFO */
 	bcm2835_rd_fifo(bs);
 	/* Write as many bytes as possible to FIFO */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1094 @
 	unsigned long hz_per_byte, byte_limit;
 	u32 cs = bs->prepare_cs[spi->chip_select];
 
+	if (unlikely(!tfr->len)) {
+		static int warned;
+
+		if (!warned)
+			dev_warn(&spi->dev,
+				 "zero-length SPI transfer ignored\n");
+		warned = 1;
+		return 0;
+	}
+
 	/* set clock */
 	spi_hz = tfr->speed_hz;
 	clk_hz = clk_get_rate(bs->clk);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1302 @
 	struct bcm2835_spi *bs;
 	int err;
 
+	if (of_gpio_named_count(pdev->dev.of_node, "cs-gpios") >
+	    BCM2835_SPI_NUM_CS)
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				     "too many chip selects\n");
+
 	ctlr = devm_spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs),
 						  dma_get_cache_alignment()));
 	if (!ctlr)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1350 @
 	bcm2835_wr(bs, BCM2835_SPI_CS,
 		   BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
 
-	err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
+	err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt,
+			       IRQF_SHARED,
 			       dev_name(&pdev->dev), bs);
 	if (err) {
 		dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/spi/spi.c linux-5.10.52-v7l+/drivers/spi/spi.c
--- linux-5.10.52-orig/drivers/spi/spi.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/spi/spi.c	2021-07-25 16:46:24.687977005 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3341 @
  */
 int spi_setup(struct spi_device *spi)
 {
+	struct spi_controller *ctlr = spi->controller;
 	unsigned	bad_bits, ugly_bits;
 	int		status;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:3359 @
 		(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
 		 SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
 		return -EINVAL;
+
+	if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
+	    ctlr->cs_gpiods[spi->chip_select] && !(spi->mode & SPI_CS_HIGH)) {
+		dev_dbg(&spi->dev,
+			"setup: forcing CS_HIGH (use_gpio_descriptors)\n");
+		spi->mode |= SPI_CS_HIGH;
+	}
+
 	/* help drivers fail *cleanly* when they need options
 	 * that aren't supported with their current controller
 	 * SPI_CS_WORD has a fallback software implementation,
diff -Nur --no-dereference linux-5.10.52-orig/drivers/spi/spidev.c linux-5.10.52-v7l+/drivers/spi/spidev.c
--- linux-5.10.52-orig/drivers/spi/spidev.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/spi/spidev.c	2021-07-25 16:46:24.687977005 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:405 @
 		else
 			retval = get_user(tmp, (u32 __user *)arg);
 		if (retval == 0) {
-			struct spi_controller *ctlr = spi->controller;
 			u32	save = spi->mode;
 
 			if (tmp & ~SPI_MODE_MASK) {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:412 @
 				break;
 			}
 
-			if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
-			    ctlr->cs_gpiods[spi->chip_select])
-				tmp |= SPI_CS_HIGH;
-
 			tmp |= spi->mode & ~SPI_MODE_MASK;
 			spi->mode = (u16)tmp;
 			retval = spi_setup(spi);
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:735 @
 	 * compatible string, it is a Linux implementation thing
 	 * rather than a description of the hardware.
 	 */
-	WARN(spi->dev.of_node &&
+	WARN(0 && spi->dev.of_node &&
 	     of_device_is_compatible(spi->dev.of_node, "spidev"),
 	     "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
 
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/fbtft/fb_st7735r.c linux-5.10.52-v7l+/drivers/staging/fbtft/fb_st7735r.c
--- linux-5.10.52-orig/drivers/staging/fbtft/fb_st7735r.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/staging/fbtft/fb_st7735r.c	2021-07-25 16:46:24.937972813 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:19 @
 #define DEFAULT_GAMMA   "0F 1A 0F 18 2F 28 20 22 1F 1B 23 37 00 07 02 10\n" \
 			"0F 1B 0F 17 33 2C 29 2E 30 30 39 3F 00 07 03 10"
 
+#define ADAFRUIT18_GAMMA \
+			"02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n" \
+			"03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10"
+
 static const s16 default_init_sequence[] = {
 	-1, MIPI_DCS_SOFT_RESET,
 	-2, 150,                               /* delay */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:101 @
 	write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
 }
 
+static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
+					      int xs, int ys, int xe, int ye)
+{
+	write_reg(par, 0x2A, 0, xs + 2, 0, xe + 2);
+	write_reg(par, 0x2B, 0, ys + 1, 0, ye + 1);
+	write_reg(par, 0x2C);
+}
+
 #define MY BIT(7)
 #define MX BIT(6)
 #define MV BIT(5)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:189 @
 	},
 };
 
-FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7735r", &display);
+int variant_adafruit18(struct fbtft_display *display)
+{
+	display->gamma = ADAFRUIT18_GAMMA;
+	return 0;
+}
+
+int variant_adafruit18_green(struct fbtft_display *display)
+{
+	display->gamma = ADAFRUIT18_GAMMA;
+	display->fbtftops.set_addr_win = adafruit18_green_tab_set_addr_win;
+	return 0;
+}
+
+FBTFT_REGISTER_DRIVER_START(&display)
+FBTFT_COMPATIBLE("sitronix,st7735r")
+FBTFT_COMPATIBLE("fbtft,sainsmart18")
+FBTFT_VARIANT_COMPATIBLE("fbtft,adafruit18", variant_adafruit18)
+FBTFT_VARIANT_COMPATIBLE("fbtft,adafruit18_green", variant_adafruit18_green)
+FBTFT_REGISTER_DRIVER_END(DRVNAME, &display);
 
 MODULE_ALIAS("spi:" DRVNAME);
 MODULE_ALIAS("platform:" DRVNAME);
 MODULE_ALIAS("spi:st7735r");
 MODULE_ALIAS("platform:st7735r");
+MODULE_ALIAS("spi:sainsmart18");
+MODULE_ALIAS("platform:sainsmart");
+MODULE_ALIAS("spi:adafruit18");
+MODULE_ALIAS("platform:adafruit18");
+MODULE_ALIAS("spi:adafruit18_green");
+MODULE_ALIAS("platform:adafruit18_green");
 
 MODULE_DESCRIPTION("FB driver for the ST7735R LCD Controller");
 MODULE_AUTHOR("Noralf Tronnes");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/fbtft/fb_st7789v.c linux-5.10.52-v7l+/drivers/staging/fbtft/fb_st7789v.c
--- linux-5.10.52-orig/drivers/staging/fbtft/fb_st7789v.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/staging/fbtft/fb_st7789v.c	2021-07-25 16:46:24.937972813 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:69 @
 #define MADCTL_MX BIT(6) /* bitmask for column address order */
 #define MADCTL_MY BIT(7) /* bitmask for page address order */
 
+static u32 col_offset = 0;
+static u32 row_offset = 0;
+static u8 col_hack_fix_offset = 0;
+static short x_offset = 0;
+static short y_offset = 0;
+
 /**
  * init_display() - initialize the display controller
  *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:154 @
 	return 0;
 }
 
+static void minipitft13_set_addr_win(struct fbtft_par *par, int xs, int ys,
+				     int xe, int ye)
+{
+	xs += x_offset;
+	xe += x_offset;
+	ys += y_offset;
+	ye += y_offset;
+	write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
+		  xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+	write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
+		  ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+	write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
+}
+
 /**
  * set_var() - apply LCD properties like rotation and BGR mode
  *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:180 @
 static int set_var(struct fbtft_par *par)
 {
 	u8 madctl_par = 0;
+	struct fbtft_display *display = &par->pdata->display;
+	u32 width = display->width;
+	u32 height = display->height;
 
 	if (par->bgr)
 		madctl_par |= MADCTL_BGR;
 	switch (par->info->var.rotate) {
 	case 0:
+		x_offset = 0;
+		y_offset = 0;
 		break;
 	case 90:
 		madctl_par |= (MADCTL_MV | MADCTL_MY);
+		x_offset = (320 - height) - row_offset;
+		y_offset = (240 - width) - col_offset;
 		break;
 	case 180:
 		madctl_par |= (MADCTL_MX | MADCTL_MY);
+		x_offset = (240 - width) - col_offset + col_hack_fix_offset;
+		// hack tweak to account for extra pixel width to make even
+		y_offset = (320 - height) - row_offset;
 		break;
 	case 270:
 		madctl_par |= (MADCTL_MV | MADCTL_MX);
+		x_offset = row_offset;
+		y_offset = col_offset;
 		break;
 	default:
 		return -EINVAL;
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:302 @
 	},
 };
 
-FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7789v", &display);
+int variant_minipitft13(struct fbtft_display *display)
+{
+	display->fbtftops.set_addr_win = minipitft13_set_addr_win;
+	return 0;
+}
+
+FBTFT_REGISTER_DRIVER_START(&display)
+FBTFT_COMPATIBLE("sitronix,st7789v")
+FBTFT_VARIANT_COMPATIBLE("fbtft,minipitft13", variant_minipitft13)
+FBTFT_REGISTER_DRIVER_END(DRVNAME, &display);
 
 MODULE_ALIAS("spi:" DRVNAME);
 MODULE_ALIAS("platform:" DRVNAME);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/fbtft/fbtft-core.c linux-5.10.52-v7l+/drivers/staging/fbtft/fbtft-core.c
--- linux-5.10.52-orig/drivers/staging/fbtft/fbtft-core.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/staging/fbtft/fbtft-core.c	2021-07-25 16:46:24.937972813 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:27 @
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <video/mipi_display.h>
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1199 @
  * @display: Display properties
  * @sdev: SPI device
  * @pdev: Platform device
+ * @dt_ids: Compatible string table
  *
  * Allocates, initializes and registers a framebuffer
  *
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1209 @
  */
 int fbtft_probe_common(struct fbtft_display *display,
 		       struct spi_device *sdev,
-		       struct platform_device *pdev)
+		       struct platform_device *pdev,
+		       const struct of_device_id *dt_ids)
 {
 	struct device *dev;
 	struct fb_info *info;
 	struct fbtft_par *par;
 	struct fbtft_platform_data *pdata;
+	const struct of_device_id *match;
+	int (*variant)(struct fbtft_display *);
 	int ret;
 
 	if (sdev)
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:1233 @
 		pdata = fbtft_properties_read(dev);
 		if (IS_ERR(pdata))
 			return PTR_ERR(pdata);
+		match = of_match_device(dt_ids, dev);
+		if (match && match->data) {
+			/* apply the variant */
+			variant = match->data;
+			ret = (*variant)(display);
+			if (ret)
+				return ret;
+		}
 	}
 
 	info = fbtft_framebuffer_alloc(display, dev, pdata);
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/fbtft/fbtft.h linux-5.10.52-v7l+/drivers/staging/fbtft/fbtft.h
--- linux-5.10.52-orig/drivers/staging/fbtft/fbtft.h	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/staging/fbtft/fbtft.h	2021-07-25 16:46:24.937972813 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:254 @
 void fbtft_unregister_backlight(struct fbtft_par *par);
 int fbtft_init_display(struct fbtft_par *par);
 int fbtft_probe_common(struct fbtft_display *display, struct spi_device *sdev,
-		       struct platform_device *pdev);
+		       struct platform_device *pdev,
+		       const struct of_device_id *dt_ids);
 int fbtft_remove_common(struct device *dev, struct fb_info *info);
 
 /* fbtft-io.c */
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:276 @
 void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...);
 void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...);
 
-#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display)                \
+#define FBTFT_REGISTER_DRIVER_START(_display)                              \
+									   \
+static const struct of_device_id dt_ids[];                                 \
 									   \
 static int fbtft_driver_probe_spi(struct spi_device *spi)                  \
 {                                                                          \
-	return fbtft_probe_common(_display, spi, NULL);                    \
+	return fbtft_probe_common(_display, spi, NULL, dt_ids);	           \
 }                                                                          \
 									   \
 static int fbtft_driver_remove_spi(struct spi_device *spi)                 \
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:294 @
 									   \
 static int fbtft_driver_probe_pdev(struct platform_device *pdev)           \
 {                                                                          \
-	return fbtft_probe_common(_display, NULL, pdev);                   \
+	return fbtft_probe_common(_display, NULL, pdev, dt_ids);           \
 }                                                                          \
 									   \
 static int fbtft_driver_remove_pdev(struct platform_device *pdev)          \
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:304 @
 	return fbtft_remove_common(&pdev->dev, info);                      \
 }                                                                          \
 									   \
-static const struct of_device_id dt_ids[] = {                              \
-	{ .compatible = _compatible },                                     \
+static const struct of_device_id dt_ids[] = {
+
+#define FBTFT_COMPATIBLE(_compatible)                                      \
+	{ .compatible = _compatible },
+
+#define FBTFT_VARIANT_COMPATIBLE(_compatible, _variant)                    \
+	{ .compatible = _compatible, .data = _variant },
+
+#define FBTFT_REGISTER_DRIVER_END(_name, _display)                         \
+									   \
 	{},                                                                \
 };                                                                         \
 									   \
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:358 @
 module_init(fbtft_driver_module_init);                                     \
 module_exit(fbtft_driver_module_exit);
 
+#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display)                \
+	FBTFT_REGISTER_DRIVER_START(_display)                              \
+	FBTFT_COMPATIBLE(_compatible)                                      \
+	FBTFT_REGISTER_DRIVER_END(_name, _display)
+
 /* Debug macros */
 
 /* shorthand debug levels */
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/Kconfig linux-5.10.52-v7l+/drivers/staging/media/Kconfig
--- linux-5.10.52-orig/drivers/staging/media/Kconfig	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/staging/media/Kconfig	2021-07-25 16:46:25.047970969 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:37 @
 
 source "drivers/staging/media/rkvdec/Kconfig"
 
+source "drivers/staging/media/rpivid/Kconfig"
+
 source "drivers/staging/media/sunxi/Kconfig"
 
 source "drivers/staging/media/tegra-vde/Kconfig"
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/Makefile linux-5.10.52-v7l+/drivers/staging/media/Makefile
--- linux-5.10.52-orig/drivers/staging/media/Makefile	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/staging/media/Makefile	2021-07-25 16:46:25.047970969 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:8 @
 obj-$(CONFIG_VIDEO_MESON_VDEC)	+= meson/vdec/
 obj-$(CONFIG_VIDEO_OMAP4)	+= omap4iss/
 obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC)	+= rkvdec/
+obj-$(CONFIG_VIDEO_RPIVID)	+= rpivid/
 obj-$(CONFIG_VIDEO_SUNXI)	+= sunxi/
 obj-$(CONFIG_VIDEO_TEGRA)	+= tegra-video/
 obj-$(CONFIG_TEGRA_VDE)		+= tegra-vde/
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/Kconfig linux-5.10.52-v7l+/drivers/staging/media/rpivid/Kconfig
--- linux-5.10.52-orig/drivers/staging/media/rpivid/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/Kconfig	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+# SPDX-License-Identifier: GPL-2.0
+
+config VIDEO_RPIVID
+	tristate "Rpi H265 driver"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on OF
+	select MEDIA_CONTROLLER
+	select MEDIA_CONTROLLER_REQUEST_API
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	help
+	  Support for the Rpi H265 h/w decoder.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called rpivid-hevc.
+
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/Makefile linux-5.10.52-v7l+/drivers/staging/media/rpivid/Makefile
--- linux-5.10.52-orig/drivers/staging/media/rpivid/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/Makefile	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:2 @
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_VIDEO_RPIVID) += rpivid-hevc.o
+
+rpivid-hevc-y = rpivid.o rpivid_video.o rpivid_dec.o \
+		 rpivid_hw.o rpivid_h265.o
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid.c linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid.c
--- linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid.c	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Raspberry Pi HEVC driver
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rpivid.h"
+#include "rpivid_video.h"
+#include "rpivid_hw.h"
+#include "rpivid_dec.h"
+
+/*
+ * Default /dev/videoN node number.
+ * Deliberately avoid the very low numbers as these are often taken by webcams
+ * etc, and simple apps tend to only go for /dev/video0.
+ */
+static int video_nr = 19;
+module_param(video_nr, int, 0644);
+MODULE_PARM_DESC(video_nr, "decoder video device number");
+
+static const struct rpivid_control rpivid_ctrls[] = {
+	{
+		.cfg = {
+			.id	= V4L2_CID_MPEG_VIDEO_HEVC_SPS,
+			.ops	= &rpivid_hevc_sps_ctrl_ops,
+		},
+		.required	= true,
+	},
+	{
+		.cfg = {
+			.id	= V4L2_CID_MPEG_VIDEO_HEVC_PPS,
+			.ops	= &rpivid_hevc_pps_ctrl_ops,
+		},
+		.required	= true,
+	},
+	{
+		.cfg = {
+			.id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX,
+		},
+		.required	= false,
+	},
+	{
+		.cfg = {
+			.id	= V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS,
+		},
+		.required	= true,
+	},
+	{
+		.cfg = {
+			.id	= V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
+			.max	= V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
+			.def	= V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
+		},
+		.required	= false,
+	},
+	{
+		.cfg = {
+			.id	= V4L2_CID_MPEG_VIDEO_HEVC_START_CODE,
+			.max	= V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
+			.def	= V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
+		},
+		.required	= false,
+	},
+};
+
+#define rpivid_ctrls_COUNT	ARRAY_SIZE(rpivid_ctrls)
+
+struct v4l2_ctrl *rpivid_find_ctrl(struct rpivid_ctx *ctx, u32 id)
+{
+	unsigned int i;
+
+	for (i = 0; ctx->ctrls[i]; i++)
+		if (ctx->ctrls[i]->id == id)
+			return ctx->ctrls[i];
+
+	return NULL;
+}
+
+void *rpivid_find_control_data(struct rpivid_ctx *ctx, u32 id)
+{
+	struct v4l2_ctrl *const ctrl = rpivid_find_ctrl(ctx, id);
+
+	return !ctrl ? NULL : ctrl->p_cur.p;
+}
+
+static int rpivid_init_ctrls(struct rpivid_dev *dev, struct rpivid_ctx *ctx)
+{
+	struct v4l2_ctrl_handler *hdl = &ctx->hdl;
+	struct v4l2_ctrl *ctrl;
+	unsigned int ctrl_size;
+	unsigned int i;
+
+	v4l2_ctrl_handler_init(hdl, rpivid_ctrls_COUNT);
+	if (hdl->error) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Failed to initialize control handler\n");
+		return hdl->error;
+	}
+
+	ctrl_size = sizeof(ctrl) * rpivid_ctrls_COUNT + 1;
+
+	ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL);
+	if (!ctx->ctrls)
+		return -ENOMEM;
+
+	for (i = 0; i < rpivid_ctrls_COUNT; i++) {
+		ctrl = v4l2_ctrl_new_custom(hdl, &rpivid_ctrls[i].cfg,
+					    ctx);
+		if (hdl->error) {
+			v4l2_err(&dev->v4l2_dev,
+				 "Failed to create new custom control id=%#x\n",
+				 rpivid_ctrls[i].cfg.id);
+
+			v4l2_ctrl_handler_free(hdl);
+			kfree(ctx->ctrls);
+			return hdl->error;
+		}
+
+		ctx->ctrls[i] = ctrl;
+	}
+
+	ctx->fh.ctrl_handler = hdl;
+	v4l2_ctrl_handler_setup(hdl);
+
+	return 0;
+}
+
+static int rpivid_request_validate(struct media_request *req)
+{
+	struct media_request_object *obj;
+	struct v4l2_ctrl_handler *parent_hdl, *hdl;
+	struct rpivid_ctx *ctx = NULL;
+	struct v4l2_ctrl *ctrl_test;
+	unsigned int count;
+	unsigned int i;
+
+	list_for_each_entry(obj, &req->objects, list) {
+		struct vb2_buffer *vb;
+
+		if (vb2_request_object_is_buffer(obj)) {
+			vb = container_of(obj, struct vb2_buffer, req_obj);
+			ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+			break;
+		}
+	}
+
+	if (!ctx)
+		return -ENOENT;
+
+	count = vb2_request_buffer_cnt(req);
+	if (!count) {
+		v4l2_info(&ctx->dev->v4l2_dev,
+			  "No buffer was provided with the request\n");
+		return -ENOENT;
+	} else if (count > 1) {
+		v4l2_info(&ctx->dev->v4l2_dev,
+			  "More than one buffer was provided with the request\n");
+		return -EINVAL;
+	}
+
+	parent_hdl = &ctx->hdl;
+
+	hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl);
+	if (!hdl) {
+		v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control(s)\n");
+		return -ENOENT;
+	}
+
+	for (i = 0; i < rpivid_ctrls_COUNT; i++) {
+		if (!rpivid_ctrls[i].required)
+			continue;
+
+		ctrl_test =
+			v4l2_ctrl_request_hdl_ctrl_find(hdl,
+							rpivid_ctrls[i].cfg.id);
+		if (!ctrl_test) {
+			v4l2_info(&ctx->dev->v4l2_dev,
+				  "Missing required codec control\n");
+			v4l2_ctrl_request_hdl_put(hdl);
+			return -ENOENT;
+		}
+	}
+
+	v4l2_ctrl_request_hdl_put(hdl);
+
+	return vb2_request_validate(req);
+}
+
+static int rpivid_open(struct file *file)
+{
+	struct rpivid_dev *dev = video_drvdata(file);
+	struct rpivid_ctx *ctx = NULL;
+	int ret;
+
+	if (mutex_lock_interruptible(&dev->dev_mutex))
+		return -ERESTARTSYS;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		mutex_unlock(&dev->dev_mutex);
+		ret = -ENOMEM;
+		goto err_unlock;
+	}
+
+	mutex_init(&ctx->ctx_mutex);
+
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	ctx->dev = dev;
+
+	ret = rpivid_init_ctrls(dev, ctx);
+	if (ret)
+		goto err_free;
+
+	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+					    &rpivid_queue_init);
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+		goto err_ctrls;
+	}
+
+	/* The only bit of format info that we can guess now is H265 src
+	 * Everything else we need more info for
+	 */
+	ctx->src_fmt.pixelformat = RPIVID_SRC_PIXELFORMAT_DEFAULT;
+	rpivid_prepare_src_format(&ctx->src_fmt);
+
+	v4l2_fh_add(&ctx->fh);
+
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+
+err_ctrls:
+	v4l2_ctrl_handler_free(&ctx->hdl);
+err_free:
+	mutex_destroy(&ctx->ctx_mutex);
+	kfree(ctx);
+err_unlock:
+	mutex_unlock(&dev->dev_mutex);
+
+	return ret;
+}
+
+static int rpivid_release(struct file *file)
+{
+	struct rpivid_dev *dev = video_drvdata(file);
+	struct rpivid_ctx *ctx = container_of(file->private_data,
+					      struct rpivid_ctx, fh);
+
+	mutex_lock(&dev->dev_mutex);
+
+	v4l2_fh_del(&ctx->fh);
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+	v4l2_ctrl_handler_free(&ctx->hdl);
+	kfree(ctx->ctrls);
+
+	v4l2_fh_exit(&ctx->fh);
+	mutex_destroy(&ctx->ctx_mutex);
+
+	kfree(ctx);
+
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations rpivid_fops = {
+	.owner		= THIS_MODULE,
+	.open		= rpivid_open,
+	.release	= rpivid_release,
+	.poll		= v4l2_m2m_fop_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= v4l2_m2m_fop_mmap,
+};
+
+static const struct video_device rpivid_video_device = {
+	.name		= RPIVID_NAME,
+	.vfl_dir	= VFL_DIR_M2M,
+	.fops		= &rpivid_fops,
+	.ioctl_ops	= &rpivid_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release_empty,
+	.device_caps	= V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
+};
+
+static const struct v4l2_m2m_ops rpivid_m2m_ops = {
+	.device_run	= rpivid_device_run,
+};
+
+static const struct media_device_ops rpivid_m2m_media_ops = {
+	.req_validate	= rpivid_request_validate,
+	.req_queue	= v4l2_m2m_request_queue,
+};
+
+static int rpivid_probe(struct platform_device *pdev)
+{
+	struct rpivid_dev *dev;
+	struct video_device *vfd;
+	int ret;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->vfd = rpivid_video_device;
+	dev->dev = &pdev->dev;
+	dev->pdev = pdev;
+
+	ret = 0;
+	ret = rpivid_hw_probe(dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to probe hardware\n");
+		return ret;
+	}
+
+	dev->dec_ops = &rpivid_dec_ops_h265;
+
+	mutex_init(&dev->dev_mutex);
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register V4L2 device\n");
+		return ret;
+	}
+
+	vfd = &dev->vfd;
+	vfd->lock = &dev->dev_mutex;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+
+	snprintf(vfd->name, sizeof(vfd->name), "%s", rpivid_video_device.name);
+	video_set_drvdata(vfd, dev);
+
+	dev->m2m_dev = v4l2_m2m_init(&rpivid_m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Failed to initialize V4L2 M2M device\n");
+		ret = PTR_ERR(dev->m2m_dev);
+
+		goto err_v4l2;
+	}
+
+	dev->mdev.dev = &pdev->dev;
+	strscpy(dev->mdev.model, RPIVID_NAME, sizeof(dev->mdev.model));
+	strscpy(dev->mdev.bus_info, "platform:" RPIVID_NAME,
+		sizeof(dev->mdev.bus_info));
+
+	media_device_init(&dev->mdev);
+	dev->mdev.ops = &rpivid_m2m_media_ops;
+	dev->v4l2_dev.mdev = &dev->mdev;
+
+	ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		goto err_m2m;
+	}
+
+	v4l2_info(&dev->v4l2_dev,
+		  "Device registered as /dev/video%d\n", vfd->num);
+
+	ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
+						 MEDIA_ENT_F_PROC_VIDEO_DECODER);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Failed to initialize V4L2 M2M media controller\n");
+		goto err_video;
+	}
+
+	ret = media_device_register(&dev->mdev);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
+		goto err_m2m_mc;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	return 0;
+
+err_m2m_mc:
+	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+err_video:
+	video_unregister_device(&dev->vfd);
+err_m2m:
+	v4l2_m2m_release(dev->m2m_dev);
+err_v4l2:
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	return ret;
+}
+
+static int rpivid_remove(struct platform_device *pdev)
+{
+	struct rpivid_dev *dev = platform_get_drvdata(pdev);
+
+	if (media_devnode_is_registered(dev->mdev.devnode)) {
+		media_device_unregister(&dev->mdev);
+		v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+		media_device_cleanup(&dev->mdev);
+	}
+
+	v4l2_m2m_release(dev->m2m_dev);
+	video_unregister_device(&dev->vfd);
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	rpivid_hw_remove(dev);
+
+	return 0;
+}
+
+static const struct of_device_id rpivid_dt_match[] = {
+	{
+		.compatible = "raspberrypi,rpivid-vid-decoder",
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rpivid_dt_match);
+
+static struct platform_driver rpivid_driver = {
+	.probe		= rpivid_probe,
+	.remove		= rpivid_remove,
+	.driver		= {
+		.name = RPIVID_NAME,
+		.of_match_table	= of_match_ptr(rpivid_dt_match),
+	},
+};
+module_platform_driver(rpivid_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("John Cox <jc@kynesim.co.uk>");
+MODULE_DESCRIPTION("Raspberry Pi HEVC V4L2 driver");
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_dec.c linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_dec.c
--- linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_dec.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_dec.c	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Raspberry Pi HEVC driver
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rpivid.h"
+#include "rpivid_dec.h"
+
+void rpivid_device_run(void *priv)
+{
+	struct rpivid_ctx *const ctx = priv;
+	struct rpivid_dev *const dev = ctx->dev;
+	struct rpivid_run run = {};
+	struct media_request *src_req;
+
+	run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+	if (!run.src || !run.dst) {
+		v4l2_err(&dev->v4l2_dev, "%s: Missing buffer: src=%p, dst=%p\n",
+			 __func__, run.src, run.dst);
+		goto fail;
+	}
+
+	/* Apply request(s) controls */
+	src_req = run.src->vb2_buf.req_obj.req;
+	if (!src_req) {
+		v4l2_err(&dev->v4l2_dev, "%s: Missing request\n", __func__);
+		goto fail;
+	}
+
+	v4l2_ctrl_request_setup(src_req, &ctx->hdl);
+
+	switch (ctx->src_fmt.pixelformat) {
+	case V4L2_PIX_FMT_HEVC_SLICE:
+		run.h265.sps =
+			rpivid_find_control_data(ctx,
+						 V4L2_CID_MPEG_VIDEO_HEVC_SPS);
+		run.h265.pps =
+			rpivid_find_control_data(ctx,
+						 V4L2_CID_MPEG_VIDEO_HEVC_PPS);
+		run.h265.slice_params =
+			rpivid_find_control_data(ctx,
+						 V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS);
+		run.h265.scaling_matrix =
+			rpivid_find_control_data(ctx,
+						 V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX);
+		break;
+
+	default:
+		break;
+	}
+
+	v4l2_m2m_buf_copy_metadata(run.src, run.dst, true);
+
+	dev->dec_ops->setup(ctx, &run);
+
+	/* Complete request(s) controls */
+	v4l2_ctrl_request_complete(src_req, &ctx->hdl);
+
+	dev->dec_ops->trigger(ctx);
+	return;
+
+fail:
+	/* We really shouldn't get here but tidy up what we can */
+	v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+					 VB2_BUF_STATE_ERROR);
+}
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_dec.h linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_dec.h
--- linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_dec.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_dec.h	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Raspberry Pi HEVC driver
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#ifndef _RPIVID_DEC_H_
+#define _RPIVID_DEC_H_
+
+void rpivid_device_run(void *priv);
+
+#endif
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid.h linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid.h
--- linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid.h	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Raspberry Pi HEVC driver
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#ifndef _RPIVID_H_
+#define _RPIVID_H_
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define OPT_DEBUG_POLL_IRQ  0
+
+#define RPIVID_DEC_ENV_COUNT 6
+#define RPIVID_P1BUF_COUNT 3
+#define RPIVID_P2BUF_COUNT 3
+
+#define RPIVID_NAME			"rpivid"
+
+#define RPIVID_CAPABILITY_UNTILED	BIT(0)
+#define RPIVID_CAPABILITY_H265_DEC	BIT(1)
+
+#define RPIVID_QUIRK_NO_DMA_OFFSET	BIT(0)
+
+#define RPIVID_SRC_PIXELFORMAT_DEFAULT	V4L2_PIX_FMT_HEVC_SLICE
+
+enum rpivid_irq_status {
+	RPIVID_IRQ_NONE,
+	RPIVID_IRQ_ERROR,
+	RPIVID_IRQ_OK,
+};
+
+struct rpivid_control {
+	struct v4l2_ctrl_config cfg;
+	unsigned char		required:1;
+};
+
+struct rpivid_h265_run {
+	u32 slice_ents;
+	const struct v4l2_ctrl_hevc_sps			*sps;
+	const struct v4l2_ctrl_hevc_pps			*pps;
+	const struct v4l2_ctrl_hevc_slice_params	*slice_params;
+	const struct v4l2_ctrl_hevc_scaling_matrix	*scaling_matrix;
+};
+
+struct rpivid_run {
+	struct vb2_v4l2_buffer	*src;
+	struct vb2_v4l2_buffer	*dst;
+
+	struct rpivid_h265_run	h265;
+};
+
+struct rpivid_buffer {
+	struct v4l2_m2m_buffer          m2m_buf;
+};
+
+struct rpivid_dec_state;
+struct rpivid_dec_env;
+
+struct rpivid_gptr {
+	size_t size;
+	__u8 *ptr;
+	dma_addr_t addr;
+	unsigned long attrs;
+};
+
+struct rpivid_dev;
+typedef void (*rpivid_irq_callback)(struct rpivid_dev *dev, void *ctx);
+
+struct rpivid_q_aux;
+#define RPIVID_AUX_ENT_COUNT VB2_MAX_FRAME
+
+
+#define RPIVID_CTX_STATE_STOPPED	0	/* stream_off */
+#define RPIVID_CTX_STATE_STREAM_ON	1	/* decoding */
+#define RPIVID_CTX_STATE_STREAM_STOP	2	/* in stream_off */
+#define RPIVID_CTX_STATE_STREAM_ERR	3	/* stream_on but broken */
+
+struct rpivid_ctx {
+	struct v4l2_fh			fh;
+	struct rpivid_dev		*dev;
+
+	struct v4l2_pix_format_mplane	src_fmt;
+	struct v4l2_pix_format_mplane	dst_fmt;
+	int dst_fmt_set;
+
+	atomic_t 			stream_state;
+	struct clk_request		*clk_req;
+	int 				src_stream_on;
+	int 				dst_stream_on;
+
+	// fatal_err is set if an error has occurred s.t. decode cannot
+	// continue (such as running out of CMA)
+	int fatal_err;
+
+	/* Lock for queue operations */
+	struct mutex			ctx_mutex;
+
+	struct v4l2_ctrl_handler	hdl;
+	struct v4l2_ctrl		**ctrls;
+
+	/* Decode state - stateless decoder my *** */
+	/* state contains stuff that is only needed in phase0
+	 * it could be held in dec_env but that would be wasteful
+	 */
+	struct rpivid_dec_state *state;
+	struct rpivid_dec_env *dec0;
+
+	/* Spinlock protecting dec_free */
+	spinlock_t dec_lock;
+	struct rpivid_dec_env *dec_free;
+
+	struct rpivid_dec_env *dec_pool;
+
+	unsigned int p1idx;
+	atomic_t p1out;
+	struct rpivid_gptr bitbufs[RPIVID_P1BUF_COUNT];
+
+	/* *** Should be in dev *** */
+	unsigned int p2idx;
+	struct rpivid_gptr pu_bufs[RPIVID_P2BUF_COUNT];
+	struct rpivid_gptr coeff_bufs[RPIVID_P2BUF_COUNT];
+
+	/* Spinlock protecting aux_free */
+	spinlock_t aux_lock;
+	struct rpivid_q_aux *aux_free;
+
+	struct rpivid_q_aux *aux_ents[RPIVID_AUX_ENT_COUNT];
+
+	unsigned int colmv_stride;
+	unsigned int colmv_picsize;
+};
+
+struct rpivid_dec_ops {
+	void (*setup)(struct rpivid_ctx *ctx, struct rpivid_run *run);
+	int (*start)(struct rpivid_ctx *ctx);
+	void (*stop)(struct rpivid_ctx *ctx);
+	void (*trigger)(struct rpivid_ctx *ctx);
+};
+
+struct rpivid_variant {
+	unsigned int	capabilities;
+	unsigned int	quirks;
+	unsigned int	mod_rate;
+};
+
+struct rpivid_hw_irq_ent;
+
+#define RPIVID_ICTL_ENABLE_UNLIMITED (-1)
+
+struct rpivid_hw_irq_ctrl {
+	/* Spinlock protecting claim and tail */
+	spinlock_t lock;
+	struct rpivid_hw_irq_ent *claim;
+	struct rpivid_hw_irq_ent *tail;
+
+	/* Ent for pending irq - also prevents sched */
+	struct rpivid_hw_irq_ent *irq;
+	/* Non-zero => do not start a new job - outer layer sched pending */
+	int no_sched;
+	/* Enable count. -1 always OK, 0 do not sched, +ve shed & count down */
+	int enable;
+	/* Thread CB requested */
+	bool thread_reqed;
+};
+
+struct rpivid_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	vfd;
+	struct media_device	mdev;
+	struct media_pad	pad[2];
+	struct platform_device	*pdev;
+	struct device		*dev;
+	struct v4l2_m2m_dev	*m2m_dev;
+	const struct rpivid_dec_ops *dec_ops;
+
+	/* Device file mutex */
+	struct mutex		dev_mutex;
+
+	void __iomem		*base_irq;
+	void __iomem		*base_h265;
+
+	struct clk		*clock;
+
+	int			cache_align;
+
+	struct rpivid_hw_irq_ctrl ic_active1;
+	struct rpivid_hw_irq_ctrl ic_active2;
+};
+
+extern const struct rpivid_dec_ops rpivid_dec_ops_h265;
+extern const struct v4l2_ctrl_ops rpivid_hevc_sps_ctrl_ops;
+extern const struct v4l2_ctrl_ops rpivid_hevc_pps_ctrl_ops;
+
+struct v4l2_ctrl *rpivid_find_ctrl(struct rpivid_ctx *ctx, u32 id);
+void *rpivid_find_control_data(struct rpivid_ctx *ctx, u32 id);
+
+#endif
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_h265.c linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_h265.c
--- linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_h265.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_h265.c	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Raspberry Pi HEVC driver
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "rpivid.h"
+#include "rpivid_hw.h"
+#include "rpivid_video.h"
+
+#define DEBUG_TRACE_P1_CMD 0
+#define DEBUG_TRACE_EXECUTION 0
+
+#define USE_REQUEST_PIN 1
+
+#if DEBUG_TRACE_EXECUTION
+#define xtrace_in(dev_, de_)\
+	v4l2_info(&(dev_)->v4l2_dev, "%s[%d]: in\n",   __func__,\
+		  (de_) == NULL ? -1 : (de_)->decode_order)
+#define xtrace_ok(dev_, de_)\
+	v4l2_info(&(dev_)->v4l2_dev, "%s[%d]: ok\n",   __func__,\
+		  (de_) == NULL ? -1 : (de_)->decode_order)
+#define xtrace_fin(dev_, de_)\
+	v4l2_info(&(dev_)->v4l2_dev, "%s[%d]: finish\n", __func__,\
+		  (de_) == NULL ? -1 : (de_)->decode_order)
+#define xtrace_fail(dev_, de_)\
+	v4l2_info(&(dev_)->v4l2_dev, "%s[%d]: FAIL\n", __func__,\
+		  (de_) == NULL ? -1 : (de_)->decode_order)
+#else
+#define xtrace_in(dev_, de_)
+#define xtrace_ok(dev_, de_)
+#define xtrace_fin(dev_, de_)
+#define xtrace_fail(dev_, de_)
+#endif
+
+enum hevc_slice_type {
+	HEVC_SLICE_B = 0,
+	HEVC_SLICE_P = 1,
+	HEVC_SLICE_I = 2,
+};
+
+enum hevc_layer { L0 = 0, L1 = 1 };
+
+static int gptr_alloc(struct rpivid_dev *const dev, struct rpivid_gptr *gptr,
+		      size_t size, unsigned long attrs)
+{
+	gptr->size = size;
+	gptr->attrs = attrs;
+	gptr->addr = 0;
+	gptr->ptr = dma_alloc_attrs(dev->dev, gptr->size, &gptr->addr,
+				    GFP_KERNEL, gptr->attrs);
+	return !gptr->ptr ? -ENOMEM : 0;
+}
+
+static void gptr_free(struct rpivid_dev *const dev,
+		      struct rpivid_gptr *const gptr)
+{
+	if (gptr->ptr)
+		dma_free_attrs(dev->dev, gptr->size, gptr->ptr, gptr->addr,
+			       gptr->attrs);
+	gptr->size = 0;
+	gptr->ptr = NULL;
+	gptr->addr = 0;
+	gptr->attrs = 0;
+}
+
+/* Realloc but do not copy
+ *
+ * Frees then allocs.
+ * If the alloc fails then it attempts to re-allocote the old size
+ * On error then check gptr->ptr to determine if anything is currently
+ * allocated.
+ */
+static int gptr_realloc_new(struct rpivid_dev * const dev,
+			    struct rpivid_gptr * const gptr, size_t size)
+{
+	const size_t old_size = gptr->size;
+
+	if (size == gptr->size)
+		return 0;
+
+	if (gptr->ptr)
+		dma_free_attrs(dev->dev, gptr->size, gptr->ptr,
+			       gptr->addr, gptr->attrs);
+
+	gptr->addr = 0;
+	gptr->size = size;
+	gptr->ptr = dma_alloc_attrs(dev->dev, gptr->size,
+				    &gptr->addr, GFP_KERNEL, gptr->attrs);
+
+	if (!gptr->ptr) {
+		gptr->addr = 0;
+		gptr->size = old_size;
+		gptr->ptr = dma_alloc_attrs(dev->dev, gptr->size,
+					    &gptr->addr, GFP_KERNEL, gptr->attrs);
+		if (!gptr->ptr) {
+			gptr->size = 0;
+			gptr->addr = 0;
+			gptr->attrs = 0;
+		}
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static size_t next_size(const size_t x)
+{
+	return rpivid_round_up_size(x + 1);
+}
+
+#define NUM_SCALING_FACTORS 4064 /* Not a typo = 0xbe0 + 0x400 */
+
+#define AXI_BASE64 0
+
+#define PROB_BACKUP ((20 << 12) + (20 << 6) + (0 << 0))
+#define PROB_RELOAD ((20 << 12) + (20 << 0) + (0 << 6))
+
+#define HEVC_MAX_REFS V4L2_HEVC_DPB_ENTRIES_NUM_MAX
+
+//////////////////////////////////////////////////////////////////////////////
+
+struct rpi_cmd {
+	u32 addr;
+	u32 data;
+} __packed;
+
+struct rpivid_q_aux {
+	unsigned int refcount;
+	unsigned int q_index;
+	struct rpivid_q_aux *next;
+	struct rpivid_gptr col;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+enum rpivid_decode_state {
+	RPIVID_DECODE_SLICE_START,
+	RPIVID_DECODE_SLICE_CONTINUE,
+	RPIVID_DECODE_ERROR_CONTINUE,
+	RPIVID_DECODE_ERROR_DONE,
+	RPIVID_DECODE_PHASE1,
+	RPIVID_DECODE_END,
+};
+
+struct rpivid_dec_env {
+	struct rpivid_ctx *ctx;
+	struct rpivid_dec_env *next;
+
+	enum rpivid_decode_state state;
+	unsigned int decode_order;
+	int p1_status;		/* P1 status - what to realloc */
+
+	struct rpi_cmd *cmd_fifo;
+	unsigned int cmd_len, cmd_max;
+	unsigned int num_slice_msgs;
+	unsigned int pic_width_in_ctbs_y;
+	unsigned int pic_height_in_ctbs_y;
+	unsigned int dpbno_col;
+	u32 reg_slicestart;
+	int collocated_from_l0_flag;
+	/*
+	 * Last CTB/Tile X,Y processed by (wpp_)entry_point
+	 * Could be in _state as P0 only but needs updating where _state
+	 * is const
+	 */
+	unsigned int entry_ctb_x;
+	unsigned int entry_ctb_y;
+	unsigned int entry_tile_x;
+	unsigned int entry_tile_y;
+	unsigned int entry_qp;
+	u32 entry_slice;
+
+	u32 rpi_config2;
+	u32 rpi_framesize;
+	u32 rpi_currpoc;
+
+	struct vb2_v4l2_buffer *frame_buf; // Detached dest buffer
+	struct vb2_v4l2_buffer *src_buf;   // Detached src buffer
+	unsigned int frame_c_offset;
+	unsigned int frame_stride;
+	dma_addr_t frame_addr;
+	dma_addr_t ref_addrs[16];
+	struct rpivid_q_aux *frame_aux;
+	struct rpivid_q_aux *col_aux;
+
+	dma_addr_t cmd_addr;
+	size_t cmd_size;
+
+	dma_addr_t pu_base_vc;
+	dma_addr_t coeff_base_vc;
+	u32 pu_stride;
+	u32 coeff_stride;
+
+	struct rpivid_gptr *bit_copy_gptr;
+	size_t bit_copy_len;
+
+#define SLICE_MSGS_MAX (2 * HEVC_MAX_REFS * 8 + 3)
+	u16 slice_msgs[SLICE_MSGS_MAX];
+	u8 scaling_factors[NUM_SCALING_FACTORS];
+
+#if USE_REQUEST_PIN
+	struct media_request *req_pin;
+#else
+	struct media_request_object *req_obj;
+#endif
+	struct rpivid_hw_irq_ent irq_ent;
+};
+
+#define member_size(type, member) sizeof(((type *)0)->member)
+
+struct rpivid_dec_state {
+	struct v4l2_ctrl_hevc_sps sps;
+	struct v4l2_ctrl_hevc_pps pps;
+
+	// Helper vars & tables derived from sps/pps
+	unsigned int log2_ctb_size;     /* log2 width of a CTB */
+	unsigned int ctb_width;         /* Width in CTBs */
+	unsigned int ctb_height;        /* Height in CTBs */
+	unsigned int ctb_size;          /* Pic area in CTBs */
+	unsigned int tile_width;        /* Width in tiles */
+	unsigned int tile_height;       /* Height in tiles */
+
+	int *col_bd;
+	int *row_bd;
+	int *ctb_addr_rs_to_ts;
+	int *ctb_addr_ts_to_rs;
+
+	// Aux starage for DPB
+	// Hold refs
+	struct rpivid_q_aux *ref_aux[HEVC_MAX_REFS];
+	struct rpivid_q_aux *frame_aux;
+
+	// Slice vars
+	unsigned int slice_idx;
+	bool frame_end;
+	bool slice_temporal_mvp;  /* Slice flag but constant for frame */
+
+	// Temp vars per run - don't actually need to persist
+	u8 *src_buf;
+	dma_addr_t src_addr;
+	const struct v4l2_ctrl_hevc_slice_params *sh;
+	unsigned int nb_refs[2];
+	unsigned int slice_qp;
+	unsigned int max_num_merge_cand; // 0 if I-slice
+	bool dependent_slice_segment_flag;
+
+	unsigned int start_ts;          /* slice_segment_addr -> ts */
+	unsigned int start_ctb_x;       /* CTB X,Y of start_ts */
+	unsigned int start_ctb_y;
+	unsigned int prev_ctb_x;        /* CTB X,Y of start_ts - 1 */
+	unsigned int prev_ctb_y;
+};
+
+#if !USE_REQUEST_PIN
+static void dst_req_obj_release(struct media_request_object *object)
+{
+	kfree(object);
+}
+
+static const struct media_request_object_ops dst_req_obj_ops = {
+	.release = dst_req_obj_release,
+};
+#endif
+
+static inline int clip_int(const int x, const int lo, const int hi)
+{
+	return x < lo ? lo : x > hi ? hi : x;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Phase 1 command and bit FIFOs
+
+#if DEBUG_TRACE_P1_CMD
+static int p1_z;
+#endif
+
+static int cmds_check_space(struct rpivid_dec_env *const de, unsigned int n)
+{
+	struct rpi_cmd *a;
+	unsigned int newmax;
+
+	if (n > 0x100000) {
+		v4l2_err(&de->ctx->dev->v4l2_dev,
+			 "%s: n %u implausible\n", __func__, n);
+		return -ENOMEM;
+	}
+
+	if (de->cmd_len + n <= de->cmd_max)
+		return 0;
+
+	newmax = roundup_pow_of_two(de->cmd_len + n);
+
+	a = krealloc(de->cmd_fifo, newmax * sizeof(struct rpi_cmd),
+		     GFP_KERNEL);
+	if (!a) {
+		v4l2_err(&de->ctx->dev->v4l2_dev,
+			 "Failed cmd buffer realloc from %u to %u\n",
+			 de->cmd_max, newmax);
+		return -ENOMEM;
+	}
+	v4l2_info(&de->ctx->dev->v4l2_dev,
+		  "cmd buffer realloc from %u to %u\n", de->cmd_max, newmax);
+
+	de->cmd_fifo = a;
+	de->cmd_max = newmax;
+	return 0;
+}
+
+// ???? u16 addr - put in u32
+static void p1_apb_write(struct rpivid_dec_env *const de, const u16 addr,
+			 const u32 data)
+{
+	if (de->cmd_len >= de->cmd_max) {
+		v4l2_err(&de->ctx->dev->v4l2_dev,
+			 "%s: Overflow @ %d\n", __func__, de->cmd_len);
+		return;
+	}
+
+	de->cmd_fifo[de->cmd_len].addr = addr;
+	de->cmd_fifo[de->cmd_len].data = data;
+
+#if DEBUG_TRACE_P1_CMD
+	if (++p1_z < 256) {
+		v4l2_info(&de->ctx->dev->v4l2_dev, "[%02x] %x %x\n",
+			  de->cmd_len, addr, data);
+	}
+#endif
+	de->cmd_len++;
+}
+
+static int ctb_to_tile(unsigned int ctb, unsigned int *bd, int num)
+{
+	int i;
+
+	for (i = 1; ctb >= bd[i]; i++)
+		; // bd[] has num+1 elements; bd[0]=0;
+	return i - 1;
+}
+
+static unsigned int ctb_to_tile_x(const struct rpivid_dec_state *const s,
+				  const unsigned int ctb_x)
+{
+	return ctb_to_tile(ctb_x, s->col_bd, s->tile_width);
+}
+
+static unsigned int ctb_to_tile_y(const struct rpivid_dec_state *const s,
+				  const unsigned int ctb_y)
+{
+	return ctb_to_tile(ctb_y, s->row_bd, s->tile_height);
+}
+
+static void aux_q_free(struct rpivid_ctx *const ctx,
+		       struct rpivid_q_aux *const aq)
+{
+	struct rpivid_dev *const dev = ctx->dev;
+
+	gptr_free(dev, &aq->col);
+	kfree(aq);
+}
+
+static struct rpivid_q_aux *aux_q_alloc(struct rpivid_ctx *const ctx,
+					const unsigned int q_index)
+{
+	struct rpivid_dev *const dev = ctx->dev;
+	struct rpivid_q_aux *const aq = kzalloc(sizeof(*aq), GFP_KERNEL);
+
+	if (!aq)
+		return NULL;
+
+	if (gptr_alloc(dev, &aq->col, ctx->colmv_picsize,
+		       DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_KERNEL_MAPPING))
+		goto fail;
+
+	/*
+	 * Spinlock not required as called in P0 only and
+	 * aux checks done by _new
+	 */
+	aq->refcount = 1;
+	aq->q_index = q_index;
+	ctx->aux_ents[q_index] = aq;
+	return aq;
+
+fail:
+	kfree(aq);
+	return NULL;
+}
+
+static struct rpivid_q_aux *aux_q_new(struct rpivid_ctx *const ctx,
+				      const unsigned int q_index)
+{
+	struct rpivid_q_aux *aq;
+	unsigned long lockflags;
+
+	spin_lock_irqsave(&ctx->aux_lock, lockflags);
+	/*
+	 * If we already have this allocated to a slot then use that
+	 * and assume that it will all work itself out in the pipeline
+	 */
+	if ((aq = ctx->aux_ents[q_index]) != NULL) {
+		++aq->refcount;
+	} else if ((aq = ctx->aux_free) != NULL) {
+		ctx->aux_free = aq->next;
+		aq->next = NULL;
+		aq->refcount = 1;
+		aq->q_index = q_index;
+		ctx->aux_ents[q_index] = aq;
+	}
+	spin_unlock_irqrestore(&ctx->aux_lock, lockflags);
+
+	if (!aq)
+		aq = aux_q_alloc(ctx, q_index);
+
+	return aq;
+}
+
+static struct rpivid_q_aux *aux_q_ref_idx(struct rpivid_ctx *const ctx,
+					  const int q_index)
+{
+	unsigned long lockflags;
+	struct rpivid_q_aux *aq;
+
+	spin_lock_irqsave(&ctx->aux_lock, lockflags);
+	if ((aq = ctx->aux_ents[q_index]) != NULL)
+		++aq->refcount;
+	spin_unlock_irqrestore(&ctx->aux_lock, lockflags);
+
+	return aq;
+}
+
+static struct rpivid_q_aux *aux_q_ref(struct rpivid_ctx *const ctx,
+				      struct rpivid_q_aux *const aq)
+{
+	if (aq) {
+		unsigned long lockflags;
+
+		spin_lock_irqsave(&ctx->aux_lock, lockflags);
+
+		++aq->refcount;
+
+		spin_unlock_irqrestore(&ctx->aux_lock, lockflags);
+	}
+	return aq;
+}
+
+static void aux_q_release(struct rpivid_ctx *const ctx,
+			  struct rpivid_q_aux **const paq)
+{
+	struct rpivid_q_aux *const aq = *paq;
+	unsigned long lockflags;
+
+	if (!aq)
+		return;
+
+	*paq = NULL;
+
+	spin_lock_irqsave(&ctx->aux_lock, lockflags);
+	if (--aq->refcount == 0) {
+		aq->next = ctx->aux_free;
+		ctx->aux_free = aq;
+		ctx->aux_ents[aq->q_index] = NULL;
+		aq->q_index = ~0U;
+	}
+	spin_unlock_irqrestore(&ctx->aux_lock, lockflags);
+}
+
+static void aux_q_init(struct rpivid_ctx *const ctx)
+{
+	spin_lock_init(&ctx->aux_lock);
+	ctx->aux_free = NULL;
+}
+
+static void aux_q_uninit(struct rpivid_ctx *const ctx)
+{
+	struct rpivid_q_aux *aq;
+
+	ctx->colmv_picsize = 0;
+	ctx->colmv_stride = 0;
+	while ((aq = ctx->aux_free) != NULL) {
+		ctx->aux_free = aq->next;
+		aux_q_free(ctx, aq);
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Initialisation process for context variables (CABAC init)
+ * see H.265 9.3.2.2
+ *
+ * N.B. If comparing with FFmpeg note that this h/w uses slightly different
+ * offsets to FFmpegs array
+ */
+
+/* Actual number of values */
+#define RPI_PROB_VALS 154U
+/* Rounded up as we copy words */
+#define RPI_PROB_ARRAY_SIZE ((154 + 3) & ~3)
+
+/* Initialiser values - see tables H.265 9-4 through 9-42 */
+static const u8 prob_init[3][156] = {
+	{
+		153, 200, 139, 141, 157, 154, 154, 154, 154, 154, 184, 154, 154,
+		154, 184, 63,  154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+		154, 154, 154, 153, 138, 138, 111, 141, 94,  138, 182, 154, 154,
+		154, 140, 92,  137, 138, 140, 152, 138, 139, 153, 74,  149, 92,
+		139, 107, 122, 152, 140, 179, 166, 182, 140, 227, 122, 197, 110,
+		110, 124, 125, 140, 153, 125, 127, 140, 109, 111, 143, 127, 111,
+		79,  108, 123, 63,  110, 110, 124, 125, 140, 153, 125, 127, 140,
+		109, 111, 143, 127, 111, 79,  108, 123, 63,  91,  171, 134, 141,
+		138, 153, 136, 167, 152, 152, 139, 139, 111, 111, 125, 110, 110,
+		94,  124, 108, 124, 107, 125, 141, 179, 153, 125, 107, 125, 141,
+		179, 153, 125, 107, 125, 141, 179, 153, 125, 140, 139, 182, 182,
+		152, 136, 152, 136, 153, 136, 139, 111, 136, 139, 111, 0,   0,
+	},
+	{
+		153, 185, 107, 139, 126, 197, 185, 201, 154, 149, 154, 139, 154,
+		154, 154, 152, 110, 122, 95,  79,  63,  31,  31,  153, 153, 168,
+		140, 198, 79,  124, 138, 94,  153, 111, 149, 107, 167, 154, 154,
+		154, 154, 196, 196, 167, 154, 152, 167, 182, 182, 134, 149, 136,
+		153, 121, 136, 137, 169, 194, 166, 167, 154, 167, 137, 182, 125,
+		110, 94,  110, 95,  79,  125, 111, 110, 78,  110, 111, 111, 95,
+		94,  108, 123, 108, 125, 110, 94,  110, 95,  79,  125, 111, 110,
+		78,  110, 111, 111, 95,  94,  108, 123, 108, 121, 140, 61,  154,
+		107, 167, 91,  122, 107, 167, 139, 139, 155, 154, 139, 153, 139,
+		123, 123, 63,  153, 166, 183, 140, 136, 153, 154, 166, 183, 140,
+		136, 153, 154, 166, 183, 140, 136, 153, 154, 170, 153, 123, 123,
+		107, 121, 107, 121, 167, 151, 183, 140, 151, 183, 140, 0,   0,
+	},
+	{
+		153, 160, 107, 139, 126, 197, 185, 201, 154, 134, 154, 139, 154,
+		154, 183, 152, 154, 137, 95,  79,  63,  31,  31,  153, 153, 168,
+		169, 198, 79,  224, 167, 122, 153, 111, 149, 92,  167, 154, 154,
+		154, 154, 196, 167, 167, 154, 152, 167, 182, 182, 134, 149, 136,
+		153, 121, 136, 122, 169, 208, 166, 167, 154, 152, 167, 182, 125,
+		110, 124, 110, 95,  94,  125, 111, 111, 79,  125, 126, 111, 111,
+		79,  108, 123, 93,  125, 110, 124, 110, 95,  94,  125, 111, 111,
+		79,  125, 126, 111, 111, 79,  108, 123, 93,  121, 140, 61,  154,
+		107, 167, 91,  107, 107, 167, 139, 139, 170, 154, 139, 153, 139,
+		123, 123, 63,  124, 166, 183, 140, 136, 153, 154, 166, 183, 140,
+		136, 153, 154, 166, 183, 140, 136, 153, 154, 170, 153, 138, 138,
+		122, 121, 122, 121, 167, 151, 183, 140, 151, 183, 140, 0,   0,
+	},
+};
+
+#define CMDS_WRITE_PROB ((RPI_PROB_ARRAY_SIZE / 4) + 1)
+static void write_prob(struct rpivid_dec_env *const de,
+		       const struct rpivid_dec_state *const s)
+{
+	u8 dst[RPI_PROB_ARRAY_SIZE];
+
+	const unsigned int init_type =
+		((s->sh->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT) != 0 &&
+		 s->sh->slice_type != HEVC_SLICE_I) ?
+			s->sh->slice_type + 1 :
+			2 - s->sh->slice_type;
+	const u8 *p = prob_init[init_type];
+	const int q = clip_int(s->slice_qp, 0, 51);
+	unsigned int i;
+
+	for (i = 0; i < RPI_PROB_VALS; i++) {
+		int init_value = p[i];
+		int m = (init_value >> 4) * 5 - 45;
+		int n = ((init_value & 15) << 3) - 16;
+		int pre = 2 * (((m * q) >> 4) + n) - 127;
+
+		pre ^= pre >> 31;
+		if (pre > 124)
+			pre = 124 + (pre & 1);
+		dst[i] = pre;
+	}
+	for (i = RPI_PROB_VALS; i != RPI_PROB_ARRAY_SIZE; ++i)
+		dst[i] = 0;
+
+	for (i = 0; i < RPI_PROB_ARRAY_SIZE; i += 4)
+		p1_apb_write(de, 0x1000 + i,
+			     dst[i] + (dst[i + 1] << 8) + (dst[i + 2] << 16) +
+				     (dst[i + 3] << 24));
+
+	/*
+	 * Having written the prob array back it up
+	 * This is not always needed but is a small overhead that simplifies
+	 * (and speeds up) some multi-tile & WPP scenarios
+	 * There are no scenarios where having written a prob we ever want
+	 * a previous (non-initial) state back
+	 */
+	p1_apb_write(de, RPI_TRANSFER, PROB_BACKUP);
+}
+
+#define CMDS_WRITE_SCALING_FACTORS NUM_SCALING_FACTORS
+static void write_scaling_factors(struct rpivid_dec_env *const de)
+{
+	int i;
+	const u8 *p = (u8 *)de->scaling_factors;
+
+	for (i = 0; i < NUM_SCALING_FACTORS; i += 4, p += 4)
+		p1_apb_write(de, 0x2000 + i,
+			     p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24));
+}
+
+static inline __u32 dma_to_axi_addr(dma_addr_t a)
+{
+	return (__u32)(a >> 6);
+}
+
+#define CMDS_WRITE_BITSTREAM 4
+static int write_bitstream(struct rpivid_dec_env *const de,
+			   const struct rpivid_dec_state *const s)
+{
+	// Note that FFmpeg V4L2 does not remove emulation prevention bytes,
+	// so this is matched in the configuration here.
+	// Whether that is the correct behaviour or not is not clear in the
+	// spec.
+	const int rpi_use_emu = 1;
+	unsigned int offset = s->sh->data_bit_offset / 8 + 1;
+	const unsigned int len = (s->sh->bit_size + 7) / 8 - offset;
+	dma_addr_t addr;
+
+	if (s->src_addr != 0) {
+		addr = s->src_addr + offset;
+	} else {
+		if (len + de->bit_copy_len > de->bit_copy_gptr->size) {
+			v4l2_warn(&de->ctx->dev->v4l2_dev,
+				  "Bit copy buffer overflow: size=%zu, offset=%zu, len=%u\n",
+				  de->bit_copy_gptr->size,
+				  de->bit_copy_len, len);
+			return -ENOMEM;
+		}
+		memcpy(de->bit_copy_gptr->ptr + de->bit_copy_len,
+		       s->src_buf + offset, len);
+		addr = de->bit_copy_gptr->addr + de->bit_copy_len;
+		de->bit_copy_len += (len + 63) & ~63;
+	}
+	offset = addr & 63;
+
+	p1_apb_write(de, RPI_BFBASE, dma_to_axi_addr(addr));
+	p1_apb_write(de, RPI_BFNUM, len);
+	p1_apb_write(de, RPI_BFCONTROL, offset + (1 << 7)); // Stop
+	p1_apb_write(de, RPI_BFCONTROL, offset + (rpi_use_emu << 6));
+	return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*
+ * The slice constant part of the slice register - width and height need to
+ * be ORed in later as they are per-tile / WPP-row
+ */
+static u32 slice_reg_const(const struct rpivid_dec_state *const s)
+{
+	u32 x = (s->max_num_merge_cand << 0) |
+		(s->nb_refs[L0] << 4) |
+		(s->nb_refs[L1] << 8) |
+		(s->sh->slice_type << 12);
+
+	if (s->sh->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA)
+		x |= BIT(14);
+	if (s->sh->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA)
+		x |= BIT(15);
+	if (s->sh->slice_type == HEVC_SLICE_B &&
+	    (s->sh->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO))
+		x |= BIT(16);
+
+	return x;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define CMDS_NEW_SLICE_SEGMENT (4 + CMDS_WRITE_SCALING_FACTORS)
+static void new_slice_segment(struct rpivid_dec_env *const de,
+			      const struct rpivid_dec_state *const s)
+{
+	const struct v4l2_ctrl_hevc_sps *const sps = &s->sps;
+	const struct v4l2_ctrl_hevc_pps *const pps = &s->pps;
+
+	p1_apb_write(de,
+		     RPI_SPS0,
+		     ((sps->log2_min_luma_coding_block_size_minus3 + 3) << 0) |
+		     (s->log2_ctb_size << 4) |
+		     ((sps->log2_min_luma_transform_block_size_minus2 + 2)
+							<< 8) |
+		     ((sps->log2_min_luma_transform_block_size_minus2 + 2 +
+		       sps->log2_diff_max_min_luma_transform_block_size)
+						<< 12) |
+		     ((sps->bit_depth_luma_minus8 + 8) << 16) |
+		     ((sps->bit_depth_chroma_minus8 + 8) << 20) |
+		     (sps->max_transform_hierarchy_depth_intra << 24) |
+		     (sps->max_transform_hierarchy_depth_inter << 28));
+
+	p1_apb_write(de,
+		     RPI_SPS1,
+		     ((sps->pcm_sample_bit_depth_luma_minus1 + 1) << 0) |
+		     ((sps->pcm_sample_bit_depth_chroma_minus1 + 1) << 4) |
+		     ((sps->log2_min_pcm_luma_coding_block_size_minus3 + 3)
+						<< 8) |
+		     ((sps->log2_min_pcm_luma_coding_block_size_minus3 + 3 +
+		       sps->log2_diff_max_min_pcm_luma_coding_block_size)
+						<< 12) |
+		     (((sps->flags & V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE) ?
+				0 : sps->chroma_format_idc) << 16) |
+		     ((!!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED)) << 18) |
+		     ((!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) << 19) |
+		     ((!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED))
+						<< 20) |
+		     ((!!(sps->flags &
+			   V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED))
+						<< 21));
+
+	p1_apb_write(de,
+		     RPI_PPS,
+		     ((s->log2_ctb_size - pps->diff_cu_qp_delta_depth) << 0) |
+		     ((!!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED))
+						 << 4) |
+		     ((!!(pps->flags &
+				V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED))
+						 << 5) |
+		     ((!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED))
+						 << 6) |
+		     ((!!(pps->flags &
+				V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED))
+						<< 7) |
+		     (((pps->pps_cb_qp_offset + s->sh->slice_cb_qp_offset) & 255)
+						<< 8) |
+		     (((pps->pps_cr_qp_offset + s->sh->slice_cr_qp_offset) & 255)
+						<< 16) |
+		     ((!!(pps->flags &
+				V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED))
+						<< 24));
+
+	if ((sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) != 0)
+		write_scaling_factors(de);
+
+	if (!s->dependent_slice_segment_flag) {
+		int ctb_col = s->sh->slice_segment_addr %
+							de->pic_width_in_ctbs_y;
+		int ctb_row = s->sh->slice_segment_addr /
+							de->pic_width_in_ctbs_y;
+
+		de->reg_slicestart = (ctb_col << 0) + (ctb_row << 16);
+	}
+
+	p1_apb_write(de, RPI_SLICESTART, de->reg_slicestart);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Slice messages
+
+static void msg_slice(struct rpivid_dec_env *const de, const u16 msg)
+{
+	de->slice_msgs[de->num_slice_msgs++] = msg;
+}
+
+#define CMDS_PROGRAM_SLICECMDS (1 + SLICE_MSGS_MAX)
+static void program_slicecmds(struct rpivid_dec_env *const de,
+			      const int sliceid)
+{
+	int i;
+
+	p1_apb_write(de, RPI_SLICECMDS, de->num_slice_msgs + (sliceid << 8));
+
+	for (i = 0; i < de->num_slice_msgs; i++)
+		p1_apb_write(de, 0x4000 + 4 * i, de->slice_msgs[i] & 0xffff);
+}
+
+// NoBackwardPredictionFlag 8.3.5
+// Simply checks POCs
+static int has_backward(const struct v4l2_hevc_dpb_entry *const dpb,
+			const __u8 *const idx, const unsigned int n,
+			const unsigned int cur_poc)
+{
+	unsigned int i;
+
+	for (i = 0; i < n; ++i) {
+		// Compare mod 2^16
+		// We only get u16 pocs & 8.3.1 says
+		// "The bitstream shall not contain data that result in values
+		//  of DiffPicOrderCnt( picA, picB ) used in the decoding
+		//  process that are not in the range of −2^15 to 2^15 − 1,
+		//  inclusive."
+		if (((cur_poc - dpb[idx[i]].pic_order_cnt[0]) & 0x8000) != 0)
+			return 0;
+	}
+	return 1;
+}
+
+static void pre_slice_decode(struct rpivid_dec_env *const de,
+			     const struct rpivid_dec_state *const s)
+{
+	const struct v4l2_ctrl_hevc_slice_params *const sh = s->sh;
+	int weighted_pred_flag, idx;
+	u16 cmd_slice;
+	unsigned int collocated_from_l0_flag;
+
+	de->num_slice_msgs = 0;
+
+	cmd_slice = 0;
+	if (sh->slice_type == HEVC_SLICE_I)
+		cmd_slice = 1;
+	if (sh->slice_type == HEVC_SLICE_P)
+		cmd_slice = 2;
+	if (sh->slice_type == HEVC_SLICE_B)
+		cmd_slice = 3;
+
+	cmd_slice |= (s->nb_refs[L0] << 2) | (s->nb_refs[L1] << 6) |
+		     (s->max_num_merge_cand << 11);
+
+	collocated_from_l0_flag =
+		!s->slice_temporal_mvp ||
+		sh->slice_type != HEVC_SLICE_B ||
+		(sh->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0);
+	cmd_slice |= collocated_from_l0_flag << 14;
+
+	if (sh->slice_type == HEVC_SLICE_P || sh->slice_type == HEVC_SLICE_B) {
+		// Flag to say all reference pictures are from the past
+		const int no_backward_pred_flag =
+			has_backward(sh->dpb, sh->ref_idx_l0, s->nb_refs[L0],
+				     sh->slice_pic_order_cnt) &&
+			has_backward(sh->dpb, sh->ref_idx_l1, s->nb_refs[L1],
+				     sh->slice_pic_order_cnt);
+		cmd_slice |= no_backward_pred_flag << 10;
+		msg_slice(de, cmd_slice);
+
+		if (s->slice_temporal_mvp) {
+			const __u8 *const rpl = collocated_from_l0_flag ?
+						sh->ref_idx_l0 : sh->ref_idx_l1;
+			de->dpbno_col = rpl[sh->collocated_ref_idx];
+			//v4l2_info(&de->ctx->dev->v4l2_dev,
+			//	    "L0=%d col_ref_idx=%d,
+			//          dpb_no=%d\n", collocated_from_l0_flag,
+			//          sh->collocated_ref_idx, de->dpbno_col);
+		}
+
+		// Write reference picture descriptions
+		weighted_pred_flag =
+			sh->slice_type == HEVC_SLICE_P ?
+				!!(s->pps.flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED) :
+				!!(s->pps.flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED);
+
+		for (idx = 0; idx < s->nb_refs[L0]; ++idx) {
+			unsigned int dpb_no = sh->ref_idx_l0[idx];
+			//v4l2_info(&de->ctx->dev->v4l2_dev,
+			//	  "L0[%d]=dpb[%d]\n", idx, dpb_no);
+
+			msg_slice(de,
+				  dpb_no |
+				  (sh->dpb[dpb_no].rps ==
+					V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR ?
+						 (1 << 4) : 0) |
+				  (weighted_pred_flag ? (3 << 5) : 0));
+			msg_slice(de, sh->dpb[dpb_no].pic_order_cnt[0]);
+
+			if (weighted_pred_flag) {
+				const struct v4l2_hevc_pred_weight_table
+					*const w = &sh->pred_weight_table;
+				const int luma_weight_denom =
+					(1 << w->luma_log2_weight_denom);
+				const unsigned int chroma_log2_weight_denom =
+					(w->luma_log2_weight_denom +
+					 w->delta_chroma_log2_weight_denom);
+				const int chroma_weight_denom =
+					(1 << chroma_log2_weight_denom);
+
+				msg_slice(de,
+					  w->luma_log2_weight_denom |
+					  (((w->delta_luma_weight_l0[idx] +
+					     luma_weight_denom) & 0x1ff)
+						 << 3));
+				msg_slice(de, w->luma_offset_l0[idx] & 0xff);
+				msg_slice(de,
+					  chroma_log2_weight_denom |
+					  (((w->delta_chroma_weight_l0[idx][0] +
+					     chroma_weight_denom) & 0x1ff)
+						   << 3));
+				msg_slice(de,
+					  w->chroma_offset_l0[idx][0] & 0xff);
+				msg_slice(de,
+					  chroma_log2_weight_denom |
+					  (((w->delta_chroma_weight_l0[idx][1] +
+					     chroma_weight_denom) & 0x1ff)
+						   << 3));
+				msg_slice(de,
+					  w->chroma_offset_l0[idx][1] & 0xff);
+			}
+		}
+
+		for (idx = 0; idx < s->nb_refs[L1]; ++idx) {
+			unsigned int dpb_no = sh->ref_idx_l1[idx];
+			//v4l2_info(&de->ctx->dev->v4l2_dev,
+			//          "L1[%d]=dpb[%d]\n", idx, dpb_no);
+			msg_slice(de,
+				  dpb_no |
+				  (sh->dpb[dpb_no].rps ==
+					 V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR ?
+						 (1 << 4) : 0) |
+					(weighted_pred_flag ? (3 << 5) : 0));
+			msg_slice(de, sh->dpb[dpb_no].pic_order_cnt[0]);
+			if (weighted_pred_flag) {
+				const struct v4l2_hevc_pred_weight_table
+					*const w = &sh->pred_weight_table;
+				const int luma_weight_denom =
+					(1 << w->luma_log2_weight_denom);
+				const unsigned int chroma_log2_weight_denom =
+					(w->luma_log2_weight_denom +
+					 w->delta_chroma_log2_weight_denom);
+				const int chroma_weight_denom =
+					(1 << chroma_log2_weight_denom);
+
+				msg_slice(de,
+					  w->luma_log2_weight_denom |
+					  (((w->delta_luma_weight_l1[idx] +
+					     luma_weight_denom) & 0x1ff) << 3));
+				msg_slice(de, w->luma_offset_l1[idx] & 0xff);
+				msg_slice(de,
+					  chroma_log2_weight_denom |
+					  (((w->delta_chroma_weight_l1[idx][0] +
+					     chroma_weight_denom) & 0x1ff)
+							<< 3));
+				msg_slice(de,
+					  w->chroma_offset_l1[idx][0] & 0xff);
+				msg_slice(de,
+					  chroma_log2_weight_denom |
+					  (((w->delta_chroma_weight_l1[idx][1] +
+					     chroma_weight_denom) & 0x1ff)
+						   << 3));
+				msg_slice(de,
+					  w->chroma_offset_l1[idx][1] & 0xff);
+			}
+		}
+	} else {
+		msg_slice(de, cmd_slice);
+	}
+
+	msg_slice(de,
+		  (sh->slice_beta_offset_div2 & 15) |
+		  ((sh->slice_tc_offset_div2 & 15) << 4) |
+		  ((sh->flags &
+		    V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED) ?
+						1 << 8 : 0) |
+		  ((sh->flags &
+			  V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED) ?
+						1 << 9 : 0) |
+		  ((s->pps.flags &
+			  V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED) ?
+						1 << 10 : 0));
+
+	msg_slice(de, ((sh->slice_cr_qp_offset & 31) << 5) +
+		       (sh->slice_cb_qp_offset & 31)); // CMD_QPOFF
+}
+
+#define CMDS_WRITE_SLICE 1
+static void write_slice(struct rpivid_dec_env *const de,
+			const struct rpivid_dec_state *const s,
+			const u32 slice_const,
+			const unsigned int ctb_col,
+			const unsigned int ctb_row)
+{
+	const unsigned int cs = (1 << s->log2_ctb_size);
+	const unsigned int w_last = s->sps.pic_width_in_luma_samples & (cs - 1);
+	const unsigned int h_last = s->sps.pic_height_in_luma_samples & (cs - 1);
+
+	p1_apb_write(de, RPI_SLICE,
+		     slice_const |
+		     ((ctb_col + 1 < s->ctb_width || !w_last ?
+				cs : w_last) << 17) |
+		     ((ctb_row + 1 < s->ctb_height || !h_last ?
+				cs : h_last) << 24));
+}
+
+#define PAUSE_MODE_WPP  1
+#define PAUSE_MODE_TILE 0xffff
+
+/*
+ * N.B. This can be called to fill in data from the previous slice so must not
+ * use any state data that may change from slice to slice (e.g. qp)
+ */
+#define CMDS_NEW_ENTRY_POINT (6 + CMDS_WRITE_SLICE)
+static void new_entry_point(struct rpivid_dec_env *const de,
+			    const struct rpivid_dec_state *const s,
+			    const bool do_bte,
+			    const bool reset_qp_y,
+			    const u32 pause_mode,
+			    const unsigned int tile_x,
+			    const unsigned int tile_y,
+			    const unsigned int ctb_col,
+			    const unsigned int ctb_row,
+			    const unsigned int slice_qp,
+			    const u32 slice_const)
+{
+	const unsigned int endx = s->col_bd[tile_x + 1] - 1;
+	const unsigned int endy = (pause_mode == PAUSE_MODE_WPP) ?
+		ctb_row : s->row_bd[tile_y + 1] - 1;
+
+	p1_apb_write(de, RPI_TILESTART,
+		     s->col_bd[tile_x] | (s->row_bd[tile_y] << 16));
+	p1_apb_write(de, RPI_TILEEND, endx | (endy << 16));
+
+	if (do_bte)
+		p1_apb_write(de, RPI_BEGINTILEEND, endx | (endy << 16));
+
+	write_slice(de, s, slice_const, endx, endy);
+
+	if (reset_qp_y) {
+		unsigned int sps_qp_bd_offset =
+			6 * s->sps.bit_depth_luma_minus8;
+
+		p1_apb_write(de, RPI_QP, sps_qp_bd_offset + slice_qp);
+	}
+
+	p1_apb_write(de, RPI_MODE,
+		     pause_mode |
+			((endx == s->ctb_width - 1) << 17) |
+			((endy == s->ctb_height - 1) << 18));
+
+	p1_apb_write(de, RPI_CONTROL, (ctb_col << 0) | (ctb_row << 16));
+
+	de->entry_tile_x = tile_x;
+	de->entry_tile_y = tile_y;
+	de->entry_ctb_x = ctb_col;
+	de->entry_ctb_y = ctb_row;
+	de->entry_qp = slice_qp;
+	de->entry_slice = slice_const;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Wavefront mode
+
+#define CMDS_WPP_PAUSE 4
+static void wpp_pause(struct rpivid_dec_env *const de, int ctb_row)
+{
+	p1_apb_write(de, RPI_STATUS, (ctb_row << 18) | 0x25);
+	p1_apb_write(de, RPI_TRANSFER, PROB_BACKUP);
+	p1_apb_write(de, RPI_MODE,
+		     ctb_row == de->pic_height_in_ctbs_y - 1 ?
+							0x70000 : 0x30000);
+	p1_apb_write(de, RPI_CONTROL, (ctb_row << 16) + 2);
+}
+
+#define CMDS_WPP_ENTRY_FILL_1 (CMDS_WPP_PAUSE + 2 + CMDS_NEW_ENTRY_POINT)
+static int wpp_entry_fill(struct rpivid_dec_env *const de,
+			  const struct rpivid_dec_state *const s,
+			  const unsigned int last_y)
+{
+	int rv;
+	const unsigned int last_x = s->ctb_width - 1;
+
+	rv = cmds_check_space(de, CMDS_WPP_ENTRY_FILL_1 *
+				  (last_y - de->entry_ctb_y));
+	if (rv)
+		return rv;
+
+	while (de->entry_ctb_y < last_y) {
+		/* wpp_entry_x/y set by wpp_entry_point */
+		if (s->ctb_width > 2)
+			wpp_pause(de, de->entry_ctb_y);
+		p1_apb_write(de, RPI_STATUS,
+			     (de->entry_ctb_y << 18) | (last_x << 5) | 2);
+
+		/* if width == 1 then the saved state is the init one */
+		if (s->ctb_width == 2)
+			p1_apb_write(de, RPI_TRANSFER, PROB_BACKUP);
+		else
+			p1_apb_write(de, RPI_TRANSFER, PROB_RELOAD);
+
+		new_entry_point(de, s, false, true, PAUSE_MODE_WPP,
+				0, 0, 0, de->entry_ctb_y + 1,
+				de->entry_qp, de->entry_slice);
+	}
+	return 0;
+}
+
+static int wpp_end_previous_slice(struct rpivid_dec_env *const de,
+				  const struct rpivid_dec_state *const s)
+{
+	int rv;
+
+	rv = wpp_entry_fill(de, s, s->prev_ctb_y);
+	if (rv)
+		return rv;
+
+	rv = cmds_check_space(de, CMDS_WPP_PAUSE + 2);
+	if (rv)
+		return rv;
+
+	if (de->entry_ctb_x < 2 &&
+	    (de->entry_ctb_y < s->start_ctb_y || s->start_ctb_x > 2) &&
+	    s->ctb_width > 2)
+		wpp_pause(de, s->prev_ctb_y);
+	p1_apb_write(de, RPI_STATUS,
+		     1 | (s->prev_ctb_x << 5) | (s->prev_ctb_y << 18));
+	if (s->start_ctb_x == 2 ||
+	    (s->ctb_width == 2 && de->entry_ctb_y < s->start_ctb_y))
+		p1_apb_write(de, RPI_TRANSFER, PROB_BACKUP);
+	return 0;
+}
+
+/* Only main profile supported so WPP => !Tiles which makes some of the
+ * next chunk code simpler
+ */
+static int wpp_decode_slice(struct rpivid_dec_env *const de,
+			    const struct rpivid_dec_state *const s)
+{
+	bool reset_qp_y = true;
+	const bool indep = !s->dependent_slice_segment_flag;
+	int rv;
+
+	if (s->start_ts) {
+		rv = wpp_end_previous_slice(de, s);
+		if (rv)
+			return rv;
+	}
+	pre_slice_decode(de, s);
+
+	rv = cmds_check_space(de,
+			      CMDS_WRITE_BITSTREAM +
+				CMDS_WRITE_PROB +
+				CMDS_PROGRAM_SLICECMDS +
+				CMDS_NEW_SLICE_SEGMENT +
+				CMDS_NEW_ENTRY_POINT);
+	if (rv)
+		return rv;
+
+	rv = write_bitstream(de, s);
+	if (rv)
+		return rv;
+
+	if (!s->start_ts || indep || s->ctb_width == 1)
+		write_prob(de, s);
+	else if (!s->start_ctb_x)
+		p1_apb_write(de, RPI_TRANSFER, PROB_RELOAD);
+	else
+		reset_qp_y = false;
+
+	program_slicecmds(de, s->slice_idx);
+	new_slice_segment(de, s);
+	new_entry_point(de, s, indep, reset_qp_y, PAUSE_MODE_WPP,
+			0, 0, s->start_ctb_x, s->start_ctb_y,
+			s->slice_qp, slice_reg_const(s));
+
+	if (s->frame_end) {
+		rv = wpp_entry_fill(de, s, s->ctb_height - 1);
+		if (rv)
+			return rv;
+
+		rv = cmds_check_space(de, CMDS_WPP_PAUSE + 1);
+		if (rv)
+			return rv;
+
+		if (de->entry_ctb_x < 2 && s->ctb_width > 2)
+			wpp_pause(de, s->ctb_height - 1);
+
+		p1_apb_write(de, RPI_STATUS,
+			     1 | ((s->ctb_width - 1) << 5) |
+				((s->ctb_height - 1) << 18));
+	}
+	return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Tiles mode
+
+// Guarantees 1 cmd entry free on exit
+static int tile_entry_fill(struct rpivid_dec_env *const de,
+			   const struct rpivid_dec_state *const s,
+			   const unsigned int last_tile_x,
+			   const unsigned int last_tile_y)
+{
+	while (de->entry_tile_y < last_tile_y ||
+	       (de->entry_tile_y == last_tile_y &&
+		de->entry_tile_x < last_tile_x)) {
+		int rv;
+		unsigned int t_x = de->entry_tile_x;
+		unsigned int t_y = de->entry_tile_y;
+		const unsigned int last_x = s->col_bd[t_x + 1] - 1;
+		const unsigned int last_y = s->row_bd[t_y + 1] - 1;
+
+		// One more than needed here
+		rv = cmds_check_space(de, CMDS_NEW_ENTRY_POINT + 3);
+		if (rv)
+			return rv;
+
+		p1_apb_write(de, RPI_STATUS,
+			     2 | (last_x << 5) | (last_y << 18));
+		p1_apb_write(de, RPI_TRANSFER, PROB_RELOAD);
+
+		// Inc tile
+		if (++t_x >= s->tile_width) {
+			t_x = 0;
+			++t_y;
+		}
+
+		new_entry_point(de, s, false, true, PAUSE_MODE_TILE,
+				t_x, t_y, s->col_bd[t_x], s->row_bd[t_y],
+				de->entry_qp, de->entry_slice);
+	}
+	return 0;
+}
+
+/*
+ * Write STATUS register with expected end CTU address of previous slice
+ */
+static int end_previous_slice(struct rpivid_dec_env *const de,
+			      const struct rpivid_dec_state *const s)
+{
+	int rv;
+
+	rv = tile_entry_fill(de, s,
+			     ctb_to_tile_x(s, s->prev_ctb_x),
+			     ctb_to_tile_y(s, s->prev_ctb_y));
+	if (rv)
+		return rv;
+
+	p1_apb_write(de, RPI_STATUS,
+		     1 | (s->prev_ctb_x << 5) | (s->prev_ctb_y << 18));
+	return 0;
+}
+
+static int decode_slice(struct rpivid_dec_env *const de,
+			const struct rpivid_dec_state *const s)
+{
+	bool reset_qp_y;
+	unsigned int tile_x = ctb_to_tile_x(s, s->start_ctb_x);
+	unsigned int tile_y = ctb_to_tile_y(s, s->start_ctb_y);
+	int rv;
+
+	if (s->start_ts) {
+		rv = end_previous_slice(de, s);
+		if (rv)
+			return rv;
+	}
+
+	rv = cmds_check_space(de,
+			      CMDS_WRITE_BITSTREAM +
+				CMDS_WRITE_PROB +
+				CMDS_PROGRAM_SLICECMDS +
+				CMDS_NEW_SLICE_SEGMENT +
+				CMDS_NEW_ENTRY_POINT);
+	if (rv)
+		return rv;
+
+	pre_slice_decode(de, s);
+	rv = write_bitstream(de, s);
+	if (rv)
+		return rv;
+
+	reset_qp_y = !s->start_ts ||
+		!s->dependent_slice_segment_flag ||
+		tile_x != ctb_to_tile_x(s, s->prev_ctb_x) ||
+		tile_y != ctb_to_tile_y(s, s->prev_ctb_y);
+	if (reset_qp_y)
+		write_prob(de, s);
+
+	program_slicecmds(de, s->slice_idx);
+	new_slice_segment(de, s);
+	new_entry_point(de, s, !s->dependent_slice_segment_flag, reset_qp_y,
+			PAUSE_MODE_TILE,
+			tile_x, tile_y, s->start_ctb_x, s->start_ctb_y,
+			s->slice_qp, slice_reg_const(s));
+
+	/*
+	 * If this is the last slice then fill in the other tile entries
+	 * now, otherwise this will be done at the start of the next slice
+	 * when it will be known where this slice finishes
+	 */
+	if (s->frame_end) {
+		rv = tile_entry_fill(de, s,
+				     s->tile_width - 1,
+				     s->tile_height - 1);
+		if (rv)
+			return rv;
+		p1_apb_write(de, RPI_STATUS,
+			     1 | ((s->ctb_width - 1) << 5) |
+				((s->ctb_height - 1) << 18));
+	}
+	return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Scaling factors
+
+static void expand_scaling_list(const unsigned int size_id,
+				u8 *const dst0,
+				const u8 *const src0, uint8_t dc)
+{
+	u8 *d;
+	unsigned int x, y;
+
+	switch (size_id) {
+	case 0:
+		memcpy(dst0, src0, 16);
+		break;
+	case 1:
+		memcpy(dst0, src0, 64);
+		break;
+	case 2:
+		d = dst0;
+
+		for (y = 0; y != 16; y++) {
+			const u8 *s = src0 + (y >> 1) * 8;
+
+			for (x = 0; x != 8; ++x) {
+				*d++ = *s;
+				*d++ = *s++;
+			}
+		}
+		dst0[0] = dc;
+		break;
+	default:
+		d = dst0;
+
+		for (y = 0; y != 32; y++) {
+			const u8 *s = src0 + (y >> 2) * 8;
+
+			for (x = 0; x != 8; ++x) {
+				*d++ = *s;
+				*d++ = *s;
+				*d++ = *s;
+				*d++ = *s++;
+			}
+		}
+		dst0[0] = dc;
+		break;
+	}
+}
+
+static void populate_scaling_factors(const struct rpivid_run *const run,
+				     struct rpivid_dec_env *const de,
+				     const struct rpivid_dec_state *const s)
+{
+	const struct v4l2_ctrl_hevc_scaling_matrix *const sl =
+		run->h265.scaling_matrix;
+	// Array of constants for scaling factors
+	static const u32 scaling_factor_offsets[4][6] = {
+		// MID0    MID1    MID2    MID3    MID4    MID5
+		// SID0 (4x4)
+		{ 0x0000, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050 },
+		// SID1 (8x8)
+		{ 0x0060, 0x00A0, 0x00E0, 0x0120, 0x0160, 0x01A0 },
+		// SID2 (16x16)
+		{ 0x01E0, 0x02E0, 0x03E0, 0x04E0, 0x05E0, 0x06E0 },
+		// SID3 (32x32)
+		{ 0x07E0, 0x0BE0, 0x0000, 0x0000, 0x0000, 0x0000 }
+	};
+
+	unsigned int mid;
+
+	for (mid = 0; mid < 6; mid++)
+		expand_scaling_list(0, de->scaling_factors +
+					    scaling_factor_offsets[0][mid],
+				    sl->scaling_list_4x4[mid], 0);
+	for (mid = 0; mid < 6; mid++)
+		expand_scaling_list(1, de->scaling_factors +
+					    scaling_factor_offsets[1][mid],
+				    sl->scaling_list_8x8[mid], 0);
+	for (mid = 0; mid < 6; mid++)
+		expand_scaling_list(2, de->scaling_factors +
+					    scaling_factor_offsets[2][mid],
+				    sl->scaling_list_16x16[mid],
+				    sl->scaling_list_dc_coef_16x16[mid]);
+	for (mid = 0; mid < 2; mid++)
+		expand_scaling_list(3, de->scaling_factors +
+					    scaling_factor_offsets[3][mid],
+				    sl->scaling_list_32x32[mid],
+				    sl->scaling_list_dc_coef_32x32[mid]);
+}
+
+static void free_ps_info(struct rpivid_dec_state *const s)
+{
+	kfree(s->ctb_addr_rs_to_ts);
+	s->ctb_addr_rs_to_ts = NULL;
+	kfree(s->ctb_addr_ts_to_rs);
+	s->ctb_addr_ts_to_rs = NULL;
+
+	kfree(s->col_bd);
+	s->col_bd = NULL;
+	kfree(s->row_bd);
+	s->row_bd = NULL;
+}
+
+static unsigned int tile_width(const struct rpivid_dec_state *const s,
+			       const unsigned int t_x)
+{
+	return s->col_bd[t_x + 1] - s->col_bd[t_x];
+}
+
+static unsigned int tile_height(const struct rpivid_dec_state *const s,
+				const unsigned int t_y)
+{
+	return s->row_bd[t_y + 1] - s->row_bd[t_y];
+}
+
+static void fill_rs_to_ts(struct rpivid_dec_state *const s)
+{
+	unsigned int ts = 0;
+	unsigned int t_y;
+	unsigned int tr_rs = 0;
+
+	for (t_y = 0; t_y != s->tile_height; ++t_y) {
+		const unsigned int t_h = tile_height(s, t_y);
+		unsigned int t_x;
+		unsigned int tc_rs = tr_rs;
+
+		for (t_x = 0; t_x != s->tile_width; ++t_x) {
+			const unsigned int t_w = tile_width(s, t_x);
+			unsigned int y;
+			unsigned int rs = tc_rs;
+
+			for (y = 0; y != t_h; ++y) {
+				unsigned int x;
+
+				for (x = 0; x != t_w; ++x) {
+					s->ctb_addr_rs_to_ts[rs + x] = ts;
+					s->ctb_addr_ts_to_rs[ts] = rs + x;
+					++ts;
+				}
+				rs += s->ctb_width;
+			}
+			tc_rs += t_w;
+		}
+		tr_rs += t_h * s->ctb_width;
+	}
+}
+
+static int updated_ps(struct rpivid_dec_state *const s)
+{
+	unsigned int i;
+
+	free_ps_info(s);
+
+	// Inferred parameters
+	s->log2_ctb_size = s->sps.log2_min_luma_coding_block_size_minus3 + 3 +
+			   s->sps.log2_diff_max_min_luma_coding_block_size;
+
+	s->ctb_width = (s->sps.pic_width_in_luma_samples +
+			(1 << s->log2_ctb_size) - 1) >>
+		       s->log2_ctb_size;
+	s->ctb_height = (s->sps.pic_height_in_luma_samples +
+			 (1 << s->log2_ctb_size) - 1) >>
+			s->log2_ctb_size;
+	s->ctb_size = s->ctb_width * s->ctb_height;
+
+	// Inferred parameters
+
+	s->ctb_addr_rs_to_ts = kmalloc_array(s->ctb_size,
+					     sizeof(*s->ctb_addr_rs_to_ts),
+					     GFP_KERNEL);
+	if (!s->ctb_addr_rs_to_ts)
+		goto fail;
+	s->ctb_addr_ts_to_rs = kmalloc_array(s->ctb_size,
+					     sizeof(*s->ctb_addr_ts_to_rs),
+					     GFP_KERNEL);
+	if (!s->ctb_addr_ts_to_rs)
+		goto fail;
+
+	if (!(s->pps.flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)) {
+		s->tile_width = 1;
+		s->tile_height = 1;
+	} else {
+		s->tile_width = s->pps.num_tile_columns_minus1 + 1;
+		s->tile_height = s->pps.num_tile_rows_minus1 + 1;
+	}
+
+	s->col_bd = kmalloc((s->tile_width + 1) * sizeof(*s->col_bd),
+			    GFP_KERNEL);
+	if (!s->col_bd)
+		goto fail;
+	s->row_bd = kmalloc((s->tile_height + 1) * sizeof(*s->row_bd),
+			    GFP_KERNEL);
+	if (!s->row_bd)
+		goto fail;
+
+	s->col_bd[0] = 0;
+	for (i = 1; i < s->tile_width; i++)
+		s->col_bd[i] = s->col_bd[i - 1] +
+			s->pps.column_width_minus1[i - 1] + 1;
+	s->col_bd[s->tile_width] = s->ctb_width;
+
+	s->row_bd[0] = 0;
+	for (i = 1; i < s->tile_height; i++)
+		s->row_bd[i] = s->row_bd[i - 1] +
+			s->pps.row_height_minus1[i - 1] + 1;
+	s->row_bd[s->tile_height] = s->ctb_height;
+
+	fill_rs_to_ts(s);
+	return 0;
+
+fail:
+	free_ps_info(s);
+	/* Set invalid to force reload */
+	s->sps.pic_width_in_luma_samples = 0;
+	return -ENOMEM;
+}
+
+static int write_cmd_buffer(struct rpivid_dev *const dev,
+			    struct rpivid_dec_env *const de,
+			    const struct rpivid_dec_state *const s)
+{
+	const size_t cmd_size = ALIGN(de->cmd_len * sizeof(de->cmd_fifo[0]),
+				      dev->cache_align);
+
+	de->cmd_addr = dma_map_single(dev->dev, de->cmd_fifo,
+				      cmd_size, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev->dev, de->cmd_addr)) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Map cmd buffer (%zu): FAILED\n", cmd_size);
+		return -ENOMEM;
+	}
+	de->cmd_size = cmd_size;
+	return 0;
+}
+
+static void setup_colmv(struct rpivid_ctx *const ctx, struct rpivid_run *run,
+			struct rpivid_dec_state *const s)
+{
+	ctx->colmv_stride = ALIGN(s->sps.pic_width_in_luma_samples, 64);
+	ctx->colmv_picsize = ctx->colmv_stride *
+		(ALIGN(s->sps.pic_height_in_luma_samples, 64) >> 4);
+}
+
+// Can be called from irq context
+static struct rpivid_dec_env *dec_env_new(struct rpivid_ctx *const ctx)
+{
+	struct rpivid_dec_env *de;
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(&ctx->dec_lock, lock_flags);
+
+	de = ctx->dec_free;
+	if (de) {
+		ctx->dec_free = de->next;
+		de->next = NULL;
+		de->state = RPIVID_DECODE_SLICE_START;
+	}
+
+	spin_unlock_irqrestore(&ctx->dec_lock, lock_flags);
+	return de;
+}
+
+// Can be called from irq context
+static void dec_env_delete(struct rpivid_dec_env *const de)
+{
+	struct rpivid_ctx * const ctx = de->ctx;
+	unsigned long lock_flags;
+
+	if (de->cmd_size) {
+		dma_unmap_single(ctx->dev->dev, de->cmd_addr, de->cmd_size,
+				 DMA_TO_DEVICE);
+		de->cmd_size = 0;
+	}
+
+	aux_q_release(ctx, &de->frame_aux);
+	aux_q_release(ctx, &de->col_aux);
+
+	spin_lock_irqsave(&ctx->dec_lock, lock_flags);
+
+	de->state = RPIVID_DECODE_END;
+	de->next = ctx->dec_free;
+	ctx->dec_free = de;
+
+	spin_unlock_irqrestore(&ctx->dec_lock, lock_flags);
+}
+
+static void dec_env_uninit(struct rpivid_ctx *const ctx)
+{
+	unsigned int i;
+
+	if (ctx->dec_pool) {
+		for (i = 0; i != RPIVID_DEC_ENV_COUNT; ++i) {
+			struct rpivid_dec_env *const de = ctx->dec_pool + i;
+
+			kfree(de->cmd_fifo);
+		}
+
+		kfree(ctx->dec_pool);
+	}
+
+	ctx->dec_pool = NULL;
+	ctx->dec_free = NULL;
+}
+
+static int dec_env_init(struct rpivid_ctx *const ctx)
+{
+	unsigned int i;
+
+	ctx->dec_pool = kzalloc(sizeof(*ctx->dec_pool) * RPIVID_DEC_ENV_COUNT,
+				GFP_KERNEL);
+	if (!ctx->dec_pool)
+		return -1;
+
+	spin_lock_init(&ctx->dec_lock);
+
+	// Build free chain
+	ctx->dec_free = ctx->dec_pool;
+	for (i = 0; i != RPIVID_DEC_ENV_COUNT - 1; ++i)
+		ctx->dec_pool[i].next = ctx->dec_pool + i + 1;
+
+	// Fill in other bits
+	for (i = 0; i != RPIVID_DEC_ENV_COUNT; ++i) {
+		struct rpivid_dec_env *const de = ctx->dec_pool + i;
+
+		de->ctx = ctx;
+		de->decode_order = i;
+//		de->cmd_max = 1024;
+		de->cmd_max = 8096;
+		de->cmd_fifo = kmalloc_array(de->cmd_max,
+					     sizeof(struct rpi_cmd),
+					     GFP_KERNEL);
+		if (!de->cmd_fifo)
+			goto fail;
+	}
+
+	return 0;
+
+fail:
+	dec_env_uninit(ctx);
+	return -1;
+}
+
+// Assume that we get exactly the same DPB for every slice
+// it makes no real sense otherwise
+#if V4L2_HEVC_DPB_ENTRIES_NUM_MAX > 16
+#error HEVC_DPB_ENTRIES > h/w slots
+#endif
+
+static u32 mk_config2(const struct rpivid_dec_state *const s)
+{
+	const struct v4l2_ctrl_hevc_sps *const sps = &s->sps;
+	const struct v4l2_ctrl_hevc_pps *const pps = &s->pps;
+	u32 c;
+	// BitDepthY
+	c = (sps->bit_depth_luma_minus8 + 8) << 0;
+	 // BitDepthC
+	c |= (sps->bit_depth_chroma_minus8 + 8) << 4;
+	 // BitDepthY
+	if (sps->bit_depth_luma_minus8)
+		c |= BIT(8);
+	// BitDepthC
+	if (sps->bit_depth_chroma_minus8)
+		c |= BIT(9);
+	c |= s->log2_ctb_size << 10;
+	if (pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED)
+		c |= BIT(13);
+	if (sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED)
+		c |= BIT(14);
+	if (sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED)
+		c |= BIT(15); /* Write motion vectors to external memory */
+	c |= (pps->log2_parallel_merge_level_minus2 + 2) << 16;
+	if (s->slice_temporal_mvp)
+		c |= BIT(19);
+	if (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED)
+		c |= BIT(20);
+	c |= (pps->pps_cb_qp_offset & 31) << 21;
+	c |= (pps->pps_cr_qp_offset & 31) << 26;
+	return c;
+}
+
+static void rpivid_h265_setup(struct rpivid_ctx *ctx, struct rpivid_run *run)
+{
+	struct rpivid_dev *const dev = ctx->dev;
+	const struct v4l2_ctrl_hevc_slice_params *const sh =
+						run->h265.slice_params;
+//	const struct v4l2_hevc_pred_weight_table *pred_weight_table;
+	struct rpivid_q_aux *dpb_q_aux[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+	struct rpivid_dec_state *const s = ctx->state;
+	struct vb2_queue *vq;
+	struct rpivid_dec_env *de = ctx->dec0;
+	unsigned int prev_rs;
+	unsigned int i;
+	int use_aux;
+	int rv;
+	bool slice_temporal_mvp;
+
+	xtrace_in(dev, de);
+
+//	pred_weight_table = &sh->pred_weight_table;
+
+	s->frame_end =
+		((run->src->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF) == 0);
+
+	slice_temporal_mvp = (sh->flags &
+		   V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED);
+
+	if (de && de->state != RPIVID_DECODE_END) {
+		++s->slice_idx;
+
+		switch (de->state) {
+		case RPIVID_DECODE_SLICE_CONTINUE:
+			// Expected state
+			break;
+		default:
+			v4l2_err(&dev->v4l2_dev, "%s: Unexpected state: %d\n",
+				 __func__, de->state);
+		/* FALLTHRU */
+		case RPIVID_DECODE_ERROR_CONTINUE:
+			// Uncleared error - fail now
+			goto fail;
+		}
+
+		if (s->slice_temporal_mvp != slice_temporal_mvp) {
+			v4l2_warn(&dev->v4l2_dev,
+				  "Slice Temporal MVP non-constant\n");
+			goto fail;
+		}
+	} else {
+		/* Frame start */
+		unsigned int ctb_size_y;
+		bool sps_changed = false;
+
+		if (memcmp(&s->sps, run->h265.sps, sizeof(s->sps)) != 0) {
+			/* SPS changed */
+			v4l2_info(&dev->v4l2_dev, "SPS changed\n");
+			memcpy(&s->sps, run->h265.sps, sizeof(s->sps));
+			sps_changed = true;
+		}
+		if (sps_changed ||
+		    memcmp(&s->pps, run->h265.pps, sizeof(s->pps)) != 0) {
+			/* SPS changed */
+			v4l2_info(&dev->v4l2_dev, "PPS changed\n");
+			memcpy(&s->pps, run->h265.pps, sizeof(s->pps));
+
+			/* Recalc stuff as required */
+			rv = updated_ps(s);
+			if (rv)
+				goto fail;
+		}
+
+		de = dec_env_new(ctx);
+		if (!de) {
+			v4l2_err(&dev->v4l2_dev,
+				 "Failed to find free decode env\n");
+			goto fail;
+		}
+		ctx->dec0 = de;
+
+		ctb_size_y =
+			1U << (s->sps.log2_min_luma_coding_block_size_minus3 +
+			       3 +
+			       s->sps.log2_diff_max_min_luma_coding_block_size);
+
+		de->pic_width_in_ctbs_y =
+			(s->sps.pic_width_in_luma_samples + ctb_size_y - 1) /
+				ctb_size_y; // 7-15
+		de->pic_height_in_ctbs_y =
+			(s->sps.pic_height_in_luma_samples + ctb_size_y - 1) /
+				ctb_size_y; // 7-17
+		de->cmd_len = 0;
+		de->dpbno_col = ~0U;
+
+		de->bit_copy_gptr = ctx->bitbufs + ctx->p1idx;
+		de->bit_copy_len = 0;
+
+		de->frame_c_offset = ctx->dst_fmt.height * 128;
+		de->frame_stride = ctx->dst_fmt.plane_fmt[0].bytesperline * 128;
+		de->frame_addr =
+			vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0);
+		de->frame_aux = NULL;
+
+		if (s->sps.bit_depth_luma_minus8 !=
+		    s->sps.bit_depth_chroma_minus8) {
+			v4l2_warn(&dev->v4l2_dev,
+				  "Chroma depth (%d) != Luma depth (%d)\n",
+				  s->sps.bit_depth_chroma_minus8 + 8,
+				  s->sps.bit_depth_luma_minus8 + 8);
+			goto fail;
+		}
+		if (s->sps.bit_depth_luma_minus8 == 0) {
+			if (ctx->dst_fmt.pixelformat !=
+						V4L2_PIX_FMT_NV12_COL128) {
+				v4l2_err(&dev->v4l2_dev,
+					 "Pixel format %#x != NV12_COL128 for 8-bit output",
+					 ctx->dst_fmt.pixelformat);
+				goto fail;
+			}
+		} else if (s->sps.bit_depth_luma_minus8 == 2) {
+			if (ctx->dst_fmt.pixelformat !=
+						V4L2_PIX_FMT_NV12_10_COL128) {
+				v4l2_err(&dev->v4l2_dev,
+					 "Pixel format %#x != NV12_10_COL128 for 10-bit output",
+					 ctx->dst_fmt.pixelformat);
+				goto fail;
+			}
+		} else {
+			v4l2_warn(&dev->v4l2_dev,
+				  "Luma depth (%d) unsupported\n",
+				  s->sps.bit_depth_luma_minus8 + 8);
+			goto fail;
+		}
+		if (run->dst->vb2_buf.num_planes != 1) {
+			v4l2_warn(&dev->v4l2_dev, "Capture planes (%d) != 1\n",
+				  run->dst->vb2_buf.num_planes);
+			goto fail;
+		}
+		if (run->dst->planes[0].length <
+		    ctx->dst_fmt.plane_fmt[0].sizeimage) {
+			v4l2_warn(&dev->v4l2_dev,
+				  "Capture plane[0] length (%d) < sizeimage (%d)\n",
+				  run->dst->planes[0].length,
+				  ctx->dst_fmt.plane_fmt[0].sizeimage);
+			goto fail;
+		}
+
+		// Fill in ref planes with our address s.t. if we mess
+		// up refs somehow then we still have a valid address
+		// entry
+		for (i = 0; i != 16; ++i)
+			de->ref_addrs[i] = de->frame_addr;
+
+		/*
+		 * Stash initial temporal_mvp flag
+		 * This must be the same for all pic slices (7.4.7.1)
+		 */
+		s->slice_temporal_mvp = slice_temporal_mvp;
+
+		// Phase 2 reg pre-calc
+		de->rpi_config2 = mk_config2(s);
+		de->rpi_framesize = (s->sps.pic_height_in_luma_samples << 16) |
+				    s->sps.pic_width_in_luma_samples;
+		de->rpi_currpoc = sh->slice_pic_order_cnt;
+
+		if (s->sps.flags &
+		    V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) {
+			setup_colmv(ctx, run, s);
+		}
+
+		s->slice_idx = 0;
+
+		if (sh->slice_segment_addr != 0) {
+			v4l2_warn(&dev->v4l2_dev,
+				  "New frame but segment_addr=%d\n",
+				  sh->slice_segment_addr);
+			goto fail;
+		}
+
+		/* Allocate a bitbuf if we need one - don't need one if single
+		 * slice as we can use the src buf directly
+		 */
+		if (!s->frame_end && !de->bit_copy_gptr->ptr) {
+			size_t bits_alloc;
+			bits_alloc = rpivid_bit_buf_size(s->sps.pic_width_in_luma_samples,
+							 s->sps.pic_height_in_luma_samples,
+							 s->sps.bit_depth_luma_minus8);
+
+			if (gptr_alloc(dev, de->bit_copy_gptr,
+				       bits_alloc,
+				       DMA_ATTR_FORCE_CONTIGUOUS) != 0) {
+				v4l2_err(&dev->v4l2_dev,
+					 "Unable to alloc buf (%zu) for bit copy\n",
+					 bits_alloc);
+				goto fail;
+			}
+			v4l2_info(&dev->v4l2_dev,
+				  "Alloc buf (%zu) for bit copy OK\n",
+				  bits_alloc);
+		}
+	}
+
+	// Either map src buffer or use directly
+	s->src_addr = 0;
+	s->src_buf = NULL;
+
+	if (run->src->planes[0].bytesused < (sh->bit_size + 7) / 8) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "Bit size %d > bytesused %d\n",
+			  sh->bit_size, run->src->planes[0].bytesused);
+		goto fail;
+	}
+	if (sh->data_bit_offset >= sh->bit_size ||
+	    sh->bit_size - sh->data_bit_offset < 8) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "Bit size %d < Bit offset %d + 8\n",
+			  sh->bit_size, sh->data_bit_offset);
+		goto fail;
+	}
+
+	if (s->frame_end)
+		s->src_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf,
+							    0);
+	if (!s->src_addr)
+		s->src_buf = vb2_plane_vaddr(&run->src->vb2_buf, 0);
+	if (!s->src_addr && !s->src_buf) {
+		v4l2_err(&dev->v4l2_dev, "Failed to map src buffer\n");
+		goto fail;
+	}
+
+	// Pre calc a few things
+	s->sh = sh;
+	s->slice_qp = 26 + s->pps.init_qp_minus26 + s->sh->slice_qp_delta;
+	s->max_num_merge_cand = sh->slice_type == HEVC_SLICE_I ?
+					0 :
+					(5 - sh->five_minus_max_num_merge_cand);
+	// * SH DSS flag invented by me - but clearly needed
+	s->dependent_slice_segment_flag =
+		((sh->flags &
+		  V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT) != 0);
+
+	s->nb_refs[0] = (sh->slice_type == HEVC_SLICE_I) ?
+				0 :
+				sh->num_ref_idx_l0_active_minus1 + 1;
+	s->nb_refs[1] = (sh->slice_type != HEVC_SLICE_B) ?
+				0 :
+				sh->num_ref_idx_l1_active_minus1 + 1;
+
+	if (s->sps.flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED)
+		populate_scaling_factors(run, de, s);
+
+	// Calc all the random coord info to avoid repeated conversion in/out
+	s->start_ts = s->ctb_addr_rs_to_ts[sh->slice_segment_addr];
+	s->start_ctb_x = sh->slice_segment_addr % de->pic_width_in_ctbs_y;
+	s->start_ctb_y = sh->slice_segment_addr / de->pic_width_in_ctbs_y;
+	// Last CTB of previous slice
+	prev_rs = !s->start_ts ? 0 : s->ctb_addr_ts_to_rs[s->start_ts - 1];
+	s->prev_ctb_x = prev_rs % de->pic_width_in_ctbs_y;
+	s->prev_ctb_y = prev_rs / de->pic_width_in_ctbs_y;
+
+	if ((s->pps.flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED))
+		rv = wpp_decode_slice(de, s);
+	else
+		rv = decode_slice(de, s);
+	if (rv)
+		goto fail;
+
+	if (!s->frame_end) {
+		xtrace_ok(dev, de);
+		return;
+	}
+
+	// Frame end
+	memset(dpb_q_aux, 0,
+	       sizeof(*dpb_q_aux) * V4L2_HEVC_DPB_ENTRIES_NUM_MAX);
+	/*
+	 * Need Aux ents for all (ref) DPB ents if temporal MV could
+	 * be enabled for any pic
+	 * ** At the moment we create aux ents for all pics whether or not
+	 *    they are ref - they should then be discarded by the DPB-aux
+	 *    garbage collection code
+	 */
+	use_aux = ((s->sps.flags &
+		  V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) != 0);
+
+	// Locate ref frames
+	// At least in the current implementation this is constant across all
+	// slices. If this changes we will need idx mapping code.
+	// Uses sh so here rather than trigger
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+			     V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+	if (!vq) {
+		v4l2_err(&dev->v4l2_dev, "VQ gone!\n");
+		goto fail;
+	}
+
+	//        v4l2_info(&dev->v4l2_dev, "rpivid_h265_end of frame\n");
+	if (write_cmd_buffer(dev, de, s))
+		goto fail;
+
+	for (i = 0; i < sh->num_active_dpb_entries; ++i) {
+		int buffer_index =
+			vb2_find_timestamp(vq, sh->dpb[i].timestamp, 0);
+		struct vb2_buffer *buf = buffer_index < 0 ?
+					NULL :
+					vb2_get_buffer(vq, buffer_index);
+
+		if (!buf) {
+			v4l2_warn(&dev->v4l2_dev,
+				  "Missing DPB ent %d, timestamp=%lld, index=%d\n",
+				  i, (long long)sh->dpb[i].timestamp,
+				  buffer_index);
+			continue;
+		}
+
+		if (use_aux) {
+			dpb_q_aux[i] = aux_q_ref_idx(ctx, buffer_index);
+			if (!dpb_q_aux[i])
+				v4l2_warn(&dev->v4l2_dev,
+					  "Missing DPB AUX ent %d, timestamp=%lld, index=%d\n",
+					  i, (long long)sh->dpb[i].timestamp,
+					  buffer_index);
+		}
+
+		de->ref_addrs[i] =
+			vb2_dma_contig_plane_dma_addr(buf, 0);
+	}
+
+	// Move DPB from temp
+	for (i = 0; i != V4L2_HEVC_DPB_ENTRIES_NUM_MAX; ++i) {
+		aux_q_release(ctx, &s->ref_aux[i]);
+		s->ref_aux[i] = dpb_q_aux[i];
+	}
+	// Unref the old frame aux too - it is either in the DPB or not
+	// now
+	aux_q_release(ctx, &s->frame_aux);
+
+	if (use_aux) {
+		// New frame so new aux ent
+		// ??? Do we need this if non-ref ??? can we tell
+		s->frame_aux = aux_q_new(ctx, run->dst->vb2_buf.index);
+
+		if (!s->frame_aux) {
+			v4l2_err(&dev->v4l2_dev,
+				 "Failed to obtain aux storage for frame\n");
+			goto fail;
+		}
+
+		de->frame_aux = aux_q_ref(ctx, s->frame_aux);
+	}
+
+	if (de->dpbno_col != ~0U) {
+		if (de->dpbno_col >= sh->num_active_dpb_entries) {
+			v4l2_err(&dev->v4l2_dev,
+				 "Col ref index %d >= %d\n",
+				 de->dpbno_col,
+				 sh->num_active_dpb_entries);
+		} else {
+			// Standard requires that the col pic is
+			// constant for the duration of the pic
+			// (text of collocated_ref_idx in H265-2 2018
+			// 7.4.7.1)
+
+			// Spot the collocated ref in passing
+			de->col_aux = aux_q_ref(ctx,
+						dpb_q_aux[de->dpbno_col]);
+
+			if (!de->col_aux) {
+				v4l2_warn(&dev->v4l2_dev,
+					  "Missing DPB ent for col\n");
+				// Probably need to abort if this fails
+				// as P2 may explode on bad data
+				goto fail;
+			}
+		}
+	}
+
+	de->state = RPIVID_DECODE_PHASE1;
+	xtrace_ok(dev, de);
+	return;
+
+fail:
+	if (de)
+		// Actual error reporting happens in Trigger
+		de->state = s->frame_end ? RPIVID_DECODE_ERROR_DONE :
+					   RPIVID_DECODE_ERROR_CONTINUE;
+	xtrace_fail(dev, de);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Handle PU and COEFF stream overflow
+
+// Returns:
+// -1  Phase 1 decode error
+//  0  OK
+// >0  Out of space (bitmask)
+
+#define STATUS_COEFF_EXHAUSTED	8
+#define STATUS_PU_EXHAUSTED	16
+
+static int check_status(const struct rpivid_dev *const dev)
+{
+	const u32 cfstatus = apb_read(dev, RPI_CFSTATUS);
+	const u32 cfnum = apb_read(dev, RPI_CFNUM);
+	u32 status = apb_read(dev, RPI_STATUS);
+
+	// Handle PU and COEFF stream overflow
+
+	// this is the definition of successful completion of phase 1
+	// it assures that status register is zero and all blocks in each tile
+	// have completed
+	if (cfstatus == cfnum)
+		return 0;	//No error
+
+	status &= (STATUS_PU_EXHAUSTED | STATUS_COEFF_EXHAUSTED);
+	if (status)
+		return status;
+
+	return -1;
+}
+
+static void phase2_cb(struct rpivid_dev *const dev, void *v)
+{
+	struct rpivid_dec_env *const de = v;
+
+	xtrace_in(dev, de);
+
+	/* Done with buffers - allow new P1 */
+	rpivid_hw_irq_active1_enable_claim(dev, 1);
+
+	v4l2_m2m_buf_done(de->frame_buf, VB2_BUF_STATE_DONE);
+	de->frame_buf = NULL;
+
+#if USE_REQUEST_PIN
+	media_request_unpin(de->req_pin);
+	de->req_pin = NULL;
+#else
+	media_request_object_complete(de->req_obj);
+	de->req_obj = NULL;
+#endif
+
+	xtrace_ok(dev, de);
+	dec_env_delete(de);
+}
+
+static void phase2_claimed(struct rpivid_dev *const dev, void *v)
+{
+	struct rpivid_dec_env *const de = v;
+	unsigned int i;
+
+	xtrace_in(dev, de);
+
+	apb_write_vc_addr(dev, RPI_PURBASE, de->pu_base_vc);
+	apb_write_vc_len(dev, RPI_PURSTRIDE, de->pu_stride);
+	apb_write_vc_addr(dev, RPI_COEFFRBASE, de->coeff_base_vc);
+	apb_write_vc_len(dev, RPI_COEFFRSTRIDE, de->coeff_stride);
+
+	apb_write_vc_addr(dev, RPI_OUTYBASE, de->frame_addr);
+	apb_write_vc_addr(dev, RPI_OUTCBASE,
+			  de->frame_addr + de->frame_c_offset);
+	apb_write_vc_len(dev, RPI_OUTYSTRIDE, de->frame_stride);
+	apb_write_vc_len(dev, RPI_OUTCSTRIDE, de->frame_stride);
+
+	//    v4l2_info(&dev->v4l2_dev, "Frame: Y=%llx, C=%llx, Stride=%x\n",
+	//              de->frame_addr, de->frame_addr + de->frame_c_offset,
+	//              de->frame_stride);
+
+	for (i = 0; i < 16; i++) {
+		// Strides are in fact unused but fill in anyway
+		apb_write_vc_addr(dev, 0x9000 + 16 * i, de->ref_addrs[i]);
+		apb_write_vc_len(dev, 0x9004 + 16 * i, de->frame_stride);
+		apb_write_vc_addr(dev, 0x9008 + 16 * i,
+				  de->ref_addrs[i] + de->frame_c_offset);
+		apb_write_vc_len(dev, 0x900C + 16 * i, de->frame_stride);
+	}
+
+	apb_write(dev, RPI_CONFIG2, de->rpi_config2);
+	apb_write(dev, RPI_FRAMESIZE, de->rpi_framesize);
+	apb_write(dev, RPI_CURRPOC, de->rpi_currpoc);
+	//    v4l2_info(&dev->v4l2_dev, "Config2=%#x, FrameSize=%#x, POC=%#x\n",
+	//    de->rpi_config2, de->rpi_framesize, de->rpi_currpoc);
+
+	// collocated reads/writes
+	apb_write_vc_len(dev, RPI_COLSTRIDE,
+			 de->ctx->colmv_stride); // Read vals
+	apb_write_vc_len(dev, RPI_MVSTRIDE,
+			 de->ctx->colmv_stride); // Write vals
+	apb_write_vc_addr(dev, RPI_MVBASE,
+			  !de->frame_aux ? 0 : de->frame_aux->col.addr);
+	apb_write_vc_addr(dev, RPI_COLBASE,
+			  !de->col_aux ? 0 : de->col_aux->col.addr);
+
+	//v4l2_info(&dev->v4l2_dev,
+	//	   "Mv=%llx, Col=%llx, Stride=%x, Buf=%llx->%llx\n",
+	//	   de->rpi_mvbase, de->rpi_colbase, de->ctx->colmv_stride,
+	//	   de->ctx->colmvbuf.addr, de->ctx->colmvbuf.addr +
+	//	   de->ctx->colmvbuf.size);
+
+	rpivid_hw_irq_active2_irq(dev, &de->irq_ent, phase2_cb, de);
+
+	apb_write_final(dev, RPI_NUMROWS, de->pic_height_in_ctbs_y);
+
+	xtrace_ok(dev, de);
+}
+
+static void phase1_claimed(struct rpivid_dev *const dev, void *v);
+
+// release any and all objects associated with de
+// and reenable phase 1 if required
+static void phase1_err_fin(struct rpivid_dev *const dev,
+			   struct rpivid_ctx *const ctx,
+			   struct rpivid_dec_env *const de)
+{
+	/* Return all detached buffers */
+	if (de->src_buf)
+		v4l2_m2m_buf_done(de->src_buf, VB2_BUF_STATE_ERROR);
+	de->src_buf = NULL;
+	if (de->frame_buf)
+		v4l2_m2m_buf_done(de->frame_buf, VB2_BUF_STATE_ERROR);
+	de->frame_buf = NULL;
+#if USE_REQUEST_PIN
+	if (de->req_pin)
+		media_request_unpin(de->req_pin);
+	de->req_pin = NULL;
+#else
+	if (de->req_obj)
+		media_request_object_complete(de->req_obj);
+	de->req_obj = NULL;
+#endif
+
+	dec_env_delete(de);
+
+	/* Reenable phase 0 if we were blocking */
+	if (atomic_add_return(-1, &ctx->p1out) >= RPIVID_P1BUF_COUNT - 1)
+		v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
+
+	/* Done with P1-P2 buffers - allow new P1 */
+	rpivid_hw_irq_active1_enable_claim(dev, 1);
+}
+
+static void phase1_thread(struct rpivid_dev *const dev, void *v)
+{
+	struct rpivid_dec_env *const de = v;
+	struct rpivid_ctx *const ctx = de->ctx;
+
+	struct rpivid_gptr *const pu_gptr = ctx->pu_bufs + ctx->p2idx;
+	struct rpivid_gptr *const coeff_gptr = ctx->coeff_bufs + ctx->p2idx;
+
+	xtrace_in(dev, de);
+
+	if (de->p1_status & STATUS_PU_EXHAUSTED) {
+		if (gptr_realloc_new(dev, pu_gptr, next_size(pu_gptr->size))) {
+			v4l2_err(&dev->v4l2_dev,
+				 "%s: PU realloc (%zx) failed\n",
+				 __func__, pu_gptr->size);
+			goto fail;
+		}
+		v4l2_info(&dev->v4l2_dev, "%s: PU realloc (%zx) OK\n",
+			  __func__, pu_gptr->size);
+	}
+
+	if (de->p1_status & STATUS_COEFF_EXHAUSTED) {
+		if (gptr_realloc_new(dev, coeff_gptr,
+				     next_size(coeff_gptr->size))) {
+			v4l2_err(&dev->v4l2_dev,
+				 "%s: Coeff realloc (%zx) failed\n",
+				 __func__, coeff_gptr->size);
+			goto fail;
+		}
+		v4l2_info(&dev->v4l2_dev, "%s: Coeff realloc (%zx) OK\n",
+			  __func__, coeff_gptr->size);
+	}
+
+	phase1_claimed(dev, de);
+	xtrace_ok(dev, de);
+	return;
+
+fail:
+	if (!pu_gptr->addr || !coeff_gptr->addr) {
+		v4l2_err(&dev->v4l2_dev,
+			 "%s: Fatal: failed to reclaim old alloc\n",
+			 __func__);
+		ctx->fatal_err = 1;
+	}
+	xtrace_fail(dev, de);
+	phase1_err_fin(dev, ctx, de);
+}
+
+/* Always called in irq context (this is good) */
+static void phase1_cb(struct rpivid_dev *const dev, void *v)
+{
+	struct rpivid_dec_env *const de = v;
+	struct rpivid_ctx *const ctx = de->ctx;
+
+	xtrace_in(dev, de);
+
+	de->p1_status = check_status(dev);
+
+	if (de->p1_status != 0) {
+		v4l2_info(&dev->v4l2_dev, "%s: Post wait: %#x\n",
+			  __func__, de->p1_status);
+
+		if (de->p1_status < 0)
+			goto fail;
+
+		/* Need to realloc - push onto a thread rather than IRQ */
+		rpivid_hw_irq_active1_thread(dev, &de->irq_ent,
+					     phase1_thread, de);
+		return;
+	}
+
+	v4l2_m2m_buf_done(de->src_buf, VB2_BUF_STATE_DONE);
+	de->src_buf = NULL;
+
+	/* All phase1 error paths done - it is safe to inc p2idx */
+	ctx->p2idx =
+		(ctx->p2idx + 1 >= RPIVID_P2BUF_COUNT) ? 0 : ctx->p2idx + 1;
+
+	/* Renable the next setup if we were blocking */
+	if (atomic_add_return(-1, &ctx->p1out) >= RPIVID_P1BUF_COUNT - 1) {
+		xtrace_fin(dev, de);
+		v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
+	}
+
+	rpivid_hw_irq_active2_claim(dev, &de->irq_ent, phase2_claimed, de);
+
+	xtrace_ok(dev, de);
+	return;
+
+fail:
+	xtrace_fail(dev, de);
+	phase1_err_fin(dev, ctx, de);
+}
+
+static void phase1_claimed(struct rpivid_dev *const dev, void *v)
+{
+	struct rpivid_dec_env *const de = v;
+	struct rpivid_ctx *const ctx = de->ctx;
+
+	const struct rpivid_gptr * const pu_gptr = ctx->pu_bufs + ctx->p2idx;
+	const struct rpivid_gptr * const coeff_gptr = ctx->coeff_bufs +
+						      ctx->p2idx;
+
+	xtrace_in(dev, de);
+
+	if (ctx->fatal_err)
+		goto fail;
+
+	de->pu_base_vc = pu_gptr->addr;
+	de->pu_stride =
+		ALIGN_DOWN(pu_gptr->size / de->pic_height_in_ctbs_y, 64);
+
+	de->coeff_base_vc = coeff_gptr->addr;
+	de->coeff_stride =
+		ALIGN_DOWN(coeff_gptr->size / de->pic_height_in_ctbs_y, 64);
+
+	/* phase1_claimed blocked until cb_phase1 completed so p2idx inc
+	 * in cb_phase1 after error detection
+	 */
+
+	apb_write_vc_addr(dev, RPI_PUWBASE, de->pu_base_vc);
+	apb_write_vc_len(dev, RPI_PUWSTRIDE, de->pu_stride);
+	apb_write_vc_addr(dev, RPI_COEFFWBASE, de->coeff_base_vc);
+	apb_write_vc_len(dev, RPI_COEFFWSTRIDE, de->coeff_stride);
+
+	// Trigger command FIFO
+	apb_write(dev, RPI_CFNUM, de->cmd_len);
+
+	// Claim irq
+	rpivid_hw_irq_active1_irq(dev, &de->irq_ent, phase1_cb, de);
+
+	// And start the h/w
+	apb_write_vc_addr_final(dev, RPI_CFBASE, de->cmd_addr);
+
+	xtrace_ok(dev, de);
+	return;
+
+fail:
+	xtrace_fail(dev, de);
+	phase1_err_fin(dev, ctx, de);
+}
+
+static void dec_state_delete(struct rpivid_ctx *const ctx)
+{
+	unsigned int i;
+	struct rpivid_dec_state *const s = ctx->state;
+
+	if (!s)
+		return;
+	ctx->state = NULL;
+
+	free_ps_info(s);
+
+	for (i = 0; i != HEVC_MAX_REFS; ++i)
+		aux_q_release(ctx, &s->ref_aux[i]);
+	aux_q_release(ctx, &s->frame_aux);
+
+	kfree(s);
+}
+
+static void rpivid_h265_stop(struct rpivid_ctx *ctx)
+{
+	struct rpivid_dev *const dev = ctx->dev;
+	unsigned int i;
+
+	v4l2_info(&dev->v4l2_dev, "%s\n", __func__);
+
+	dec_env_uninit(ctx);
+	dec_state_delete(ctx);
+
+	// dec_env & state must be killed before this to release the buffer to
+	// the free pool
+	aux_q_uninit(ctx);
+
+	for (i = 0; i != ARRAY_SIZE(ctx->bitbufs); ++i)
+		gptr_free(dev, ctx->bitbufs + i);
+	for (i = 0; i != ARRAY_SIZE(ctx->pu_bufs); ++i)
+		gptr_free(dev, ctx->pu_bufs + i);
+	for (i = 0; i != ARRAY_SIZE(ctx->coeff_bufs); ++i)
+		gptr_free(dev, ctx->coeff_bufs + i);
+}
+
+static int rpivid_h265_start(struct rpivid_ctx *ctx)
+{
+	struct rpivid_dev *const dev = ctx->dev;
+	unsigned int i;
+
+	unsigned int w = ctx->dst_fmt.width;
+	unsigned int h = ctx->dst_fmt.height;
+	unsigned int wxh;
+	size_t pu_alloc;
+	size_t coeff_alloc;
+
+#if DEBUG_TRACE_P1_CMD
+	p1_z = 0;
+#endif
+
+	// Generate a sanitised WxH for memory alloc
+	// Assume HD if unset
+	if (w == 0)
+		w = 1920;
+	if (w > 4096)
+		w = 4096;
+	if (h == 0)
+		h = 1088;
+	if (h > 4096)
+		h = 4096;
+	wxh = w * h;
+
+	v4l2_info(&dev->v4l2_dev, "%s: (%dx%d)\n", __func__,
+		  ctx->dst_fmt.width, ctx->dst_fmt.height);
+
+	ctx->fatal_err = 0;
+	ctx->dec0 = NULL;
+	ctx->state = kzalloc(sizeof(*ctx->state), GFP_KERNEL);
+	if (!ctx->state) {
+		v4l2_err(&dev->v4l2_dev, "Failed to allocate decode state\n");
+		goto fail;
+	}
+
+	if (dec_env_init(ctx) != 0) {
+		v4l2_err(&dev->v4l2_dev, "Failed to allocate decode envs\n");
+		goto fail;
+	}
+
+	// Finger in the air PU & Coeff alloc
+	// Will be realloced if too small
+	coeff_alloc = rpivid_round_up_size(wxh);
+	pu_alloc = rpivid_round_up_size(wxh / 4);
+	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))
+			goto fail;
+		if (gptr_alloc(dev, ctx->coeff_bufs + i, coeff_alloc,
+			       DMA_ATTR_NO_KERNEL_MAPPING))
+			goto fail;
+	}
+	aux_q_init(ctx);
+
+	return 0;
+
+fail:
+	rpivid_h265_stop(ctx);
+	return -ENOMEM;
+}
+
+static void rpivid_h265_trigger(struct rpivid_ctx *ctx)
+{
+	struct rpivid_dev *const dev = ctx->dev;
+	struct rpivid_dec_env *const de = ctx->dec0;
+
+	xtrace_in(dev, de);
+
+	switch (!de ? RPIVID_DECODE_ERROR_CONTINUE : de->state) {
+	case RPIVID_DECODE_SLICE_START:
+		de->state = RPIVID_DECODE_SLICE_CONTINUE;
+	/* FALLTHRU */
+	case RPIVID_DECODE_SLICE_CONTINUE:
+		v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+						 VB2_BUF_STATE_DONE);
+		xtrace_ok(dev, de);
+		break;
+
+	default:
+		v4l2_err(&dev->v4l2_dev, "%s: Unexpected state: %d\n", __func__,
+			 de->state);
+	/* FALLTHRU */
+	case RPIVID_DECODE_ERROR_DONE:
+		ctx->dec0 = NULL;
+		dec_env_delete(de);
+	/* FALLTHRU */
+	case RPIVID_DECODE_ERROR_CONTINUE:
+		xtrace_fin(dev, de);
+		v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+						 VB2_BUF_STATE_ERROR);
+		break;
+
+	case RPIVID_DECODE_PHASE1:
+		ctx->dec0 = NULL;
+
+#if !USE_REQUEST_PIN
+		/* Alloc a new request object - needs to be alloced dynamically
+		 * as the media request will release it some random time after
+		 * it is completed
+		 */
+		de->req_obj = kmalloc(sizeof(*de->req_obj), GFP_KERNEL);
+		if (!de->req_obj) {
+			xtrace_fail(dev, de);
+			dec_env_delete(de);
+			v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev,
+							 ctx->fh.m2m_ctx,
+							 VB2_BUF_STATE_ERROR);
+			break;
+		}
+		media_request_object_init(de->req_obj);
+#warning probably needs to _get the req obj too
+#endif
+		ctx->p1idx = (ctx->p1idx + 1 >= RPIVID_P1BUF_COUNT) ?
+							0 : ctx->p1idx + 1;
+
+		/* We know we have src & dst so no need to test */
+		de->src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		de->frame_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+#if USE_REQUEST_PIN
+		de->req_pin = de->src_buf->vb2_buf.req_obj.req;
+		media_request_pin(de->req_pin);
+#else
+		media_request_object_bind(de->src_buf->vb2_buf.req_obj.req,
+					  &dst_req_obj_ops, de, false,
+					  de->req_obj);
+#endif
+
+		/* We could get rid of the src buffer here if we've already
+		 * copied it, but we don't copy the last buffer unless it
+		 * didn't return a contig dma addr and that shouldn't happen
+		 */
+
+		/* Enable the next setup if our Q isn't too big */
+		if (atomic_add_return(1, &ctx->p1out) < RPIVID_P1BUF_COUNT) {
+			xtrace_fin(dev, de);
+			v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
+		}
+
+		rpivid_hw_irq_active1_claim(dev, &de->irq_ent, phase1_claimed,
+					    de);
+		xtrace_ok(dev, de);
+		break;
+	}
+}
+
+const struct rpivid_dec_ops rpivid_dec_ops_h265 = {
+	.setup = rpivid_h265_setup,
+	.start = rpivid_h265_start,
+	.stop = rpivid_h265_stop,
+	.trigger = rpivid_h265_trigger,
+};
+
+static int try_ctrl_sps(struct v4l2_ctrl *ctrl)
+{
+	const struct v4l2_ctrl_hevc_sps *const sps = ctrl->p_new.p_hevc_sps;
+	struct rpivid_ctx *const ctx = ctrl->priv;
+	struct rpivid_dev *const dev = ctx->dev;
+
+	if (sps->chroma_format_idc != 1) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "Chroma format (%d) unsupported\n",
+			  sps->chroma_format_idc);
+		return -EINVAL;
+	}
+
+	if (sps->bit_depth_luma_minus8 != 0 &&
+	    sps->bit_depth_luma_minus8 != 2) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "Luma depth (%d) unsupported\n",
+			  sps->bit_depth_luma_minus8 + 8);
+		return -EINVAL;
+	}
+
+	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "Chroma depth (%d) != Luma depth (%d)\n",
+			  sps->bit_depth_chroma_minus8 + 8,
+			  sps->bit_depth_luma_minus8 + 8);
+		return -EINVAL;
+	}
+
+	if (!sps->pic_width_in_luma_samples ||
+	    !sps->pic_height_in_luma_samples ||
+	    sps->pic_width_in_luma_samples > 4096 ||
+	    sps->pic_height_in_luma_samples > 4096) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "Bad sps width (%u) x height (%u)\n",
+			  sps->pic_width_in_luma_samples,
+			  sps->pic_height_in_luma_samples);
+		return -EINVAL;
+	}
+
+	if (!ctx->dst_fmt_set)
+		return 0;
+
+	if ((sps->bit_depth_luma_minus8 == 0 &&
+	     ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_COL128) ||
+	    (sps->bit_depth_luma_minus8 == 2 &&
+	     ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_10_COL128)) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "SPS luma depth %d does not match capture format\n",
+			  sps->bit_depth_luma_minus8 + 8);
+		return -EINVAL;
+	}
+
+	if (sps->pic_width_in_luma_samples > ctx->dst_fmt.width ||
+	    sps->pic_height_in_luma_samples > ctx->dst_fmt.height) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "SPS size (%dx%d) > capture size (%d,%d)\n",
+			  sps->pic_width_in_luma_samples,
+			  sps->pic_height_in_luma_samples,
+			  ctx->dst_fmt.width,
+			  ctx->dst_fmt.height);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+const struct v4l2_ctrl_ops rpivid_hevc_sps_ctrl_ops = {
+	.try_ctrl = try_ctrl_sps,
+};
+
+static int try_ctrl_pps(struct v4l2_ctrl *ctrl)
+{
+	const struct v4l2_ctrl_hevc_pps *const pps = ctrl->p_new.p_hevc_pps;
+	struct rpivid_ctx *const ctx = ctrl->priv;
+	struct rpivid_dev *const dev = ctx->dev;
+
+	if ((pps->flags &
+	     V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED) &&
+	    (pps->flags &
+	     V4L2_HEVC_PPS_FLAG_TILES_ENABLED) &&
+	    (pps->num_tile_columns_minus1 || pps->num_tile_rows_minus1)) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "WPP + Tiles not supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+const struct v4l2_ctrl_ops rpivid_hevc_pps_ctrl_ops = {
+	.try_ctrl = try_ctrl_pps,
+};
+
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_hw.c linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_hw.c
--- linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_hw.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_hw.c	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Raspberry Pi HEVC driver
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include <media/videobuf2-core.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rpivid.h"
+#include "rpivid_hw.h"
+
+static void pre_irq(struct rpivid_dev *dev, struct rpivid_hw_irq_ent *ient,
+		    rpivid_irq_callback cb, void *v,
+		    struct rpivid_hw_irq_ctrl *ictl)
+{
+	unsigned long flags;
+
+	if (ictl->irq) {
+		v4l2_err(&dev->v4l2_dev, "Attempt to claim IRQ when already claimed\n");
+		return;
+	}
+
+	ient->cb = cb;
+	ient->v = v;
+
+	spin_lock_irqsave(&ictl->lock, flags);
+	ictl->irq = ient;
+	ictl->no_sched++;
+	spin_unlock_irqrestore(&ictl->lock, flags);
+}
+
+/* Should be called from inside ictl->lock */
+static inline bool sched_enabled(const struct rpivid_hw_irq_ctrl * const ictl)
+{
+	return ictl->no_sched <= 0 && ictl->enable;
+}
+
+/* Should be called from inside ictl->lock & after checking sched_enabled() */
+static inline void set_claimed(struct rpivid_hw_irq_ctrl * const ictl)
+{
+	if (ictl->enable > 0)
+		--ictl->enable;
+	ictl->no_sched = 1;
+}
+
+/* Should be called from inside ictl->lock */
+static struct rpivid_hw_irq_ent *get_sched(struct rpivid_hw_irq_ctrl * const ictl)
+{
+	struct rpivid_hw_irq_ent *ient;
+
+	if (!sched_enabled(ictl))
+		return NULL;
+
+	ient = ictl->claim;
+	if (!ient)
+		return NULL;
+	ictl->claim = ient->next;
+
+	set_claimed(ictl);
+	return ient;
+}
+
+/* Run a callback & check to see if there is anything else to run */
+static void sched_cb(struct rpivid_dev * const dev,
+		     struct rpivid_hw_irq_ctrl * const ictl,
+		     struct rpivid_hw_irq_ent *ient)
+{
+	while (ient) {
+		unsigned long flags;
+
+		ient->cb(dev, ient->v);
+
+		spin_lock_irqsave(&ictl->lock, flags);
+
+		/* Always dec no_sched after cb exec - must have been set
+		 * on entry to cb
+		 */
+		--ictl->no_sched;
+		ient = get_sched(ictl);
+
+		spin_unlock_irqrestore(&ictl->lock, flags);
+	}
+}
+
+/* Should only ever be called from its own IRQ cb so no lock required */
+static void pre_thread(struct rpivid_dev *dev,
+		       struct rpivid_hw_irq_ent *ient,
+		       rpivid_irq_callback cb, void *v,
+		       struct rpivid_hw_irq_ctrl *ictl)
+{
+	ient->cb = cb;
+	ient->v = v;
+	ictl->irq = ient;
+	ictl->thread_reqed = true;
+	ictl->no_sched++;	/* This is unwound in do_thread */
+}
+
+// Called in irq context
+static void do_irq(struct rpivid_dev * const dev,
+		   struct rpivid_hw_irq_ctrl * const ictl)
+{
+	struct rpivid_hw_irq_ent *ient;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ictl->lock, flags);
+	ient = ictl->irq;
+	ictl->irq = NULL;
+	spin_unlock_irqrestore(&ictl->lock, flags);
+
+	sched_cb(dev, ictl, ient);
+}
+
+static void do_claim(struct rpivid_dev * const dev,
+		     struct rpivid_hw_irq_ent *ient,
+		     const rpivid_irq_callback cb, void * const v,
+		     struct rpivid_hw_irq_ctrl * const ictl)
+{
+	unsigned long flags;
+
+	ient->next = NULL;
+	ient->cb = cb;
+	ient->v = v;
+
+	spin_lock_irqsave(&ictl->lock, flags);
+
+	if (ictl->claim) {
+		// If we have a Q then add to end
+		ictl->tail->next = ient;
+		ictl->tail = ient;
+		ient = NULL;
+	} else if (!sched_enabled(ictl)) {
+		// Empty Q but other activity in progress so Q
+		ictl->claim = ient;
+		ictl->tail = ient;
+		ient = NULL;
+	} else {
+		// Nothing else going on - schedule immediately and
+		// prevent anything else scheduling claims
+		set_claimed(ictl);
+	}
+
+	spin_unlock_irqrestore(&ictl->lock, flags);
+
+	sched_cb(dev, ictl, ient);
+}
+
+/* Enable n claims.
+ * n < 0   set to unlimited (default on init)
+ * n = 0   if previously unlimited then disable otherwise nop
+ * n > 0   if previously unlimited then set to n enables
+ *         otherwise add n enables
+ * The enable count is automatically decremented every time a claim is run
+ */
+static void do_enable_claim(struct rpivid_dev * const dev,
+			    int n,
+			    struct rpivid_hw_irq_ctrl * const ictl)
+{
+	unsigned long flags;
+	struct rpivid_hw_irq_ent *ient;
+
+	spin_lock_irqsave(&ictl->lock, flags);
+	ictl->enable = n < 0 ? -1 : ictl->enable <= 0 ? n : ictl->enable + n;
+	ient = get_sched(ictl);
+	spin_unlock_irqrestore(&ictl->lock, flags);
+
+	sched_cb(dev, ictl, ient);
+}
+
+static void ictl_init(struct rpivid_hw_irq_ctrl * const ictl, int enables)
+{
+	spin_lock_init(&ictl->lock);
+	ictl->claim = NULL;
+	ictl->tail = NULL;
+	ictl->irq = NULL;
+	ictl->no_sched = 0;
+	ictl->enable = enables;
+	ictl->thread_reqed = false;
+}
+
+static void ictl_uninit(struct rpivid_hw_irq_ctrl * const ictl)
+{
+	// Nothing to do
+}
+
+#if !OPT_DEBUG_POLL_IRQ
+static irqreturn_t rpivid_irq_irq(int irq, void *data)
+{
+	struct rpivid_dev * const dev = data;
+	__u32 ictrl;
+
+	ictrl = irq_read(dev, ARG_IC_ICTRL);
+	if (!(ictrl & ARG_IC_ICTRL_ALL_IRQ_MASK)) {
+		v4l2_warn(&dev->v4l2_dev, "IRQ but no IRQ bits set\n");
+		return IRQ_NONE;
+	}
+
+	// Cancel any/all irqs
+	irq_write(dev, ARG_IC_ICTRL, ictrl & ~ARG_IC_ICTRL_SET_ZERO_MASK);
+
+	// Service Active2 before Active1 so Phase 1 can transition to Phase 2
+	// without delay
+	if (ictrl & ARG_IC_ICTRL_ACTIVE2_INT_SET)
+		do_irq(dev, &dev->ic_active2);
+	if (ictrl & ARG_IC_ICTRL_ACTIVE1_INT_SET)
+		do_irq(dev, &dev->ic_active1);
+
+	return dev->ic_active1.thread_reqed || dev->ic_active2.thread_reqed ?
+		IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+static void do_thread(struct rpivid_dev * const dev,
+		      struct rpivid_hw_irq_ctrl *const ictl)
+{
+	unsigned long flags;
+	struct rpivid_hw_irq_ent *ient = NULL;
+
+	spin_lock_irqsave(&ictl->lock, flags);
+
+	if (ictl->thread_reqed) {
+		ient = ictl->irq;
+		ictl->thread_reqed = false;
+		ictl->irq = NULL;
+	}
+
+	spin_unlock_irqrestore(&ictl->lock, flags);
+
+	sched_cb(dev, ictl, ient);
+}
+
+static irqreturn_t rpivid_irq_thread(int irq, void *data)
+{
+	struct rpivid_dev * const dev = data;
+
+	do_thread(dev, &dev->ic_active1);
+	do_thread(dev, &dev->ic_active2);
+
+	return IRQ_HANDLED;
+}
+#endif
+
+/* May only be called from Active1 CB
+ * IRQs should not be expected until execution continues in the cb
+ */
+void rpivid_hw_irq_active1_thread(struct rpivid_dev *dev,
+				  struct rpivid_hw_irq_ent *ient,
+				  rpivid_irq_callback thread_cb, void *ctx)
+{
+	pre_thread(dev, ient, thread_cb, ctx, &dev->ic_active1);
+}
+
+void rpivid_hw_irq_active1_enable_claim(struct rpivid_dev *dev,
+					int n)
+{
+	do_enable_claim(dev, n, &dev->ic_active1);
+}
+
+void rpivid_hw_irq_active1_claim(struct rpivid_dev *dev,
+				 struct rpivid_hw_irq_ent *ient,
+				 rpivid_irq_callback ready_cb, void *ctx)
+{
+	do_claim(dev, ient, ready_cb, ctx, &dev->ic_active1);
+}
+
+void rpivid_hw_irq_active1_irq(struct rpivid_dev *dev,
+			       struct rpivid_hw_irq_ent *ient,
+			       rpivid_irq_callback irq_cb, void *ctx)
+{
+	pre_irq(dev, ient, irq_cb, ctx, &dev->ic_active1);
+}
+
+void rpivid_hw_irq_active2_claim(struct rpivid_dev *dev,
+				 struct rpivid_hw_irq_ent *ient,
+				 rpivid_irq_callback ready_cb, void *ctx)
+{
+	do_claim(dev, ient, ready_cb, ctx, &dev->ic_active2);
+}
+
+void rpivid_hw_irq_active2_irq(struct rpivid_dev *dev,
+			       struct rpivid_hw_irq_ent *ient,
+			       rpivid_irq_callback irq_cb, void *ctx)
+{
+	pre_irq(dev, ient, irq_cb, ctx, &dev->ic_active2);
+}
+
+int rpivid_hw_probe(struct rpivid_dev *dev)
+{
+	struct resource *res;
+	__u32 irq_stat;
+	int irq_dec;
+	int ret = 0;
+
+	ictl_init(&dev->ic_active1, RPIVID_P2BUF_COUNT);
+	ictl_init(&dev->ic_active2, RPIVID_ICTL_ENABLE_UNLIMITED);
+
+	res = platform_get_resource_byname(dev->pdev, IORESOURCE_MEM, "intc");
+	if (!res)
+		return -ENODEV;
+
+	dev->base_irq = devm_ioremap(dev->dev, res->start, resource_size(res));
+	if (IS_ERR(dev->base_irq))
+		return PTR_ERR(dev->base_irq);
+
+	res = platform_get_resource_byname(dev->pdev, IORESOURCE_MEM, "hevc");
+	if (!res)
+		return -ENODEV;
+
+	dev->base_h265 = devm_ioremap(dev->dev, res->start, resource_size(res));
+	if (IS_ERR(dev->base_h265))
+		return PTR_ERR(dev->base_h265);
+
+	dev->clock = devm_clk_get(&dev->pdev->dev, "hevc");
+	if (IS_ERR(dev->clock))
+		return PTR_ERR(dev->clock);
+
+	dev->cache_align = dma_get_cache_alignment();
+
+	// Disable IRQs & reset anything pending
+	irq_write(dev, 0,
+		  ARG_IC_ICTRL_ACTIVE1_EN_SET | ARG_IC_ICTRL_ACTIVE2_EN_SET);
+	irq_stat = irq_read(dev, 0);
+	irq_write(dev, 0, irq_stat);
+
+#if !OPT_DEBUG_POLL_IRQ
+	irq_dec = platform_get_irq(dev->pdev, 0);
+	if (irq_dec <= 0)
+		return irq_dec;
+	ret = devm_request_threaded_irq(dev->dev, irq_dec,
+					rpivid_irq_irq,
+					rpivid_irq_thread,
+					0, dev_name(dev->dev), dev);
+	if (ret) {
+		dev_err(dev->dev, "Failed to request IRQ - %d\n", ret);
+
+		return ret;
+	}
+#endif
+	return ret;
+}
+
+void rpivid_hw_remove(struct rpivid_dev *dev)
+{
+	// IRQ auto freed on unload so no need to do it here
+	// ioremap auto freed on unload
+	ictl_uninit(&dev->ic_active1);
+	ictl_uninit(&dev->ic_active2);
+}
+
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_hw.h linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_hw.h
--- linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_hw.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_hw.h	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Raspberry Pi HEVC driver
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#ifndef _RPIVID_HW_H_
+#define _RPIVID_HW_H_
+
+struct rpivid_hw_irq_ent {
+	struct rpivid_hw_irq_ent *next;
+	rpivid_irq_callback cb;
+	void *v;
+};
+
+/* Phase 1 Register offsets */
+
+#define RPI_SPS0 0
+#define RPI_SPS1 4
+#define RPI_PPS 8
+#define RPI_SLICE 12
+#define RPI_TILESTART 16
+#define RPI_TILEEND 20
+#define RPI_SLICESTART 24
+#define RPI_MODE 28
+#define RPI_LEFT0 32
+#define RPI_LEFT1 36
+#define RPI_LEFT2 40
+#define RPI_LEFT3 44
+#define RPI_QP 48
+#define RPI_CONTROL 52
+#define RPI_STATUS 56
+#define RPI_VERSION 60
+#define RPI_BFBASE 64
+#define RPI_BFNUM 68
+#define RPI_BFCONTROL 72
+#define RPI_BFSTATUS 76
+#define RPI_PUWBASE 80
+#define RPI_PUWSTRIDE 84
+#define RPI_COEFFWBASE 88
+#define RPI_COEFFWSTRIDE 92
+#define RPI_SLICECMDS 96
+#define RPI_BEGINTILEEND 100
+#define RPI_TRANSFER 104
+#define RPI_CFBASE 108
+#define RPI_CFNUM 112
+#define RPI_CFSTATUS 116
+
+/* Phase 2 Register offsets */
+
+#define RPI_PURBASE 0x8000
+#define RPI_PURSTRIDE 0x8004
+#define RPI_COEFFRBASE 0x8008
+#define RPI_COEFFRSTRIDE 0x800C
+#define RPI_NUMROWS 0x8010
+#define RPI_CONFIG2 0x8014
+#define RPI_OUTYBASE 0x8018
+#define RPI_OUTYSTRIDE 0x801C
+#define RPI_OUTCBASE 0x8020
+#define RPI_OUTCSTRIDE 0x8024
+#define RPI_STATUS2 0x8028
+#define RPI_FRAMESIZE 0x802C
+#define RPI_MVBASE 0x8030
+#define RPI_MVSTRIDE 0x8034
+#define RPI_COLBASE 0x8038
+#define RPI_COLSTRIDE 0x803C
+#define RPI_CURRPOC 0x8040
+
+/*
+ * Write a general register value
+ * Order is unimportant
+ */
+static inline void apb_write(const struct rpivid_dev * const dev,
+			     const unsigned int offset, const u32 val)
+{
+	writel_relaxed(val, dev->base_h265 + offset);
+}
+
+/* Write the final register value that actually starts the phase */
+static inline void apb_write_final(const struct rpivid_dev * const dev,
+				   const unsigned int offset, const u32 val)
+{
+	writel(val, dev->base_h265 + offset);
+}
+
+static inline u32 apb_read(const struct rpivid_dev * const dev,
+			   const unsigned int offset)
+{
+	return readl(dev->base_h265 + offset);
+}
+
+static inline void irq_write(const struct rpivid_dev * const dev,
+			     const unsigned int offset, const u32 val)
+{
+	writel(val, dev->base_irq + offset);
+}
+
+static inline u32 irq_read(const struct rpivid_dev * const dev,
+			   const unsigned int offset)
+{
+	return readl(dev->base_irq + offset);
+}
+
+static inline void apb_write_vc_addr(const struct rpivid_dev * const dev,
+				     const unsigned int offset,
+				     const dma_addr_t a)
+{
+	apb_write(dev, offset, (u32)(a >> 6));
+}
+
+static inline void apb_write_vc_addr_final(const struct rpivid_dev * const dev,
+					   const unsigned int offset,
+					   const dma_addr_t a)
+{
+	apb_write_final(dev, offset, (u32)(a >> 6));
+}
+
+static inline void apb_write_vc_len(const struct rpivid_dev * const dev,
+				    const unsigned int offset,
+				    const unsigned int x)
+{
+	apb_write(dev, offset, (x + 63) >> 6);
+}
+
+/* *ARG_IC_ICTRL - Interrupt control for ARGON Core*
+ * Offset (byte space) = 40'h2b10000
+ * Physical Address (byte space) = 40'h7eb10000
+ * Verilog Macro Address = `ARG_IC_REG_START + `ARGON_INTCTRL_ICTRL
+ * Reset Value = 32'b100x100x_100xxxxx_xxxxxxx0_x100x100
+ * Access = RW (32-bit only)
+ * Interrupt control logic for ARGON Core.
+ */
+#define ARG_IC_ICTRL 0
+
+/* acc=LWC ACTIVE1_INT FIELD ACCESS: LWC
+ *
+ * Interrupt 1
+ * This is set and held when an hevc_active1 interrupt edge is detected
+ * The polarity of the edge is set by the ACTIVE1_EDGE field
+ * Write a 1 to this bit to clear down the latched interrupt
+ * The latched interrupt is only enabled out onto the interrupt line if
+ * ACTIVE1_EN is set
+ * Reset value is *0* decimal.
+ */
+#define ARG_IC_ICTRL_ACTIVE1_INT_SET		BIT(0)
+
+/* ACTIVE1_EDGE Sets the polarity of the interrupt edge detection logic
+ * This logic detects edges of the hevc_active1 line from the argon core
+ * 0 = negedge, 1 = posedge
+ * Reset value is *0* decimal.
+ */
+#define ARG_IC_ICTRL_ACTIVE1_EDGE_SET		BIT(1)
+
+/* ACTIVE1_EN Enables ACTIVE1_INT out onto the argon interrupt line.
+ * If this isn't set, the interrupt logic will work but no interrupt will be
+ * set to the interrupt controller
+ * Reset value is *1* decimal.
+ *
+ * [JC] The above appears to be a lie - if unset then b0 is never set
+ */
+#define ARG_IC_ICTRL_ACTIVE1_EN_SET		BIT(2)
+
+/* acc=RO ACTIVE1_STATUS FIELD ACCESS: RO
+ *
+ * The current status of the hevc_active1 signal
+ */
+#define ARG_IC_ICTRL_ACTIVE1_STATUS_SET		BIT(3)
+
+/* acc=LWC ACTIVE2_INT FIELD ACCESS: LWC
+ *
+ * Interrupt 2
+ * This is set and held when an hevc_active2 interrupt edge is detected
+ * The polarity of the edge is set by the ACTIVE2_EDGE field
+ * Write a 1 to this bit to clear down the latched interrupt
+ * The latched interrupt is only enabled out onto the interrupt line if
+ * ACTIVE2_EN is set
+ * Reset value is *0* decimal.
+ */
+#define ARG_IC_ICTRL_ACTIVE2_INT_SET		BIT(4)
+
+/* ACTIVE2_EDGE Sets the polarity of the interrupt edge detection logic
+ * This logic detects edges of the hevc_active2 line from the argon core
+ * 0 = negedge, 1 = posedge
+ * Reset value is *0* decimal.
+ */
+#define ARG_IC_ICTRL_ACTIVE2_EDGE_SET		BIT(5)
+
+/* ACTIVE2_EN Enables ACTIVE2_INT out onto the argon interrupt line.
+ * If this isn't set, the interrupt logic will work but no interrupt will be
+ * set to the interrupt controller
+ * Reset value is *1* decimal.
+ */
+#define ARG_IC_ICTRL_ACTIVE2_EN_SET		BIT(6)
+
+/* acc=RO ACTIVE2_STATUS FIELD ACCESS: RO
+ *
+ * The current status of the hevc_active2 signal
+ */
+#define ARG_IC_ICTRL_ACTIVE2_STATUS_SET		BIT(7)
+
+/* TEST_INT Forces the argon int high for test purposes.
+ * Reset value is *0* decimal.
+ */
+#define ARG_IC_ICTRL_TEST_INT			BIT(8)
+#define ARG_IC_ICTRL_SPARE			BIT(9)
+
+/* acc=RO VP9_INTERRUPT_STATUS FIELD ACCESS: RO
+ *
+ * The current status of the vp9_interrupt signal
+ */
+#define ARG_IC_ICTRL_VP9_INTERRUPT_STATUS	BIT(10)
+
+/* AIO_INT_ENABLE 1 = Or the AIO int in with the Argon int so the VPU can see
+ * it
+ * 0 = the AIO int is masked. (It should still be connected to the GIC though).
+ */
+#define ARG_IC_ICTRL_AIO_INT_ENABLE		BIT(20)
+#define ARG_IC_ICTRL_H264_ACTIVE_INT		BIT(21)
+#define ARG_IC_ICTRL_H264_ACTIVE_EDGE		BIT(22)
+#define ARG_IC_ICTRL_H264_ACTIVE_EN		BIT(23)
+#define ARG_IC_ICTRL_H264_ACTIVE_STATUS		BIT(24)
+#define ARG_IC_ICTRL_H264_INTERRUPT_INT		BIT(25)
+#define ARG_IC_ICTRL_H264_INTERRUPT_EDGE	BIT(26)
+#define ARG_IC_ICTRL_H264_INTERRUPT_EN		BIT(27)
+
+/* acc=RO H264_INTERRUPT_STATUS FIELD ACCESS: RO
+ *
+ * The current status of the h264_interrupt signal
+ */
+#define ARG_IC_ICTRL_H264_INTERRUPT_STATUS	BIT(28)
+
+/* acc=LWC VP9_INTERRUPT_INT FIELD ACCESS: LWC
+ *
+ * Interrupt 1
+ * This is set and held when an vp9_interrupt interrupt edge is detected
+ * The polarity of the edge is set by the VP9_INTERRUPT_EDGE field
+ * Write a 1 to this bit to clear down the latched interrupt
+ * The latched interrupt is only enabled out onto the interrupt line if
+ * VP9_INTERRUPT_EN is set
+ * Reset value is *0* decimal.
+ */
+#define ARG_IC_ICTRL_VP9_INTERRUPT_INT		BIT(29)
+
+/* VP9_INTERRUPT_EDGE Sets the polarity of the interrupt edge detection logic
+ * This logic detects edges of the vp9_interrupt line from the argon h264 core
+ * 0 = negedge, 1 = posedge
+ * Reset value is *0* decimal.
+ */
+#define ARG_IC_ICTRL_VP9_INTERRUPT_EDGE		BIT(30)
+
+/* VP9_INTERRUPT_EN Enables VP9_INTERRUPT_INT out onto the argon interrupt line.
+ * If this isn't set, the interrupt logic will work but no interrupt will be
+ * set to the interrupt controller
+ * Reset value is *1* decimal.
+ */
+#define ARG_IC_ICTRL_VP9_INTERRUPT_EN		BIT(31)
+
+/* Bits 19:12, 11 reserved - read ?, write 0 */
+#define ARG_IC_ICTRL_SET_ZERO_MASK		((0xff << 12) | BIT(11))
+
+/* All IRQ bits */
+#define ARG_IC_ICTRL_ALL_IRQ_MASK   (\
+		ARG_IC_ICTRL_VP9_INTERRUPT_INT  |\
+		ARG_IC_ICTRL_H264_INTERRUPT_INT |\
+		ARG_IC_ICTRL_ACTIVE1_INT_SET    |\
+		ARG_IC_ICTRL_ACTIVE2_INT_SET)
+
+/* Regulate claim Q */
+void rpivid_hw_irq_active1_enable_claim(struct rpivid_dev *dev,
+					int n);
+/* Auto release once all CBs called */
+void rpivid_hw_irq_active1_claim(struct rpivid_dev *dev,
+				 struct rpivid_hw_irq_ent *ient,
+				 rpivid_irq_callback ready_cb, void *ctx);
+/* May only be called in claim cb */
+void rpivid_hw_irq_active1_irq(struct rpivid_dev *dev,
+			       struct rpivid_hw_irq_ent *ient,
+			       rpivid_irq_callback irq_cb, void *ctx);
+/* May only be called in irq cb */
+void rpivid_hw_irq_active1_thread(struct rpivid_dev *dev,
+				  struct rpivid_hw_irq_ent *ient,
+				  rpivid_irq_callback thread_cb, void *ctx);
+
+/* Auto release once all CBs called */
+void rpivid_hw_irq_active2_claim(struct rpivid_dev *dev,
+				 struct rpivid_hw_irq_ent *ient,
+				 rpivid_irq_callback ready_cb, void *ctx);
+/* May only be called in claim cb */
+void rpivid_hw_irq_active2_irq(struct rpivid_dev *dev,
+			       struct rpivid_hw_irq_ent *ient,
+			       rpivid_irq_callback irq_cb, void *ctx);
+
+int rpivid_hw_probe(struct rpivid_dev *dev);
+void rpivid_hw_remove(struct rpivid_dev *dev);
+
+#endif
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_video.c linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_video.c
--- linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_video.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_video.c	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Raspberry Pi HEVC driver
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rpivid.h"
+#include "rpivid_hw.h"
+#include "rpivid_video.h"
+#include "rpivid_dec.h"
+
+#define RPIVID_DECODE_SRC	BIT(0)
+#define RPIVID_DECODE_DST	BIT(1)
+
+#define RPIVID_MIN_WIDTH	16U
+#define RPIVID_MIN_HEIGHT	16U
+#define RPIVID_MAX_WIDTH	4096U
+#define RPIVID_MAX_HEIGHT	4096U
+
+static inline struct rpivid_ctx *rpivid_file2ctx(struct file *file)
+{
+	return container_of(file->private_data, struct rpivid_ctx, fh);
+}
+
+/* constrain x to y,y*2 */
+static inline unsigned int constrain2x(unsigned int x, unsigned int y)
+{
+	return (x < y) ?
+			y :
+			(x > y * 2) ? y : x;
+}
+
+size_t rpivid_round_up_size(const size_t x)
+{
+	/* Admit no size < 256 */
+	const unsigned int n = x < 256 ? 8 : ilog2(x);
+
+	return x >= (3 << n) ? 4 << n : (3 << n);
+}
+
+size_t rpivid_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8)
+{
+	const size_t wxh = w * h;
+	size_t bits_alloc;
+
+	/* Annex A gives a min compression of 2 @ lvl 3.1
+	 * (wxh <= 983040) and min 4 thereafter but avoid
+	 * the odity of 983041 having a lower limit than
+	 * 983040.
+	 * Multiply by 3/2 for 4:2:0
+	 */
+	bits_alloc = wxh < 983040 ? wxh * 3 / 4 :
+		wxh < 983040 * 2 ? 983040 * 3 / 4 :
+		wxh * 3 / 8;
+	/* Allow for bit depth */
+	bits_alloc += (bits_alloc * bits_minus8) / 8;
+	return rpivid_round_up_size(bits_alloc);
+}
+
+int rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt)
+{
+	size_t size;
+	u32 w;
+	u32 h;
+
+	if (pix_fmt->pixelformat != V4L2_PIX_FMT_HEVC_SLICE)
+		return -EINVAL;
+
+	w = pix_fmt->width;
+	h = pix_fmt->height;
+	if (!w || !h) {
+		w = 1920;
+		h = 1080;
+	}
+	if (w > 4096)
+		w = 4096;
+	if (h > 4096)
+		h = 4096;
+
+	if (!pix_fmt->plane_fmt[0].sizeimage ||
+	    pix_fmt->plane_fmt[0].sizeimage > SZ_32M) {
+		/* Unspecified or way too big - pick max for size */
+		size = rpivid_bit_buf_size(w, h, 2);
+	}
+	/* Set a minimum */
+	size = max_t(u32, SZ_4K, pix_fmt->plane_fmt[0].sizeimage);
+
+	pix_fmt->width = w;
+	pix_fmt->height = h;
+	pix_fmt->num_planes = 1;
+	pix_fmt->field = V4L2_FIELD_NONE;
+	/* Zero bytes per line for encoded source. */
+	pix_fmt->plane_fmt[0].bytesperline = 0;
+	pix_fmt->plane_fmt[0].sizeimage = size;
+
+	return 0;
+}
+
+int rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt)
+{
+	unsigned int width = pix_fmt->width;
+	unsigned int height = pix_fmt->height;
+	unsigned int sizeimage = pix_fmt->plane_fmt[0].sizeimage;
+	unsigned int bytesperline = pix_fmt->plane_fmt[0].bytesperline;
+
+	switch (pix_fmt->pixelformat) {
+	/* For column formats set bytesperline to column height (stride2) */
+	case V4L2_PIX_FMT_NV12_COL128:
+		/* Width rounds up to columns */
+		width = ALIGN(min(width, RPIVID_MAX_WIDTH), 128);
+
+		/* 16 aligned height - not sure we even need that */
+		height = ALIGN(height, 16);
+		/* column height
+		 * Accept suggested shape if at least min & < 2 * min
+		 */
+		bytesperline = constrain2x(bytesperline, height * 3 / 2);
+
+		/* image size
+		 * Again allow plausible variation in case added padding is
+		 * required
+		 */
+		sizeimage = constrain2x(sizeimage, bytesperline * width);
+		break;
+
+	case V4L2_PIX_FMT_NV12_10_COL128:
+		/* width in pixels (3 pels = 4 bytes) rounded to 128 byte
+		 * columns
+		 */
+		width = ALIGN(((min(width, RPIVID_MAX_WIDTH) + 2) / 3), 32) * 3;
+
+		/* 16-aligned height. */
+		height = ALIGN(height, 16);
+
+		/* column height
+		 * Accept suggested shape if at least min & < 2 * min
+		 */
+		bytesperline = constrain2x(bytesperline, height * 3 / 2);
+
+		/* image size
+		 * Again allow plausible variation in case added padding is
+		 * required
+		 */
+		sizeimage = constrain2x(sizeimage,
+					bytesperline * width * 4 / 3);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	pix_fmt->width = width;
+	pix_fmt->height = height;
+
+	pix_fmt->field = V4L2_FIELD_NONE;
+	pix_fmt->plane_fmt[0].bytesperline = bytesperline;
+	pix_fmt->plane_fmt[0].sizeimage = sizeimage;
+	pix_fmt->num_planes = 1;
+	return 0;
+}
+
+static int rpivid_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strscpy(cap->driver, RPIVID_NAME, sizeof(cap->driver));
+	strscpy(cap->card, RPIVID_NAME, sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "platform:%s", RPIVID_NAME);
+
+	return 0;
+}
+
+static int rpivid_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	// Input formats
+
+	// H.265 Slice only currently
+	if (f->index == 0) {
+		f->pixelformat = V4L2_PIX_FMT_HEVC_SLICE;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int rpivid_hevc_validate_sps(const struct v4l2_ctrl_hevc_sps * const sps)
+{
+	const unsigned int ctb_log2_size_y =
+			sps->log2_min_luma_coding_block_size_minus3 + 3 +
+			sps->log2_diff_max_min_luma_coding_block_size;
+	const unsigned int min_tb_log2_size_y =
+			sps->log2_min_luma_transform_block_size_minus2 + 2;
+	const unsigned int max_tb_log2_size_y = min_tb_log2_size_y +
+			sps->log2_diff_max_min_luma_transform_block_size;
+
+	/* Local limitations */
+	if (sps->pic_width_in_luma_samples < 32 ||
+	    sps->pic_width_in_luma_samples > 4096)
+		return 0;
+	if (sps->pic_height_in_luma_samples < 32 ||
+	    sps->pic_height_in_luma_samples > 4096)
+		return 0;
+	if (!(sps->bit_depth_luma_minus8 == 0 ||
+	      sps->bit_depth_luma_minus8 == 2))
+		return 0;
+	if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+		return 0;
+	if (sps->chroma_format_idc != 1)
+		return 0;
+
+	/*  Limits from H.265 7.4.3.2.1 */
+	if (sps->log2_max_pic_order_cnt_lsb_minus4 > 12)
+		return 0;
+	if (sps->sps_max_dec_pic_buffering_minus1 > 15)
+		return 0;
+	if (sps->sps_max_num_reorder_pics >
+				sps->sps_max_dec_pic_buffering_minus1)
+		return 0;
+	if (ctb_log2_size_y > 6)
+		return 0;
+	if (max_tb_log2_size_y > 5)
+		return 0;
+	if (max_tb_log2_size_y > ctb_log2_size_y)
+		return 0;
+	if (sps->max_transform_hierarchy_depth_inter >
+				(ctb_log2_size_y - min_tb_log2_size_y))
+		return 0;
+	if (sps->max_transform_hierarchy_depth_intra >
+				(ctb_log2_size_y - min_tb_log2_size_y))
+		return 0;
+	/* Check pcm stuff */
+	if (sps->num_short_term_ref_pic_sets > 64)
+		return 0;
+	if (sps->num_long_term_ref_pics_sps > 32)
+		return 0;
+	return 1;
+}
+
+static inline int is_sps_set(const struct v4l2_ctrl_hevc_sps * const sps)
+{
+	return sps && sps->pic_width_in_luma_samples != 0;
+}
+
+static u32 pixelformat_from_sps(const struct v4l2_ctrl_hevc_sps * const sps,
+				const int index)
+{
+	u32 pf = 0;
+
+	// Use width 0 as a signifier of unsetness
+	if (!is_sps_set(sps)) {
+		/* Treat this as an error? For now return both */
+		if (index == 0)
+			pf = V4L2_PIX_FMT_NV12_COL128;
+		else if (index == 1)
+			pf = V4L2_PIX_FMT_NV12_10_COL128;
+	} else if (index == 0 && rpivid_hevc_validate_sps(sps)) {
+		if (sps->bit_depth_luma_minus8 == 0)
+			pf = V4L2_PIX_FMT_NV12_COL128;
+		else if (sps->bit_depth_luma_minus8 == 2)
+			pf = V4L2_PIX_FMT_NV12_10_COL128;
+	}
+
+	return pf;
+}
+
+static struct v4l2_pix_format_mplane
+rpivid_hevc_default_dst_fmt(struct rpivid_ctx * const ctx)
+{
+	const struct v4l2_ctrl_hevc_sps * const sps =
+		rpivid_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS);
+	struct v4l2_pix_format_mplane pix_fmt = {
+		.width = sps->pic_width_in_luma_samples,
+		.height = sps->pic_height_in_luma_samples,
+		.pixelformat = pixelformat_from_sps(sps, 0)
+	};
+
+	rpivid_prepare_dst_format(&pix_fmt);
+	return pix_fmt;
+}
+
+static u32 rpivid_hevc_get_dst_pixelformat(struct rpivid_ctx * const ctx,
+					   const int index)
+{
+	const struct v4l2_ctrl_hevc_sps * const sps =
+		rpivid_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS);
+
+	return pixelformat_from_sps(sps, index);
+}
+
+static int rpivid_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	struct rpivid_ctx * const ctx = rpivid_file2ctx(file);
+
+	const u32 pf = rpivid_hevc_get_dst_pixelformat(ctx, f->index);
+
+	if (pf == 0)
+		return -EINVAL;
+
+	f->pixelformat = pf;
+	return 0;
+}
+
+static int rpivid_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct rpivid_ctx *ctx = rpivid_file2ctx(file);
+
+	if (!ctx->dst_fmt_set)
+		ctx->dst_fmt = rpivid_hevc_default_dst_fmt(ctx);
+	f->fmt.pix_mp = ctx->dst_fmt;
+	return 0;
+}
+
+static int rpivid_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct rpivid_ctx *ctx = rpivid_file2ctx(file);
+
+	f->fmt.pix_mp = ctx->src_fmt;
+	return 0;
+}
+
+static inline void copy_color(struct v4l2_pix_format_mplane *d,
+			      const struct v4l2_pix_format_mplane *s)
+{
+	d->colorspace   = s->colorspace;
+	d->xfer_func    = s->xfer_func;
+	d->ycbcr_enc    = s->ycbcr_enc;
+	d->quantization = s->quantization;
+}
+
+static int rpivid_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct rpivid_ctx *ctx = rpivid_file2ctx(file);
+	const struct v4l2_ctrl_hevc_sps * const sps =
+		rpivid_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS);
+	u32 pixelformat;
+	int i;
+
+	for (i = 0; (pixelformat = pixelformat_from_sps(sps, i)) != 0; i++) {
+		if (f->fmt.pix_mp.pixelformat == pixelformat)
+			break;
+	}
+
+	// If we can't use requested fmt then set to default
+	if (pixelformat == 0) {
+		pixelformat = pixelformat_from_sps(sps, 0);
+		// If we don't have a default then give up
+		if (pixelformat == 0)
+			return -EINVAL;
+	}
+
+	// We don't have any way of finding out colourspace so believe
+	// anything we are told - take anything set in src as a default
+	if (f->fmt.pix_mp.colorspace == V4L2_COLORSPACE_DEFAULT)
+		copy_color(&f->fmt.pix_mp, &ctx->src_fmt);
+
+	f->fmt.pix_mp.pixelformat = pixelformat;
+	return rpivid_prepare_dst_format(&f->fmt.pix_mp);
+}
+
+static int rpivid_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	if (rpivid_prepare_src_format(&f->fmt.pix_mp)) {
+		// Set default src format
+		f->fmt.pix_mp.pixelformat = RPIVID_SRC_PIXELFORMAT_DEFAULT;
+		rpivid_prepare_src_format(&f->fmt.pix_mp);
+	}
+	return 0;
+}
+
+static int rpivid_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct rpivid_ctx *ctx = rpivid_file2ctx(file);
+	struct vb2_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (vb2_is_busy(vq))
+		return -EBUSY;
+
+	ret = rpivid_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	ctx->dst_fmt = f->fmt.pix_mp;
+	ctx->dst_fmt_set = 1;
+
+	return 0;
+}
+
+static int rpivid_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct rpivid_ctx *ctx = rpivid_file2ctx(file);
+	struct vb2_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (vb2_is_busy(vq))
+		return -EBUSY;
+
+	ret = rpivid_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	ctx->src_fmt = f->fmt.pix_mp;
+	ctx->dst_fmt_set = 0;  // Setting src invalidates dst
+
+	vq->subsystem_flags |=
+		VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
+
+	/* Propagate colorspace information to capture. */
+	copy_color(&ctx->dst_fmt, &f->fmt.pix_mp);
+	return 0;
+}
+
+const struct v4l2_ioctl_ops rpivid_ioctl_ops = {
+	.vidioc_querycap		= rpivid_querycap,
+
+	.vidioc_enum_fmt_vid_cap	= rpivid_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap_mplane	= rpivid_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap_mplane	= rpivid_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap_mplane	= rpivid_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out	= rpivid_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out_mplane	= rpivid_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out_mplane	= rpivid_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out_mplane	= rpivid_s_fmt_vid_out,
+
+	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
+	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
+	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
+	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
+	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
+	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
+	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
+
+	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
+	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
+
+	.vidioc_try_decoder_cmd		= v4l2_m2m_ioctl_stateless_try_decoder_cmd,
+	.vidioc_decoder_cmd		= v4l2_m2m_ioctl_stateless_decoder_cmd,
+
+	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+};
+
+static int rpivid_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
+			      unsigned int *nplanes, unsigned int sizes[],
+			      struct device *alloc_devs[])
+{
+	struct rpivid_ctx *ctx = vb2_get_drv_priv(vq);
+	struct v4l2_pix_format_mplane *pix_fmt;
+
+	if (V4L2_TYPE_IS_OUTPUT(vq->type))
+		pix_fmt = &ctx->src_fmt;
+	else
+		pix_fmt = &ctx->dst_fmt;
+
+	if (*nplanes) {
+		if (sizes[0] < pix_fmt->plane_fmt[0].sizeimage)
+			return -EINVAL;
+	} else {
+		sizes[0] = pix_fmt->plane_fmt[0].sizeimage;
+		*nplanes = 1;
+	}
+
+	return 0;
+}
+
+static void rpivid_queue_cleanup(struct vb2_queue *vq, u32 state)
+{
+	struct rpivid_ctx *ctx = vb2_get_drv_priv(vq);
+	struct vb2_v4l2_buffer *vbuf;
+
+	for (;;) {
+		if (V4L2_TYPE_IS_OUTPUT(vq->type))
+			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		else
+			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+		if (!vbuf)
+			return;
+
+		v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
+					   &ctx->hdl);
+		v4l2_m2m_buf_done(vbuf, state);
+	}
+}
+
+static int rpivid_buf_out_validate(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	vbuf->field = V4L2_FIELD_NONE;
+	return 0;
+}
+
+static int rpivid_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct rpivid_ctx *ctx = vb2_get_drv_priv(vq);
+	struct v4l2_pix_format_mplane *pix_fmt;
+
+	if (V4L2_TYPE_IS_OUTPUT(vq->type))
+		pix_fmt = &ctx->src_fmt;
+	else
+		pix_fmt = &ctx->dst_fmt;
+
+	if (vb2_plane_size(vb, 0) < pix_fmt->plane_fmt[0].sizeimage)
+		return -EINVAL;
+
+	vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage);
+
+	return 0;
+}
+
+/* Only stops the clock if streaom off on both output & capture */
+static void stop_clock(struct rpivid_dev *dev, struct rpivid_ctx *ctx)
+{
+	if (ctx->src_stream_on ||
+	    ctx->dst_stream_on ||
+	    !ctx->clk_req)
+		return;
+
+	clk_request_done(ctx->clk_req);
+	ctx->clk_req = NULL;
+
+	clk_disable_unprepare(dev->clock);
+}
+
+/* Always starts the clock if it isn't already on this ctx */
+static int start_clock(struct rpivid_dev *dev, struct rpivid_ctx *ctx)
+{
+	long max_hevc_clock;
+	int rv;
+
+	if (ctx->clk_req)
+		return 0;
+
+	max_hevc_clock = clk_round_rate(dev->clock, ULONG_MAX);
+
+	ctx->clk_req = clk_request_start(dev->clock, max_hevc_clock);
+	if (!ctx->clk_req) {
+		dev_err(dev->dev, "Failed to set clock rate\n");
+		return -EIO;
+	}
+
+	rv = clk_prepare_enable(dev->clock);
+	if (rv) {
+		dev_err(dev->dev, "Failed to enable clock\n");
+		clk_request_done(ctx->clk_req);
+		ctx->clk_req = NULL;
+		return rv;
+	}
+
+	return 0;
+}
+
+static int rpivid_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct rpivid_ctx *ctx = vb2_get_drv_priv(vq);
+	struct rpivid_dev *dev = ctx->dev;
+	int ret = 0;
+
+	if (!V4L2_TYPE_IS_OUTPUT(vq->type)) {
+		ctx->dst_stream_on = 1;
+		goto ok;
+	}
+
+	if (ctx->src_fmt.pixelformat != V4L2_PIX_FMT_HEVC_SLICE) {
+		ret = -EINVAL;
+		goto fail_cleanup;
+	}
+
+	if (ctx->src_stream_on)
+		goto ok;
+
+	ret = start_clock(dev, ctx);
+	if (ret)
+		goto fail_cleanup;
+
+	if (dev->dec_ops->start)
+		ret = dev->dec_ops->start(ctx);
+	if (ret)
+		goto fail_stop_clock;
+
+	ctx->src_stream_on = 1;
+ok:
+	return 0;
+
+fail_stop_clock:
+	stop_clock(dev, ctx);
+fail_cleanup:
+	v4l2_err(&dev->v4l2_dev, "%s: qtype=%d: FAIL\n", __func__, vq->type);
+	rpivid_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
+	return ret;
+}
+
+static void rpivid_stop_streaming(struct vb2_queue *vq)
+{
+	struct rpivid_ctx *ctx = vb2_get_drv_priv(vq);
+	struct rpivid_dev *dev = ctx->dev;
+
+	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+		ctx->src_stream_on = 0;
+		if (dev->dec_ops->stop)
+			dev->dec_ops->stop(ctx);
+	} else {
+		ctx->dst_stream_on = 0;
+	}
+
+	rpivid_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
+
+	vb2_wait_for_all_buffers(vq);
+
+	stop_clock(dev, ctx);
+}
+
+static void rpivid_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct rpivid_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static void rpivid_buf_request_complete(struct vb2_buffer *vb)
+{
+	struct rpivid_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
+}
+
+static struct vb2_ops rpivid_qops = {
+	.queue_setup		= rpivid_queue_setup,
+	.buf_prepare		= rpivid_buf_prepare,
+	.buf_queue		= rpivid_buf_queue,
+	.buf_out_validate	= rpivid_buf_out_validate,
+	.buf_request_complete	= rpivid_buf_request_complete,
+	.start_streaming	= rpivid_start_streaming,
+	.stop_streaming		= rpivid_stop_streaming,
+	.wait_prepare		= vb2_ops_wait_prepare,
+	.wait_finish		= vb2_ops_wait_finish,
+};
+
+int rpivid_queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq)
+{
+	struct rpivid_ctx *ctx = priv;
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct rpivid_buffer);
+	src_vq->min_buffers_needed = 1;
+	src_vq->ops = &rpivid_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->lock = &ctx->ctx_mutex;
+	src_vq->dev = ctx->dev->dev;
+	src_vq->supports_requests = true;
+	src_vq->requires_requests = true;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct rpivid_buffer);
+	dst_vq->min_buffers_needed = 1;
+	dst_vq->ops = &rpivid_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->lock = &ctx->ctx_mutex;
+	dst_vq->dev = ctx->dev->dev;
+
+	return vb2_queue_init(dst_vq);
+}
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_video.h linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_video.h
--- linux-5.10.52-orig/drivers/staging/media/rpivid/rpivid_video.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.10.52-v7l+/drivers/staging/media/rpivid/rpivid_video.h	2021-07-25 16:46:25.637961078 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:4 @
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Raspberry Pi HEVC driver
+ *
+ * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
+ *
+ * Based on the Cedrus VPU driver, that is:
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#ifndef _RPIVID_VIDEO_H_
+#define _RPIVID_VIDEO_H_
+
+struct rpivid_format {
+	u32		pixelformat;
+	u32		directions;
+	unsigned int	capabilities;
+};
+
+extern const struct v4l2_ioctl_ops rpivid_ioctl_ops;
+
+int rpivid_queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq);
+
+size_t rpivid_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8);
+size_t rpivid_round_up_size(const size_t x);
+
+int rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt);
+int rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt);
+
+#endif
diff -Nur --no-dereference linux-5.10.52-orig/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c linux-5.10.52-v7l+/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
--- linux-5.10.52-orig/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c	2021-07-20 16:05:59.000000000 +0200
+++ linux-5.10.52-v7l+/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c	2021-07-25 16:46:26.507946492 +0200
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:9 @
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #include "bcm2835.h"
+#include <soc/bcm2835/raspberrypi-firmware.h>
 
-static bool enable_hdmi;
+static bool enable_hdmi, enable_hdmi0, enable_hdmi1;
 static bool enable_headphones;
 static bool enable_compat_alsa = true;
-static int num_channels = MAX_SUBSTREAMS;
 
 module_param(enable_hdmi, bool, 0444);
 MODULE_PARM_DESC(enable_hdmi, "Enables HDMI virtual audio device");
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:25 @
 module_param(enable_compat_alsa, bool, 0444);
 MODULE_PARM_DESC(enable_compat_alsa,
 		 "Enables ALSA compatibility virtual audio device");
-module_param(num_channels, int, 0644);
-MODULE_PARM_DESC(num_channels, "Number of audio channels (default: 8)");
 
 static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res)
 {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:83 @
 	if (err)
 		return err;
 
-	err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
+	err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true);
+	if (err)
+		return err;
+
+	err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true);
 	if (err)
 		return err;
 
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:114 @
 	.newctl = snd_bcm2835_new_ctl,
 };
 
-static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
+static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = {
 	.driver = {
 		.name = "bcm2835_hdmi",
 		.owner = THIS_MODULE,
 	},
-	.shortname = "bcm2835 HDMI",
-	.longname  = "bcm2835 HDMI",
+	.shortname = "bcm2835 HDMI 1",
+	.longname  = "bcm2835 HDMI 1",
 	.minchannels = 1,
 	.newpcm = bcm2835_audio_simple_newpcm,
 	.newctl = snd_bcm2835_new_hdmi_ctl,
-	.route = AUDIO_DEST_HDMI
+	.route = AUDIO_DEST_HDMI0
+};
+
+static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = {
+	.driver = {
+		.name = "bcm2835_hdmi",
+		.owner = THIS_MODULE,
+	},
+	.shortname = "bcm2835 HDMI 2",
+	.longname  = "bcm2835 HDMI 2",
+	.minchannels = 1,
+	.newpcm = bcm2835_audio_simple_newpcm,
+	.newctl = snd_bcm2835_new_hdmi_ctl,
+	.route = AUDIO_DEST_HDMI1
 };
 
 static struct bcm2835_audio_driver bcm2835_audio_headphones = {
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:164 @
 		.is_enabled = &enable_compat_alsa,
 	},
 	{
-		.audio_driver = &bcm2835_audio_hdmi,
-		.is_enabled = &enable_hdmi,
+		.audio_driver = &bcm2835_audio_hdmi0,
+		.is_enabled = &enable_hdmi0,
+	},
+	{
+		.audio_driver = &bcm2835_audio_hdmi1,
+		.is_enabled = &enable_hdmi1,
 	},
 	{
 		.audio_driver = &bcm2835_audio_headphones,
@ linux-5.10.52-v7l+/arch/arm/boot/dts/bcm2708.dtsi:316 @
 	return 0;
 }
 
+static void set_hdmi_enables(struct device *dev)
+{
+	struct device_node *firmware_node;
+	struct rpi_firmware *firmware;
+	u32 num_displays, i, display_id;
+	int ret;
+
+	firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
+	firmware = rpi_firmware_get(firmware_node);
+
+	if (!firmware)
+		return;
+
+	of_node_put(firmware_node);
+
+	ret = rpi_firmware_property(firmware,
+				    RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
+				    &num_displays, sizeof(u32));
+
+	if (ret)
+		return;
+
+	for (i = 0; i < num_displays; i++) {
+		display_id = i;
+		ret = rpi_firmware_property(firmware,
+				RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
+				&display_id, sizeof(display_id));
+		if (!ret) {
+			if (display_id == 2)
+				enable_hdmi0 = true;
+			if (display_id == 7)
+				enable_hdmi1 = true;
+		}
+	}
+
+	if (!enable_hdmi0 && enable_hdmi1) {
+		/* Swap them over and reassign route. This means
+		 * that if we only have one connected, it is always named
+		 *  HDMI1, irrespective of if its on port HDMI0 or HDMI1.
+		 *  This should match with the naming of HDMI ports in DRM
+		 */
+		enable_hdmi0 = true;
+		enable_hdmi1 = false;
+		bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1;
+	}
+}
+
 static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	u32 numchans;
 	int err;
 
-	if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) {
-		num_channels = MAX_SUBSTREAMS;
-		dev_warn(dev, "Illegal num_channels value, will use %u\n",
-			 num_channels);
+	err = of_property_read_u32(dev->of_node, "brcm,pwm-channels",
+				   &numchans);
+	if (err) {
+		dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'");
+		return err;
+	}
+
+	if (numchans == 0 || numchans > MAX_SUBSTREAMS) {
+		numchans = MAX_SUBSTREAMS;
+		dev_warn(dev,
+			 "Illegal 'brcm,pwm-channels' value, will use %u\n",
+			 numchans);
+	}
+
+	if (!enable_compat_alsa) {
+		// In this mode, enable analog output by default
+		u32 disable_headphones = 0;
+
+		if (!of_property_read_bool(dev->of_node, "brcm,disable-hdmi"))
+