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>; +}; + +ð_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 = <ð_phy>,"microchip,eee-enabled?"; + tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0"; + eth_led0 = <ð_phy>,"microchip,led-modes:0"; + eth_led1 = <ð_phy>,"microchip,led-modes:4"; + eth_downshift_after = <ð_phy>,"microchip,downshift-after:0"; + eth_max_speed = <ð_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 = <ð1_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 = <ð1>, "interrupts:0", + <ð1_pins>, "brcm,pins:0"; + speed = <ð1>, "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 = <ð1_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 = <ð1>, "interrupts:0", + <ð1_pins>, "brcm,pins:0"; + speed = <ð1>, "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 = <®_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 = <& 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 = <&>,"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", + <>9271>,"interrupts:0", + <>9271>,"irq-gpios:4"; + reset = <&goodix_pins>,"brcm,pins:4", + <>9271>,"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 = <<c2941>, "lltc,resistor-sense:0", + <<c2942>, "lltc,resistor-sense:0", + <<c2943>, "lltc,resistor-sense:0", + <<c2944>, "lltc,resistor-sense:0"; + prescaler-exponent = <<c2941>, "lltc,prescaler-exponent:0", + <<c2942>, "lltc,prescaler-exponent:0", + <<c2943>, "lltc,prescaler-exponent:0", + <<c2944>, "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 = <®_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", + <®_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi0-0-xceiver", + <®_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", + <®_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi0-1-xceiver", + <®_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", + <®_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi1-0-xceiver", + <®_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", + <®_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi1-1-xceiver", + <®_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", + <®_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi1-2-xceiver", + <®_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", + <®_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi2-0-xceiver", + <®_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", + <®_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi2-1-xceiver", + <®_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", + <®_mcp251xfd_xceiver>, "name=reg-mcp251xfd-spi2-2-xceiver", + <®_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", + <®_mcp251xfd_xceiver>, "gpio:4"; + xceiver_active_high = <®_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 = <ð1_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 = <ð1>, "interrupts:0", + <ð1_pins>, "brcm,pins:0"; + speed = <ð1>, "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 = <<070me05000_pins>,"brcm,pins:8", + <<070me05000>,"reset-gpios:4"; + + enable = <<070me05000_pins>,"brcm,pins:0", + <<070me05000>,"enable-gpios:4"; + + dcdc-en = <<070me05000_pins>,"brcm,pins:4", + <<070me05000>,"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 = <ð1_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 = <ð1>, "interrupts:0", + <ð1_pins>, "brcm,pins:0"; + speed = <ð1>, "spi-max-frequency:0"; + cs = <ð1>, "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, ¶ms->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, ®); + 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, ®); + 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 *)®_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, ¤t_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, ¤t_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, ¤t_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, + ¤t_timings); + + if (ret < 0) + return ret; + + if (v4l2_match_dv_timings(timings, ¤t_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, ®s[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")) +